首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

C語言訪問 Informix 數據庫:SQLDA 動態查詢深度解析

     編輯:關於C

Informix ESQL/C 中 ifx_sqlda_t (SQLDA) 是動態 SQL 查詢的核心結構。本文基於實戰代碼,深度解析 DESCRIBE ... INTO 空間分配機制、SQLDA 初始化流程、數據類型映射、結果集存儲佈局與按行列取值方法。

核心流程概覽

  1. DESCRIBE ... INTO sqlda — 自動分配並填充元數據
  2. db_ifx_init_sqlda — 計算行大小、分配數據緩衝區
  3. FETCH — 驅動填充數據
  4. db_ifx_get_data_by_idx/name — 應用層取值

階段 1:DESCRIBE ... INTO 空間分配


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、sqlname
  • 不分配:sqlvar->sqldata、sqlvar->sqlind(需後續初始化)

階段 2:SQLDA 初始化 (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 類型常量
SQLINTCINTTYPE
SQLFLOATCDOUBLETYPE
SQLCHARCCHARTYPE
SQLVCHARCVCHARTYPE
SQLDATECDATETYPE
SQLTEXT/BYTESCLOCATORTYPE
...完整見代碼

緩衝區分配 (db_ifx_init_sqldata / db_ifx_alloc_loc)

  • 普通類型:calloc(alloc_num, sqllen) → sqldata
  • 指示符:calloc(alloc_num, sizeof(short)) → sqlind
  • TEXT/BYTE:分配 loc_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;
    // ... 完整見代碼
}

關鍵設計亮點

  • 列優先存儲 → 適合列式訪問、聚合計算
  • 統一轉為字符串返回 → 應用層無需關心 C 類型
  • 緩衝區複用 context->convert → 減少分配
  • 指示符 sqlind 獨立管理 → 正確處理 NULL 值

常見坑點

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
問題原因對策
FETCH 後數據亂碼sqllen 未轉換為 C 端大小必須調用 rtypmsize
TEXT/BYTE 讀取失敗未分配 loc_buffer走 db_ifx_alloc_loc 路徑
行號越界未檢查 row <= context->rows取值前驗證
列名大小寫不匹配Informix 列名不敏感用 strcasecmp