1.3.2.11.5. Goldendb-MySQL

1.3.2.11.5.1. PL/SQL 匿名块

描述

程序由三个块组成,即声明部分(DECLARE)、执行部分(BEGIN)和异常处理部分(EXCEPTION)。

三个部分的作用如下:

声明部分:在此声明 PL/SQL 用到的变量、常量、游标、类型等。

执行部分:包含程序的主要逻辑,执行SQL操作,控制结构和其他语句。

异常处理部分:捕获和处理在执行部分出现的异常。

语法

[DECLARE]
   -- 声明部分 (可选)
BEGIN
   -- 执行部分:  过程及 SQL 语句,即程序的主要部分
[EXCEPTION]
   -- 异常处理部分: 错误处理
END;

警告

  1. 不支持匿名块带标签名称。

示例

-- 转换前Oracle :
DECLARE
        v int;
BEGIN
        NULL;
EXCEPTION
        WHEN OTHERS THEN
        NULL;
END;

-- 转换后匿名块:
CREATE PROCEDURE ano6dd8c2a63cfc4e218478135bdfecf62c()
BEGIN
        DECLARE sqlcode int;
        DECLARE sqlerrm text;
        DECLARE v bigint;
        DECLARE EXIT HANDLER FOR NOT FOUND , SQLEXCEPTION
        BEGIN
                GET CURRENT DIAGNOSTICS CONDITION 1 sqlcode = MYSQL_ERRNO,sqlerrm = MESSAGE_TEXT;
                SELECT 1;
        END;
        SELECT 1;
END;
CALL ano6dd8c2a63cfc4e218478135bdfecf62c();
DROP PROCEDURE IF EXISTS ano6dd8c2a63cfc4e218478135bdfecf62c;

1.3.2.11.5.2. 数据类型

基础类型转换 参见 数据类型转换映射表

警告

  1. BINARY_FLOAT, BINARY_DOUBLE 源库和目标库精度存在差异,以实际目标库为准。如1.3 在Oracle中输出为1.29999995E+000(不同环境可能存在差异),而在Goldendb-MySQL中输出为1.3 。

  2. CHAR(N) CHARACTER(N) NCHAR(N) 最大支持255 。

  3. NCHAR VARYING(N) NVARCHAR2(N) RAW(N) 最大支持2000 。

  4. VARCHAR2(N) VARCHAR(N) Oracle N 最大支持32767, Goldendb-MySQL N 最大支持16383 。

  5. DECIMAL(p,s) DEC(p,s) NUMBER(p,s) NUMERIC(p,s) p 应该位于 [1,38] 之间,s 应该位于 [0,30] 之间,s应该小于p ,另外ORACLE中小数0会截断掉,Goldendb-MySQL中小数0会保留。

  6. FLOAT Oracle 与 Goldendb-MySQL 精度存在差异,目标库精度更高。

1.3.2.11.5.3. 声明

语法

variable_name datatype [:=|DEFAULT expression]

警告

  1. 不支持出现重名的变量

示例

-- 转换前Oracle:
DECLARE
        c_MAX_SALARY NUMBER := 10000;
        c_DEFAULT_NAME VARCHAR2(50) := 'Default Name';
        v11 NUMBER;
BEGIN
        v11 := 100;
END;

-- 转换后:
CREATE PROCEDURE ano1b40ea8cc3e244c8a968ac840c34c160()
BEGIN
        DECLARE sqlcode int;
        DECLARE sqlerrm text;
        DECLARE c_max_salary decimal DEFAULT 10000;
        DECLARE c_default_name varchar(50) DEFAULT 'Default Name';
        DECLARE v11 decimal;
        SET v11 = 100;
END;
CALL ano1b40ea8cc3e244c8a968ac840c34c160();
DROP PROCEDURE IF EXISTS ano1b40ea8cc3e244c8a968ac840c34c160;

1.3.2.11.5.4. 条件控制

1.3.2.11.5.4.1. IF

语法

IF condition_1 THEN
        statements_1
[ ELSIF condition_2 THEN
        statements_2
]
[ ELSIF condition_3 THEN
        statements_3
]...
[ ELSE
        else_statements
]
END IF;

示例

-- 转换前Oracle:
DECLARE
        grade CHAR(1);
        msg VARCHAR(200);
