LINUX C ORACLE動(dòng)態(tài)SQL第四種

原代碼地址:https://blog.csdn.net/numbibi/article/details/8446704
根據(jù)自己的理解加上了注釋

程序代碼

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <setjmp.h>     //提供了一個(gè)類型jmp_buf jb和兩個(gè)函數(shù)setjmp(jp)尾抑、longjmp(jp,[1~n]); setjmp(jp)用來(lái)保存當(dāng)前的環(huán)境缅叠,未使用longjmp時(shí)
                        //其返回值總為0。而當(dāng)使用了longjmp后,程序會(huì)直接跳轉(zhuǎn)到setjmp執(zhí)行后,而且其返回值會(huì)改變,常用來(lái)模擬異常處理
#include <sqlcpr.h>     // Pro*C產(chǎn)生的與平臺(tái)相關(guān)的SQLLIB函數(shù)的ANSI原形定義
#include <sqlda.h>      //使用動(dòng)態(tài)SQL語(yǔ)句時(shí),需準(zhǔn)備DynamicStagingArea對(duì)象(全局對(duì)象SQLSA)和DynamicDescriptionArea對(duì)象(全局對(duì)象SQLDA)
#include <sqlca.h>      //系統(tǒng)默認(rèn)事務(wù)對(duì)象

//定義綁定變量和選擇列表項(xiàng)的最大個(gè)數(shù)
#define MAX_ITEMS 40

//定義綁定變量和選擇列表項(xiàng)名稱的最大長(zhǎng)度
#define MAX_VNAME_LEN 30

//定義指示變量名稱的最大長(zhǎng)度
#define MAX_INAME_LEN 30

