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;
警告
不支持匿名块带标签名称。
示例
-- 转换前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. 数据类型
基础类型转换 参见 数据类型转换映射表
警告
BINARY_FLOAT,BINARY_DOUBLE源库和目标库精度存在差异,以实际目标库为准。如1.3 在Oracle中输出为1.29999995E+000(不同环境可能存在差异),而在Goldendb-MySQL中输出为1.3 。CHAR(N)CHARACTER(N)NCHAR(N)最大支持255 。NCHAR VARYING(N)NVARCHAR2(N)RAW(N)最大支持2000 。VARCHAR2(N)VARCHAR(N)Oracle N 最大支持32767, Goldendb-MySQL N 最大支持16383 。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会保留。FLOATOracle 与 Goldendb-MySQL 精度存在差异,目标库精度更高。
1.3.2.11.5.3. 声明
语法
variable_name datatype [:=|DEFAULT expression]
警告
不支持出现重名的变量
示例
-- 转换前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;
警告
在Oracle中variable必须是记录类型,不能是简单类型。而目标库中并不支持记录类型,所以会展开为多个变量并且类型为
text,形式为variable_xx。xx的取名优先使用查询的AS别名,其次是列名,都不满足则自动化生成一个变量名称。由于使用的是 ``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;
警告
转换后注释将会被丢弃
示例
-- 转换前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;
警告
仅支持无参数的静态游标
隐式游标仅支持
cur_name%notfoundcur_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 [,...]]
警告
当且仅当
dynamic_sql_string为字符串文本时,会对dynamic_sql_string进行SQL语句转换,其他情况(如变量,表达式)只会透传。当
dynamic_sql_string使用Q语法(不支持多字节的Q语法)包裹字符串时,转后会改写为单引号的形式。USINGbind_arg未支持指定OUT/IN修饰关键字。USINGbind_arg语句中的绑定参数个数需要与USING指定的绑定参数个数完全一致。不支持动态语句中为匿名块。
示例
-- 转换前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;
警告
预定义的异常名称
NO_DATA_FOUNDOTHERS支持,其他的异常未做支持。ORACLE 匿名块静态语句时编译时会检查语义,因此不会触发运行时异常。 而Goldendb-MySQL 编译时未检查语义,因此会触发运行时异常。所以
OTHERS在源库不会捕捉到这类异常,而在目标库中会捕捉到。例如:静态语句SELECT 查询不存在的表。ORACLE 会产生除0异常,而Goldendb-MySQL中不会产生除0异常,因此
OTHERS在源库可以捕获到该类异常,而在目标库不会不会到该类异常。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;