1.9.2. 统一SQL C 接口

1.9.2.1. 简介

统一SQL提供了 C API ,可供 C/C++ 程序直接调用;用户只需要正确地引用 unisql.h 与链接 libunisql.so 即可使用 C API。

1.9.2.2. TransferSQL接口

1.9.2.2.1. 接口说明

转换SQL语句(带缓存)

接口签名:

extern int TransferSQL(
    int sourceDbTypeCode,
    int targetDbTypeCode,
    const char* sourceSqlStr,
    char* targetSqlStr,
    int targetSqlMemoryLen,
    const char* jsonParameter);

要使用 C 接口,您需要发布包中对应操作系统平台的 so 动态库,以及 unisql.h 头文件。

C 接口同样支持读取统一 SQL 配置文件,具体使用方法可参考 配置文件

1.9.2.2.2. 接口请求参数

C 接口的每一项参数说明如下:

接口请求参数

参数名

类型

是否必须

说明

示例

sourceDbTypeCode

int

源数据库方言编码,见发布包中 unisql.h 的 UNISQL_DBTYPE_ 的定义

UNISQL_DBTYPE_ORACLE

targetDbTypeCode

int

目标数据库方言编码,见发布包中 unisql.h 的 UNISQL_DBTYPE_ 的定义

UNISQL_DBTYPE_GAUSSDB_ORACLE

sourceSqlStr

const char*

源SQL语句

"select name, avg(score) from student_score group by name"

targetSqlStr

char*

转换后的 SQL 内存空间,内存由调用方自行管理,推荐使用源 SQL 长度的 4 倍大小

buffer

targetSqlMemoryLen

int

targetSqlStr 的内存大小,比如传入 101 则可以存储长度为 100 的字符

101

jsonParameter

const char*

转换配置选项,预留扩展字段,目前传 NULL 即可

NULL

1.9.2.2.3. 接口枚举说明

统一 SQL 的 C API 方言编码枚举如下:

#define UNISQL_DBTYPE_LIGHTDB_MYSQL         1  // LIGHTDB MYSQL模式
#define UNISQL_DBTYPE_LIGHTDB_ORACLE        2  // LIGHTDB ORACLE模式
#define UNISQL_DBTYPE_LIGHTDB_POSTGRESQL    3  // LIGHTDB POSTGRESQL模式
#define UNISQL_DBTYPE_DM                    4  // 达梦
#define UNISQL_DBTYPE_MYSQL                 5  // MYSQL
#define UNISQL_DBTYPE_TDSQL_MYSQL           6  // TDSQL MYSQL模式
#define UNISQL_DBTYPE_MYSQL_80              7  // MYSQL8
#define UNISQL_DBTYPE_OCEAN_BASE_MYSQL      8  // OceanBase MYSQL模式
#define UNISQL_DBTYPE_OCEAN_BASE_ORACLE     9  // OceanBase ORACLE模式
#define UNISQL_DBTYPE_OPENGAUSS             10 // OPENGAUSS
#define UNISQL_DBTYPE_ORACLE                11 // ORACLE
#define UNISQL_DBTYPE_POSTGRESQL            12 // POSTGRESQL
#define UNISQL_DBTYPE_GOLDENDB_MYSQL        13 // GOLDENDB MYSQL模式
#define UNISQL_DBTYPE_GOLDENDB_ORACLE       14 // GOLDENDB ORACLE模式
#define UNISQL_DBTYPE_GAUSSDB_MYSQL         15 // 高斯 MYSQL模式
#define UNISQL_DBTYPE_GAUSSDB_ORACLE        16 // 高斯 ORACLE模式
#define UNISQL_DBTYPE_SQLSVR                17 // SQLSVR模式
#define UNISQL_DBTYPE_TDSQL_PG_ORACLE       18 // tdsql_pg oracle模式
#define UNISQL_DBTYPE_GAUSSDB500_ORACLE     19 // 高斯 ORACLE模式,(GaussDB Kernel V500R002C10 build f6002322)版本
#define UNISQL_DBTYPE_SQLITE                20 // SQLITE
#define UNISQL_DBTYPE_LTMEMDB               21 // LTMEMDB内存数据库
#define UNISQL_DBTYPE_ORACLE_19C            22 // ORACLE 19C版本
#define UNISQL_DBTYPE_GAUSSDB_MYSQL_B       23 // 高斯 MYSQL B版本
#define UNISQL_DBTYPE_TDSQL_PG              24 // TDSQL PG模式
#define UNISQL_DBTYPE_OPENGAUSS_MYSQL       25 // OPENGAUSS MYSQL模式
#define UNISQL_DBTYPE_GAUSSDB_PG            26 // 高斯 PG模式
#define UNISQL_DBTYPE_KINGBASE_ORACLE       27 // 人大金仓 ORACLE模式
#define UNISQL_DBTYPE_INFLUXDB1             28 // INFLUXDB1时序数据库
#define UNISQL_DBTYPE_INFLUXDB3             29 // INFLUXDB3时序数据库
#define UNISQL_DBTYPE_CLICKHOUSE            30 // CLICKHOUSE分析型数据库
#define UNISQL_DBTYPE_TDENGINE              31 // TDENGINE时序数据库
#define UNISQL_DBTYPE_DOLPHINDB             32 // DOLPHINDB时序数据库
#define UNISQL_DBTYPE_DORIS                 33 // DORIS分析型数据库
#define UNISQL_DBTYPE_TSDB                  34 // TSDB时序数据库
#define UNISQL_DBTYPE_GAUSSDB503_ORACLE     35 // 高斯 ORACLE模式,GaussDB Kernel 503版本

