十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

PL/SQL存储过程loop死循环,Codex走TaoToken就能查出缓冲溢出原因

PL/SQL存储过程loop死循环,Codex走TaoToken就能查出缓冲溢出原因 早上的存储过程又一次栽在 loop 里。逻辑不复杂打开一个游标按工资条件查 emp然后 FETCH 出来逐行打印。可偏偏那行exit when cur_emp%notfound被我注释掉之后PL/SQL 窗口开始刷同一行数据刷到 Oracle 直接抛缓冲溢出。我一边把这段代码贴给 Codex一边打开 TaoToken 把 Key 和 Base URL 配好。Codex 看完只指了一句fetch 之后没有退出条件循环怎么可能停下来。1. 一个存储过程死循环先于 ORA-20000 出现1.1 你看到的错误并不是语法错误写 PL/SQL 的人对 ORA-20000 不会陌生但真正读透它的人不多。这个错误后面常跟着ORU-10027: buffer overflow直译是缓冲区溢出。很多帖子的方向是放大dbms_output缓冲区于是让你SET SERVEROUTPUT ON SIZE 100000000甚至SIZE UNLIMITED。调完重跑一样崩。原因不在缓冲区大小而在 FETCH 之后每一次循环都在向缓冲区写内容循环没有出口时再大的缓冲区也只是把爆炸时间延后。1.2 网上的解法为什么绕远了今天这个例子更典型作者是写过很多次存储过程的熟手exit when cur_emp%notfound被注释后第一反应不是检查游标而是怀疑输出设置。论坛里一堆回复也顺着这个方向走越调越远。我自己也踩过所以现在遇到这种「报错在输出、病根在循环」的问题会先把代码丢给 Codex 做静态审查让它把循环结构从头到尾过一遍。2. 现场还原exit when cur_emp%notfound 被注释之后2.1 带注释的坏版本下面是当初运行的匿名块变量名保留原文风格。注意注释掉的那一行就是整个死循环的起点DECLARE TYPE cur_type IS REF CURSOR; cur_emp cur_type; r_emp emp%ROWTYPE; v_sql VARCHAR2(500); BEGIN v_sql : SELECT * FROM emp WHERE sal :sal; OPEN cur_emp FOR v_sql USING input_sal; LOOP FETCH cur_emp INTO r_emp; -- exit when cur_emp%notfound; DBMS_OUTPUT.PUT_LINE(r_emp.ename || - || r_emp.sal); END LOOP; CLOSE cur_emp; END; /虽然没有把exit when cur_emp%notfound删除仅仅注释效果一样FETCH不会自动叫停循环。2.2 loop 里少了什么逐个看循环体OPEN cur_emp FOR v_sql USING 工资打开游标每次FETCH把当前行读到r_emp接着PUT_LINE打印。问题在于FETCH到结果集末尾时只是把cur_emp%NOTFOUND置为 TRUE并不会主动跳出。此时r_emp里保存的是上一次取到的数据所以你会看到同一行内容被反复打印。死循环成立缓冲溢出只是它在 Oracle 外层的表现。2.3 调大 serveroutput 是对症不对因serveroutput管理的是dbms_output服务打开后控制台才能看到输出。但死循环每秒产生几十行字符串默认 20000 字节的缓冲区迅速被填满就算改成SIZE UNLIMITED输出会没完没了还是要停下来。换句话说缺的不是输出容量是循环的退出条件。3. 给 Codex 接上 TaoToken把代码贴过去3.1 去官网创建 Key我不想在多个配置里反复切换官方 Key所以这次换用统一通道。先打开 TaoToken 注册登录后在控制台创建一把 API Key这就是后面配置里的YOUR_API_KEY。模型 ID 不用猜打开官网模型广场以当时列表里能用的为准复制到配置文件即可。3.2 Codex 的 config.toml 指向 TaoTokenCodex 默认读~/.codex/config.toml。在文件里加一个 providermodel YOUR_MODEL_ID model_provider taotoken [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api env_key TAOTOKEN_API_KEY然后设置环境变量export TAOTOKEN_API_KEYYOUR_API_KEY启动codex它就会用 TaoToken 通道去请求模型。这里的关键点是base_url填到接口根路径就够不要加/v1更不要把官网页面地址当成 Base URL 填进来。Codex 只负责分析代码、生成建议并不会真的去连 Oracle这一点后面验证时很重要。4. Codex 的诊断路径fetch 后缺的不是输出是退出条件4.1 把这段贴给 Codex在终端里运行codex exec 请诊断这段 PL/SQL为什么运行后无限循环最后报 buffer overflow然后把 2.1 的匿名块贴在对话里。Codex 会先扫描循环结构通常会指出LOOP中没有EXIT WHEN或IF ... EXITFETCH之后的PUT_LINE在%NOTFOUND为 TRUE 时仍会执行r_emp保留旧值于是输出同一行数据。结论是加上退出条件而不是调整serveroutput。4.2 修复后的版本Codex 给的修复看起来很简单关键位置只加一行DECLARE TYPE cur_type IS REF CURSOR; cur_emp cur_type; r_emp emp%ROWTYPE; v_sql VARCHAR2(500); BEGIN v_sql : SELECT * FROM emp WHERE sal :sal; OPEN cur_emp FOR v_sql USING input_sal; LOOP FETCH cur_emp INTO r_emp; EXIT WHEN cur_emp%NOTFOUND; DBMS_OUTPUT.PUT_LINE(r_emp.ename || - || r_emp.sal); END LOOP; CLOSE cur_emp; END; /也许它还会提出另一种写法用FOR r_emp IN (SELECT ename, sal FROM emp WHERE sal :sal) LOOP连显式游标都省掉规避同类问题。两种都比调大缓冲区干净。提示Codex 在当前流程中只做代码解释和改写。真正执行上面这段请在本地 SQL*Plus 或 PL/SQL Developer 里进行把结果贴回对话即可。5. 验证修复SQL*Plus 里跑一遍把输出贴回对话5.1 在本地执行修改后的匿名块打开 SQL*Plus先打开输出开关SET SERVEROUTPUT ON;然后执行修复版匿名块。如果不想每次弹输入框可以把USING input_sal换成实际值例如USING 3000。执行结束后不会出现 ORA-20000几行打印完正常退出。如果还有报错把报错原文贴回 Codex它会根据错误码继续给修改建议。这样来回两三次问题基本收敛。5.2 换模型或核对用量要是觉得当前模型解释得不够清楚随时回到 TaoToken 官网查看模型广场里有没有更合适的 ID更新config.toml里的model字段再跑。控制台也会记录这次调用的用量方便确认 Key 是否正常工作。6. 再遇到缓冲溢出排障顺序别乱6.1 三条排查线把这次踩坑压缩成三行第一先看 LOOP 有没有出口。没有EXIT的死循环一切输出设置都是摆设。第二再看 FETCH 后是否判断%NOTFOUND。特别是REF CURSOR动态 SQL游标状态需要显式检查。第三最后才考虑调大serveroutput。只有确认输出内容本身很多、而且确实需要全部显示时才去动大小限制。调大serveroutput不该是首选方法它只是给偷懒掩盖死循环的一种止痛药。6.2 下次我会让 Codex 先扫一遍以前我遇到这种问题习惯先搜论坛再把各种set serveroutput的偏方试一轮浪费时间。现在我会直接打开 Codex把 PL/SQL 贴进去顺便检查一遍循环和游标状态。Codex 走的还是那套 Token 通道只是 Base URL 换成了 TaoToken 的接口地址模型响应速度、Key 管理都比之前在多个官方入口之间切换省心很多。需要正式起步的话先到 创建 Key 复制一把把 config.toml 里的YOUR_API_KEY换成实际值想先在对话里试一把同样的排障可以打开 模型对话 发一段 PL/SQL看看模型回给你的第一条意见是不是也指向那个被注释的 exit。
返回列表