【发布时间】:2020-02-12 15:51:42
【问题描述】:
将 50661 个字符的 XML 文档加载到 Oracle XMLTABLE 中时,它似乎在位置 40000 处去除了一个空格字符,但继续处理 XML 文档的其余部分,为什么?
我已经包含一个简单的测试脚本来演示 Oracle 数据库 11g 企业版版本 11.2.0.4.0 - 64 位生产上的这个问题
create or replace TYPE SPCBH_V_COLUMNS_OBJECT AS OBJECT
(
COLUMN_ID NUMBER(3),
COLUMN_NAME VARCHAR2(15),
DATA_TYPE VARCHAR2(16),
PRECISION NUMBER(3),
MAX_LENGTH NUMBER(6),
SCALE NUMBER(3),
IS_NULLABLE NUMBER(1),
IS_IDENTITY NUMBER(1),
IDENTITY_NAME VARCHAR2(50),
SEED_VALUE NUMBER(3),
INCREMENT_VALUE NUMBER(3),
LAST_VALUE NUMBER(3),
DEFAULT_CONSTRAINT_NAME VARCHAR2(51),
DEFAULT_CONSTRAINT_TYPE VARCHAR2(3),
DEFAULT_CONSTRAINT_TYPE_DESC VARCHAR2(61),
DEFAULT_CONSTRAINT_DEFINITION VARCHAR2(4000),
COLUMN_USER_NAME VARCHAR2(100),
COLUMN_PARENT_NAME VARCHAR2(9),
COLUMN_PARENT_COLUMN_NAME VARCHAR2(16),
COLUMN_PARENT_SUB_TYPE VARCHAR2(9),
COLUMN_COMMENTS VARCHAR2(2001),
COLUMN_UPDATED_FLAG VARCHAR2(2),
COLUMN_AUDITED_FLAG VARCHAR2(2)
);
create or replace TYPE SPCBH_V_COLUMNS_TABLE AS TABLE OF SPCBH_V_COLUMNS_OBJECT;
这里是测试匿名块
declare
V_XML_PATH VARCHAR2(200);
V_PARSED_COLUMNS SPCBH_V_COLUMNS_TABLE;
DDLXMLSTRING XMLTYPE;
V_TEMP_XML_PATH VARCHAR2(200);
v_length int;
BEGIN
V_XML_PATH := '\\ipcbhcs01\systems\231\PW6\Staging\PW-0231-70\AZLASRL.XML';
V_TEMP_XML_PATH := REPLACE(SUBSTR(V_XML_PATH,INSTR(V_XML_PATH,'\',1,4),200),'\','/');
SELECT XMLTYPE(bfilename('PWSTAGING',V_TEMP_XML_PATH),NLS_CHARSET_ID('WE8ISO8859P15'))
INTO DDLXMLSTRING FROM dual ;
WITH
table_data AS (
SELECT td.*
FROM XMLTABLE('/xml/table'
PASSING (ddlxmlstring)
COLUMNS
table_name VARCHAR2(50) PATH '@table_name',
table_user_name VARCHAR2(100) PATH 'table_user_name',
table_comments CLOB PATH 'table_comments',
table_file_sub_type VARCHAR2(10) PATH 'table_file_sub_type',
table_product VARCHAR2(3) PATH 'table_product',
table_directory VARCHAR2(10) PATH 'table_directory',
table_number NUMBER(5) PATH 'table_number',
table_prim_maint_view VARCHAR2(30) PATH 'table_prim_maint_view',
table_stf_flag VARCHAR2(2) PATH 'table_stf_flag',
table_public VARCHAR2(2) PATH 'table_public',
table_updated_flag VARCHAR2(2) PATH 'table_updated_flag',
table_audited_flag VARCHAR2(2) PATH 'table_audited_flag',
columns XMLTYPE PATH 'columns',
indexes XMLTYPE PATH 'indexes'
) td),
column_data AS (
SELECT cd.*
FROM table_data td,
XMLTABLE('/columns/column'
PASSING td.columns
COLUMNS
column_id NUMBER(3) PATH '@column_id',
column_name VARCHAR2(15) PATH 'column_name',
data_type VARCHAR2(16) PATH 'data_type',
precision NUMBER(3) PATH 'precision',
max_length NUMBER(6) PATH 'max_length',
scale NUMBER(3) PATH 'scale',
is_nullable VARCHAR2(1) PATH 'is_nullable',
is_identity VARCHAR2(1) PATH 'is_identity',
identity_name VARCHAR2(50) PATH 'identity_name',
seed_value NUMBER(3) PATH 'seed_value',
increment_value NUMBER(3) PATH 'increment_value',
last_value NUMBER(3) PATH 'last_value',
default_constraint_name VARCHAR2(51) PATH 'default_constraint_name',
default_constraint_type VARCHAR2(3) PATH 'default_constraint_type',
default_constraint_type_desc VARCHAR2(61) PATH 'default_constraint_type_desc',
default_constraint_definition VARCHAR2(4000) PATH 'default_constraint_definition',
column_user_name VARCHAR2(100) PATH 'column_user_name',
column_parent_name VARCHAR2(9) PATH 'column_parent_name',
column_parent_column_name VARCHAR2(16) PATH 'column_parent_column_name',
column_parent_sub_type VARCHAR2(9) PATH 'column_parent_sub_type',
column_comments VARCHAR2(2001) PATH 'column_comments',
column_updated_flag VARCHAR2(2) PATH 'column_updated_flag',
column_audited_flag VARCHAR2(2) PATH 'column_audited_flag'
) cd )
SELECT SPCBH_V_COLUMNS_OBJECT(
COLUMN_ID,
COLUMN_NAME,
DATA_TYPE,
PRECISION,
MAX_LENGTH,
SCALE,
IS_NULLABLE,
IS_IDENTITY,
IDENTITY_NAME,
SEED_VALUE,
INCREMENT_VALUE,
LAST_VALUE,
DEFAULT_CONSTRAINT_NAME,
DEFAULT_CONSTRAINT_TYPE,
DEFAULT_CONSTRAINT_TYPE_DESC,
DEFAULT_CONSTRAINT_DEFINITION,
COLUMN_USER_NAME,
COLUMN_PARENT_NAME,
COLUMN_PARENT_COLUMN_NAME,
COLUMN_PARENT_SUB_TYPE,
COLUMN_COMMENTS,
COLUMN_UPDATED_FLAG,
COLUMN_AUDITED_FLAG)
BULK COLLECT INTO V_PARSED_COLUMNS
FROM column_data;
select length(DDLXMLSTRING.getClobVal()) into v_length from dual;
dbms_output.put_line('length(DDLXMLSTRING):'||v_length);
DBMS_OUTPUT.PUT_LINE(RPAD('COLUMN_ID',10) || RPAD('COLUMN_NAME',18) || RPAD('COLUMN_PARENT_COLUMN_NAME',30) || RPAD('COLUMN_PARENT_SUB_TYPE',30));
FOR MY_CURSOR IN (SELECT
COLUMN_ID,
COLUMN_NAME,
DATA_TYPE,
PRECISION,
MAX_LENGTH,
SCALE,
IS_NULLABLE,
IS_IDENTITY,
IDENTITY_NAME,
SEED_VALUE,
INCREMENT_VALUE,
LAST_VALUE,
DEFAULT_CONSTRAINT_NAME,
DEFAULT_CONSTRAINT_TYPE,
DEFAULT_CONSTRAINT_TYPE_DESC,
DEFAULT_CONSTRAINT_DEFINITION,
COLUMN_USER_NAME,
COLUMN_PARENT_NAME,
COLUMN_PARENT_COLUMN_NAME,
COLUMN_PARENT_SUB_TYPE,
COLUMN_COMMENTS,
COLUMN_UPDATED_FLAG,
COLUMN_AUDITED_FLAG
FROM TABLE(V_PARSED_COLUMNS) ORDER BY COLUMN_ID)
LOOP
DBMS_OUTPUT.PUT_LINE(RPAD(MY_CURSOR.COLUMN_ID ,10) || RPAD(MY_CURSOR.COLUMN_NAME,18) || RPAD(NVL(MY_CURSOR.COLUMN_PARENT_COLUMN_NAME,'NULL'),30) || RPAD(NVL(MY_CURSOR.COLUMN_PARENT_SUB_TYPE,'NULL'),30));
END LOOP;
end;
在位置 40000,XML 阅读器似乎跳过了空格并加载了带有 NULL 的 XMLTYPE,这在其他任何地方都不会发生。如果我将值更改为单个空格以外的值,例如两个空格,或“ABC”,它工作正常。
XML 文档和屏幕截图显示了该文档的第 40,000 个字符,可在https://drive.google.com/open?id=124zDZYiNJnNzenQScgCbT3RKk7SApYPO找到
您需要指向一个可用的数据库目录。
【问题讨论】:
-
它似乎不是第 40,000 个字符,而是第 39,999 个字符。 minimal reproducible exampledb<>fiddle。
-
另外,为什么将数据读入一个集合只是把它放回游标中循环打印出来呢?您可以遍历集合并跳过光标;否则跳过集合并将
XMLTABLE查询作为游标打开。 -
更新了db<>fiddle 对不同字符串的测试。它似乎不会影响 Oracle 18c db<>fiddle
-
感谢您提供了一个极简可重现示例的优秀示例。这段代码只是一个更大的 SP 的一部分,它不只是用光标在 XMLTABLE 中旋转,它是为测试添加的以显示无效结果。
-
我目前无权访问 12c 实例,并已联系我们组织中的一些 DBA 让他们在 12c 上也进行测试。你同意这是一个至少 11g 的错误吗?