1.9.2.2.4. 接口返回参数

返回类型是一个 int ,取值有 3 种情况:

  • 返回 0: 代表转换成功

  • 返回 -1: 代表转换异常,需要在统一 SQL 的日志中查看具体失败原因

  • 返回大于 0 的数字:代表传入的 targetSqlMemoryLen 空间不足,返回值表示需要的空间

1.9.2.2.5. 调用示例

本例子假设统一 SQL 的发布包放在 /home/lightdb/LightDB1.0-unisql-V202403-00-000 下,示例步骤为:

  1. 设置环境变量,为了运行示例: export LD_LIBRARY_PATH=/home/lightdb/LightDB1.0-unisql-V202403-00-000/c/x86_64/lib:$LD_LIBRARY_PATH

  2. 编写示例代码,命名为 test.c

  3. 编译示例代码: gcc test.c -L /home/lightdb/LightDB1.0-unisql-V202403-00-000/c/x86_64/lib -I /home/lightdb/LightDB1.0-unisql-V202403-00-000/c/x86_64/include -lunisql -o test

  4. 执行示例代码查看效果

示例代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "unisql.h"
#include "unisql_dbtype.h"

int main() {
    // 数据库类型见unisql.h
    // 原始SQL数据库类型
    int sourceDbTypeCode=UNISQL_DBTYPE_ORACLE;
    // 目标SQL数据库类型
    int targetDbTypeCode=UNISQL_DBTYPE_GAUSSDB_ORACLE;
    // 原始SQL
    char* sourceSqlStr="SELECT o.order_id, o.order_date, c.customer_name, c.city, o.amount FROM unisql_orders o JOIN unisql_customers c ON o.customer_id = c.customer_id and c.customer_id=? and c.city=?;";
    // 目标SQL
    char* targetSqlStr=NULL;
    // 转换配置选项,预留扩展字段,目前传 NULL 即可
    char* jsonParameter = NULL;
    // 转换结果 0表示成功,>0表示目标串长度不够,<0表示失败
    int transRet=0;
    // 预设目标SQL的长度为原始SQL的4倍
    int targetSqlStrLen = strlen(sourceSqlStr)*4;
    // 分配内存
    targetSqlStr=(char*)malloc(targetSqlStrLen);

    printf("Before transfer sql is:%s\n",sourceSqlStr);

    // 调用TransferSQL转换函数
    transRet = TransferSQL(sourceDbTypeCode, targetDbTypeCode, sourceSqlStr, targetSqlStr, targetSqlStrLen, jsonParameter);
    if (transRet>0){
        // 预设目标SQL的长度不够,重新分配内存
        targetSqlStr=(char*) realloc (targetSqlStr, transRet) ;
        transRet =TransferSQL (sourceDbTypeCode, targetDbTypeCode, sourceSqlStr, targetSqlStr, transRet, jsonParameter);
    }
    if(transRet == 0)
    {
        printf("After transfer sql is:%s\n",targetSqlStr);
    }else if(transRet < 0)
    {
        printf("SQL Convert Failed:%d\n",transRet);
    }

    // 释放内存
    free(targetSqlStr);
    return 0;
}

