概述
目标读者:C/C++ 应用开发者。
用途:本文概述了UXDB嵌入式 SQL(ECUX)、SQLDA、uxtypes、大对象、动态 SQL 相关文档,形成从"概念 → 连接 → 变量传递 → 动态 SQL → 大对象 → 编译"的完整开发路线。适合作为 C/C++ 嵌入式 SQL 开发的入门与速查。
一、ECUX 概念
UXDB 的嵌入式 SQL 包称为 ECUX,用于在 C 程序中内嵌 SQL 命令。构建流程:
源文件 (*.uxc) --ecux 预处理器--> C 文件 (*.c) --C 编译器--> 可执行程序
↓ 链接 ecuxlib(内部调用 libuxsql)
嵌入式 SQL 语句以 EXEC SQL ...; 形式出现,语法上替代一条 C 语句,可出现在全局层或函数中。其优势:
- 自动处理 C 变量与 SQL 之间的数据传递;
- SQL 在编译期即做语法检查;
- 符合 SQL 标准,便于从其他数据库移植。
注意:嵌入式 SQL 遵循 SQL 的大小写规则(而非 C 的大小写规则),支持嵌套 C 风格注释。
二、连接管理
EXEC SQL CONNECT TO target [AS connection-name] [USER user-name]; EXEC SQL SET CONNECTION [TO| =] connection-name; -- 切换连接 EXEC SQL DISCONNECT connection-name; -- 断开连接
target 支持 dbname@host:port、tcp:postgresql://host:port/dbname 等 libuxsql 连接串。
三、主变量(Host Variable)
主变量是 C 变量在 SQL 语句中的引用方式,前面加冒号 ::
EXEC SQL BEGIN DECLARE SECTION;
int v1;
char name[50];
VARCHAR val; -- 特殊类型,自带长度
EXEC SQL END DECLARE SECTION;
EXEC SQL INSERT INTO sometable VALUES (:v1, :name);
EXEC SQL SELECT col1 INTO :v1 FROM t WHERE id = 1;
可见范围:ecux 能理解 C 的块级变量作用域;但 C++ 类成员变量(代码块与定义块不一致)无法被识别,应避免在 C++ 类方法中直接使用嵌入式 SQL(见第十节)。
字符串处理
char[n]:C 字符串,需保证以\0结尾。VARCHAR[n]:带长度的字符类型,自动维护实际长度。
指示符(Indicator)
处理 NULL 值必须为每个可空主变量配套一个指示符变量:
EXEC SQL BEGIN DECLARE SECTION;
int val;
int val_ind; -- 指示符
EXEC SQL END DECLARE SECTION;
EXEC SQL SELECT col INTO :val :val_ind FROM t WHERE id=1;
if (val_ind < 0) { /* val 为 NULL */ }
四、游标
EXEC SQL DECLARE cur CURSOR FOR SELECT id, name FROM t; EXEC SQL OPEN cur; EXEC SQL FETCH cur INTO :id, :name; -- 循环读取 EXEC SQL CLOSE cur;
五、动态 SQL
运行时构造的 SQL 需用动态方式执行:
/* 无结果集:EXECUTE IMMEDIATE */
EXEC SQL EXECUTE IMMEDIATE :stmt;
/* 有参数:PREPARE + EXECUTE USING */
EXEC SQL PREPARE stmt FROM :sql;
EXEC SQL EXECUTE stmt USING :param1, :param2;
/* 有结果集:PREPARE + DECLARE CURSOR + FETCH */
EXEC SQL PREPARE stmt FROM :sql;
EXEC SQL DECLARE cur CURSOR FOR stmt;
EXEC SQL OPEN cur;
EXEC SQL FETCH cur INTO :col1, :col2;
EXEC SQL CLOSE cur;
六、异常处理
两种非互斥的手段:
1. WHENEVER 回调
EXEC SQL WHENEVER SQLERROR GOTO error_label; EXEC SQL WHENEVER SQLWARNING CONTINUE; EXEC SQL WHENEVER NOT FOUND CONTINUE;
2. sqlca 结构
#include <sqlca.h>
EXEC SQL INCLUDE sqlca;
/* 出错后读取 sqlca.sqlcode / sqlca.sqlerrm.sqlerrmc 获取错误码与消息 */
七、uxtypes 库
uxtypes 库将 UXDB 特殊类型(numeric、decimal、date、timestamp、interval)映射到 C 类型,并提供不依赖服务器的本地计算函数:
EXEC SQL BEGIN DECLARE SECTION;
date date1;
timestamp ts1, ts2;
EXEC SQL END DECLARE SECTION;
/* 例如从文本解析时间戳 */
ts1 = UXTYPEStimestamp_from_asc("2026-01-01 10:00:00", NULL);
- numeric:任意精度,只能在堆上创建/释放(
UXTYPESnumeric_new/UXTYPESnumeric_free)。 - decimal:精度上限 30 位,可在栈或堆上创建。
- interval / date / timestamp:分别由
UXTYPESinterval_*、UXTYPESdate_*、UXTYPEStimestamp_*系列函数操作。
错误码(errno)常量前缀 UXTYPES_*,如 UXTYPES_NUM_OVERFLOW、UXTYPES_DATE_BAD_MONTH 等,解析失败后应同时检查 errno。
八、大对象(Large Object)
大对象提供对超大值的流式访问(open/read/write/lseek),适合无法一次性放入内存的数据。
- 数据存于系统表
ux_largeobject,元数据在ux_largeobject_metadata。 - 必须在事务块内操作,文件描述符仅在事务期间有效。
#include <libuxsql-fe.h>
Oid lobjId = lo_creat(conn, INV_READ | INV_WRITE);
int fd = lo_open(conn, lobjId, INV_WRITE);
lo_write(conn, fd, buf, len);
lo_close(conn, fd);
在 ECUX 应用中,可通过
ECUXget_UXconn()取得底层连接对象再调用 libuxsql 大对象函数,但需谨慎,不建议与其他 ECUX 调用混用。
九、SQLDA(描述符区域)
SQLDA 用于处理结构未知的结果集或参数(动态 SQL),是 C 结构体方案:
EXEC SQL INCLUDE sqlda.h;
sqlda_t *mysqlda;
EXEC SQL FETCH 3 FROM mycursor INTO DESCRIPTOR mysqlda;
/* 通过 sqlda_t->sqln 判断列数,遍历 sqlvar_t 获取每列类型与值 */
SQLDA 由 sqlda_t、sqlvar_t、struct sqlname 三种结构组成,与 IBM DB2 的 SQLDA 类似。
用 SQLDA 传参数:PREPARE 准备语句 → 声明输入 sqlda_t → 分配内存 → OPEN cursor USING DESCRIPTOR ...。
另一套方案是命名 SQL 描述符区域(ALLOCATE DESCRIPTOR / GET DESCRIPTOR / SET DESCRIPTOR / DEALLOCATE DESCRIPTOR),更适合结果行性质无法预知的场景。
十、C++ 应用
- ecux 对 C++ 支持有限:预处理器只理解 C,不识别 C++ 特定语法与类成员作用域。
- 推荐做法:将嵌入式 SQL 独立到 C 文件(
*.uxc),导出 C 函数供 C++ 调用,在链接阶段把 C 对象与 C++ 对象链接。
/* test_mod.uxc —— C + ECUX 模块,导出 C 接口 */
void test_mod_query(void);
十一、编译
ecux prog1.uxc # 生成 prog1.c
cc -o prog1 prog1.c -I<include> -L<lib> -lecux -luxsql
预处理指令:EXEC SQL INCLUDE filename、EXEC SQL DEFINE name、EXEC SQL UNDEF name。
调试:ECUXdebug(1, stderr) 打开调试日志,输出所有带变量的 SQL 语句及服务器返回。
总结
本文串起了 ECUX 从概念、连接、主变量与游标,到动态 SQL、异常处理、uxtypes、大对象、SQLDA 与 C++ 集成的完整开发路线。
其价值在于"遇到什么场景用什么机制"的映射:遇到 NULL 用指示符、遇到结构未知的结果集用 SQLDA、遇到超大值用大对象、遇到运行时构造的语句用 PREPARE/EXECUTE IMMEDIATE。开发主线可记为"DECLARE SECTION 声明主变量 → CONNECT → 静态/动态 SQL → WHENEVER/sqlca 处理异常"。C++ 项目务必把嵌入式 SQL 隔离到 C 模块(*.uxc),规避预处理器不识别 C++ 语法的问题。




