程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C >> 關於C >> C語言訪問INFORMIX數據庫 — SQLDA使用

C語言訪問INFORMIX數據庫 — SQLDA使用

編輯:關於C

一、前言概述
    之前寫過3篇關於C語言訪問INFORMIX數據的博文:第一篇講述ESQL基本語法;第二篇講述接口實現;第三篇講述SQLDA結構。此篇根據以上3篇的內容,進一步分析執行動態查找語句中關於ifx_sqlda_t的使用。

二、用法分析

2.1 DESCRIBE ... INTO

在接口實現中的db_ifx_mquery()函數中有這樣一段代碼:

代碼段一:

[html]
ifx_sqlda_t *sqlda = NULL; 
 
... 
 
EXEC SQL DESCRIBE QUERY_SQLSTMT_ID INTO sqlda;     
代碼分析:

     定義變量sqlda為一個空指針,但執行DESCRIBE ... INTO後,就能對sqlda進行其他操作處理了。我想這時每個人看到這裡心中都有一個疑問:DESCRIBE ... INTO到底對空指針sqlda做了什麼處理?

    ①、分配空間

            1. 定義變量sqlda為空指針,但DESCRIBE...INTO之後就能夠進行操作,很顯然,DESCRIBE...INTO為變量sqlda分配了內存空間

            2. 分配的空間包括:sqlda和sqlda->sqlvar。且sqlda->sqlvar指向大小為sqld*sizeof(struct sqlvar_struct)內存塊。(sqlvar:指向struct sqlvar_struct結構體,即指向描述第一列信息的sqlvar結構體)

            3. 但未給sqlda->sqlvar中其他指針分配內存

    ②、獲取語句信息,並存放在ifx_sqlda_t結構中

            獲取的語句信息包括:

                sqld:使用的sqlvar結構的個數,即:輸出列的個數

                sqlvar:指向struct sqlvar_struct結構體,即:指向描述第一列信息的sqlvar結構體

                desc_name:sqlda名稱

                desc_occ:sqlda結構的大小

                sqltype:代表參數或列的數據類型。它是一個整數數據類型代碼。

                sqllen:代表傳送數據的長度

                sqlname:代表列名或變量名

            有了以上的語句信息,就可以為後續數據行的空間分配提供依據。

    舉例分析:

            假設需執行查詢2列的SQL語句,在執行DESCRIBE...INTO後,變量sqlda的內存結構圖為:

 

圖1 變量sqlda的內存結構圖

2.2 SQLDA初始化

代碼段二:

[cpp]
/* 依據sqlda的信息,初始化其他數據 */ 
int db_ifx_init_sqlda(db_ifx_cntx_t *context, ifx_sqlda_t *sqlda) 

    int ret = 0, 
        idx = 0, 
        msg_len = 0, 
        row_size = 0, 
        alloc_num = 0; 
    struct sqlvar_struct *sqlvar = NULL; 
     
    context->result = sqlda; 
 
    /* Step 1. 獲取一行數據的長度 */ 
    sqlvar = sqlda->sqlvar; 
    for(idx=0; idx<sqlda->sqld; idx++, sqlvar++) 
    { 
            /* 非C下一行數據的長度 */ 
            msg_len += sqlvar->sqllen; 
 
            /* 為col->sqllen 重新賦值,該值是在C下的大小。
            如:在數據庫中的字符串,在C中應該多一個字節空間來存放NULL的結束符 */ 
            sqlvar->sqllen = rtypmsize(sqlvar->sqltype, sqlvar->sqllen); 
 
            /* C下一行數據的長度 */ 
            row_size += sqlvar->sqllen; 
    } 
 
        /* Step2. 設置FetArrSize的值 */ 
    if(-1 == FetArrSize) 
    { 
        if(FetBufSize < msg_len) 
        { 
            FetBufSize = msg_len; 
        } 
        FetArrSize = FetBufSize/msglen; 
    } 
 
         alloc_num = (FetArrSize <= 0)?1:FetArrSize; 
 
    /* Step3. 初始化列:列的取值分配空間等 */ 
    sqlvar = sqlda->sqlvar; 
    for(idx=0; idx<sqlda->sqld; idx++, sqlvar++) 
    { 
        ret = db_ifx_set_sqltype(sqlvar); 
        if(ret < 0) 
        { 
            return ret; 
        } 
 
        ret = db_ifx_init_sqldata(context, sqlvar, alloc_num); 
        if(ret < 0) 
        { 
            return ret; 
        } 
    } 
 
    return msg_len; 

