You need to enable JavaScript to run this app. Sybase存储过程转DB2后执行报SQLCODE=-104语法错误排错咨询
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.06 14:36:02