示例执行结果:

Before transfer sql is:SELECT o.order_id, o.order_date, c.customer_name, c.city, o.amount FROM unisql_orders o JOIN unisql_customers c ON o.customer_id = c.customer_id and c.customer_id=? and c.city=?;
After transfer sql is:SELECT o.order_id,o.order_date,c.customer_name,c.city,o.amount FROM unisql_orders AS o JOIN unisql_customers AS c ON o.customer_id=c.customer_id AND c.customer_id=? AND c.city=?

1.9.2.3. UnisqlParseSimpleStatement接口

1.9.2.3.1. 接口说明

接口签名:

extern char* UnisqlParseSimpleStatement(const char* sourceSql);

要使用 C 接口,您需要发布包中对应操作系统平台的 so 动态库,以及 unisql.h 头文件。

1.9.2.3.2. 接口请求参数

UnisqlParseSimpleStatement接口的每一项参数说明如下:

接口请求参数

参数名

类型

是否必须

说明

示例

sourceSql

const char*

用户输入的待解析的SQL语句, 只支持针对单表的简单增删改查语句

"select * from t1 where c1 = 2 and c2 = 3"

1.9.2.3.3. 接口返回参数

UnisqlParseSimpleStatement 接口返回类型是一个char*, 是解析结果的序列化形式, 包含内容: set子句和where子句后面的键值对、表名、语句类型、解析状态、是否存在where子句

  • ParseStatus: 解析状态,0 成功, -1 失败

  • SourceType: SQL类型, 1 insert、2 update、3 delete、4 select

  • TableName: 表名

  • ExistsWhere: 是否存在where子句,对于insert语句,表示是否指定了列名

  • SetClause: set子句中的键值对

  • WhereClause: where子句中的键值对

1.9.2.3.4. 调用示例

本例子假设统一 SQL 的发布包放在 /home/lightdb/LightDB1.0-unisql-V202403-00-000 下,示例步骤为:

  1. 设置环境变量,为了运行示例: export LD_LIBRARY_PATH=/home/lightdb/LightDB1.0-unisql-V202403-00-000/c/x86_64/lib:$LD_LIBRARY_PATH

  2. 编写示例代码,命名为 test.c

  3. 编译示例代码: gcc test.c -L /home/lightdb/LightDB1.0-unisql-V202403-00-000/c/x86_64/lib -I /home/lightdb/LightDB1.0-unisql-V202403-00-000/c/x86_64/include -lunisql -o test

  4. 执行示例代码查看效果

示例代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "unisql.h"
#include "unisql_dbtype.h"

int main() {
    const char* sql = "select * from t1 where c1 = 1 and c2 = 2";
    char* parseResult = NULL;

    parseResult = UnisqlParseSimpleStatement(sql);
    printf("%s\n", parseResult);
    // 释放内存
    free(parseResult);

    return 0;
}

示例执行结果:

parseStatus: 0, sourceType: 4, tableName: "t1", existsWhere: true, setClause: [], whereClause: [{"c1" "1"} {"c2" "2"}]

1.9.2.4. UnisqlParseSimpleStatementInfo接口