BEGIN
        grade := 'B';

        if grade = 'A' THEN
                msg := 'Excellent';
        ELSIF grade = 'B' THEN
                msg := 'Very Good';
        ELSIF grade = 'C' THEN
                msg := 'Good';
        ELSIF grade = 'D' THEN
                msg := 'Fair';
        ELSIF grade = 'F' THEN
                msg := 'Poor';
        ELSE
                msg := 'No such grade';
        END IF;
END;

-- 转换后:
CREATE PROCEDURE anoab1f71e9beb645f2866f2fdc1a0a7024()
BEGIN
        DECLARE sqlcode int;
        DECLARE sqlerrm text;
        DECLARE grade char(1);
        DECLARE msg varchar(200);
        SET grade = 'B';
        IF grade='A' THEN
                SET msg = 'Excellent';
        ELSIF grade='B' THEN
                SET msg = 'Very Good';
        ELSIF grade='C' THEN
                SET msg = 'Good';
        ELSIF grade='D' THEN
                SET msg = 'Fair';
        ELSIF grade='F' THEN
                SET msg = 'Poor';
        ELSE
                SET msg = 'No such grade';
        END IF;
END;
CALL anoab1f71e9beb645f2866f2fdc1a0a7024();
DROP PROCEDURE IF EXISTS anoab1f71e9beb645f2866f2fdc1a0a7024;

1.3.2.11.5.4.2. CASE 语句

语法

CASE selector
WHEN selector_value_1 THEN statements_1
WHEN selector_value_2 THEN statements_2
...
WHEN selector_value_n THEN statements_n
[ ELSE
        else_statements ]
END CASE;


CASE
WHEN condition_1 THEN statements_1
WHEN condition_2 THEN statements_2
...
WHEN condition_n THEN statements_n
[ ELSE
else_statements ]
END CASE;

示例

-- 转换前Oracle:
DECLARE
        grade CHAR(1);
        msg varchar(200);
BEGIN
        grade := 'B';

        CASE grade
                WHEN 'A' THEN
                        msg := 'Excellent';
                WHEN 'B' THEN
                        msg := 'Very Good';
                WHEN 'C' THEN
                        msg := 'Good';
                WHEN 'D' THEN
                        msg := 'Fair';
                WHEN 'F' THEN
                        msg := 'Poor';
                ELSE
                        msg := 'No such grade';
        END CASE;
END;

-- 转换后:
CREATE PROCEDURE anoba036ee869e84fe5ab0c19414a4d9895()
BEGIN
        DECLARE sqlcode int;
        DECLARE sqlerrm text;
        DECLARE grade char(1);
        DECLARE msg varchar(200);
        SET grade = 'B';
        CASE grade
                WHEN 'A' THEN
                        SET msg = 'Excellent';
                WHEN 'B' THEN
                        SET msg = 'Very Good';
                WHEN 'C' THEN
                        SET msg = 'Good';
                WHEN 'D' THEN
                        SET msg = 'Fair';
                WHEN 'F' THEN
                        SET msg = 'Poor';
                ELSE
                        SET msg = 'No such grade';
        END CASE;
END;
CALL anoba036ee869e84fe5ab0c19414a4d9895();
DROP PROCEDURE IF EXISTS anoba036ee869e84fe5ab0c19414a4d9895;

1.3.2.11.5.5. 循环控制语句

1.3.2.11.5.5.1. LOOP

LOOP
        statements
END LOOP;

示例

-- 转换前Oracle :
DECLARE
        v_counter NUMBER := 1;
BEGIN
        LOOP
                v_counter := v_counter + 1;
                EXIT WHEN v_counter > 3;
        END LOOP;
END;

-- 转换后:
CREATE PROCEDURE ano44b2fea05ff847dfa69f4d5dd86be6c8()
BEGIN
        DECLARE sqlcode int;
        DECLARE sqlerrm text;
        DECLARE v_counter decimal DEFAULT 1;
        unisql_autoLabel1: LOOP
                SET v_counter = v_counter+1;
                IF v_counter>3 THEN
                        LEAVE unisql_autoLabel1;
                END IF;
        END LOOP unisql_autoLabel1;
END;
CALL ano44b2fea05ff847dfa69f4d5dd86be6c8();
DROP PROCEDURE IF EXISTS ano44b2fea05ff847dfa69f4d5dd86be6c8;

1.3.2.11.5.5.2. FOR LOOP

