【发布时间】:2016-11-08 20:40:02
【问题描述】:
我正在使用自定义 STRAGG,它在 4000 处截断字符串,如下所示,
从 TBL_CHANGE_SUMMARY 中选择 STRAGG('000 - ' || CHANGE_TEXT)
这在开发 oracle 服务器中运行良好,但是在生产环境中会出现以下错误。
ORA-06502:PL/SQL:数字或值错误:字符串缓冲区太小
以下是修改 STRAGG 的自定义代码,
CREATE OR REPLACE TYPE "STRING_AGG_TYPE" as object
(
total varchar2(4000),
static function ODCIAggregateInitialize(sctx IN OUT string_agg_type) return number,
member function ODCIAggregateIterate(self IN OUT string_agg_type,
value IN varchar2) return number,
member function ODCIAggregateTerminate(self IN string_agg_type,
returnValue OUT varchar2,
flags IN number) return number,
member function ODCIAggregateMerge(self IN OUT string_agg_type,
ctx2 IN string_agg_type) return number
);
CREATE OR REPLACE TYPE BODY "STRING_AGG_TYPE" is
static function ODCIAggregateInitialize(sctx IN OUT string_agg_type ) return number is
begin
sctx := string_agg_type(null);
return ODCIConst.Success;
end;
member function ODCIAggregateIterate(self IN OUT string_agg_type,
value IN varchar2) return number is
BEGIN
--prevent buffer overflow for more than 4,000 characters
IF NVL(LENGTH(self.total), 0) + NVL(LENGTH(VALUE), 0) < 3930 THEN
IF (self.total IS NULL) THEN
self.total := VALUE;
ELSIF INSTR ('~#~' || self.total || '~#~', '~#~' || VALUE || '~#~',1,1) = 0 AND INSTR ( self.total, '[TRUNCATED]',1,1) = 0 THEN
self.total := self.total || '~#~' || VALUE;
END IF;
ELSE
IF INSTR ( self.total, '[TRUNCATED]',1,1) = 0 THEN
self.total := self.total || '[TRUNCATED]';
END IF;
END IF;
RETURN ODCIConst.Success;
END;
MEMBER FUNCTION ODCIAggregateTerminate (self IN string_agg_type,
returnValue OUT VARCHAR2,
flags IN NUMBER)
RETURN NUMBER
IS
BEGIN
IF INSTR ( self.total, '[TRUNCATED]',1,1) = 0 THEN
returnValue := LTRIM (self.total, '~#~');
ELSE
IF (self.total IS NOT NULL) THEN
returnValue := SUBSTR(self.total, 1, INSTR ( self.total, '[TRUNCATED]',1,1) - 1) || '..... Truncated because of system limitation';
END IF;
END IF;
RETURN ODCIConst.Success;
END;
member function ODCIAggregateMerge(self IN OUT string_agg_type,
ctx2 IN string_agg_type) return number is
begin
self.total := self.total || ctx2.total;
return ODCIConst.Success;
end;
end;
为什么相同的代码会有不同的行为?在 Oracle 环境中我需要更改或设置什么吗?
以下是其在各个环境中对字符的用法的不同,
Character set in Production,
NLS_CHARACTERSET AL32UTF8
NLS_NCHAR_CHARACTERSET UTF8
NLS_LENGTH_SEMANTICS BYTE
Character set in Development,
NLS_CHARACTERSET AL32UTF8
NLS_NCHAR_CHARACTERSET AL16UTF16
NLS_LENGTH_SEMANTICS BYTE
【问题讨论】:
-
那么,错误在哪一行?您必须在 prod 中有不同的数据,不是吗?
-
您使用的是什么字符集?您能否运行此查询:
select * from nls_database_parameters where parameter like '%SEMA%' or parameter like '%SET';并将其结果附加到问题中? -
错误行不会出现在 STRING_AGG_TYPE 中,但会出现在实际的 sql 中,这与我的第一个示例“select STRAGG('000 - ' || CHANGE_TEXT) from...”相同。是的,它是生产中的不同数据,但我不认为它不是数据,因为我探索了许多数据大小的场景,它总是在开发环境中工作。
-
谢谢,已添加字符集信息。
标签: oracle overflow aggregation truncate