/*
struct sqlda
{                       //SLI=SELECT-List   P=占位符 BV=綁定變量 IV=指示變量
    long N;             //SLI或P的最大個(gè)數(shù)
    char * * V;         //指向SLI或BV值的地址數(shù)組的指針
    long * L;           //指向SLI或BV地址的長(zhǎng)度數(shù)組的指針
    short * T;          //指向SLI或BV值的數(shù)據(jù)類型數(shù)組的指針
    short * * I;        //指向IV值的地址數(shù)組指針
    long F;             //SLI或P的實(shí)際個(gè)數(shù)
    char * * S;         //指向SLI或P名字的地址數(shù)組的指針
    short * M;          //指向SLI或P名字的最大長(zhǎng)度數(shù)組的指針
    short * C;          //指向SLI或P名字的當(dāng)前長(zhǎng)度數(shù)據(jù)組的指針
    char * * X;         //指向IV名字的地址數(shù)組的指針
    short * Y;          //指向IV名字最大長(zhǎng)度數(shù)組的指針
    short * Z;          //指向IV名字當(dāng)前長(zhǎng)度數(shù)組的指針
};

P   占位符 SQL語(yǔ)句中不可缺少的類似 :oraName 這樣的東西
BV  綁定變量 用來(lái)減少硬連接赏壹,提高SQL語(yǔ)句的解析效率
IV  指示變量

//這部分注釋來(lái)源于 https://lj-zhu.iteye.com/blog/682465

N 執(zhí)行DESCRIBE前必須執(zhí)行SQLSQLDAAlloc()函數(shù)給N進(jìn)行復(fù)制,設(shè)定描述數(shù)組的維數(shù)衔沼,其決定了描述字
  結(jié)構(gòu)成員數(shù)組的最大元素的最大元素個(gè)數(shù)蝌借。在DESCRIBE命令后昔瞧,必須將存儲(chǔ)在F中的變量真實(shí)個(gè)數(shù)賦值
  給N。
V 是一個(gè)指向一個(gè)地址數(shù)組的指針菩佑,在該數(shù)組中存儲(chǔ)SELECT-LIST列值或綁定變量的值自晰。當(dāng)使用SQLSQLDAAlloc
  函數(shù)之前,系統(tǒng)給V[0]到V[n-]賦值為0.在使用select descriptors時(shí)稍坯,必須在FETCH語(yǔ)句前酬荞,給V指針
  數(shù)組分配內(nèi)存空間,應(yīng)為下列語(yǔ)句要用到兩種描述字的具體的值:
  EXEC SQL FETCH ... USING 'select descriptors'
  對(duì)于bind descriptors,必須在OPEN語(yǔ)句前分配空間
  EXEC SQL OPEN ... USING 'bind descriptors'
L 是一個(gè)指向存放SLI或BV變量值長(zhǎng)度數(shù)組的指針瞧哟。對(duì)于select descriotprs,DESCRIBE SELECT LIST語(yǔ)
  句設(shè)置數(shù)組中各元素的值混巧,對(duì)不在SLI的對(duì)應(yīng)長(zhǎng)度設(shè)置成該類型的可定義的最大長(zhǎng)度 。在FETCH語(yǔ)句前勤揩,
  用NUMVER類型數(shù)據(jù)存儲(chǔ)到C語(yǔ)言char[]類型咧党,
  就需要通過(guò)SQLNumberPrecV6()函數(shù)得到NUMBER長(zhǎng)度,然后轉(zhuǎn)換成字符串后的真實(shí)長(zhǎng)度陨亡。
  對(duì)于bind descriptors,用戶必須在OPEN語(yǔ)句前傍衡,給數(shù)組成員賦對(duì)應(yīng)V變量成員長(zhǎng)度的值。
  因?yàn)镺racle間接的通過(guò)使用存儲(chǔ)在V[i]變量的地址訪問數(shù)據(jù)區(qū)域负蠕,如果不指定L[i]變量蛙埂,就不能得到
  V[i]的存儲(chǔ)數(shù)據(jù)的長(zhǎng)度,如果用戶需要更改V[i]指定數(shù)據(jù)區(qū)域的長(zhǎng)度遮糖,只需要簡(jiǎn)單更改L[i]的值即可
T 指向一個(gè)數(shù)組的指針绣的,在這個(gè)數(shù)組中存放著SLI或者BV的數(shù)據(jù)類型。這個(gè)成員決定了Oracle數(shù)據(jù)存儲(chǔ)到
  V數(shù)組中時(shí)如何進(jìn)行轉(zhuǎn)換欲账。
  對(duì)于select descriptors,DESCRIBE SELECT LIST語(yǔ)句設(shè)置數(shù)據(jù)類型數(shù)組值為Oracle內(nèi)部數(shù)據(jù)了類型(
  char,number或dare等)。在進(jìn)行FETCH前,用戶可能需要重新更改此數(shù)組某元素的值斜脂,因?yàn)镺racle內(nèi)部
  數(shù)據(jù)類型很難被C語(yǔ)言所采用玷或。通常為了對(duì)SLI對(duì)用的select descriptors數(shù)據(jù)進(jìn)行線束,需要將數(shù)據(jù)
  轉(zhuǎn)換成varchar2或STRING類型。T[i]的高位用來(lái)指示其對(duì)應(yīng)的SLI列值的"NULL/NOT NULL"狀態(tài)京景。在使
  用OPEN或FETCH語(yǔ)句前较鼓,需要調(diào)用SQLColumnNummCheck()接受T[i]數(shù)據(jù)類型值禽篱,并清空高位NULL/NOT-
  NULL狀態(tài)。
  對(duì)于bind descriptors馅精,DECRIBE BIND VARIABLES設(shè)置數(shù)據(jù)類型數(shù)組的各元素為0.用戶必須在OPEN命
  令前設(shè)置各輸入宿主變量的數(shù)據(jù)類型第队。變量類型值采用Oracle外部數(shù)據(jù)類型描述哮塞。通常,綁定變量值
  存儲(chǔ)在字符串?dāng)?shù)組中凳谦,其對(duì)應(yīng)的T[i]就設(shè)置為1(Varchar2)或者5(STRING).
I 這是一個(gè)指向存儲(chǔ)指示變量值數(shù)組的指針忆畅。
  對(duì)于select descriptors,在FETCH語(yǔ)句前必須設(shè)置I數(shù)組各元素所指向的地址。
  EXEC SQL FETCH ... USING 'select descriptor'
  如果第i各SLI對(duì)應(yīng)的列值為空尸执,則I[i]值為-1 否則是個(gè)》=0的證書家凯。
  對(duì)于bind descriptors,必須在OPEN語(yǔ)句前設(shè)置I數(shù)組各變量的值如失。
  EXEC SQL OPEN ... USING 'bind descriptor'
F 存放通過(guò)DESCRIBE語(yǔ)句得到的SLI或占位符的真實(shí)數(shù)組绊诲,如果經(jīng)過(guò)DECRIBE語(yǔ)句后F小于零標(biāo)識(shí)DECRIBE
  語(yǔ)句發(fā)現(xiàn)的SLI數(shù)目或占位符數(shù)目比分配描述符時(shí)指定的最大數(shù)據(jù)數(shù)目N,例如褪贵,如果設(shè)置N=10但
  DESCRIBE發(fā)現(xiàn)SLI的數(shù)目時(shí)11個(gè)掂之,那么F將被設(shè)置成-11,這允許用戶根據(jù)此值那么F將被設(shè)置成-11脆丁,這允許用戶根據(jù)此值重新調(diào)用SQLSQLDAAlloc函數(shù)分配大的描述符存儲(chǔ)區(qū)域世舰。
*/

