在Oracle PLSQL中将动态字符串分配给varchar 2/clob变量时出错(没有更多数据可从套接字读取)

z8dt9xmd  于 2023-11-17  发布在  Oracle
关注(0)|答案(1)|浏览(111)

我通过连接多个参数/值并赋值给包中定义的局部变量来创建一个动态字符串。一旦我编译包,连接就会下降,并显示错误"No more data to read from socket“。
由于这是连接被丢弃的一般错误,但在编译包时也是如此,它让我想知道如何查看代码,我发现它发生在使用多个串联的动态字符串被分配给clob变量时。
我已经在匿名块中简化并复制了该场景。
当连接字符串长度超过2277个字符时,它会导致错误,而变量声明为varchar 2(4000个字符)。如果我删除连接并简单地传递字符串,它可以根据声明的限制正常工作(在这种情况下最多4000个字符)。
Oracle数据库19 c EE

连接(导致错误):

select length(
'1'||'2'||'3'||'4'||'5'||'6'||'7'||'8'||'9'||'0'||
-- (removed the part, it is copy paste of above line until characters length reaches 2278)
'1'||'2'||'3'||'4'||'5'||'6'||'7'||'8'
) len_concat_string from dual;

字符串
Executed Output Screenshot1

declare
v_sql varchar2(4000 char);
begin
v_sql :=
'1'||'2'||'3'||'4'||'5'||'6'||'7'||'8'||'9'||'0'||
'1'||'2'||'3'||'4'||'5'||'6'||'7'||'8'||'9'||'0'||
-- (removed the part, it is copy paste of above line until characters length reaches 2278)
'1'||'2'||'3'||'4'||'5'||'6'||'7'||'8'
;
end;
/


Executed Output Screenshot2
此外,如果我删除一个字符(长度最多为2277),那么它就会像预期的那样工作。
Executed Output Screenshot3

无连接(按预期工作):

select length(
'1234567890
-- (removed the part, it is copy paste of 1234567890 until characters length reaches 4000)
01234567890'
) len_string from dual;


Executed Output Screenshot4

declare
v_sql varchar2(4000 char);
begin
v_sql :=
'1234567890
-- (removed the part, it is copy paste of 1234567890 until characters length reaches 4000)
01234567890'
;
end;
/


Executed Output Screenshot5

Oracle数据库版本:

Executed Output Screenshot6

i7uaboj4

i7uaboj41#

我相信您的过度串联代码遇到了堆栈溢出异常错误,类似于此Oracle支持文档中所述的异常错误:“Select Fails with ORA-3113 When IN Clause is Very Long(Doc ID 1351212.1)"。解决方案是更改oracle.exe的线程堆栈大小(这可能很危险),或者重写代码以避免过度串联。
我能够在Windows 10 Pro上的Oracle EE 19.3上重现您的问题。虽然我只得到PL/SQL代码的错误而没有SQL语句的错误。解决此问题很困难,因为ORA-3113错误确实会在预警日志中创建一个条目,它也不会创建一个带有ORA-600错误的跟踪文件。我唯一能找到的记录是文件orclcore.log中的一个小条目。(我不确定文件名的“orcl”部分是基于SID还是始终为“orcl”。)orclcore.log文件包含以下行,这使我在My Oracle Support上找到了该文档:“例外代码:0xc 00000 fd例外类型:STACK_OVER标志:0x 00000000”的值。“
第一个建议的解决方案是更改oracle.exe线程的堆栈大小。尽管我可以找到有关此方法的来源警告说,它可能会引起其他问题,并且您需要记住在打补丁后重新应用更改。此修复将允许更多的连接,但不一定允许无限数量的连接。以下是在Windows上对我有效的(修改后的)说明:

  • 使用下一个命令检查默认堆栈大小的当前值:orastack %ORACLE_HOME%\bin\oracle.exe
  • 停止数据库(在Windows上,停止名称类似“OracleServiceSID”的服务)
  • 使用下一个命令将默认堆栈大小修改为更大的值:orastack %ORACLE_HOME%\bin\oracle.exe<new_value>
  • 启动数据库(在Windows上,启动服务)
  • 测试

但我同意Paul W的观点,这是一种你最好通过代码更改来避免的问题,而不是试图通过官方的方式来解决。
如果您 * 确实 * 需要保留连接代码,但又不能修改每个oracle.exe文件(例如,如果您使用的是Amazon RDS或Oracle Autonomous数据库等托管数据库),则可能有另一种解决方案。
我敢打赌,被破坏的代码是PL/SQL解析器的一部分。堆栈溢出在递归函数中最常见,我敢打赌Oracle使用了递归下降解析器,它为每个关键字调用一个函数。在Oracle代码中的某个地方,我敢打赌,有一个名为CONCAT_OPERATOR的C函数,每次找到标记||时都会调用它。且每次在同一语句中有另一个||时,该函数都会调用它自己。
由于bug位于解析器中,因此您只需避免一次。在您可以完全控制的位置创建一个Oracle数据库。使用orastack.exe为一个示例增加堆栈空间。将破坏性代码放入单个过程中,编译它,然后[把它包起来]。 Package 源代码是为了混淆源代码,使其他人无法阅读它。但这种混淆并不是某种超级安全的加密-它只存储过程的字节码。
该字节代码不会被再次解析,因此当您安装或运行新的、 Package 的过程时,解析器错误应该不会发生。

相关问题