1.9.2.4.1. 接口说明

接口签名:

extern char* UnisqlParseSimpleStatementInfo(const char* sourceSql);

要使用 C 接口,您需要发布包中对应操作系统平台的 so 动态库,以及 unisql.h 头文件。

1.9.2.4.2. 接口请求参数

UnisqlParseSimpleStatementInfo接口的每一项参数说明如下:

接口请求参数

参数名

类型

是否必须

说明

示例

sourceSql

const char*

用户输入的待解析的SQL语句, 只支持针对单表的简单增删改查语句

"select * from t1 where c1 = 2 and c2 = 3"

1.9.2.4.3. 接口返回参数

UnisqlParseSimpleStatementInfo 接口返回类型是一个char*, 是解析结果的序列化形式, 包含内容: where子句的字符串、表名、是否多表、语句类型、解析状态、是否存在where子句、insert语句的键值对、update语句的where子句中第一个绑定变量的下标

  • ParseStatus: 解析状态,0 成功, -1 失败

  • MultiTable: 是否操作多表

  • SourceType: SQL类型, 1 insert、2 update、3 delete、4 select

  • TableName: 表名

  • ExistsWhere: 是否存在where子句, 对于insert语句, 表示是否指定了列名

  • InsertKV: insert语句中的列名和值

  • WhereCondition: where子句的条件

  • WhereBindParamPos: update语句的where子句中第一个绑定变量的下标(从1开始), 0表示没有绑定变量

1.9.2.4.4. 调用示例

本例子假设统一 SQL 的发布包放在 /home/lightdb/LightDB1.0-unisql-V202403-00-000 下,示例步骤为:

  1. 设置环境变量,为了运行示例: export LD_LIBRARY_PATH=/home/lightdb/LightDB1.0-unisql-V202403-00-000/c/x86_64/lib:$LD_LIBRARY_PATH

  2. 编写示例代码,命名为 test.c

  3. 编译示例代码: gcc test.c -L /home/lightdb/LightDB1.0-unisql-V202403-00-000/c/x86_64/lib -I /home/lightdb/LightDB1.0-unisql-V202403-00-000/c/x86_64/include -lunisql -o test

  4. 执行示例代码查看效果

示例代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "unisql.h"

int main() {
    const char* sql = "select * from t1 where c1 = 1 and c2 = 2";
    char* parseResult = NULL;

    parseResult = UnisqlParseSimpleStatementInfo(sql);
    printf("%s\n", parseResult);
    // 释放内存
    free(parseResult);
    return 0;
}

示例执行结果:

parseStatus: 0, multiTable: false, sourceType: 4, tableName: "t1", existsWhere: true, insertKV: [], whereCondition: "c1=1 AND c2=2", whereBindParamPos: 0

1.9.2.5. UnisqlParseSimpleStatementInfoWithBuffer接口

1.9.2.5.1. 接口说明

解析简单SQL语句并返回解析信息(缓冲区模式)。与 UnisqlParseSimpleStatementInfo 功能相同,但采用调用者预分配缓冲区的方式,避免内存分配开销,适合高频调用场景。

接口签名:

extern int UnisqlParseSimpleStatementInfoWithBuffer(
    const char* sourceSql,
    char* buf,
    int bufSize);

要使用 C 接口,您需要发布包中对应操作系统平台的 so 动态库,以及 unisql.h 头文件。

1.9.2.5.2. 接口请求参数

接口请求参数

参数名

类型

是否必须

说明

示例

sourceSql

const char*

用户输入的待解析的SQL语句, 只支持针对单表的简单增删改查语句

"select * from t1 where c1 = 2 and c2 = 3"

buf

char*

解析结果的输出缓冲区,内存由调用方自行管理

buffer

bufSize

int

buf 的内存大小

推荐使用原有sql长度的10倍

1.9.2.5.3. 接口返回参数

