/ 三方言语法手册 / 总览
DbSql · 文档

三方言语法手册

每条支持 / 不支持 / 与厂商数据库的差异,都由 verify.sh 在真实二进制上跑过。

适用版本:target/release/dbsql(2026-11-10 构建)+ plugins/libdbsql_oracle_plugin.so、plugins/libdbsql_mysql_plugin.so(2026-11-13 重建)。 结论口径:每条都在这套二进制上真跑过;复现脚本见 verify.sh,实测记录见 验证附录.md。 单方言细节:T-SQL · PL/SQL · MySQL

1. 三个运行时方言

方言只决定怎么解析和改写 SQL。三种方言共用同一套存储、同一批库表、同一套约束校验和同一个执行引擎——所以数据类型的行为(CHAR(n)、VARCHAR(n)、DECIMAL(p,s))在三种方言下是一致的。

显示名 CLI 取值 旧标识(仍兼容) 执行路径 是否需要插件
T-SQL standard(默认) mssql 内置解析器 → 标准引擎 不需要;配了 --plugin 会直接报错
PL/SQL procedural oracle 插件 libdbsql_oracle_plugin.so + 标准引擎 必需
MySQL mysql — 插件 libdbsql_mysql_plugin.so + 标准引擎 必需

2. 怎么选方言

CLI

# 默认 T-SQL
dbsql --root /data sql mydb "SELECT TOP 5 * FROM t"

# PL/SQL(插件按方言名自动探测)
dbsql --root /data --dialect procedural sql mydb "SELECT 1 FROM DUAL"

# MySQL
dbsql --root /data --dialect mysql sql mydb "SELECT * FROM t LIMIT 1, 5"

# 显式指定插件(--plugin 必须写在子命令之前)
dbsql --root /data --dialect mysql --plugin /opt/dbsql/libdbsql_mysql_plugin.so \
      sql mydb "SELECT 1"

插件探测顺序(未给 --plugin 时):plugins/dbsql_<方言>_plugin.<ext>、plugins/libdbsql_<方言>_plugin.<ext>、当前目录同名文件。 为 so / dll / dylib。

缺插件时的报错:

PL/SQL 方言需要插件,请用 --plugin <路径> 指定 dbsql_oracle_plugin.so
MySQL 方言需要插件,请用 --plugin <路径> 指定 dbsql_mysql_plugin.so

T-SQL 配 --plugin 时:

--plugin 只在 procedural/mysql 方言下生效,当前方言为 standard;请加 --dialect procedural 或 --dialect mysql(收到的插件路径:…)

HTTP / Web

POST /api/sql、POST /api/select、建例程接口都接受请求体里的 "dialect" 字段,取值同上(standard / procedural / mysql,旧值 mssql / oracle 兼容)。注意:无法识别的取值会静默退回 T-SQL,不会报错;拼错方言名时会表现为“语法不支持”。

3. 方言之间是隔离的(例程层面)

4. 三方言共同支持的基础语法

5. 三方言共同不支持

功能 实测报错 替代
外键(REFERENCES / FOREIGN KEY) 外键约束 '…'(引用 '…')暂不支持:外键的跨表校验还没有实现,收下声明只会让孤儿行照插进来。请改用 NOT NULL + 应用层校验,或把引用关系交给存储过程检查。 NOT NULL + 应用层 / 过程校验
CROSS JOIN 错误:SELECT 语句末尾存在多余内容(位于 …) 逗号连接(FROM a, b)或显式 INNER JOIN … ON 1=1
一条命令执行多条顶层语句 错误:SELECT 语句末尾存在多余内容 / 只支持单条语句;语句结束后仍有多余内容:'SELECT' 一次一条;PL/SQL 可用匿名块,过程体内可分多条
跨库/带架构前缀的表名 表名 'dbo' 带库/架构前缀,dbsql 不支持跨库引用(请改写为同库表名) 只写同库表名
事务跨命令/跨连接 单独执行 COMMIT → 错误:没有活动事务 见第 7 节
列长度/精度“装饰”(VARCHAR(n) 校验、NUMBER(p,s) 校验) 不报错也不生效(VARCHAR(5) 可存 8 个字符) 应用层校验;需要严格小数位时用 T-SQL 的 DECIMAL(p,s)

6. 横向矩阵

✔ = 实测可用;✘ = 实测不可用或有明确限制;— = 该方言不存在此语法。