代碼說明:
    1. 全局變量FetBufSize、FetArrSize說明
           FetBufSize:是INFORMIX中的全局變量。此值決定了取數據庫數據時的緩存大小
           FetArrSize:是INFORMIX中的全局變量。此值決定了一次FETCH可以從數據庫取多少行數據

    2. 變量alloc_num的值決定了一次FETCH可以從數據庫取多少行數據,其將成為後續初始化過程中空間申請大小的依據

代碼段三:

[cpp] 
/* 依據數據庫中的數據類型,設置C下數據類型 */ 
int db_ifx_set_sqltype(struct sqlvar_struct *sqlvar) 
{    
    switch(sqlvar->sqltype) 
    { 
        case SQLBOOL: 
        { 
            sqlvar->sqltype = CBOOLTYPE; 
            break; 
        } 
        case SQLSMINT: 
        { 
            sqlvar->sqltype = CSHORTTYPE; 
            break; 
        } 
        case SQLINT: 
        { 
            sqlvar->sqltype = CINTTYPE; 
            break; 
        } 
        case SQLINT8: 
        case SQLSERIAL: 
        case SQLSERIAL8: 
        { 
            sqlvar->sqltype = CINT8TYPE; 
            break; 
        } 
        case SQLBIGSERIAL: 
        case SQLINFXBIGINT: 
        { 
            sqlvar->sqltype = CBIGINTTYPE; 
            break; 
        } 
        case SQLDECIMAL: 
        { 
            sqlvar->sqltype = CDECIMALTYPE; 
            break; 
        } 
        case SQLSMFLOAT: 
        { 
            sqlvar->sqltype = CFLOATTYPE; 
            break; 
        } 
        case SQLFLOAT: 
        { 
            sqlvar->sqltype = CDOUBLETYPE; 
            break; 
        } 
        case SQLCHAR: 
        { 
            sqlvar->sqltype = CCHARTYPE; 
            break; 
        } 
        case SQLNCHAR: 
        { 
            sqlvar->sqltype = CFIXCHARTYPE; 
            break; 
        } 
        case SQLVCHAR: 
        case SQLNVCHAR: 
        { 
            sqlvar->sqltype = CVCHARTYPE; 
            break; 
        } 
        case SQLLVARCHAR: 
        { 
            sqlvar->sqltype = CLVCHARTYPE; 
            break; 
        } 
        case SQLMONEY: 
        { 
            sqlvar->sqltype = CMONEYTYPE; 
            break; 
        } 
        case SQLINTERVAL: 
        { 
            sqlvar->sqltype = CINVTYPE; 
            break; 
        } 
        case SQLDATE: 
        { 
            sqlvar->sqltype = CDATETYPE; 
            break; 
        } 
        case SQLDTIME: 
        { 
            sqlvar->sqltype = CDTIMETYPE; 
            break; 
        } 
        case SQLROW: 
        { 
            sqlvar->sqltype = CROWTYPE; 
            break; 
        } 
        case SQLSET: 
        case SQLLIST: 
        case SQLMULTISET: 
        case SQLCOLLECTION: 
        { 
            sqlvar->sqltype = CCOLLTYPE; 
            break; 
        } 
        case SQLTEXT: 
        case SQLBYTES: 
        { 
            sqlvar->sqltype = CLOCATORTYPE; 
            break; 
        } 
        default: /* Other data type */ 
        { 
            return -1; 
        } 
    } 
 
    return 0; 

代碼說明:
    1.  數據類型的轉換對應關系,請參考:http://blog.csdn.net/royalapex/article/details/8205654

代碼段四:

[cpp] 
/* 初始化sqldata數據空間 */ 
int db_ifx_init_sqldata(db_ifx_cntx_t *context, struct sqlvar_struct *sqlvar, int alloc_num) 

    char errmsg[DB_ERR_MSG_MAX_LEN] = {0}; 
    int ret = 0, alloc_size = 0; 
     
    /* 1. 為指示符變量申請空間 */ 
    sqlvar->sqlind = (short *)calloc(alloc_num, sizeof(short)); 
    if(NULL == sqlvar->sqlind) 
    { 
        return -1; 
    } 
 
    /* 2. 為存放非TEXT 和BLOB的數據類型的sqldata申請空間.
        注意: 申請的地址是(char *),在輸出數據時,要按照相應的數據類型做轉換 */ 
    if(CLOCATORTYPE != sqlvar->sqltype) 
    { 
        alloc_size = alloc_num*sqlvar->sqllen; 
        if(sqlvar->sqllen > context->convert_size) 
        { 
            context->convert_size = sqlvar->sqllen; 
        } 
 
        sqlvar->sqldata = (char*)calloc(1, alloc_size); 
        if(NULL == sqlvar->sqldata) 
        { 
            return -1; 
        } 
        return 0; 
    } 
 
    /* 3. 為TEXT和BLOB的數據類型的sqldata申請空間 */ 
    return db_ifx_alloc_loc(context, sqlvar, alloc_num); 

代碼段五:
[cpp] 
/* 申請loc_t類型的數據空間 */ 
int db_ifx_alloc_loc(db_ifx_cntx_t *context, struct sqlvar_struct *sqlvar, int alloc_num) 

    char errmsg[DB_ERR_MSG_MAX_LEN] = {0}; 
    int idx = 0, alloc_size = 0; 
    loc_t *loc = NULL; 
 
    alloc_size = alloc_num*sqlvar->sqllen; 
    if(sqlvar->sqllen > context->convert_size) 
    { 
        context->convert_size = sqlvar->sqllen; 
    } 
 
    /* 1. 為存放TEXT或BYTE列數據申請空間 */ 
    loc = (loc_t*)calloc(1, alloc_size); 
    if(NULL == loc) 
    {  
        return -1;               
    } 
    sqlvar->sqldata = (char *)loc; 
 
    /* 2. 初試化loc_t結構 */ 
    byfill(loc, alloc_size, 0); 
 
    for(idx=0; idx<alloc_num; idx++) 
    { 
        loc->loc_loctype = LOCMEMORY; 
        loc->loc_bufsize = DB_IFX_BLOB_SIZE; 
 
        loc->loc_buffer = (char *)calloc(1, DB_IFX_BLOB_SIZE); 
        if(NULL == loc->loc_buffer) 
        { 
            return -1; 
        } 
         
        loc->loc_oflags = 0; 
        loc++; 
    } 
     
    return 0; 

代碼說明:
    1. 由申請的空間大小的值,可以發現當取多行數據時,同一列的結果值在內存空間是並排存放的。其內存結構圖:

 

圖2 結果集存儲結構圖

    圖2說明:

              1. 圖上每個格子代表一列數據

              2. 行列關系:

                   A:處在第一個sqlvar_struct中的結果集sqldata中第一列代表第一行第一列,第二列代表第二行第一列,第三列代表第三行第一列,....,以此類推;

                   B:處在第二個sqlvar_struct中的結果集sqldata中第一列代表第一行第二列,第二列代表第二行第二列,第三列代表第三行第二列, ...,以此類推;

                   C:依照AB的規律可推出其他的行列關系

 

3. 獲取數據

    在執行FETCH後,結果集就會存放在sqlda之中,應用程序如何通過行號-列號 或 行號-列名獲取對應列的取值呢?可通過如下方式:

代碼段六:

[cpp] 
/* 根據行號+列號從結果集中取數據 */ 
char *db_ifx_get_data_by_idx(int row, int col, void *cntx) 

    ifx_sqlda_t *current = NULL; 
    struct sqlvar_struct *sqlvar = NULL; 
    db_ifx_cntx_t *context = (db_ifx_cntx_t *)cntx; 
 
    if(NULL == context->result 
        || NULL == context->result->sqlvar 
        || col <= 0 
        || col > context->result->sqld 
        || row <= 0 
        || row > context->rows) 
    { 
        return NULL; 
    } 
 
    /* 1. 定位列 */ 
    sqlvar = context->result->sqlvar+col-1; 
 
    /* 2. 返回結果 */ 
    return db_ifx_get_value(sqlvar, context, rowno); 

代碼段七:

[cpp] view plaincopy
/* 通過行號+列明從結果集中取數據 */ 
char *db_ifx_get_data_by_name(int rowno, const char *name, db_ifx_cntx_t *context) 

    int idx = 0; 
    struct sqlvar_struct *sqlvar = NULL; 
    if(NULL == context->result 
        || NULL == context->result->sqlvar 
        || rowno <= 0 
        || rowno > context->rows) 
    { 
        return NULL; 
    } 
 
    /* 1. 定位列 */ 
    sqlvar = context->result->sqlvar; 
    for(idx=0; idx<context->result->sqld; idx++) 
    { 
        if(0 == strcasecmp(name, sqlvar->sqlname)) 
        { 
            break; 
        } 
        sqlvar++; 
    } 
     
    if(idx == context->result->sqld) 
    {        
        return NULL; 
    } 
      
    /* 3. 返回結果 */ 
    return db_ifx_get_value(sqlvar, context, rowno); 

代碼段八:

[cpp] view plaincopy
/* 轉換並以字符串形式返回結果集數據 */ 
char *db_ifx_get_value(struct sqlvar_struct *sqlvar,  db_ifx_cntx_t *cntx, int rowno) 

    int ret = 0; 
    loc_t *loc = NULL; 
    char *data = sqlvar->sqldata + (rowno-1)*sqlvar->sqllen, 
         *convert = cntx->convert, 
         *pconvert = NULL; 
 
    memset(convert, 0, cntx->convert_size); 
     
    switch (sqlvar->sqltype) 
    { 
        case CBOOLTYPE: 
        { 
            snprintf(convert, cntx->convert_size, "%d", *((unsigned char*)data)); 
            return convert; 
        } 
        case CSHORTTYPE: 
        { 
            snprintf(convert, cntx->convert_size, "%d", *((short*)data)); 
            return convert; 
        } 
        case CINTTYPE: 
        { 
            snprintf(convert, cntx->convert_size, "%d", *((int*)data)); 
            return convert; 
        } 
        case CLONGTYPE: 
        { 
            snprintf(convert, cntx->convert_size, "%l", *((long*)data)); 
            return convert; 
        } 
        case CINT8TYPE: 
        { 
            snprintf(convert, cntx->convert_size, "%ll", *((long long*)data)); 
            return convert; 
        } 
        case CBIGINTTYPE: 
        { 
            snprintf(convert, cntx->convert_size, "%ll", *((long long*)data)); 
            return convert; 
        } 
        case CDECIMALTYPE: 
        { 
            pconvert = convert; 
            dectoasc((dec_t*)data, convert, cntx->convert_size, -1); 
            /* Note: dectoasc() Left align and fill blank, so must delete blank */ 
            while('\0' != *pconvert) 
            { 
                if(isblank(*pconvert)) 
                { 
                    *pconvert = '\0'; 
                    break; 
                } 
                pconvert++; 
            } 
            return convert; 
        } 
        case CFLOATTYPE: 
        { 
            snprintf(convert, cntx->convert_size, "%f", (double)(*(float*)data)); 
            return convert; 
        } 
        case CDOUBLETYPE: 
        { 
            snprintf(convert, cntx->convert_size, "%f", *((double*)data)); 
            return convert; 
        } 
        case CMONEYTYPE: 
        { 
            snprintf(convert, cntx->convert_size, "%d", *(int*)data); 
            return convert; 
        } 
        case CINVTYPE: 
        { 
            intoasc((intrvl_t*)data, convert); 
            return convert; 
        } 
        case CDATETYPE: 
        { 
            rfmtdate(*(int*)data, "YYYYMMDD", convert); 
            return convert; 
        } 
        case CDTIMETYPE: 
        { 
            dttoasc((dtime_t*)data, convert); 
            return convert; 
        } 
        case CROWTYPE: 
        case CCOLLTYPE: 
        { 
            return data; 
        } 
        case CCHARTYPE: 
        case CFIXCHARTYPE: 
        case CVCHARTYPE: 
        case CLVCHARTYPE: 
        { 
            return data; 
        } 
        case CLOCATORTYPE: 
        { 
            loc = (loc_t *)sqlvar->sqldata; 
 
            return loc->loc_buffer; 
        } 
        default: 
        { 
            return NULL; 
        } 
    }  
 
    return NULL; 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved