Informix ESQL/C 中 ifx_sqlda_t (SQLDA) 是動態 SQL 查詢的核心結構。本文基於實戰代碼,深度解析 DESCRIBE ... INTO 空間分配機制、SQLDA 初始化流程、數據類型映射、結果集存儲佈局與按行列取值方法。
DESCRIBE ... INTO sqlda — 自動分配並填充元數據db_ifx_init_sqlda — 計算行大小、分配數據緩衝區FETCH — 驅動填充數據db_ifx_get_data_by_idx/name — 應用層取值
ifx_sqlda_t *sqlda = NULL;
EXEC SQL DESCRIBE QUERY_SQLSTMT_ID INTO sqlda;
自動完成:
sqlda 本體sqlda->sqlvar 陣列(大小 = sqld * sizeof(sqlvar_struct))sqld、sqlvar、desc_name、desc_occ、sqltype、sqllen、sqlnamesqlvar->sqldata、sqlvar->sqlind(需後續初始化)db_ifx_init_sqlda)
int db_ifx_init_sqlda(db_ifx_cntx_t *context, ifx_sqlda_t *sqlda) {
// Step 1: 計算行大小
sqlvar = sqlda->sqlvar;
for(idx=0; idxsqld; idx++, sqlvar++) {
msg_len += sqlvar->sqllen; // DB 端長度
sqlvar->sqllen = rtypmsize(sqlvar->sqltype, sqlvar->sqllen); // C 端長度
row_size += sqlvar->sqllen;
}
// Step 2: 設置 FetArrSize (每次 FETCH 行數)
// Step 3: 逐列初始化 sqldata/sqlind
for(idx=0; idxsqld; idx++) {
db_ifx_set_sqltype(sqlvar); // 類型映射
db_ifx_init_sqldata(context, sqlvar, alloc_num); // 分配緩衝
}
}
db_ifx_set_sqltype)| Informix 類型 | C 類型常量 |
|---|---|
| SQLINT | CINTTYPE |
| SQLFLOAT | CDOUBLETYPE |
| SQLCHAR | CCHARTYPE |
| SQLVCHAR | CVCHARTYPE |
| SQLDATE | CDATETYPE |
| SQLTEXT/BYTES | CLOCATORTYPE |
| ... | 完整見代碼 |
db_ifx_init_sqldata / db_ifx_alloc_loc)calloc(alloc_num, sqllen) → sqldatacalloc(alloc_num, sizeof(short)) → sqlindloc_t 陣列,每項含 loc_buffer列優先佈局 (Column-major): sqlvar[0]->sqldata: [Row0_Col0][Row1_Col0][Row2_Col0]... sqlvar[1]->sqldata: [Row0_Col1][Row1_Col1][Row2_Col1]... ...
第 row 行、第 col 列的偏移:
data_ptr = sqlvar[col-1]->sqldata + (row-1) * sqlvar[col-1]->sqllen;
char *db_ifx_get_data_by_idx(int row, int col, void *cntx) {
sqlvar = context->result->sqlvar + col - 1;
return db_ifx_get_value(sqlvar, context, row);
}
char *db_ifx_get_data_by_name(int rowno, const char *name, db_ifx_cntx_t *context) {
for(idx=0; idxresult->sqld; idx++) {
if(strcasecmp(name, sqlvar->sqlname) == 0) break;
sqlvar++;
}
return db_ifx_get_value(sqlvar, context, rowno);
}
db_ifx_get_value)
switch(sqlvar->sqltype) {
case CINTTYPE: snprintf(convert, size, "%d", *(int*)data); break;
case CDOUBLETYPE: snprintf(convert, size, "%f", *(double*)data); break;
case CCHARTYPE: return data; // 直接返回字符串指針
case CLOCATORTYPE: return ((loc_t*)sqlvar->sqldata)->loc_buffer;
// ... 完整見代碼
}
context->convert → 減少分配sqlind 獨立管理 → 正確處理 NULL 值| 問題 | 原因 | 對策 |
|---|---|---|
| FETCH 後數據亂碼 | sqllen 未轉換為 C 端大小 | 必須調用 rtypmsize |
| TEXT/BYTE 讀取失敗 | 未分配 loc_buffer | 走 db_ifx_alloc_loc 路徑 |
| 行號越界 | 未檢查 row <= context->rows | 取值前驗證 |
| 列名大小寫不匹配 | Informix 列名不敏感 | 用 strcasecmp |