FOR variable IN [REVERSE] lower_bound..upper_bound LOOP
        statements
END LOOP;

示例

-- 转换前Oracle :
DECLARE
        first  INTEGER := 1;
        last   INTEGER := 10;
        high   INTEGER := 100;
        low    INTEGER := 12;
BEGIN
        FOR j IN -5..5 LOOP
                log_info (j);
        END LOOP;

        FOR k IN REVERSE first..last LOOP
                log_info (k);
        END LOOP;

        FOR step IN 0..(TRUNC(high/low) * 2) LOOP
                log_info (step);
        END LOOP;
END;

-- 转换后:
CREATE PROCEDURE anoe4eccae9e4204ad0b2c9ae0864405304()
BEGIN
        DECLARE sqlcode int;
        DECLARE sqlerrm text;
        DECLARE first bigint DEFAULT 1;
        DECLARE last bigint DEFAULT 10;
        DECLARE high bigint DEFAULT 100;
        DECLARE low bigint DEFAULT 12;
        BEGIN
        DECLARE j INT DEFAULT -5;
        unisql_autoLabel1: LOOP
                IF j > (5) THEN
                        LEAVE unisql_autoLabel1;
                END IF;
                CALL log_info(j);
                SET j=j+1;
        END LOOP unisql_autoLabel1;
        END;
        BEGIN
        DECLARE k INT DEFAULT last;
        unisql_autoLabel2: LOOP
                IF k < (first) THEN
                        LEAVE unisql_autoLabel2;
                END IF;
                CALL log_info(k);
                SET k=k-1;
        END LOOP unisql_autoLabel2;
        END;
        BEGIN
        DECLARE step INT DEFAULT 0;
        unisql_autoLabel3: LOOP
                IF step > ((TRUNC(high/low)*2)) THEN
                        LEAVE unisql_autoLabel3;
                END IF;
                CALL log_info(step);
                SET step=step+1;
        END LOOP unisql_autoLabel3;
        END;
END;
CALL anoe4eccae9e4204ad0b2c9ae0864405304();
DROP PROCEDURE IF EXISTS anoe4eccae9e4204ad0b2c9ae0864405304;

1.3.2.11.5.5.3. WHILE LOOP

WHILE condition LOOP
        statements
END LOOP;

示例

-- 转换前Oracle :
DECLARE
        v_counter NUMBER := 1;
BEGIN
        WHILE v_counter <= 3 LOOP
                log_info('Counter value in WHILE loop: ' || v_counter);
                v_counter := v_counter + 1;
        END LOOP;
END;

-- 转换后:
CREATE PROCEDURE anoc6786b1b01d84fee92c96d65a12461c6()
BEGIN
        DECLARE sqlcode int;
        DECLARE sqlerrm text;
        DECLARE v_counter decimal DEFAULT 1;
        unisql_autoLabel1: WHILE v_counter<=3 DO
                CALL log_info(concat(ifnull('Counter value in WHILE loop: ', ''), ifnull(v_counter, '')));
                SET v_counter = v_counter+1;
        END WHILE unisql_autoLabel1;
END;
CALL anoc6786b1b01d84fee92c96d65a12461c6();
DROP PROCEDURE IF EXISTS anoc6786b1b01d84fee92c96d65a12461c6;

1.3.2.11.5.5.4. CURSOR FOR

FOR variable IN ( Select ... ) LOOP
        statements
END LOOP;

警告

  1. 在Oracle中variable必须是记录类型,不能是简单类型。而目标库中并不支持记录类型,所以会展开为多个变量并且类型为 text ,形式为 variable_xxxx 的取名优先使用查询的AS别名,其次是列名,都不满足则自动化生成一个变量名称。

  2. 由于使用的是 ``text``类型接收结果,所以可能会触发隐式转换,并且结果受目标库隐式转换效果影响。建议只有查询结果是字符串类型时使用,存在其他类型建议使用静态游标。

示例

-- 转换前Oracle :
DECLARE
        /* 自定义变量 */
        v_dept_id     NUMBER(10);
        v_dept_name   VARCHAR2(50);
        v_location    VARCHAR2(50);
        v_loop_count  NUMBER := 0; /* 统计循环次数 */
