暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

UXDB嵌入式开发-SQL与C接口一本通

原创 优炫数据库 1天前
3

概述

目标读者: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 语句,可出现在全局层或函数中。其优势:

  1. 自动处理 C 变量与 SQL 之间的数据传递;
  2. SQL 在编译期即做语法检查;
  3. 符合 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:porttcp: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_OVERFLOWUXTYPES_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_tsqlvar_tstruct 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 filenameEXEC SQL DEFINE nameEXEC 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++ 语法的问题。

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论