返回类型是一个 int ,取值有以下情况:

  • 返回 0: 代表解析成功,结果写入 buf 中

  • 返回 -1: 代表参数错误(sourceSql为NULL、buf为NULL、bufSize<=0)

  • 返回 -10001: 代表SQL解析失败

  • 返回 -10002: 代表多表操作不支持

  • 返回 -10003: 代表INSERT多行不支持

  • 返回 -10004: 代表UPDATE表别名不支持

  • 返回 -10005: 代表DELETE表别名不支持

  • 返回 -10006: 代表SELECT表别名不支持

  • 返回 -10007: 代表INSERT列名和值数量不匹配

  • 返回大于 0 的数字:代表传入的 bufSize 空间不足,返回值表示需要的空间大小

1.9.2.5.4. 解析结果格式

解析成功时,buf 中存储的内容格式与 UnisqlParseSimpleStatementInfo 相同:

  • ParseStatus: 解析状态,0 成功, -1 失败

  • MultiTable: 是否操作多表

  • SourceType: SQL类型, 1 insert、2 update、3 delete、4 select

  • TableName: 表名

  • ExistsWhere: 是否存在where子句, 对于insert语句, 表示是否指定了列名

  • InsertKV: insert语句中的列名和值

  • WhereCondition: where子句的条件

  • WhereBindParamPos: update语句的where子句中第一个绑定变量的下标(从1开始), 0表示没有绑定变量

1.9.2.5.5. 调用示例

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "unisql.h"

int main() {
    const char* sql = "select * from t1 where c1 = 1 and c2 = 2";
    // 预分配缓冲区
    int bufSize = 4096;
    char* buf = (char*)malloc(bufSize);
    int ret;

    // 调用解析函数
    ret = UnisqlParseSimpleStatementInfoWithBuffer(sql, buf, bufSize);

    if (ret > 0) {
        // 缓冲区不足,重新分配
        buf = (char*)realloc(buf, ret);
        ret = UnisqlParseSimpleStatementInfoWithBuffer(sql, buf, ret);
    }

    if (ret == 0) {
        printf("Parse result: %s\n", buf);
    } else {
        printf("Parse failed: %d\n", ret);
    }

    // 释放内存
    free(buf);
    return 0;
}

示例执行结果:

Parse result: parseStatus: 0, multiTable: false, sourceType: 4, tableName: "t1", existsWhere: true, insertKV: [], whereCondition: "c1=1 AND c2=2", whereBindParamPos: 0

1.9.2.6. TransferSQLWithBindInfo接口

1.9.2.6.1. 接口说明

转换SQL语句并返回绑定参数信息(带缓存)。注意:本接口仅支持Linux平台,Windows版本不支持。

接口签名:

extern int TransferSQLWithBindInfo(
    int sourceDbTypeCode,
    int targetDbTypeCode,
    const char* sourceSqlStr,
    char* targetSqlStr,
    int targetSqlStrLen,
    int** bindVariableOrder,
    int* bindVariableOrderSize,
    const char* jsonParameter);

1.9.2.6.2. 接口请求参数

接口请求参数

参数名

类型

是否必须

说明

示例

sourceDbTypeCode

int

源数据库方言编码,见 UNISQL_DBTYPE_ 定义

UNISQL_DBTYPE_ORACLE

targetDbTypeCode

int

目标数据库方言编码,见 UNISQL_DBTYPE_ 定义

UNISQL_DBTYPE_GOLDENDB_MYSQL

sourceSqlStr

const char*

源SQL语句

"SELECT lpad(?, 10) FROM t"

targetSqlStr

char*

转换后的SQL内存空间,内存由调用方自行管理

buffer

targetSqlStrLen

int

targetSqlStr 的内存大小

1024

bindVariableOrder

int**

绑定参数顺序数组指针,输出参数。指向的内存位于targetSqlStr末尾,无需单独释放

&bindOrder

bindVariableOrderSize

int*

绑定参数顺序数组大小,输出参数。为0表示绑定参数不存在或未修改

&bindSize

jsonParameter

const char*

json格式的选项,预留未使用