BEGIN
        /* 单层 FOR SELECT 循环:遍历部门表所有数据 */
        FOR dept_rec IN (
                SELECT department_id, department_name, location
                FROM departments
                ORDER BY department_id
        ) LOOP
                /* 直接提取循环记录中的字段(无需 %ROWTYPE,通过记录名.字段名访问) */
                v_dept_id := dept_rec.department_id;
                v_dept_name := dept_rec.department_name;
                v_location := dept_rec.location;

                /* 输出日志 */
                test_log_info('场景1-部门信息:ID=' || v_dept_id || ', 名称=' || v_dept_name || ', 地点=' || v_location);

                v_loop_count := v_loop_count + 1;
        END LOOP;

        test_log_info('场景1-单层循环执行完成,共遍历 ' || TO_CHAR(v_loop_count) || ' 个部门');

EXCEPTION
        WHEN NO_DATA_FOUND THEN
                test_log_info('场景1-无数据异常:未查询到任何部门信息');
        WHEN OTHERS THEN
                test_log_info('场景1-执行异常:错误代码=' || SQLCODE || ', 错误信息=' || SQLERRM);
END;

-- 转换后:
CREATE PROCEDURE ano73ec16b442ae48c79f1758adc3626325()
BEGIN
        DECLARE sqlcode int;
        DECLARE sqlerrm text;
        DECLARE v_dept_id decimal(10);
        DECLARE v_dept_name varchar(50);
        DECLARE v_location varchar(50);
        DECLARE v_loop_count decimal DEFAULT 0;
        DECLARE EXIT HANDLER FOR NOT FOUND
        BEGIN
                GET CURRENT DIAGNOSTICS CONDITION 1 sqlcode = MYSQL_ERRNO,sqlerrm = MESSAGE_TEXT;
                CALL test_log_info('场景1-无数据异常:未查询到任何部门信息');
        END;
        DECLARE EXIT HANDLER FOR SQLEXCEPTION
        BEGIN
                GET CURRENT DIAGNOSTICS CONDITION 1 sqlcode = MYSQL_ERRNO,sqlerrm = MESSAGE_TEXT;
                CALL test_log_info(concat(concat(concat(ifnull('场景1-执行异常:错误代码=', ''), ifnull(SQLCODE, '')), ifnull(', 错误信息=', '')), ifnull(SQLERRM, '')));
        END;
        BEGIN
                DECLARE dept_rec_department_id,dept_rec_department_name,dept_rec_location text;
                DECLARE _unisql_anoCursor2_notfound int;
                DECLARE unisql_anoCursor2 CURSOR FOR SELECT department_id,department_name,location FROM departments ORDER BY department_id;
                OPEN unisql_anoCursor2;
                        unisql_autoLabel1: LOOP
                        BEGIN
                                DECLARE EXIT HANDLER FOR NOT FOUND
                                BEGIN
                                CLOSE unisql_anoCursor2;
                                set _unisql_anoCursor2_notfound = 1;
                                END;
                                set _unisql_anoCursor2_notfound = 0;
                                FETCH unisql_anoCursor2 INTO dept_rec_department_id , dept_rec_department_name , dept_rec_location;
                        END;
                        IF _unisql_anoCursor2_notfound THEN
                                LEAVE unisql_autoLabel1;
                        END IF;
                        SET v_dept_id = dept_rec_department_id;
                        SET v_dept_name = dept_rec_department_name;
                        SET v_location = dept_rec_location;
                        CALL test_log_info(concat(concat(concat(concat(concat(ifnull('场景1-部门信息:ID=', ''), ifnull(v_dept_id, '')), ifnull(', 名称=', '')), ifnull(v_dept_name, '')), ifnull(', 地点=', '')), ifnull(v_location, '')));
                        SET v_loop_count = v_loop_count+1;
                END LOOP unisql_autoLabel1;
        END;
        CALL test_log_info(concat(concat(ifnull('场景1-单层循环执行完成,共遍历 ', ''), ifnull(TO_CHAR(v_loop_count), '')), ifnull(' 个部门', '')));
END;
CALL ano73ec16b442ae48c79f1758adc3626325();
DROP PROCEDURE IF EXISTS ano73ec16b442ae48c79f1758adc3626325;

1.3.2.11.5.6. 注释

单行注释和多行注释转换时,会被丢掉,不影响程序的执行。

语法

BEGIN
        -- 单行注释
        /*
        多行注释
        */
END;

