使用C嵌入式SQL从Ingres通过SQLDA获取整数/长整数异常问题
问题分析与解决方案
你遇到的核心问题是没有正确解析SQLDA中二进制存储的整数类型,而是把它们当成ASCII字符或单字节数据来处理了。Ingres的SQLDA里,数值类型(int、long等)是以二进制形式存储的,不是人类可读的ASCII,直接按char数组打印或者只取第一个字节转long肯定会出问题。
具体错误点
- 错误的打印/解析方式:你直接遍历
sqldata的char字节并打印,还通过*sqlda->sqlvar[i].sqldata把第一个字节转成long——这只对1字节的极小整数有效,2字节/4字节的整数是多字节连续存储的二进制值,必须按对应的数据类型整体解析。 - 未利用sqltype字段判断类型:SQLDA的
sqlvar[i].sqltype字段明确标记了该列的数据类型,你需要根据这个类型来选择对应的解析方式,而不是统一按char处理。
修正后的代码示例
首先确保你包含了Ingres的SQLDA头文件:#include <iisqlda.h>,然后修改FETCH后的解析循环:
EXEC SQL FETCH csr0 USING DESCRIPTOR sqlda; for( i=0; i<sqlda->sqld; i++) { printf("Column %d | Type: %d | Length: %d | ", i+1, sqlda->sqlvar[i].sqltype, sqlda->sqlvar[i].sqllen); // 根据字段类型解析二进制数据 switch(sqlda->sqlvar[i].sqltype) { case IIAPI_SMALLINT_TYPE: // 2字节短整数 if (sqlda->sqlvar[i].sqllen == sizeof(short)) { short small_val = *(short*)sqlda->sqlvar[i].sqldata; printf("Value: %hd", small_val); } break; case IIAPI_INT_TYPE: // 4字节整数(对应C的int/long,取决于平台) if (sqlda->sqlvar[i].sqllen == sizeof(int)) { int int_val = *(int*)sqlda->sqlvar[i].sqldata; printf("Value: %d", int_val); } break; case IIAPI_CHAR_TYPE: // 字符串类型 // 如果是VARCHAR类型,前2字节是长度,需要跳过 if (sqlda->sqlvar[i].sqltype == IIAPI_VARCHAR_TYPE) { printf("Value: %s", sqlda->sqlvar[i].sqldata + 2); } else { printf("Value: %s", sqlda->sqlvar[i].sqldata); } break; default: printf("Unsupported data type"); break; } // 检查是否为NULL值(sqlind为-1表示空) if (*sqlda->sqlvar[i].sqlind == -1) { printf(" (NULL)"); } printf("\n"); }
关键注意事项
- 类型匹配:Ingres的类型常量(如
IIAPI_SMALLINT_TYPE)定义在iisqlda.h中,要确保你引用的常量和实际返回的sqltype一致——如果不确定,可以先打印sqlvar[i].sqltype的值,对照Ingres文档确认对应的类型。 - 字节序问题:通常嵌入式SQL的SQLDA会使用主机字节序,直接强制类型转换即可;如果遇到数值颠倒的情况,可能需要用
ntohs()(针对2字节)或ntohl()(针对4字节)进行字节序转换。 - 字符串截断问题:你提到字符串被截断2字节,大概率是因为该字段是
VARCHAR类型——Ingres的VARCHAR会在sqldata的前2字节存储字符串长度,后面才是实际字符,所以需要跳过前2字节才能拿到完整字符串。
补充说明
你的SQLDA分配代码里(longs+ints+strings)这个变量看起来没定义,虽然程序能运行,但建议直接用列数(这里是5)来计算分配大小,避免潜在的错误:
sqlda = (IISQLDA *)calloc(1, IISQDA_HEAD_SIZE + (5 * IISQDA_VAR_SIZE));
内容的提问来源于stack exchange,提问作者Zooloo10
相关产品推荐
相关产品推荐