功能 T-SQL PL/SQL MySQL
SELECT / JOIN / GROUP BY / HAVING / ORDER BY ✔ ✔ ✔
CROSS JOIN ✘ ✘ ✘
CTE(非递归) ✔ ✔ ✔
递归 CTE ✔(UNION ALL) ✘(递归名被当表名) ✔(WITH RECURSIVE)
UNION / INTERSECT / EXCEPT ✔(同类可链式) ✔ UNION / INTERSECT / MINUS;EXCEPT 不识别 ✔
ROW_NUMBER() OVER (ORDER BY …) ✔ ✘(窗口语法未解析) ✘(窗口语法未解析)
PARTITION BY ✘ ✘ ✘
LIMIT / OFFSET ✔ ✔ ✔
OFFSET … FETCH NEXT / FETCH FIRST ✔ ✔(FETCH NEXT 须跟在 OFFSET 后;单独写报「期望关键字 'FIRST'」) ✘(用 LIMIT)
TOP n ✔ — —
TOP n PERCENT ✘ — —
多行 VALUES (…),(…) ✔ ✔ ✔
INSERT … SELECT ✔ ✘ ✘
INSERT IGNORE / REPLACE / ON DUPLICATE KEY UPDATE — — ✔(只探测主键)
复合主键 ✔ ✔(列须显式 NOT NULL) ✔
UNIQUE / CHECK / DEFAULT ✔ ✔ ✔
外键 ✘ ✘ ✘
列默认可空性 默认 NOT NULL 默认可空 默认可空
CHAR(n) ✔(单字符,非定长 n) ✔(同左) ✔(同左)
VARCHAR(n) 长度校验 ✘ ✘ ✘
DECIMAL(p,s) 小数位校验 ✔(超位报错,不舍入) ✘(NUMBER(p,s) 不校验) ✔
CREATE INDEX ✔ ✘ ✘
DROP INDEX ✘ ✘ ✘
TRUNCATE ✘ ✘ ✔(等价 DELETE + 重置自增)
ALTER TABLE ✔ ADD / MODIFY / RENAME ✔ ADD 列 / DROP COLUMN ✔ ADD / DROP / MODIFY / CHANGE / RENAME(单子句)
CREATE OR REPLACE VIEW ✘ ✔ ✘
触发器 ✔(受限语法) ✘ ✘
存储过程 ✔(CALL p()) ✔(CALL p()) ✔(CALL p();体内字符串字面量有缺陷)
匿名块 ✘ ✔ ✘
序列 / 包 / 同义词 — ✘ —
双引号标识符 ✘(当字符串) ✔(有同名列时) ✔(有同名列时,否则当字符串)
反引号标识符 ✘ ✘ ✔
方括号标识符 ✔ ✘ ✘
显式事务 BEGIN / COMMIT / ROLLBACK ✔(同一进程内) ✔(同一进程内) ✔(同一进程内)

7. 事务模型

$ dbsql --root /data --dialect procedural sql db "COMMIT"
错误:没有活动事务

8. 内置函数(三方言共享同一张注册表)

sysdate, current_timestamp, now, getdate, rand, coalesce, nvl, ifnull, concat,
length, len, trim, ltrim, rtrim, lower, upper, isnumeric, isdate, abs, floor,
ceiling, ceil, sign, reverse, ascii, space, year, month, day, to_char, substr,
substring, instr, charindex, patindex, left, right, replicate, datepart,
dateadd, datediff, replace, iif, stuff, round, mod

9. 文档索引

文件 内容
tsql.md T-SQL:支持项、类型映射、过程/触发器/SET 白名单、不支持项、与 SQL Server 的差异
plsql.md PL/SQL:DUAL/匿名块/过程、支持项、不支持项、与 Oracle 的差异
mysql.md MySQL:反引号/LIMIT/自增/SHOW/过程、支持项、不支持项、与 MySQL 的差异与已知缺陷
verify.sh 自包含复核脚本:新建临时数据根,逐条打印 SQL 与结果
验证附录.md 复核环境、运行方法、关键声明的实测输出

10. 已知缺陷(与语法文档分开记)

  1. MySQL 存储过程体内的字符串字面量被当成列名:CALL 时报 列 'v' 的值写错了:表中不存在列 'x';SELECT 'x' AS s 报 无法计算表达式:x AS s。纯数字/参数的过程体正常。
  2. MySQL INSERT IGNORE / REPLACE / ON DUPLICATE KEY UPDATE 只探测主键:唯一键冲突不会按 MySQL 语义忽略/替换,而是报 唯一约束 'uk' 冲突。
  3. SHOW CREATE TABLE 查不存在的表返回空骨架(CREATE TABLE \nope` (\n\n) ENGINE=InnoDB…`),不报错。
  4. MySQL SELECT @v 把 @v 当字符串字面量原样返回,不报“不支持”。
  5. PL/SQL 的 ROWNUM 解析器收下但执行不了:投影报 SELECT 列 'ROWNUM' 不存在,WHERE 报 表中不存在列 'ROWNUM'。
  6. T-SQL CHAR(n) 是单字符类型;VARCHAR(n) 不校验长度(迁移时依赖长度的数据要单独核对)。
  7. MySQL SHOW CREATE TABLE 只回显主键,UNIQUE KEY / 普通 KEY 全部丢失(见 mysql.md)。