警告

  1. 转换后注释将会被丢弃

示例

-- 转换前Oracle:
DECLARE
        v date;
BEGIN
        -- 这是单行注释
        /*
                这是多行注释
                示例e.g SELECT CURRENT_DATE INTO v FROM dual
        */
        SELECT CURRENT_DATE INTO v FROM dual /*这是测试*/ ;
END;

-- 转换后:
CREATE PROCEDURE ano3fbc4fee090a485fa8ec82e9c633a154()
BEGIN
        DECLARE sqlcode int;
        DECLARE sqlerrm text;
        DECLARE v datetime;
        SELECT current_timestamp(0) INTO v FROM dual;
END;
CALL ano3fbc4fee090a485fa8ec82e9c633a154();
DROP PROCEDURE IF EXISTS ano3fbc4fee090a485fa8ec82e9c633a154;

1.3.2.11.5.7. 游标

语法

声明游标:
CURSOR cur_name IS select_statement;

打开:
OPEN cur_name;

获取游标:
FETCH cur_name INTO variable [,...];

关闭游标:
CLOSE cur_name;

警告

  1. 仅支持无参数的静态游标

  2. 隐式游标仅支持 cur_name%notfound cur_name%isopen 并且仅支持在 IF/CONTINUE/EXIT 语句中判断,如: IF cur_name%notfound THEN 其他暂不支持。

示例

-- 转换前Oracle:
DECLARE
-- 1. 声明游标
CURSOR cur_employees IS
        SELECT employee_id, name, salary
        FROM employees
        WHERE salary >= 5000 ORDER BY employee_id asc;

-- 定义变量存储游标数据
v_emp_id   NUMBER;
v_emp_name  VARCHAR2(50);
v_salary  NUMBER;
BEGIN
-- 2. 打开游标
OPEN cur_employees;

-- 3. 循环提取数据
LOOP
        FETCH cur_employees INTO v_emp_id, v_emp_name, v_salary;
        EXIT WHEN cur_employees%NOTFOUND;  -- 游标属性判断是否结束

        log_info(
        'Employee ID:' || v_emp_id ||
        ', Name:' || v_emp_name ||
        ', Salary:' || v_salary
        );
END LOOP;

-- 4. 关闭游标
CLOSE cur_employees;
END;

-- 转换后:
CREATE PROCEDURE anoaa095dcaab6746eabbb0908308ae7edf()
BEGIN
        DECLARE sqlcode int;
        DECLARE sqlerrm text;
        DECLARE _cur_employees_notfound int DEFAULT 0;
        DECLARE _cur_employees_isopen int DEFAULT 0;
        DECLARE v_emp_id decimal;
        DECLARE v_emp_name varchar(50);
        DECLARE v_salary decimal;
        DECLARE cur_employees CURSOR FOR SELECT employee_id,name,salary FROM employees WHERE salary>=5000 ORDER BY employee_id;
        OPEN cur_employees;
        SET _cur_employees_isopen = 1;
        unisql_autoLabel1: LOOP
                BEGIN
                        DECLARE EXIT HANDLER FOR NOT found set _cur_employees_notfound = 1;
                        set _cur_employees_notfound = 0;
                        FETCH cur_employees  INTO v_emp_id, v_emp_name, v_salary;
                END;
                IF _cur_employees_notfound THEN
                        LEAVE unisql_autoLabel1;
                END IF;
                CALL log_info(concat(concat(concat(concat(concat(ifnull('Employee ID:', ''), ifnull(v_emp_id, '')), ifnull(', Name:', '')), ifnull(v_emp_name, '')), ifnull(', Salary:', '')), ifnull(v_salary, '')));
        END LOOP unisql_autoLabel1;
        CLOSE cur_employees;
        SET _cur_employees_isopen = 0;
END;
CALL anoaa095dcaab6746eabbb0908308ae7edf();
DROP PROCEDURE IF EXISTS anoaa095dcaab6746eabbb0908308ae7edf;

1.3.2.11.5.8. 静态SQL

语法

SELECT ... ;

INSERT ... ;

DELETE ... ;

UPDATE ... ;

COMMIT;

示例

-- 转换前Oracle:
DECLARE
        v_name varchar(64);
        v_bonus   NUMBER(8,2);
        v_employee_id NUMBER(8,2) default 100;