SQLDA *bindDp;          //綁定描述區(qū) 用來(lái)設(shè)置類似 select * from table where ID = :userId  中 userId的值以及相關(guān)設(shè)置
SQLDA *selectDp;        //選擇描述區(qū) 用來(lái)設(shè)置使用select語(yǔ)句時(shí),從數(shù)據(jù)庫(kù)中FETCH到的值以及相關(guān)設(shè)置

int OracleConnect();    //數(shù)據(jù)庫(kù)連接函數(shù)
int GetConfValue(char *, char *);       //取得設(shè)置文件中的數(shù)據(jù),ourVar實(shí)際上是為了保存取得的值
void Trim(char *);                      //去除字符串兩邊的空格
void AllocDescriptors(int, int, int);   //分配空間給選擇描述區(qū)和綁定描述區(qū)
void DeallocDescriptors();      //釋放分配給選擇描述區(qū)和綁定描述區(qū)的空間
void SetBindVariables();        //設(shè)置綁定變量
void PrintQueryResult();        //輸出從數(shù)據(jù)庫(kù)查詢到的值

int main(int argc, char *argv[])
{
    //定義用來(lái)存放動(dòng)態(tài)sql語(yǔ)句的宿主變量槽卫、
    EXEC SQL BEGIN DECLARE SECTION;
        char SqlQuery[100];
    EXEC SQL END DECLARE SECTION;
    //連接數(shù)據(jù)庫(kù)
    OracleConnect();        
    //分配綁定描述區(qū)與選擇描述區(qū)
    AllocDescriptors(MAX_ITEMS, MAX_VNAME_LEN, MAX_INAME_LEN);

    for (; ;)
    {
        printf("請(qǐng)輸入SQL語(yǔ)句(exit退出): \n");
        fgets(SqlQuery, 100, stdin);

        if ((strncmp(SqlQuery, "exit", 4) == 0) || (strncmp(SqlQuery, "EXIT", 4) == 0))
        {
            break;
        }

        //準(zhǔn)備動(dòng)態(tài)sql語(yǔ)句
        EXEC SQL PREPARE S FROM :SqlQuery;
        if (sqlca.sqlcode != 0)
        {
            continue;
        }
        
        //定義游標(biāo)
        EXEC SQL DECLARE C CURSOR FOR S;

        if (sqlca.sqlcode != 0)
        {
            continue;
        }

        //設(shè)置綁定變量
        SetBindVariables();

        //打開游標(biāo)
        EXEC SQL OPEN C USING DESCRIPTOR bindDp;
        printf("open cursor sqlcode : %d\n", sqlca.sqlcode);
        printf("list :\n|%s|\n", SqlQuery);

        //如果是select語(yǔ)句跟压,那么就要打印結(jié)果集
        if ((strncmp(SqlQuery, "select", 6)  ==0) || (strncmp(SqlQuery, "SELECT", 6) == 0))
        {   
            printf("Printf Query Result:\n");
            PrintQueryResult(); 
        }

        printf("return code %d\n", sqlca.sqlcode);
        //關(guān)閉游標(biāo)  提交結(jié)果
        EXEC SQL CLOSE C;
        EXEC SQL COMMIT WORK;

    }

        //釋放綁定描述符與選擇描述符
        printf("DEAllocDescriptors :\n");
        DeallocDescriptors();
        
        //提交更改  釋放數(shù)據(jù)庫(kù)連接
        printf("EXEC SQL COMMIT WORK RELEASW:\n");
        EXEC SQL COMMIT WORK RELEASE;
        printf("程序關(guān)閉\n");
        return 0;
}

