提问人:ZeRoOo 提问时间:11/3/2023 最后编辑:MT0ZeRoOo 更新时间:11/5/2023 访问量:122
在 Oracle PLSQL 中将动态字符串分配给 varchar2/clob 变量时发生错误(没有更多数据可从套接字读取)
Error occured (No more data to read from socket) while assigning a dynamic string to varchar2/clob variable in Oracle PLSQL
问:
我通过连接多个参数/值并分配给包中定义的局部变量来创建动态字符串。一旦我编译了包连接,就会出现错误,指出“没有更多数据可从套接字读取”。
由于这是连接断开的一般错误,但在编译包时也是如此,这让我想知道查看代码,我发现当使用多个串联的动态字符串被分配给 clob 变量时,就会发生这种情况。
我已经在一个匿名块中简化并复制了该场景。
当连接字符串长度超过 2277 个字符时,它会导致错误,而变量使用 varchar2(4000 char) 声明。如果我删除串联并简单地传递字符串,它就可以按照声明的限制(在这种情况下最多 4000 个字符)正常工作。
我正在使用 Oracle Database 19c 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;
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;
/
此外,如果我删除一个字符(长度不超过 2277),那么它就会按预期工作。
无串联(按预期工作):
select length(
'1234567890
-- (removed the part, it is copy paste of 1234567890 until characters length reaches 4000)
01234567890'
) len_string from dual;
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;
/
Oracle 数据库版本:
答:
我相信您的过度连接代码遇到了堆栈溢出异常,类似于此 Oracle 支持文档中描述的异常:“当 IN 子句很长时,选择失败并出现 ORA-3113 (文档 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 上找到了文档:“Excp.代码: 0xc00000fd Excp.类型:STACK_OVER标志:0x00000000”。
第一个建议的解决方案是更改 oracle.exe 线程的堆栈大小。尽管我能找到的有关此方法的消息来源警告说,它可能会导致其他问题,并且您需要记住在修补后重新应用更改。该修复将允许更多串联,但不一定允许无限量的串联。以下是在 Windows 上对我有用的(修改后的)说明:
- 使用 NEXT 检查默认堆栈大小的当前值:orastack %ORACLE_HOME%\bin\oracle.exe
- 停止数据库(在 Windows 上,使用类似“OracleServiceSID”的名称停止服务)
- 使用下一个命令将默认堆栈大小修改为更高的值:orastack %ORACLE_HOME%\bin\oracle.exe <new_value>
- 启动数据库(在 Windows 上,启动服务)
- 测试
但我同意 Paul W 的观点,即您最好通过更改代码来避免这种问题,而不是尝试以官方方式修复。
如果您确实需要保留串联代码,但您也不能修改每个 oracle.exe 文件(例如,如果您使用的是 Amazon RDS 或 Oracle 自治数据库等托管数据库),则可能还有另一种解决方案。
我敢打赌,中断的代码是 PL/SQL 解析器的一部分。堆栈溢出在递归函数中最为常见,我敢打赌 Oracle 使用递归下降解析器,它为每个关键字调用一个函数。在 Oracle 代码的某个地方,我敢打赌,每次找到令牌时都会调用一个名为 C 函数的 C,并且每当同一语句中有另一个函数时,该函数都会调用自身。CONCAT_OPERATOR
||
||
由于该错误在解析器中,因此您只需要避免一次。在您可以完全控制的位置创建一个 Oracle 数据库。使用 orastack.exe 仅为该实例增加堆栈空间。将中断代码放入单个过程中,对其进行编译,然后[包装它]。包装源代码是为了混淆源代码,使其他人无法读取它。但这种混淆并不是什么超级安全的加密——它只是存储过程的字节码。
该字节代码不会再次被分析,因此在安装或运行新的包装过程时,不应发生分析器错误。
评论
||