BEGIN
        INSERT INTO employees_20250707 (employee_id, name, salary, hire_date) VALUES (100, 'Bob', 5000, TO_DATE('2021-02-15', 'YYYY-MM-DD'));
        SELECT salary * 0.10, name INTO v_bonus, v_name FROM employees_20250707 WHERE employee_id = 100;
        log_info('name = ' || v_name || ' bonus = ' || TO_CHAR(v_bonus));

        UPDATE employees_20250707 SET salary = salary + 1000 WHERE employee_id = v_employee_id;
        SELECT salary * 0.10, name INTO v_bonus, v_name FROM employees_20250707 WHERE employee_id = 100;
        log_info('name = ' || v_name || ' bonus = ' || TO_CHAR(v_bonus));

        DELETE FROM employees_20250707 WHERE employee_id = v_employee_id;

        COMMIT;
END;


-- 转换后:
CREATE PROCEDURE ano4a041a1c5f2042e886bba1f5b17b17cc()
BEGIN
        DECLARE sqlcode int;
        DECLARE sqlerrm text;
        DECLARE v_name varchar(64);
        DECLARE v_bonus decimal(8,2);
        DECLARE v_employee_id decimal(8,2) DEFAULT 100;
        INSERT INTO employees_20250707 (employee_id,name,salary,hire_date) VALUES (100,'Bob',5000,CAST(str_to_date('2021-02-15', '%Y-%m-%d') AS DATETIME));
        SELECT salary*0.10,name INTO v_bonus, v_name FROM employees_20250707 WHERE employee_id=100;
        CALL log_info(concat(concat(concat(ifnull('name = ', ''), ifnull(v_name, '')), ifnull(' bonus = ', '')), ifnull(TO_CHAR(v_bonus), '')));
        UPDATE employees_20250707 SET salary=salary+1000 WHERE employee_id=v_employee_id;
        SELECT salary*0.10,name INTO v_bonus, v_name FROM employees_20250707 WHERE employee_id=100;
        CALL log_info(concat(concat(concat(ifnull('name = ', ''), ifnull(v_name, '')), ifnull(' bonus = ', '')), ifnull(TO_CHAR(v_bonus), '')));
        DELETE FROM employees_20250707 WHERE employee_id=v_employee_id;
        COMMIT;
END;
CALL ano4a041a1c5f2042e886bba1f5b17b17cc();
DROP PROCEDURE IF EXISTS ano4a041a1c5f2042e886bba1f5b17b17cc;

1.3.2.11.5.9. 动态SQL

语法

EXECUTE IMMEDIATE dynamic_sql_string
[INTO variable [,....]]
[USING bind_arg [,...]]

警告

  1. 当且仅当 dynamic_sql_string 为字符串文本时,会对 dynamic_sql_string 进行SQL语句转换,其他情况(如变量,表达式)只会透传。

  2. dynamic_sql_string 使用Q语法(不支持多字节的Q语法)包裹字符串时,转后会改写为单引号的形式。

  3. USING bind_arg 未支持指定OUT/IN修饰关键字。

  4. USING bind_arg 语句中的绑定参数个数需要与 USING 指定的绑定参数个数完全一致。

  5. 不支持动态语句中为匿名块。

示例

-- 转换前Oracle:
-- 取 v_employee_id , v_name , v_salary , v_department_id 值插入数据库
DECLARE
        v_employee_id number := 1;
        v_name varchar2(50) := 'Bob Brown';
        v_salary number := 55000;
        v_department_id NUMBER DEFAULT 10;
BEGIN
        EXECUTE IMMEDIATE q'[DELETE FROM employees_20250707]';
        EXECUTE IMMEDIATE 'INSERT INTO employees_20250707 (employee_id,name,salary,department_id) VALUES (:1,:2,:3,:4)' USING v_employee_id, v_name, v_salary, v_department_id;
END;