int OracleConnect() //數(shù)據(jù)庫(kù)連接函數(shù)
{
    char str[100] = {0};
    char port[10] = {0};
    char ip[50] = {0};
    char threadMax[5] = {0};

    EXEC SQL BEGIN DECLARE SECTION;
    char oraSid[50] = {0};
    char oraUser[50] = {0};
    char oraPass[50] = {0};
    EXEC SQL END DECLARE SECTION;

    if ((GetConfValue("oraSid", oraSid) == 0) ||        //從配置文件中取得相關(guān)信息
        (GetConfValue("oraUser", oraUser) == 0) ||
        (GetConfValue("oraPass", oraPass) == 0) ||
        (GetConfValue("ip", ip) == 0) ||
        (GetConfValue("port", port) == 0)) 
    {
        printf("value is not found\n");
        return 0;
    }
    //數(shù)據(jù)庫(kù)連接
    EXEC SQL CONNECT :oraUser IDENTIFIED BY :oraPass using :oraSid;

    if (sqlca.sqlcode != 0)
    {
        perror("db connect :");
        printf("sqlcode = %d  ->%s  ->%s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
        return 0;
    }

    printf("Connect success\n");
    return 1;
}

int GetConfValue(char *type, char *outVar)  //從配置文件中獲取信息
{
    char *confFile = "conf.txt";
    char buf[1024] = {0};
    char typeStr[1024] = {0};
    int i = 0;
    FILE *fp = NULL;        //FILE實(shí)際上是一個(gè)結(jié)構(gòu)體

    if (!(fp = fopen(confFile, "r")))   //'r'以只讀的方式打開文件,fopen返回一個(gè)指針,也可以進(jìn)行真or假判斷
    {
        perror("conf.txt open :");
        return 0;
    }
    while (fgets(buf, 1024, fp))    //fgets 讀取fp中的數(shù)據(jù)歼培,每次讀取一行震蒋,讀取size-1個(gè)字符,并在后面補(bǔ)上一個(gè)'\0'丐怯。
    {   
        for (i = 0; i < 1024; i++)      //喷好!BUG  1024寫成了2024.翔横。读跷。
        {
            if (buf[i] == '=')
            {
                strncpy(typeStr, buf ,i);   //復(fù)制 = 前面的i個(gè)字符          
                Trim(typeStr);              //去除字符串兩邊的空格
            }
            if (strcmp(type, typeStr)==0)   //截取到的字符串與輸出的字符串相同,說(shuō)明找到了想要獲取的目標(biāo)
            {
                strcpy(outVar, buf+i+1);    //將 = 后面的字符串復(fù)制到outVar中
                outVar[strlen(outVar) -1]='\0';
                Trim(outVar);
                return 1;
            }
        }
    }
    
    printf("%s not found \n", type);
    return 0;
}

void Trim(char *inVar)      //自定義函數(shù)禾唁,目的是為了去除字符串兩邊的空格
{
    int i = 0;
    int j = strlen(inVar) - 1;  //strlen一個(gè)指針數(shù)組效览,返回的長(zhǎng)度是不包含'/0'的.因?yàn)閖要作為數(shù)組下標(biāo)无切,所以這里要減去1

    while (inVar[i] == ' ')
    {
        i++;
    }
    while (inVar[j] == ' ')
    {
        j--;
    }

    strncpy(inVar, inVar + i ,j - i + 1);   //要把當(dāng)前j指向的字符也放進(jìn)去,所以要加上一個(gè)1
    inVar[j - i + 1] = '\0';        //手動(dòng)加上'/0',因?yàn)榇藭r(shí)inVar的元素有j-i+1個(gè)丐枉,而最后一個(gè)元素的下標(biāo)為j-i+1-1,所以j-i+1-1+1=j-i+1上添加一個(gè)'/0'
}

void AllocDescriptors(int size, int maxVnameLen, int maxInameLen)   //分配描述區(qū)
{
    int i;

    //分配綁定描述區(qū)和選擇描述區(qū)  size:最大STL或P數(shù)量 即N  maxVnameLen:STI或P最大名字長(zhǎng)度 即M  maxInameLen:存儲(chǔ)指示變量最大名字長(zhǎng)度 即Y
    bindDp = SQLSQLDAAlloc(0, size, maxVnameLen, maxInameLen);
    selectDp = SQLSQLDAAlloc(0, size, maxVnameLen, maxInameLen);

    //為指示變量哆键,綁定變量分配內(nèi)存
    for (i = 0; i < MAX_ITEMS; i++)
    {
        bindDp->I[i] = (short *)malloc(sizeof(short));              //I 指示變量的地址 
        selectDp->I[i] = (short *)malloc(sizeof(short));
        bindDp->V[i] = (char *)malloc(sizeof(char));                //V STI或P的地址
        selectDp->V[i] = (char *)malloc(sizeof(char));
    }
}

void DeallocDescriptors()
{
    int i = 0;

    //釋放指示變量、綁定變量或選擇列表項(xiàng)的內(nèi)存
    for (i = 0; i < MAX_ITEMS; i++)
    {   
        if (bindDp->V[i] != (char *)0)
        {
            printf("FREE bindDp the %d:\n", i);
            free(bindDp->V[i]);
            bindDp->V[i] = NULL;    //釋放數(shù)組空間后瘦锹,手動(dòng)指向NULL是一個(gè)好習(xí)慣
            printf("FREE bindDp OVER %d:\n", i);
        }
        free(bindDp->I[i]); 
        bindDp->I[i] = NULL;
        
        if (selectDp->V[i] != (char *)0)
        {
            printf("FREE selectDp the %d:\n", i);
            free(selectDp->V[i]);   
            selectDp->V[i] = NULL;
            printf("FREE selectDp OVER %d:\n", i);
        }
        free(selectDp->I[i]);
        selectDp->I[i] = NULL;
    }

    printf("SQLSQLDAFree:\n");
    //釋放綁定描述區(qū)和選擇描述區(qū)
    SQLSQLDAFree(0, bindDp);
    SQLSQLDAFree(0, selectDp);
}

void SetBindVariables()     //進(jìn)項(xiàng)綁定變量的設(shè)置
{
    int i = 0;
    char bindVar[64] = {0};
    //設(shè)置綁定變量的最大個(gè)數(shù)
    //bindDp->N = MAX_ITEMS;        //多次一舉籍嘹??弯院?前面已經(jīng)將N初始化
    //作用辱士,將S語(yǔ)句中的綁定變量放入bindDp中?
    EXEC SQL DESCRIBE BIND VARIABLES FOR S INTO bindDp;
    printf("BIND VARIABLES sqlcode : %d\n", sqlca.sqlcode);
    //DESCRIBE后听绳,將sqlda->F中綁定變量真實(shí)的數(shù)量給sqlda->N
    bindDp->N = bindDp->F;

    //開始循環(huán)處理綁定變量
    for (i = 0; i < bindDp->F; i++)
    {
        //顯示綁定變量值  這里實(shí)際上顯示的是占位符的名字
        printf("請(qǐng)輸入綁定變量 %.*s :    ", (int)bindDp->C[i], bindDp->S[i]);
        //獲得綁定變量值   fgets會(huì)讀取換行符颂碘,所以要想辦法把換行符去掉,要不然就會(huì)讀取到相鄰的數(shù)據(jù)
        fgets(bindVar, 100, stdin);
        bindVar[strlen(bindVar) - 1] = '\0';
        //也可以使用scanf scanf不會(huì)讀取到換行符
        //scanf("%s", bindVar);
        //設(shè)置綁定變量的長(zhǎng)度 Oracle通過(guò)V[i]的地址(即字符串的首地址)訪問綁定變量椅挣,所以必須告知其長(zhǎng)度L
        bindDp->L[i] = strlen(bindVar);
        printf("bindDp->L[%d] = %d\n", i, bindDp->L[i]);
        //為綁定變量緩存區(qū)重新分配內(nèi)存头岔,多一位留給'\0'  realloc重新分配地址 sqlda->L是指針的指針,sqlda->L[i]訪問外層指針?biāo)赶虻闹羔? 
        //V[i]保存的實(shí)際上是一個(gè)字符串?dāng)?shù)組鼠证,因?yàn)閏har的長(zhǎng)度為1峡竣,并且char需要一個(gè)'/0'作為終止符,所以寫法如下名惩。 int數(shù)組寫法 sizeof(int)*length
        bindDp->V[i] = (char *)realloc(bindDp->V[i], bindDp->L[i] + 1);
        //將綁定變量數(shù)據(jù)放入
        strcpy(bindDp->V[i], bindVar);

        //設(shè)置指示變量澎胡,處理NULL 可能是因?yàn)槿绻斎隢ULL,也會(huì)當(dāng)作字符串娩鹉,所以就用一個(gè)變量指定
        if ((strncmp(bindVar, "NULL", 4) == 0) || (strncmp(bindVar, "null", 4) == 0))
        {
            *bindDp->I[i] = -1;     //sqlda->I[i]表示外層指針指向的指針攻谁,*sqlda->I[i]則標(biāo)識(shí)指針指向的指針指向的值
        }
        else
        {
            *bindDp->I[i] = 0;
        }

        //設(shè)置數(shù)據(jù)緩沖區(qū)數(shù)據(jù)類型代碼 char
        bindDp->T[i] = 1;
        printf("This BindVar is : %s\n", bindDp->V[i]);
    }

}

void PrintQueryResult()     //輸出select查詢語(yǔ)句獲取到的數(shù)據(jù)庫(kù)數(shù)據(jù)
{
    int i = 0;      //循環(huán)用
    int nullOk;     
    int precision;
    int scale;
    char title[30]; //保存列名
    //設(shè)置選擇列表項(xiàng)的最大個(gè)數(shù)
    //selectDp->N = MAX_ITEMS;       //應(yīng)該也是多此一舉
    //選擇列表項(xiàng),選擇描述區(qū)
    EXEC SQL DESCRIBE SELECT LIST FOR S INTO selectDp;
    printf("DESCRIBE SELECT LIST sqlcode is : %d\n", sqlca.sqlcode);
    //設(shè)置選擇列表項(xiàng)的實(shí)際個(gè)數(shù)
    selectDp->N = selectDp->F;

    //循環(huán)處理選擇列表項(xiàng)
    for (i = 0; i < selectDp->F; i++)   
    {   
        //清除selectDp->T[i]的高位->null T保存對(duì)應(yīng)選擇列表項(xiàng)的數(shù)據(jù)類型 高位則指示其是否能為null
        //并根據(jù)數(shù)據(jù)庫(kù)中此項(xiàng)是否能夠?yàn)閚ull設(shè)置nullOk的值 如果允許為空 nullOk=1 否則為0
        //0001 0001 1001 0001 左八位為高位弯予、右八位為低位  當(dāng)然戚宦,并不知T的結(jié)構(gòu)是否如此
        SQLColumnNullCheck(0, (unsigned short *)&selectDp->T[i], (unsigned short *)&selectDp->T[i], &nullOk);
        
        //根據(jù)內(nèi)部數(shù)據(jù)類型確定外部數(shù)據(jù)類型長(zhǎng)度 很明顯T存儲(chǔ)類型是數(shù)值形式的
        switch (selectDp->T[i])
        {
            case 2:
            //number數(shù)據(jù)類型,取得精度與標(biāo)度 -4.75 精度=3锈嫩,標(biāo)度=2
            SQLNumberPrecV6(0, (unsigned int *)&selectDp->L[i], &precision, &scale);

            //oracle使用number保存所有的數(shù)值類型受楼,但現(xiàn)在要把它放出來(lái),就要有一個(gè)對(duì)應(yīng)的外部數(shù)值類型的長(zhǎng)度保存
            if (scale > 0)  //scale大于零呼寸,說(shuō)明有小數(shù)位艳汽,那么就要用float保存number
            {
                selectDp->L[i] = sizeof(float);
            }
            else            //如果沒有小數(shù)位,那么就可以愉快地使用int存了
            {
                selectDp->L[i] = sizeof(int);
            }
            break;

            case 12:
            //data數(shù)據(jù)類型
            selectDp->L[i] = 9;
            break;
        }
            
            //還有第三種數(shù)據(jù)類型 varchar類型  推測(cè)因?yàn)長(zhǎng)[i]中初始保存的數(shù)據(jù)類型長(zhǎng)度就是對(duì)應(yīng)的char[]長(zhǎng)度对雪,所以不用進(jìn)行處理河狐???        -------------含有疑問

        //根據(jù)變量長(zhǎng)度馋艺,重新為選擇列表項(xiàng)分配內(nèi)存
        if (selectDp->L[i] != 2)    //其他類型(其實(shí)本質(zhì)是字符串栅干??)      -------------------含有疑問 
        {
            selectDp->V[i] = (char *)realloc(selectDp->V[i], selectDp->L[i]+1);
        }
        else                        //number類型
        {
            selectDp->V[i] = (char *)realloc(selectDp->V[i], selectDp->L[i]);
        }
            
        //初始化title
        memset(title, ' ', 30);         //寫memset(title, '0', 30)  也行捐祠,反正這里只是用來(lái)輸出碱鳞,但是填' '輸出比較好看
        //選擇列表項(xiàng)名稱 S保存選擇列表項(xiàng)名字地址的指針 C保存選擇列表項(xiàng)名字地址長(zhǎng)度的指針
        strncpy(title, selectDp->S[i], selectDp->C[i]);

        //顯示列名
        if (selectDp->T[i] == 2)        //T保存數(shù)據(jù)類型
        {
            if (scale > 0)
            {
                printf("\t%.*s", selectDp->L[i] + 3, title);    //指向STI的地址的長(zhǎng)度的數(shù)組     在輸出列名的時(shí)候就設(shè)置好格式
            }
            else
            {
                printf("\t%.*s", selectDp->L[i], title);
            }
        }
        else
        {
            printf("\t%-.*s", selectDp->L[i], title);
        }

        //根據(jù)oracle內(nèi)部類型確定外部類型
        if (selectDp->T[i] == 2)
        {
            if (scale > 0)  //float
            {
                selectDp->T[i] = 4;
            }
            else //int
            {
                selectDp->T[i] = 3;
            }
        }
        else    //char
        {
            selectDp->T[i] = 1;
        }
    }
    printf("\n");
            
    //當(dāng)selectDp中的數(shù)據(jù)處理完畢后,跳出
    EXEC SQL whenever not found do break;
    //printf("WHEN NOT FOUND  sqlcode is : %d\n", sqlca.sqlcode);
    //EXEC SQL DECLARE C CURSOR FOR S;      //--------------含有疑問 
    //printf("DECLARE C  sqlcode is : %d\n", sqlca.sqlcode);
    int n = 0;      
    //循環(huán)輸出數(shù)據(jù)
    for(; ;)
    {
        //用選擇描述區(qū)提取數(shù)據(jù)        ----------含有疑問
        //這個(gè)語(yǔ)句有問題
        EXEC SQL FETCH C using DESCRIPTOR selectDp;
        //開始顯示數(shù)據(jù)
        for (i = 0; i < selectDp->F; i++)
        {
            //處理null值
            if (*selectDp->I[i] < 0)
            {
                printf("\tNull");
            }
            else
            {               
                if (selectDp->T[i] == 3)
                {
                    printf("\t%d", *(int *)selectDp->V[i]);
                }
                else if (selectDp->T[i] == 4)
                {
                    printf("\t%8.2f", *(float *)selectDp->V[i]);
                }
                else //char 
                {
                    printf("\t%.*s", selectDp->L[i], selectDp->V[i]);
                }
            }

        }
    
    printf("\n");
    //n++;
    /*if (n%1000 == 0)
    {
        char a[10] = {0};
        scanf("%s", &a);
        if(!strncmp(a, "break", 5))
        {
            break;
        }
    }*/
    }   
}


在定義了一個(gè)sqlda結(jié)構(gòu)體后踱蛀,要使用SQLSQLDAAlloc()函數(shù)為其分配空間窿给。

descriptor_name = SQLSQLDAAlloc (runtime_context, max_vars, max_name, max_ind_name);
//runtime_context    //運(yùn)行時(shí)上下文指針
//max_vars              //最大SLI或者P數(shù)量    即N
//max_name            //SLI或者P最大名字長(zhǎng)度  即M
//max_ind_name     /IV最大名字長(zhǎng)度 即Y

宿主變量與指示變量還有綁定變量

EXEC SQL DECLARE BEGIN SECTION;
  int oraId = 0;      //宿主變量
EXEC SQL DECLARE END SECTION;
//指示器變量是與宿主變量相關(guān)聯(lián)的一類SQL變量,它被用來(lái)監(jiān)督和管理與其相關(guān)聯(lián)的宿主變量率拒,每一個(gè)宿主變量都可以定義一個(gè)指示器變量填大。
//綁定變量  對(duì)于提交的sql語(yǔ)句,有硬解和軟解兩重方式俏橘。第一次提交的sql語(yǔ)句會(huì)采用硬解會(huì)消耗大量的系統(tǒng)資源允华。而如果提交的sql語(yǔ)句
//在數(shù)據(jù)庫(kù)中已有,則為軟解寥掐。針對(duì)查詢同一類數(shù)據(jù)的情況靴寂,就使用了綁定變量,提高效率召耘。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末百炬,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子污它,更是在濱河造成了極大的恐慌剖踊,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,376評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件衫贬,死亡現(xiàn)場(chǎng)離奇詭異德澈,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)固惯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門笤成,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)魄缚,“玉大人眷射,你說(shuō)我怎么就攤上這事词身。” “怎么了贴捡?”我有些...
    開封第一講書人閱讀 156,966評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵忽肛,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我烂斋,道長(zhǎng)屹逛,這世上最難降的妖魔是什么箍镜? 我笑而不...
    開封第一講書人閱讀 56,432評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮煎源,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘香缺。我一直安慰自己手销,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,519評(píng)論 6 385
  • 文/花漫 我一把揭開白布图张。 她就那樣靜靜地躺著锋拖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪祸轮。 梳的紋絲不亂的頭發(fā)上兽埃,一...
    開封第一講書人閱讀 49,792評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音适袜,去河邊找鬼柄错。 笑死,一個(gè)胖子當(dāng)著我的面吹牛苦酱,可吹牛的內(nèi)容都是我干的售貌。 我是一名探鬼主播,決...
    沈念sama閱讀 38,933評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼疫萤,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼颂跨!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起扯饶,我...
    開封第一講書人閱讀 37,701評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤恒削,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后尾序,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體钓丰,經(jīng)...
    沈念sama閱讀 44,143評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,488評(píng)論 2 327
  • 正文 我和宋清朗相戀三年每币,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了斑粱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,626評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡脯爪,死狀恐怖则北,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情痕慢,我是刑警寧澤尚揣,帶...
    沈念sama閱讀 34,292評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站掖举,受9級(jí)特大地震影響快骗,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,896評(píng)論 3 313
  • 文/蒙蒙 一方篮、第九天 我趴在偏房一處隱蔽的房頂上張望名秀。 院中可真熱鬧,春花似錦藕溅、人聲如沸匕得。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)汁掠。三九已至,卻和暖如春集币,著一層夾襖步出監(jiān)牢的瞬間考阱,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工鞠苟, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留乞榨,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓当娱,卻偏偏與公主長(zhǎng)得像姜凄,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子趾访,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,494評(píng)論 2 348