在多数据库环境或数据库迁移场景中,不同数据库对关键字(Keyword)的保留程度及使用限制存在差异,可能导致对象创建失败或SQL兼容性问题。
本次测试旨在系统性梳理 DM、Oracle、MySQL、PostgreSQL、SQL Server 四类数据库中关键字的使用限制,验证其是否支持作为表名、字段名及函数名使用,为数据库设计规范制定及异构迁移提供参考依据。
3.测试对象
1. 所有数据库内置关键字
2. 测试维度:
- 表名
- 字段名
- 函数名
3. 测试方式:
- 不加引号
- 加引号(数据库标准转义)
本次测试采用自动化脚本方式进行验证,核心方法如下:
3.1 从各数据库系统视图中获取关键字集合:
◦ DM: v$reserved_words
◦ Oracle:v$reserved_words
◦ MySQL:information_schema.keywords
◦ PostgreSQL:pg_get_keywords()
◦ SQL Server:基于官方关键字列表构建
3.2. 针对每个关键字,构造动态SQL进行测试:
◦ 创建表(关键字作为表名)
◦ 创建表(关键字作为字段名)
◦ 创建函数(关键字作为函数名)
3.3. 分别测试以下两种场景:
◦ 不使用转义(直接使用关键字)
◦ 使用转义(Oracle/PG使用双引号,MySQL使用反引号,SQL Server使用方括号)
3.4. 捕获执行结果:
◦ 成功:记录为支持
◦ 失败:记录错误信息(语法错误/关键字冲突等)
3.5. 将结果统一写入结果表,并导出为CSV进行分析对比。
CREATE TABLE keyword_test_result (
db_type VARCHAR(20), -- Oracle/Sqlserver/mysql/postgres
keyword VARCHAR(100),
test_type VARCHAR(20), -- TABLE / COLUMN / FUNCTION
result VARCHAR(10),
error_msg VARCHAR(4000),
test_time DATETIME
);
select keyword from information_schema.keywords;
select count(*) from information_schema.keywords;
一共747个关键词
DELIMITER $$
CREATE PROCEDURE p_mysql_keyword()
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE v_keyword VARCHAR(100);
DECLARE v_err TEXT DEFAULT NULL;
DECLARE stmt_ready INT DEFAULT 0;
DECLARE cur CURSOR FOR
SELECT WORD FROM INFORMATION_SCHEMA.KEYWORDS;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur;
read_loop: LOOP
FETCH cur INTO v_keyword;
IF done THEN
LEAVE read_loop;
END IF;
/* =====================================================
TABLE
===================================================== */
SET v_err = NULL;
SET stmt_ready = 0;
BEGIN
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET v_err = 'TABLE_FAIL';
SET @s = CONCAT('CREATE TABLE `', v_keyword, '` (id INT)');
PREPARE stmt FROM @s;
SET stmt_ready = 1;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @s = CONCAT('DROP TABLE IF EXISTS `', v_keyword, '`');
PREPARE stmt FROM @s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
INSERT INTO keyword_test_result
VALUES ('mysql', v_keyword, 'TABLE', 'OK', NULL, NOW());
END;
IF v_err IS NOT NULL THEN
INSERT INTO keyword_test_result
VALUES ('mysql', v_keyword, 'TABLE', 'FAIL', v_err, NOW());
END IF;
/* =====================================================
COLUMN 测试
===================================================== */
SET v_err = NULL;
SET stmt_ready = 0;
BEGIN
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET v_err = 'COLUMN_FAIL';
SET @s = CONCAT('CREATE TABLE t_tmp (`', v_keyword, '` INT)');
PREPARE stmt FROM @s;
SET stmt_ready = 1;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
DROP TABLE IF EXISTS t_tmp;
INSERT INTO keyword_test_result
VALUES ('mysql', v_keyword, 'COLUMN', 'OK', NULL, NOW());
END;
IF v_err IS NOT NULL THEN
INSERT INTO keyword_test_result
VALUES ('mysql', v_keyword, 'COLUMN', 'FAIL', v_err, NOW());
END IF;
/* =====================================================
FUNCTION
===================================================== */
SET v_err = NULL;
SET stmt_ready = 0;
BEGIN
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET v_err = 'FUNCTION_FAIL';
/* CREATE FUNCTION */
SET @s = CONCAT(
'CREATE FUNCTION `', v_keyword, '`(x INT) ',
'RETURNS INT DETERMINISTIC RETURN x'
);
PREPARE stmt FROM @s;
SET stmt_ready = 1;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @s = CONCAT('DROP FUNCTION IF EXISTS `', v_keyword, '`');
PREPARE stmt FROM @s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
INSERT INTO keyword_test_result
VALUES ('mysql', v_keyword, 'FUNCTION', 'OK', NULL, NOW());
END;
IF stmt_ready = 1 THEN
BEGIN
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
DEALLOCATE PREPARE stmt;
END;
END IF;
IF v_err IS NOT NULL THEN
INSERT INTO keyword_test_result
VALUES ('mysql', v_keyword, 'FUNCTION', 'FAIL', v_err, NOW());
END IF;
END LOOP;
CLOSE cur;
END$$
DELIMITER ;
DELIMITER $$
CREATE PROCEDURE p_mysql_keyword()
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE v_keyword VARCHAR(100);
DECLARE v_err TEXT DEFAULT NULL;
DECLARE stmt_ready INT DEFAULT 0;
DECLARE cur CURSOR FOR
SELECT WORD FROM INFORMATION_SCHEMA.KEYWORDS;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur;
read_loop: LOOP
FETCH cur INTO v_keyword;
IF done THEN
LEAVE read_loop;
END IF;
/* =====================================================
==================================================== */
SET v_err = NULL;
SET stmt_ready = 0;
BEGIN
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET v_err = 'TABLE_FAIL';
SET @s = CONCAT('CREATE TABLE `', v_keyword, '` (id INT)');
PREPARE stmt FROM @s;
SET stmt_ready = 1;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @s = CONCAT('DROP TABLE IF EXISTS `', v_keyword, '`');
PREPARE stmt FROM @s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
INSERT INTO keyword_test_result
VALUES ('mysql', v_keyword, 'TABLE', 'OK', NULL, NOW());
END;
IF v_err IS NOT NULL THEN
INSERT INTO keyword_test_result
VALUES ('mysql', v_keyword, 'TABLE', 'FAIL', v_err, NOW());
END IF;
SET v_err = NULL;
SET stmt_ready = 0;
BEGIN
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET v_err = 'COLUMN_FAIL';
SET @s = CONCAT('CREATE TABLE t_tmp (`', v_keyword, '` INT)');
PREPARE stmt FROM @s;
SET stmt_ready = 1;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
DROP TABLE IF EXISTS t_tmp;
INSERT INTO keyword_test_result
VALUES ('mysql', v_keyword, 'COLUMN', 'OK', NULL, NOW());
END;
IF v_err IS NOT NULL THEN
INSERT INTO keyword_test_result
VALUES ('mysql', v_keyword, 'COLUMN', 'FAIL', v_err, NOW());
END IF;
/* =====================================================
FUNCTION
===================================================== */
SET v_err = NULL;
SET stmt_ready = 0;
BEGIN
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET v_err = 'FUNCTION_FAIL';
/* CREATE FUNCTION */
SET @s = CONCAT(
'CREATE FUNCTION `', v_keyword, '`(x INT) ',
'RETURNS INT DETERMINISTIC RETURN x'
);
PREPARE stmt FROM @s;
SET stmt_ready = 1;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @s = CONCAT('DROP FUNCTION IF EXISTS `', v_keyword, '`');
PREPARE stmt FROM @s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
INSERT INTO keyword_test_result
VALUES ('mysql', v_keyword, 'FUNCTION', 'OK', NULL, NOW());
END;
IF stmt_ready = 1 THEN
BEGIN
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
DEALLOCATE PREPARE stmt;
END;
END IF;
IF v_err IS NOT NULL THEN
INSERT INTO keyword_test_result
VALUES ('mysql', v_keyword, 'FUNCTION', 'FAIL', v_err, NOW());
END IF;
END LOOP;
CLOSE cur;
END$$
DELIMITER ;
添加引号的执行结果
mysql> call p_mysql_keyword()
-> ;
Query OK, 0 rows affected (53.82 sec)
mysql> select database();
+------------+
| database() |
+------------+
| hzh |
+------------+
1 row in set (0.00 sec)
mysql> select count(*),test_type from keyword_test_result where result='OK' group by test_type;
+----------+-----------+
| count(*) | test_type |
+----------+-----------+
| 747 | TABLE |
| 747 | COLUMN |
| 747 | FUNCTION |
+----------+-----------+
不加引号执行结果
mysql> call p_mysql_raw_keyword();
Query OK, 0 rows affected (46.08 sec)
mysql> select count(*),result,test_type from keyword_test_result where db_type='mysql_raw'
-> group by result,test_type;
+----------+--------+-----------+
| count(*) | result | test_type |
+----------+--------+-----------+
| 261 | FAIL | TABLE |
| 261 | FAIL | COLUMN |
| 747 | FAIL | FUNCTION |
| 486 | OK | TABLE |
| 486 | OK | COLUMN |
+----------+--------+-----------+
5 rows in set (0.01 sec)
从执行结果
1.mysql所有的关键词使用引号以后都可以作为表名table_name、字段column_name、函数名function_name
2.mysql所有的关键词不使用引号详情如下:
PostgreSQL 没有官方关键字表
使用函数获取
SELECT word FROM pg_get_keywords();
select count(*) from pg_get_keywords();
#一共457个关键词
CREATE OR REPLACE PROCEDURE p_pg_keyword()
LANGUAGE plpgsql
AS $$
DECLARE
r RECORD;
v_sql TEXT;
BEGIN
FOR r IN SELECT word FROM pg_get_keywords() LOOP
BEGIN
v_sql := format('CREATE TABLE %I (id INT)', r.word);
EXECUTE v_sql;
EXECUTE format('DROP TABLE %I', r.word);
INSERT INTO keyword_test_result
VALUES ('pg', r.word, 'TABLE', 'OK', NULL, now());
EXCEPTION WHEN OTHERS THEN
INSERT INTO keyword_test_result
VALUES ('pg', r.word, 'TABLE', 'FAIL', SQLERRM, now());
END;
BEGIN
v_sql := format('CREATE TABLE t_tmp (%I INT)', r.word);
EXECUTE v_sql;
EXECUTE 'DROP TABLE IF EXISTS t_tmp';
INSERT INTO keyword_test_result
VALUES ('pg', r.word, 'COLUMN', 'OK', NULL, now());
EXCEPTION WHEN OTHERS THEN
INSERT INTO keyword_test_result
VALUES ('pg', r.word, 'COLUMN', 'FAIL', SQLERRM, now());
END;
BEGIN
v_sql := format(
'CREATE FUNCTION %I(x INT) RETURNS INT AS $func$ BEGIN RETURN x; END; $func$ LANGUAGE plpgsql',
r.word
);
EXECUTE v_sql;
EXECUTE format('DROP FUNCTION IF EXISTS %I(INT)', r.word);
INSERT INTO keyword_test_result
VALUES ('pg', r.word, 'FUNCTION', 'OK', NULL, now());
EXCEPTION WHEN OTHERS THEN
INSERT INTO keyword_test_result
VALUES ('pg', r.word, 'FUNCTION', 'FAIL', SQLERRM, now());
END;
END LOOP;
END;
$$;
CREATE OR REPLACE PROCEDURE p_pg_raw_keyword()
LANGUAGE plpgsql
AS $$
DECLARE
r RECORD;
v_sql TEXT;
BEGIN
FOR r IN SELECT word FROM pg_get_keywords() LOOP
/* ================= TABLE ================= */
BEGIN
v_sql := 'CREATE TABLE ' || r.word || ' (id INT)';
EXECUTE v_sql;
EXECUTE 'DROP TABLE ' || r.word;
INSERT INTO keyword_test_result
VALUES ('pg_raw', r.word, 'TABLE', 'OK', NULL, now());
EXCEPTION WHEN OTHERS THEN
INSERT INTO keyword_test_result
VALUES ('pg_raw', r.word, 'TABLE', 'FAIL', SQLERRM, now());
END;
/* ================= COLUMN ================= */
BEGIN
v_sql := 'CREATE TABLE t_tmp (' || r.word || ' INT)';
EXECUTE v_sql;
EXECUTE 'DROP TABLE IF EXISTS t_tmp';
INSERT INTO keyword_test_result
VALUES ('pg_raw', r.word, 'COLUMN', 'OK', NULL, now());
EXCEPTION WHEN OTHERS THEN
INSERT INTO keyword_test_result
VALUES ('pg_raw', r.word, 'COLUMN', 'FAIL', SQLERRM, now());
END;
/* ================= FUNCTION ================= */
BEGIN
v_sql :=
'CREATE FUNCTION ' || r.word || '(x INT) RETURNS INT AS $func$ ' ||
'BEGIN RETURN x; END; $func$ LANGUAGE plpgsql';
EXECUTE v_sql;
EXECUTE 'DROP FUNCTION IF EXISTS ' || r.word || '(INT)';
INSERT INTO keyword_test_result
VALUES ('pg_raw', r.word, 'FUNCTION', 'OK', NULL, now());
EXCEPTION WHEN OTHERS THEN
INSERT INTO keyword_test_result
VALUES ('pg_raw', r.word, 'FUNCTION', 'FAIL', SQLERRM, now());
END;
END LOOP;
END;
$$;
添加引号的执行结果
postgres=# select count(*),test_type from keyword_test_result where result='OK' group by test_type;
count | test_type
-------+-----------
457 | TABLE
457 | FUNCTION
457 | COLUMN
(3 rows)
不加引号的执行结果
从结果来看所有PostgreSQL所有的关键词使用引号都可以作为表名table_name、字段column_name、函数名function_name
如果不添加引号创建失败的关键词如下:
sqlserver目前没有系统试图和系统表能查出完整的关键字
可以考虑自己创建一张表
id INT IDENTITY(1,1) PRIMARY KEY,
db_type VARCHAR(50),
keyword VARCHAR(200),
create_time DATETIME DEFAULT GETDATE()
);
INSERT INTO db_keywords (db_type, keyword)
VALUES
('SQLSERVER','ADD'),
('SQLSERVER','ALL'),
('SQLSERVER','ALTER'),
('SQLSERVER','AND'),
('SQLSERVER','ANY'),
('SQLSERVER','AS'),
('SQLSERVER','ASC'),
('SQLSERVER','AUTHORIZATION'),
('SQLSERVER','BACKUP'),
('SQLSERVER','BEGIN'),
('SQLSERVER','BETWEEN'),
('SQLSERVER','BREAK'),
('SQLSERVER','BROWSE'),
('SQLSERVER','BULK'),
('SQLSERVER','BY'),
('SQLSERVER','CASCADE'),
('SQLSERVER','CASE'),
('SQLSERVER','CHECK'),
('SQLSERVER','CHECKPOINT'),
('SQLSERVER','CLOSE'),
('SQLSERVER','CLUSTERED'),
('SQLSERVER','COALESCE'),
('SQLSERVER','COLLATE'),
('SQLSERVER','COLUMN'),
('SQLSERVER','COMMIT'),
('SQLSERVER','COMPUTE'),
('SQLSERVER','CONSTRAINT'),
('SQLSERVER','CONTAINS'),
('SQLSERVER','CONTINUE'),
('SQLSERVER','CONVERT'),
('SQLSERVER','CREATE'),
('SQLSERVER','CROSS'),
('SQLSERVER','CURRENT'),
('SQLSERVER','DATABASE'),
('SQLSERVER','DBCC'),
('SQLSERVER','DECLARE'),
('SQLSERVER','DEFAULT'),
('SQLSERVER','DELETE'),
('SQLSERVER','DESC'),
('SQLSERVER','DISTINCT'),
('SQLSERVER','DROP'),
('SQLSERVER','EXEC'),
('SQLSERVER','EXECUTE'),
('SQLSERVER','EXISTS'),
('SQLSERVER','FROM'),
('SQLSERVER','FULL'),
('SQLSERVER','FUNCTION'),
('SQLSERVER','GRANT'),
('SQLSERVER','GROUP'),
('SQLSERVER','HAVING'),
('SQLSERVER','IN'),
('SQLSERVER','INDEX'),
('SQLSERVER','INNER'),
('SQLSERVER','INSERT'),
('SQLSERVER','INTERSECT'),
('SQLSERVER','INTO'),
('SQLSERVER','IS'),
('SQLSERVER','JOIN'),
('SQLSERVER','LEFT'),
('SQLSERVER','LIKE'),
('SQLSERVER','NOT'),
('SQLSERVER','NULL'),
('SQLSERVER','ON'),
('SQLSERVER','OR'),
('SQLSERVER','ORDER'),
('SQLSERVER','OUTER'),
('SQLSERVER','PRIMARY'),
('SQLSERVER','PROCEDURE'),
('SQLSERVER','RETURN'),
('SQLSERVER','RIGHT'),
('SQLSERVER','ROLLBACK'),
('SQLSERVER','SELECT'),
('SQLSERVER','SET'),
('SQLSERVER','TABLE'),
('SQLSERVER','THEN'),
('SQLSERVER','TO'),
('SQLSERVER','TRANSACTION'),
('SQLSERVER','TRIGGER'),
('SQLSERVER','UNION'),
('SQLSERVER','UNIQUE'),
('SQLSERVER','UPDATE'),
('SQLSERVER','USER'),
('SQLSERVER','VALUES'),
('SQLSERVER','VIEW'),
('SQLSERVER','WHERE'),
('SQLSERVER','WHILE'),
('SQLSERVER','WITH');
CREATE PROCEDURE p_sqlserver_keyword
AS
BEGIN
DECLARE @keyword NVARCHAR(100);
DECLARE @sql NVARCHAR(MAX);
DECLARE cur CURSOR FOR
SELECT keyword FROM keyword_list;
OPEN cur;
FETCH NEXT FROM cur INTO @keyword;
WHILE @@FETCH_STATUS = 0
BEGIN
BEGIN TRY
SET @sql = 'CREATE TABLE ' + QUOTENAME(@keyword) + ' (id INT)';
EXEC(@sql);
SET @sql = 'DROP TABLE ' + QUOTENAME(@keyword);
EXEC(@sql);
INSERT INTO keyword_test_result
VALUES ('sqlserver', @keyword, 'TABLE', 'OK', NULL, GETDATE());
END TRY
BEGIN CATCH
INSERT INTO keyword_test_result
VALUES ('sqlserver', @keyword, 'TABLE', 'FAIL', ERROR_MESSAGE(), GETDATE());
END CATCH;
FETCH NEXT FROM cur INTO @keyword;
END
CLOSE cur;
DEALLOCATE cur;
END;
CREATE OR ALTER PROCEDURE p_mssql_raw_keyword
AS
BEGIN
SET NOCOUNT ON;
DECLARE @keyword NVARCHAR(100);
DECLARE @sql NVARCHAR(MAX);
DECLARE cur CURSOR FOR
SELECT word FROM keyword_list;
OPEN cur;
FETCH NEXT FROM cur INTO @keyword;
WHILE @@FETCH_STATUS = 0
BEGIN
/* ================= TABLE ================= */
BEGIN TRY
SET @sql = N'CREATE TABLE ' + @keyword + N' (id INT)';
EXEC sp_executesql @sql;
SET @sql = N'DROP TABLE ' + @keyword;
EXEC sp_executesql @sql;
INSERT INTO keyword_test_result
VALUES ('mssql_raw', @keyword, 'TABLE', 'OK', NULL, GETDATE());
END TRY
BEGIN CATCH
INSERT INTO keyword_test_result
VALUES ('mssql_raw', @keyword, 'TABLE', 'FAIL', ERROR_MESSAGE(), GETDATE());
END CATCH;
/* ================= COLUMN ================= */
BEGIN TRY
SET @sql = N'CREATE TABLE t_tmp (' + @keyword + N' INT)';
EXEC sp_executesql @sql;
DROP TABLE t_tmp;
INSERT INTO keyword_test_result
VALUES ('mssql_raw', @keyword, 'COLUMN', 'OK', NULL, GETDATE());
END TRY
BEGIN CATCH
INSERT INTO keyword_test_result
VALUES ('mssql_raw', @keyword, 'COLUMN', 'FAIL', ERROR_MESSAGE(), GETDATE());
END CATCH;
/* ================= FUNCTION ================= */
BEGIN TRY
SET @sql =
N'CREATE FUNCTION ' + @keyword + N'(@x INT) RETURNS INT AS BEGIN RETURN @x END';
EXEC sp_executesql @sql;
SET @sql = N'DROP FUNCTION ' + @keyword;
EXEC sp_executesql @sql;
INSERT INTO keyword_test_result
VALUES ('mssql_raw', @keyword, 'FUNCTION', 'OK', NULL, GETDATE());
END TRY
BEGIN CATCH
INSERT INTO keyword_test_result
VALUES ('mssql_raw', @keyword, 'FUNCTION', 'FAIL', ERROR_MESSAGE(), GETDATE());
END CATCH;
FETCH NEXT FROM cur INTO @keyword;
END
CLOSE cur;
DEALLOCATE cur;
END;
CREATE OR REPLACE PROCEDURE p_oracle_keyword IS
CURSOR c_keywords IS
SELECT keyword FROM v$reserved_words;
v_sql VARCHAR2(4000);
v_errmsg VARCHAR2(4000);
BEGIN
FOR r IN c_keywords LOOP
BEGIN
v_sql := 'CREATE TABLE ' || r.keyword || ' (id NUMBER)';
EXECUTE IMMEDIATE v_sql;
EXECUTE IMMEDIATE 'DROP TABLE ' || r.keyword;
INSERT INTO keyword_test_result
VALUES ('oracle', r.keyword, 'TABLE', 'OK', NULL, SYSDATE);
EXCEPTION
WHEN OTHERS THEN
v_errmsg := SQLERRM;
INSERT INTO keyword_test_result
VALUES ('oracle', r.keyword, 'TABLE', 'FAIL', v_errmsg, SYSDATE);
END;
BEGIN
v_sql := 'CREATE TABLE t_test ( ' || r.keyword || ' NUMBER )';
EXECUTE IMMEDIATE v_sql;
EXECUTE IMMEDIATE 'DROP TABLE t_test';
INSERT INTO keyword_test_result
VALUES ('oracle', r.keyword, 'COLUMN', 'OK', NULL, SYSDATE);
EXCEPTION
WHEN OTHERS THEN
v_errmsg := SQLERRM;
INSERT INTO keyword_test_result
VALUES ('oracle', r.keyword, 'COLUMN', 'FAIL', v_errmsg, SYSDATE);
END;
BEGIN
v_sql := '
CREATE OR REPLACE FUNCTION ' || r.keyword || ' (x NUMBER)
RETURN NUMBER
IS
BEGIN
RETURN x;
END;
';
EXECUTE IMMEDIATE v_sql;
EXECUTE IMMEDIATE 'DROP FUNCTION ' || r.keyword;
INSERT INTO keyword_test_result
VALUES ('oracle', r.keyword, 'FUNCTION', 'OK', NULL, SYSDATE);
EXCEPTION
WHEN OTHERS THEN
v_errmsg := SQLERRM;
INSERT INTO keyword_test_result
VALUES ('oracle', r.keyword, 'FUNCTION', 'FAIL', v_errmsg, SYSDATE);
END;
END LOOP;
COMMIT;
END;
/
不加引号的结果
不支持的关键词如下:
SQL> select count(*) from SYS.V$RESERVED_WORDS;
LINEID COUNT(*)
---------- --------------------
1 864
CURSOR c_keywords IS
SELECT keyword FROM v$reserved_words;
v_sql VARCHAR2(4000);
v_errmsg VARCHAR2(4000);
BEGIN
FOR r IN c_keywords LOOP
BEGIN
v_sql := 'CREATE TABLE ' || r.keyword || ' (id NUMBER)';
EXECUTE IMMEDIATE v_sql;
EXECUTE IMMEDIATE 'DROP TABLE ' || r.keyword;
INSERT INTO keyword_test_result
VALUES ('dm', r.keyword, 'TABLE', 'OK', NULL, SYSDATE);
EXCEPTION
WHEN OTHERS THEN
v_errmsg := SQLERRM;
INSERT INTO keyword_test_result
VALUES ('dm', r.keyword, 'TABLE', 'FAIL', v_errmsg, SYSDATE);
END;
BEGIN
v_sql := 'CREATE TABLE t_test ( ' || r.keyword || ' NUMBER )';
EXECUTE IMMEDIATE v_sql;
EXECUTE IMMEDIATE 'DROP TABLE t_test';
INSERT INTO keyword_test_result
VALUES ('dm', r.keyword, 'COLUMN', 'OK', NULL, SYSDATE);
EXCEPTION
WHEN OTHERS THEN
v_errmsg := SQLERRM;
INSERT INTO keyword_test_result
VALUES ('dm', r.keyword, 'COLUMN', 'FAIL', v_errmsg, SYSDATE);
END;
BEGIN
v_sql := '
CREATE OR REPLACE FUNCTION ' || r.keyword || ' (x NUMBER)
RETURN NUMBER
IS
BEGIN
RETURN x;
END;
';
EXECUTE IMMEDIATE v_sql;
EXECUTE IMMEDIATE 'DROP FUNCTION ' || r.keyword;
INSERT INTO keyword_test_result
VALUES ('dm', r.keyword, 'FUNCTION', 'OK', NULL, SYSDATE);
EXCEPTION
WHEN OTHERS THEN
v_errmsg := SQLERRM;
INSERT INTO keyword_test_result
VALUES ('dm', r.keyword, 'FUNCTION', 'FAIL', v_errmsg, SYSDATE);
END;
END LOOP;
COMMIT;
END;
SQL> select db_type,test_type,result,count(*) from keyword_test_result group by db_type,test_type,result;
LINEID DB_TYPE TEST_TYPE RESULT COUNT(*)
---------- ------- --------- ------ --------------------
1 dm TABLE FAIL 239
2 dm COLUMN FAIL 202
3 dm FUNCTION FAIL 239
4 dm TABLE OK 625
5 dm COLUMN OK 662
6 dm FUNCTION OK 625
6 rows got
达梦数据库不加引号,关键不支持函数、表、字段名成的如下:
对比说明:以下关键字同时存在于达梦(DM)与 Oracle 的保留字清单中,在未使用双引号("")强制转义的原生命名场景
在不使用转义的情况下,各数据库对关键字限制差异明显:
在使用转义符后,四类数据库均显著放宽限制:
在函数名使用方面,各数据库限制更为严格
#6 工程化使用Python 模拟客户端调用驱动来访问数据库
pip install oracledb pymysql psycopg2-binary pyodbc pandas
单独部署达梦的dmPython依赖包
CREATE TABLE keyword_test_result (
db_type VARCHAR(20),
keyword VARCHAR(100),
test_type VARCHAR(20),
quoted VARCHAR(5),
success VARCHAR(5),
error_msg VARCHAR(4000),
test_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
import pandas as pd
import traceback
CONFIG = {
"oracle": {
"user": "xxx",
"password": "xxx",
"dsn": "ip:port/service"
},
"mysql": {
"host": "ip",
"user": "xxx",
"password": "xxx",
"database": "test"
},
"postgres": {
"host": "ip",
"user": "xxx",
"password": "xxx",
"dbname": "test"
},
"sqlserver": {
"conn_str": "DRIVER={ODBC Driver 17 for SQL Server};SERVER=ip;DATABASE=test;UID=xxx;PWD=xxx"
}
}
def safe_exec(cursor, sql):
try:
cursor.execute(sql)
return "yes", ""
except Exception as e:
return "no", str(e)
# ========= DM ============
def test_DM():
import dmPython
conn = oracledb.connect(**CONFIG["oracle"])
cur = conn.cursor()
cur.execute("SELECT keyword FROM v$reserved_words")
keywords = [r[0] for r in cur.fetchall()]
results = []
for kw in keywords:
# table
for quoted in [False, True]:
name = f'"{kw}"' if quoted else kw
sql = f"CREATE TABLE {name} (id NUMBER)"
ok, err = safe_exec(cur, sql)
if ok == "yes":
cur.execute(f"DROP TABLE {name}")
results.append(("dm", kw, "table", str(quoted), ok, err))
# column
for quoted in [False, True]:
col = f'"{kw}"' if quoted else kw
sql = f"CREATE TABLE t_tmp ({col} NUMBER)"
ok, err = safe_exec(cur, sql)
if ok == "yes":
cur.execute("DROP TABLE t_tmp")
results.append(("dm", kw, "column", str(quoted), ok, err))
return results
# ========= Oracle =========
def test_oracle():
import oracledb
conn = oracledb.connect(**CONFIG["oracle"])
cur = conn.cursor()
cur.execute("SELECT keyword FROM v$reserved_words")
keywords = [r[0] for r in cur.fetchall()]
results = []
for kw in keywords:
# table
for quoted in [False, True]:
name = f'"{kw}"' if quoted else kw
sql = f"CREATE TABLE {name} (id NUMBER)"
ok, err = safe_exec(cur, sql)
if ok == "yes":
cur.execute(f"DROP TABLE {name}")
results.append(("oracle", kw, "table", str(quoted), ok, err))
# column
for quoted in [False, True]:
col = f'"{kw}"' if quoted else kw
sql = f"CREATE TABLE t_tmp ({col} NUMBER)"
ok, err = safe_exec(cur, sql)
if ok == "yes":
cur.execute("DROP TABLE t_tmp")
results.append(("oracle", kw, "column", str(quoted), ok, err))
return results
# ========= MySQL =========
def test_mysql():
import pymysql
conn = pymysql.connect(**CONFIG["mysql"])
cur = conn.cursor()
cur.execute("SELECT WORD FROM INFORMATION_SCHEMA.KEYWORDS")
keywords = [r[0] for r in cur.fetchall()]
results = []
for kw in keywords:
for quoted in [False, True]:
name = f"`{kw}`" if quoted else kw
sql = f"CREATE TABLE {name} (id INT)"
ok, err = safe_exec(cur, sql)
if ok == "yes":
cur.execute(f"DROP TABLE {name}")
results.append(("mysql", kw, "table", str(quoted), ok, err))
return results
# ========= PostgreSQL =========
def test_pg():
import psycopg2
conn = psycopg2.connect(**CONFIG["postgres"])
cur = conn.cursor()
cur.execute("SELECT word FROM pg_get_keywords()")
keywords = [r[0] for r in cur.fetchall()]
results = []
for kw in keywords:
for quoted in [False, True]:
name = f'"{kw}"' if quoted else kw
sql = f"CREATE TABLE {name} (id INT)"
ok, err = safe_exec(cur, sql)
if ok == "yes":
cur.execute(f"DROP TABLE {name}")
results.append(("postgres", kw, "table", str(quoted), ok, err))
return results
# ========= SQL Server =========
def test_sqlserver():
import pyodbc
conn = pyodbc.connect(CONFIG["sqlserver"]["conn_str"])
cur = conn.cursor()
cur.execute("SELECT keyword FROM keyword_source")
keywords = [r[0] for r in cur.fetchall()]
results = []
for kw in keywords:
for quoted in [False, True]:
name = f"[{kw}]" if quoted else kw
sql = f"CREATE TABLE {name} (id INT)"
ok, err = safe_exec(cur, sql)
if ok == "yes":
cur.execute(f"DROP TABLE {name}")
results.append(("sqlserver", kw, "table", str(quoted), ok, err))
return results
def main():
all_results = []
all_results += test_oracle()
all_results += test_mysql()
all_results += test_pg()
# all_results += test_sqlserver()
df = pd.DataFrame(all_results, columns=[
"db_type", "keyword", "test_type", "quoted", "success", "error_msg"
])
df.to_csv("keyword_test_result.csv", index=False)
print("importer CSV")
if __name__ == "__main__":
main()
文章
阅读量
获赞