-- 转换后:
CREATE PROCEDURE anoe35d8de9efba45c4bd06d4e97ffceec9()
BEGIN
        DECLARE sqlcode int;
        DECLARE sqlerrm text;
        DECLARE v_employee_id decimal DEFAULT 1;
        DECLARE v_name varchar(50) DEFAULT 'Bob Brown';
        DECLARE v_salary decimal DEFAULT 55000;
        DECLARE v_department_id decimal DEFAULT 10;
        SET @_sql = 'DELETE FROM employees_20250707';
        PREPARE _stmt FROM @_sql;
        EXECUTE _stmt;
        DEALLOCATE PREPARE _stmt;
        SET @_sql = 'INSERT INTO employees_20250707 (employee_id,name,salary,department_id) VALUES (?,?,?,?)';
        PREPARE _stmt FROM @_sql;
        SET @_anoBindVar1 = v_employee_id,@_anoBindVar2 = v_name,@_anoBindVar3 = v_salary,@_anoBindVar4 = v_department_id;
        EXECUTE _stmt USING @_anoBindVar1, @_anoBindVar2, @_anoBindVar3, @_anoBindVar4;
        DEALLOCATE PREPARE _stmt;
END;
CALL anoe35d8de9efba45c4bd06d4e97ffceec9();
DROP PROCEDURE IF EXISTS anoe35d8de9efba45c4bd06d4e97ffceec9;

1.3.2.11.5.10. 异常

语法

-- plsql中异常处理:
EXCEPTION
        WHEN ex_name_1 THEN statements_1                 -- 异常处理程序
        WHEN ex_name_2 OR ex_name_3 THEN statements_2    -- 异常处理程序
        WHEN OTHERS THEN statements_3                    -- 异常处理程序
END;

警告

  1. 预定义的异常名称 NO_DATA_FOUND OTHERS 支持,其他的异常未做支持。

  2. ORACLE 匿名块静态语句时编译时会检查语义,因此不会触发运行时异常。 而Goldendb-MySQL 编译时未检查语义,因此会触发运行时异常。所以 OTHERS 在源库不会捕捉到这类异常,而在目标库中会捕捉到。例如:静态语句SELECT 查询不存在的表。

  3. ORACLE 会产生除0异常,而Goldendb-MySQL中不会产生除0异常,因此 OTHERS 在源库可以捕获到该类异常,而在目标库不会不会到该类异常。

  4. sqlcode 使用的是目标库的 MYSQL_ERRNO ; sqlerrm 使用的是目标库的 MESSAGE_TEXT 。 Oracle和Goldendb-MySQL的错误码和错误信息是不一致的,以实际运行时的错误码和错误信息为准。

示例

-- 转换前Oracle:
DECLARE
        v_int NUMBER;
BEGIN
        BEGIN
                SELECT id into v_int from log_info_12116 where id = 2;
        EXCEPTION
                WHEN NO_DATA_FOUND THEN
                        test_log_info('内置异常:无数据匹配(NO_DATA_FOUND)');
                WHEN OTHERS THEN
                        test_log_info('内置异常:无数据匹配(OTHERS)');
        END;
EXCEPTION
        WHEN OTHERS THEN
        test_log_info('内置异常:类型转换失败(VALUE_ERROR)');
END;


-- 转换后
CREATE PROCEDURE anod102334961a9425188e1cd8ffbafa4e2()
BEGIN
        DECLARE sqlcode int;
        DECLARE sqlerrm text;
        DECLARE v_int decimal;
        DECLARE EXIT HANDLER FOR NOT FOUND , SQLEXCEPTION
        BEGIN
                GET CURRENT DIAGNOSTICS CONDITION 1 sqlcode = MYSQL_ERRNO,sqlerrm = MESSAGE_TEXT;
                CALL test_log_info('内置异常:类型转换失败(VALUE_ERROR)');
        END;
        BEGIN
                DECLARE EXIT HANDLER FOR NOT FOUND
                BEGIN
                        GET CURRENT DIAGNOSTICS CONDITION 1 sqlcode = MYSQL_ERRNO,sqlerrm = MESSAGE_TEXT;
                        CALL test_log_info('内置异常:无数据匹配(NO_DATA_FOUND)');
                END;
                DECLARE EXIT HANDLER FOR SQLEXCEPTION
                BEGIN
                GET CURRENT DIAGNOSTICS CONDITION 1 sqlcode = MYSQL_ERRNO,sqlerrm = MESSAGE_TEXT;
                CALL test_log_info('内置异常:无数据匹配(OTHERS)');
                END;
                SELECT id INTO v_int FROM log_info_12116 WHERE id=2;
        END;
END;
CALL anod102334961a9425188e1cd8ffbafa4e2();
DROP PROCEDURE IF EXISTS anod102334961a9425188e1cd8ffbafa4e2;