我正在使用自定义STRAGG,它会在4000处截断字符串,如下所示,
从TBL_CHANGE_SUMMARY选择STRAGG('' || 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
答案 0 :(得分:0)
您正在使用AL32UTF8 - 在UTF-8中,某些字符使用1个字节编码,而其他字符占用2个字节或有时4个字节。
您还使用NLS_LENGTH_SEMANTICS = BYTE(这是默认设置)。
这意味着像VARCHAR2(5)
这样的声明将字符串的长度限制为最多 5个字节,不是5个字符。
使用VARCHAR2( 4000 char )
,而非简单VARCHAR2( 4000 )
请查看示例如何工作:
select *
from nls_database_parameters
where parameter like '%SEMA%'
or parameter like '%SET';
PARAMETER VALUE
------------------------- --------------------
NLS_LENGTH_SEMANTICS BYTE
NLS_NCHAR_CHARACTERSET UTF8
NLS_CHARACTERSET AL32UTF8
现在:
declare
x varchar2(10);
begin
x := 'ąśćz123456';
dbms_output.put_line( x );
end;
/
ORA-06502: PL/SQL: błąd liczby lub wartości: character string buffer too small
ORA-06512: przy linia 4
06502. 00000 - "PL/SQL: numeric or value error%s"
*Cause: An arithmetic, numeric, string, conversion, or constraint error
occurred. For example, this error occurs if an attempt is made to
assign the value NULL to a variable declared NOT NULL, or if an
attempt is made to assign an integer larger than 99 to a variable
declared NUMBER(2).
*Action: Change the data, how it is manipulated, or how it is declared so
that values do not violate constraints.
但:
declare
x varchar2(10 char);
begin
x := 'ąśćz123456';
dbms_output.put_line( x );
end;
/
ąśćz123456
PL/SQL procedure successfully completed.