Sybase存储过程转DB2后执行报SQLCODE=-104语法错误排错咨询
迁移代码报错问题定位与修正
触发SQLCODE=-104的具体问题点
- 语法不兼容:混用Sybase的
SELECT 变量 = 列名赋值写法,DB2 SQL PL不支持该语法,解析器在IF块结构中遇到未预期的SELECT语句,直接抛出语法错误 - 命名歧义:存储过程入参与TOKEN_DETAILS表的列名完全重名,DB2会自动将WHERE条件中同名的左右值解析为表列,导致查询逻辑永远等价于
1=1,无法匹配到目标行 - 保留字冲突:参数名
USER是DB2系统保留关键字,直接作为入参会触发语法解析失败 - 结构错位:原Sybase的
IF...ELSE IF分支逻辑被拆成两个独立的IF判断,既造成块结构闭合混乱,也会导致逻辑偏离原需求 - 函数参数错误:日期函数
TIMESTAMPADD缺少间隔单位、间隔值参数,唯一值生成函数GENERATE_UNIQUE()错误传入无效参数 - 逻辑错误:UPDATE语句的SET子句使用字段自赋值,没有把生成的新TOKEN、新过期时间写入表,相当于无效更新
- 输出错误:最后的返回语句依赖SYSIBM.SYSDUMMY1查询变量值,DB2无法将SQL块内的局部变量直接作为结果集返回,需要通过OUT参数或VALUES语句输出
修正后的可运行DB2存储过程代码
CREATE OR REPLACE PROCEDURE TAS_TEST ( IN P_LOGIN_ID VARCHAR(20), IN P_NAME VARCHAR(100), IN P_C_NAME VARCHAR(100), IN P_USER VARCHAR(20), IN P_DEBUG SMALLINT DEFAULT 0, OUT O_TOKEN VARCHAR(36), OUT O_EXPIRY_DATE TIMESTAMP ) LANGUAGE SQL BEGIN -- 定义内部变量 DECLARE V_TOKEN VARCHAR(36); DECLARE V_EXPIRY_DATE TIMESTAMP; DECLARE V_ERROR_MSG VARCHAR(200); -- SQL执行异常捕获 DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN GET DIAGNOSTICS V_ERROR_MSG = MESSAGE_TEXT; RESIGNAL SQLSTATE '30000' SET MESSAGE_TEXT = V_ERROR_MSG; END; -- 未匹配到TOKEN记录的处理 DECLARE NOT FOUND HANDLER FOR NOT FOUND BEGIN SET V_TOKEN = NULL; SET V_EXPIRY_DATE = NULL; END; -- 入参去除两端空格 SET P_LOGIN_ID = TRIM(P_LOGIN_ID); -- 必填参数校验 IF P_LOGIN_ID IS NULL THEN SIGNAL SQLSTATE '20000' SET MESSAGE_TEXT = 'LOGIN ID IS MUST:' || P_LOGIN_ID; END IF; IF P_NAME IS NULL THEN SIGNAL SQLSTATE '20000' SET MESSAGE_TEXT = 'NAME IS MUST:' || P_NAME; END IF; IF P_C_NAME IS NULL THEN SIGNAL SQLSTATE '20000' SET MESSAGE_TEXT = 'C_NAME IS MUST:' || P_C_NAME; END IF; IF P_USER IS NULL THEN SIGNAL SQLSTATE '20000' SET MESSAGE_TEXT = 'USER IS MUST:' || P_USER; END IF; -- 查询已存在的TOKEN记录 SELECT TOKEN, TOKEN_EXPIRY_DATE INTO V_TOKEN, V_EXPIRY_DATE FROM TOKEN_DETAILS WHERE LOGIN_ID = P_LOGIN_ID AND NAME = P_NAME AND C_NAME = P_C_NAME; -- 分支1:TOKEN不存在 IF V_TOKEN IS NULL THEN IF P_DEBUG = 1 THEN CALL DBMS_OUTPUT.PUT_LINE('No token exists'); END IF; -- 生成新TOKEN与12小时有效期 SET V_TOKEN = CAST(SYSIBM.GENERATE_UNIQUE() AS VARCHAR(36)); SET V_EXPIRY_DATE = TIMESTAMPADD(HOUR, 12, CURRENT TIMESTAMP); -- 插入TOKEN记录 INSERT INTO TOKEN_DETAILS( LOGIN_ID, TOKEN, NAME, C_NAME, TOKEN_EXPIRY_DATE, CREATED_DATE, CREATED_BY )VALUES( P_LOGIN_ID, V_TOKEN, P_NAME, P_C_NAME, V_EXPIRY_DATE, CURRENT TIMESTAMP, P_USER ); -- 分支2:TOKEN已过期 ELSEIF V_EXPIRY_DATE < CURRENT TIMESTAMP THEN IF P_DEBUG = 1 THEN CALL DBMS_OUTPUT.PUT_LINE('TOKEN EXPIRES'); END IF; -- 生成新TOKEN与12小时有效期 SET V_TOKEN = CAST(SYSIBM.GENERATE_UNIQUE() AS VARCHAR(36)); SET V_EXPIRY_DATE = TIMESTAMPADD(HOUR, 12, CURRENT TIMESTAMP); -- 更新TOKEN记录 UPDATE TOKEN_DETAILS SET TOKEN = V_TOKEN, TOKEN_EXPIRY_DATE = V_EXPIRY_DATE WHERE LOGIN_ID = P_LOGIN_ID AND NAME = P_NAME AND C_NAME = P_C_NAME; -- 分支3:TOKEN有效 ELSEIF P_DEBUG = 1 THEN CALL DBMS_OUTPUT.PUT_LINE('TOKEN EXIST'); END IF; -- 输出最终结果 SET O_TOKEN = V_TOKEN; SET O_EXPIRY_DATE = V_EXPIRY_DATE; END@ -- 权限授权 GRANT EXECUTE ON PROCEDURE TAS_TEST TO ADMIN@
注意:DB2命令行执行存储过程时,需要先设置语句结束符为非分号(如示例中的
@),避免存储过程内部的分号被误判为语句结束。
内容的提问来源于stack exchange,提问作者JDeveloper
相关产品推荐
相关产品推荐