NULL

1.9.2.6.3. 接口返回参数

返回类型是一个 int ,取值有 3 种情况:

  • 返回 0: 代表转换成功

  • 返回 -1: 代表转换异常失败

  • 返回大于 0 的数字:代表传入的 targetSqlStrLen 空间不足,返回值表示需要的空间(包括目标SQL和绑定参数信息大小)

1.9.2.6.4. 重要说明

  1. 内存结构:bindVariableOrder 指向的整型数组内存在 targetSqlStr 末尾。最终 targetSqlStr 内存结构为:targetSql(包括末尾空字符)+ bindVariableOrder + 未使用内存

  2. 内存管理:bind数组无需单独释放,会跟随 targetSql 一起释放。在 targetSql 释放后就不能再访问 bind 数组

  3. 绑定参数映射:bindVariableOrder 下标 0 表示新绑定参数的第1个位置对应的旧的绑定参数位置。例如:bindVariableOrder[0]=2, bindVariableOrder[1]=1 表示新绑定参数的第1个位置对应旧绑定参数的第2个位置,新绑定参数的第2个位置对应旧绑定参数的第1个位置

  4. 无变化情况:若绑定参数不存在,或者参数信息没改变,bindVariableOrderSize 为0,bindVariableOrder 指向的内存为NULL

1.9.2.6.5. 调用示例

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "unisql.h"
#include "unisql_dbtype.h"

int main() {
    // 数据库类型
    int sourceDbTypeCode = UNISQL_DBTYPE_ORACLE;
    int targetDbTypeCode = UNISQL_DBTYPE_GOLDENDB_MYSQL;

    // 原始SQL:lpad函数在转换时会导致绑定参数重复
    char* sourceSqlStr = "SELECT lpad(?, 10) FROM t WHERE id = ?";

    // 分配目标SQL内存(源SQL的4倍长度)
    int targetSqlStrLen = strlen(sourceSqlStr) * 4;
    char* targetSqlStr = (char*)malloc(targetSqlStrLen);

    // 绑定参数顺序输出参数
    int* bindVariableOrder = NULL;
    int bindVariableOrderSize = 0;

    printf("Before transfer sql is: %s\n", sourceSqlStr);

    // 调用TransferSQLWithBindInfo转换函数
    int transRet = TransferSQLWithBindInfo(
        sourceDbTypeCode,
        targetDbTypeCode,
        sourceSqlStr,
        targetSqlStr,
        targetSqlStrLen,
        &bindVariableOrder,
        &bindVariableOrderSize,
        NULL
    );

    if (transRet > 0) {
        // 内存不足,重新分配
        targetSqlStr = (char*)realloc(targetSqlStr, transRet);
        transRet = TransferSQLWithBindInfo(
            sourceDbTypeCode,
            targetDbTypeCode,
            sourceSqlStr,
            targetSqlStr,
            transRet,
            &bindVariableOrder,
            &bindVariableOrderSize,
            NULL
        );
    }

    if (transRet == 0) {
        printf("After transfer sql is: %s\n", targetSqlStr);
        printf("Bind variable order size: %d\n", bindVariableOrderSize);

        // 打印绑定参数顺序映射
        if (bindVariableOrderSize > 0) {
            printf("Bind variable order mapping:\n");
            for (int i = 0; i < bindVariableOrderSize; i++) {
                printf("  New position %d -> Old position %d\n",
                       i + 1, bindVariableOrder[i]);
            }
        }
    } else {
        printf("SQL Convert Failed: %d\n", transRet);
    }

    // 释放内存
    free(targetSqlStr);
    return 0;
}

示例执行结果:

Before transfer sql is: SELECT lpad(?, 10) FROM t WHERE id = ?
After transfer sql is: SELECT if(length(?)=0 OR length(10)=0 OR 10=0, NULL, lpad(?, 10, ' ')) FROM t WHERE id=?
Bind variable order size: 2
Bind variable order mapping:
  New position 1 -> Old position 1
  New position 2 -> Old position 1

1.9.2.7. UnisqlTransformSQLWithBindInfo接口

1.9.2.7.1. 接口说明

转换SQL语句并返回绑定参数信息(无缓存版本)。与 TransferSQLWithBindInfo 功能相同,但不使用缓存。

接口签名:

extern int UnisqlTransformSQLWithBindInfo(
    int sourceDbTypeCode,
    int targetDbTypeCode,
    const char* sourceSqlStr,
    char* targetSqlStr,
    int targetSqlStrLen,
    int** bindVariableOrder,
    int* bindVariableOrderSize,
    const char* jsonParameter);

1.9.2.7.2. 接口请求参数

参数与 TransferSQLWithBindInfo 完全相同,请参考上文。

1.9.2.7.3. 接口返回参数

返回类型与 TransferSQLWithBindInfo 完全相同,请参考上文。

1.9.2.7.4. 重要说明

与 TransferSQLWithBindInfo 的区别:

  1. 无缓存:本接口不使用缓存,每次调用都会进行完整的SQL转换

  2. 适用场景:适用于不需要缓存或对缓存敏感的场景

  3. 性能:由于不使用缓存,相同SQL的重复转换性能会低于 TransferSQLWithBindInfo

1.9.2.7.5. 调用示例

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "unisql.h"
#include "unisql_dbtype.h"

int main() {
    // 数据库类型
    int sourceDbTypeCode = UNISQL_DBTYPE_ORACLE;
    int targetDbTypeCode = UNISQL_DBTYPE_GOLDENDB_MYSQL;

    // 原始SQL:lpad函数在转换时会导致绑定参数重复
    char* sourceSqlStr = "SELECT lpad(?, 10) FROM t WHERE id = ?";

    // 分配目标SQL内存(源SQL的4倍长度)
    int targetSqlStrLen = strlen(sourceSqlStr) * 4;
    char* targetSqlStr = (char*)malloc(targetSqlStrLen);

    // 绑定参数顺序输出参数
    int* bindVariableOrder = NULL;
    int bindVariableOrderSize = 0;

    printf("Before transfer sql is: %s\n", sourceSqlStr);

    // 调用TransferSQLWithBindInfo转换函数
    int transRet = UnisqlTransformSQLWithBindInfo(
        sourceDbTypeCode,
        targetDbTypeCode,
        sourceSqlStr,
        targetSqlStr,
        targetSqlStrLen,
        &bindVariableOrder,
        &bindVariableOrderSize,
        NULL
    );

    if (transRet > 0) {
        // 内存不足,重新分配
        targetSqlStr = (char*)realloc(targetSqlStr, transRet);
        transRet = UnisqlTransformSQLWithBindInfo(
            sourceDbTypeCode,
            targetDbTypeCode,
            sourceSqlStr,
            targetSqlStr,
            transRet,
            &bindVariableOrder,
            &bindVariableOrderSize,
            NULL
        );
    }

    if (transRet == 0) {
        printf("After transfer sql is: %s\n", targetSqlStr);
        printf("Bind variable order size: %d\n", bindVariableOrderSize);

        // 打印绑定参数顺序映射
        if (bindVariableOrderSize > 0) {
            printf("Bind variable order mapping:\n");
            for (int i = 0; i < bindVariableOrderSize; i++) {
                printf("  New position %d -> Old position %d\n",
                       i + 1, bindVariableOrder[i]);
            }
        }
    } else {
        printf("SQL Convert Failed: %d\n", transRet);
    }

    // 释放内存
    free(targetSqlStr);
    return 0;
}

示例执行结果:

Before transfer sql is: SELECT lpad(?, 10) FROM t WHERE id = ?
After transfer sql is: SELECT if(length(?)=0 OR length(10)=0 OR 10=0, NULL, lpad(?, 10, ' ')) FROM t WHERE id=?
Bind variable order size: 2
Bind variable order mapping:
  New position 1 -> Old position 1
  New position 2 -> Old position 1