• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            Prayer

            在一般中尋求卓越
            posts - 1256, comments - 190, trackbacks - 0, articles - 0
              C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

            關(guān)于動態(tài)SQL

            Posted on 2008-09-10 10:36 Prayer 閱讀(2340) 評論(0)  編輯 收藏 引用 所屬分類: 數(shù)據(jù)庫,SQLC/C++

            前幾天一個朋友要我寫點關(guān)于數(shù)據(jù)庫編程方面的東西,可一直由于工作比較忙,到現(xiàn)在已經(jīng)一個多星期了,正好煙草的項目由于最終方案的原因而停止了,新的ATM的P端的程序昨天基本已經(jīng)順利調(diào)整完了。相信今天上午是個清閑的上午,就寫點關(guān)于動態(tài)SQL方面的東西吧。


            嵌入SQL語言都是靜態(tài)SQL語言,即在編譯時已經(jīng)確定了引用的表和列。主變量不改變表和列信息。我們使用主變量改變查詢參數(shù),但是不能用主變量代替表名或列名。否則,系統(tǒng)報錯。動態(tài)SQL語句就是來解決這個問題。
            動態(tài)SQL語句的目的是,不是在編譯時確定SQL的表和列,而是讓程序在運行時提供,并將SQL語句文本傳給DBMS執(zhí)行。靜態(tài)SQL語句在編譯時已經(jīng)生成執(zhí)行計劃。而動態(tài)SQL語句,只有在執(zhí)行時才產(chǎn)生執(zhí)行計劃。動態(tài)SQL語句首先執(zhí)行PREPARE語句要求DBMS分析、確認(rèn)和優(yōu)化語句,并為其生成執(zhí)行計劃。DBMS還設(shè)置SQLCODE以表明語句中發(fā)現(xiàn)的錯誤。當(dāng)程序執(zhí)行完“PREPARE”語句后,就可以用EXECUTE語句執(zhí)行執(zhí)行計劃,并設(shè)置SQLCODE,以表明完成狀態(tài)。
              使用動態(tài)SQL,共分成四種方法:

            方法     支持的SQL語句                                      實現(xiàn)方法

            1        該語句內(nèi)不包含宿主變量,該語句不是查詢語句         execute immediate
            2        該語句內(nèi)包含輸入宿主變量 ,該語句不是查詢語句      prepare和execute
            3        包含已知數(shù)目的輸入宿主變量或列的查詢               prepare和fetch
            4        包含未知數(shù)目的輸入宿主變量或列的查詢               prepare和fetch,用描述符
            按照功能和處理上的劃分,動態(tài)SQL應(yīng)該分成兩類來解釋:動態(tài)修改和動態(tài)查詢。方法1和方法2完成動態(tài)修改。方法3和方法4完成了動態(tài)查詢。

            一、動態(tài)修改
            方法1和方法2完成動態(tài)修改。對于方法1,表示要執(zhí)行一個完整的T-SQL語句,該語句沒有宿主變量,不是一個查詢語句。因為沒有宿主變量來帶入不同的參數(shù),所以不能通過方法1來重復(fù)執(zhí)行修改語句。具體語法為:
            exec sql [at connection_name] execute immediate
            {: host_variable | string};
            其中,host_variable和string是存放完整T-SQL語句。
            例:提示用戶輸入被更新書的條件,然后組合成為一個完整的SQL語句,并執(zhí)行更新。
            exec sql begin declare section;
            CS_CHAR sqlstring[200];
            exec sql end declare section;
            char cond[150];
            exec sql whenever sqlerror call err_p();
            exec sql whenever sqlwarning call warn_p();
            strcpy(sqlstring,
            "update titles set price=price*1.10 where ");
            printf("Enter search condition:");
            scanf("%s", cond);
            strcat(sqlstring, cond);
            exec sql execute immediate :sqlstring;
            exec sql commit work;
            對于方法2,可以執(zhí)行一個包含輸入宿主變量的動態(tài)修改語句。該方法要使用PREPARE語句和EXECUTE語句。PREPARE語句是動態(tài)SQL語句獨有的語句。其語法為:
               PREPARE 語句名  FROM 宿主變量|字符串
            該語句接收含有SQL語句串的宿主變量,并把該語句送到DBMS。DBMS編譯語句并生成執(zhí)行計劃。在語句串中包含一個“?”表明參數(shù),當(dāng)執(zhí)行語句時,DBMS需要參數(shù)來替代這些“?”。PREPRARE執(zhí)行的結(jié)果是,DBMS用語句名標(biāo)志準(zhǔn)備后的語句。SQL SERVER編譯后的語句以臨時存儲過程的形式存放在緩沖區(qū)中。語句名類似于游標(biāo)名,是一個SQL標(biāo)識符。在執(zhí)行SQL語句時,EXECUTE語句后面是這個語句名。請看下面這個例子:
            EXEC SQL BEGIN DECLARE SECTION;
            char        prep[] = "INSERT INTO mf_table VALUES(?,?,?)";
            char        name[30];
            char        car[30];
            double         num;
            EXEC SQL END DECLARE SECTION;
            EXEC SQL PREPARE prep_stat FROM :prep;
            while (SQLCODE == 0)
            {
               strcpy(name, "Elaine");
               strcpy(car, "Lamborghini");
               num = 4.9;
               EXEC SQL EXECUTE prep_stat USING :name, :car, :num;
            }
              在這個例子中,prep_stat是語句名,prep宿主變量的值是一個INSERT語句,包含了三個參數(shù)(3個“?”)。PREPARE的作用是,DBMS編譯這個語句并生成執(zhí)行計劃,并把語句名標(biāo)志這個準(zhǔn)備后的語句。值得注意的是,PREPARE中的語句名的作用范圍為整個程序,所以不允許在同一個程序中使用相同的語句名在多個PREPARE語句中。
               EXECUTE語句是動態(tài)SQL獨有的語句。它的語法如下:
            EXECUTE 語句名 USING  宿主變量 | DESCRIPTOR 描述符名
            請看上面這個例子中的“EXEC SQL EXECUTE prep_stat USING :name, :car, :num;”語句,它的作用是,請求DBMS執(zhí)行PREPARE語句準(zhǔn)備好的語句。當(dāng)要執(zhí)行的動態(tài)語句中包含一個或多個參數(shù)標(biāo)志時,在EXECUTE語句必須為每一個參數(shù)提供值,如::name、:car和:num。這樣的話,EXECUTE語句用宿主變量值逐一代替準(zhǔn)備語句中的參數(shù)標(biāo)志(“?”),從而,為動態(tài)執(zhí)行語句提供了輸入值。
            使用主變量提供值,USING子句中的主變量數(shù)必須同動態(tài)語句中的參數(shù)標(biāo)志數(shù)一致,而且每一個主變量的數(shù)據(jù)類型必須同相應(yīng)參數(shù)所需的數(shù)據(jù)類型相一致。各主變量也可以有一個伴隨主變量的指示符變量。當(dāng)處理EXECUTE語句時,如果指示符變量包含一個負(fù)值,就把NULL值賦予相應(yīng)的參數(shù)標(biāo)志。除了使用主變量為參數(shù)提供值,也可以通過SQLDA提供值(關(guān)于這個,后邊會講到)。

            二、動態(tài)游標(biāo)

            使用動態(tài)游標(biāo)可以完成方法3。
               游標(biāo)分為靜態(tài)游標(biāo)和動態(tài)游標(biāo)兩類。對于靜態(tài)游標(biāo),在定義游標(biāo)時就已經(jīng)確定了完整的SELECT語句。在SELECT語句中可以包含主變量來接收輸入值。當(dāng)執(zhí)行游標(biāo)的OPEN語句時,主變量的值被放入SELECT語句。在OPEN語句中,不用指定主變量,因為在DECLARE CURSOR語句中已經(jīng)放置了主變量。請看下面靜態(tài)游標(biāo)的例子:
            EXEC SQL BEGIN DECLARE SECTION;
            char szLastName[] = "White";
            char szFirstName[30];
            EXEC SQL END DECLARE SECTION;

            EXEC SQL
               DECLARE author_cursor CURSOR FOR
               SELECT au_fname FROM authors WHERE au_lname = :szLastName;

            EXEC SQL OPEN author_cursor;

            EXEC SQL FETCH author_cursor INTO :szFirstName;
            動態(tài)游標(biāo)和靜態(tài)游標(biāo)不同。以下是動態(tài)游標(biāo)使用的句法:
            1)、聲明游標(biāo):
             對于動態(tài)游標(biāo),在DECLARE CURSOR語句中不包含SELECT語句。而是,定義了在PREPARE中的語句名,PREPARE語句規(guī)定與查詢相關(guān)的語句名稱。具體語法為:
            exec sql [at connection_name] declare cursor_name
            cursor for statement_name;
            如:EXEC SQL DECLARE author_cursor CURSOR FOR select_statement;
            值得注意的是,聲明動態(tài)游標(biāo)是一個可執(zhí)行語句,應(yīng)該在PREPARE語句后執(zhí)行。
            2)、打開游標(biāo)
            完整語法為:OPEN 游標(biāo)名 [USING 主變量名 | DESCRIPTOR 描述名]
               在動態(tài)游標(biāo)中,OPEN語句的作用是使DBMS定位相關(guān)的游標(biāo)在第一行查詢結(jié)果前。當(dāng)OPEN語句成功執(zhí)行完畢后,游標(biāo)處于打開狀態(tài),并為FETCH語句做準(zhǔn)備。OPEN語句執(zhí)行一條由PREPARE語句預(yù)編譯的語句。如果動態(tài)查詢正文中包含有一個或多個參數(shù)標(biāo)志時,OPEN語句必須為這些參數(shù)提供參數(shù)值。USING子句的作用就是規(guī)定參數(shù)值。可以使用主變量提供參數(shù)值,也可以通過描述名(即SQLDA)提供參數(shù)值。如:EXEC SQL OPEN author_cursor USING :szLastName;。
            3)、取一行值
               FETCH語法為:FETCH 游標(biāo)名 INTO USING DESCRIPTOR 描述符名。
            動態(tài)FETCH語句的作用是,把游標(biāo)移到下一行,并把這一行的各列值送到SQLDA中。注意的是,靜態(tài)FETCH語句的作用是用主變量表接收查詢到的列值。在方法3中,使用的是靜態(tài)FETCH語句獲得值。動態(tài)FETCH語句只在方法4中使用。
            4)、關(guān)閉游標(biāo)
            如:EXEC SQL CLOSE c1;
            關(guān)閉游標(biāo)的同時,會釋放由游標(biāo)添加的鎖和放棄未處理的數(shù)據(jù)。在關(guān)閉游標(biāo)前,該游標(biāo)必須已經(jīng)聲明和打開。另外,程序終止時,系統(tǒng)會自動關(guān)閉所有打開的游標(biāo)。
            總之,在動態(tài)游標(biāo)的DECLARE CURSOR語句中不包含SELECT語句。而是,定義了在PREPARE中的語句名,用PREPARE語句規(guī)定與查詢相關(guān)的語句名稱。當(dāng)PREPARE語句中的語句包含了參數(shù),那么在OPEN語句中必須指定提供參數(shù)值的主變量或SQLDA。動態(tài)DECLARE CURSOR語句是一個可執(zhí)行語句。該子句必須在OPEN、FETCH、CLOSE語句之前使用。請看下面這個例子,描述了完成方法3的五個步驟:PREPARE、DECLARE、OPEN、FETCH和CLOSE。
            ……
            EXEC SQL BEGIN DECLARE SECTION;
            char szCommand[] = "SELECT au_fname FROM authors WHERE au_lname = ?";
            char szLastName[] = "White";
            char szFirstName[30];
            EXEC SQL END DECLARE SECTION;
            EXEC SQL  PREPARE select_statement FROM :szCommand;
            EXEC SQL DECLARE author_cursor CURSOR FOR select_statement;
            EXEC SQL OPEN author_cursor USING :szLastName;
            EXEC SQL FETCH author_cursor INTO :szFirstName;
            EXEC SQL CLOSE author_cursor;
            ………
             下面是一個實現(xiàn)方法3的實際例子。提示用戶輸入排序的條件,并把符合條件的書信息顯示出來。
            ……
            exec sql begin declare section;
            CS_CHAR sqlstring[200];
            CS_FLOAT bookprice,condprice;
            CS_CHAR booktitle[200];
            exec sql end declare section;
            char orderby[150];
            exec sql whenever sqlerror call err_p();
            exec sql whenever sqlwarning call warn_p();
            strcpy(sqlstring,
            "select title,price from titles\
            where price>? order by ");
            printf("Enter the order by clause:");
            scanf("%s", orderby);
            strcat(sqlstring, orderby);
            exec sql prepare select_state from :sqlstring;
            exec sql declare select_cur cursor for
            select_state;
            condprice = 10; /* 可以提示用戶輸入這個值*/
            exec sql open select_cur using :condprice;
            exec sql whenever not found goto end;
            for (;;)
            {
            exec sql fetch select_cur
            into :booktitle,:bookprice;
            printf("%20s %bookprice=%6.2f\n",
            booktitle, bookprice);
            }
            end:
            exec sql close select_cur;
            exec sql commit work;
            ………

            三、SQLDA

            要實現(xiàn)方法4,則需要使用SQLDA(也可以使用SQL Descriptors,請讀者參閱幫助信息)。可以通過SQLDA為嵌入SQL語句提供不確定的輸入數(shù)據(jù)和從嵌入SQ語句中輸出不確定數(shù)據(jù)。理解SQLDA的結(jié)構(gòu)是理解動態(tài)SQL的關(guān)鍵。
            我們知道,動態(tài)SQL語句在編譯時可能不知道有多少列信息。在嵌入SQL語句中,這些不確定的數(shù)據(jù)是通過SQLDA完成的。SQLDA的結(jié)構(gòu)非常靈活,在該結(jié)構(gòu)的固定部分,指明了多少列等信息(如下圖中的sqld=2,表示為兩列信息),在該結(jié)構(gòu)的后面,有一個可變長的結(jié)構(gòu)(sd_column結(jié)構(gòu)),說明每列的信息。


                         SQLDA結(jié)構(gòu)
            Sd_Sqld=2
            Sd_column
            ……


                                             
            Sd_datafmt
            Sd_Sqllen
            Sd_sqldata
            …..
                                              
            Sd_datafmt
            Sd_Sqllen
            Sd_Sqldata
            …..

                                      
              具體SQLDA的結(jié)構(gòu)在sqlda.h中定義,是:
            typedef struct _sqlda
            {
            CS_SMALLINT sd_sqln;
            CS_SMALLINT sd_sqld;
            struct _sd_column
            {
            CS_DATAFMT sd_datafmt;
            CS_VOID *sd_sqldata;
            CS_SMALLINT sd_sqlind;
               CS_INT sd_sqllen;
            CS_VOID*sd_sqlmore;
            } sd_column[1];
            } syb_sqlda;
            typedef syb_sqlda SQLDA;

            從上面這個定義看出,SQLDA是一種由兩個不同部分組成的可變長數(shù)據(jù)結(jié)構(gòu)。從位于SQLDA開端的sd_sqln到sd_sqld為固定部分,用于標(biāo)志該SQLDA,并規(guī)定這一特定的SQLDA的長度。而后是一個或多個sd_column結(jié)構(gòu) ,用于標(biāo)志列數(shù)據(jù)或參數(shù)。當(dāng)用SQLDA把參數(shù)送到執(zhí)行語句時,每一個參數(shù)都是一個sd_column結(jié)構(gòu);當(dāng)用SQLDA返回輸出列信息時,每一列都是一個sd_column 結(jié)構(gòu)。具體每個元素的含義為:
            lSd_Sqln。分配的sd_column結(jié)構(gòu)的個數(shù)。等價于可以允許的最大輸入?yún)?shù)的個數(shù)或輸出列的個數(shù)。
            lSd_Sqld。目前使用的sd_column結(jié)構(gòu)的個數(shù)。
            lSd_column[].sd_datafmt。標(biāo)志同列相關(guān)的CS_DATAFMT結(jié)構(gòu)。
            lSd_column[].sd_Sqldata。指向數(shù)據(jù)的地址。注意,僅僅是一個地址。
            lSd_column[].sd_sqllen。sd_sqldata指向的數(shù)據(jù)的長度。
            lSd_column[].sd_Sqlind。代表是否為NULL。如果該列不允許為NULL,則該字段不賦值;如果該列允許為NULL,則:該字段若為0,表示數(shù)據(jù)值不為NULL,若為-1,表示數(shù)據(jù)值為NULL。
            lSd_column[].sd_sqlmore。保留為將來使用。

            下面我們來看一個具體的例子。這個例子是通過output_descriptor查詢數(shù)據(jù)庫中的數(shù)據(jù),是通過input_descriptor傳遞參數(shù)。這個例子的作用是,模擬一個動態(tài)查詢,并顯示查詢結(jié)果。動態(tài)查詢的執(zhí)行過程如下:
            1)、如同構(gòu)造動態(tài)UPDATE語句或DELETE語句的方法一樣,程序在緩沖器中構(gòu)造一個有效的SELECT語句。
            2)、程序用PREPARE語句把動態(tài)查詢語句送到DBMS,DBMS準(zhǔn)備、確認(rèn)和優(yōu)化語句,并生成一個應(yīng)用計劃。
            3)、動態(tài)DECLARE CURSOR語句說明查詢游標(biāo),動態(tài)DECLARE CURSOR語句規(guī)定與動態(tài)SELECT語句有關(guān)的語句名稱。如:例子中的statement。
            4)、程序用DESCRIBE語句請求DBMS提供SQLDA中描述信息,即告訴程序有多少列查詢結(jié)果、各列名稱、數(shù)據(jù)類型和長度。DESCRIBE語句只用于動態(tài)查詢。具體見下一節(jié)。
            5)、為SQLDA申請存放一列查詢結(jié)果的存儲塊(即:sqldata指向的數(shù)據(jù)區(qū)),也為SQLDA的列的指示符變量申請空間。程序把數(shù)據(jù)區(qū)地址和指示符變量地址送入SQLDA,以告訴DBMS向何處回送查詢結(jié)果。
            6)、動態(tài)格式的OPEN語句。即打開存放查詢到的數(shù)據(jù)集(動態(tài)SELECT語句產(chǎn)生的數(shù)據(jù))的第一行。
            7)、動態(tài)格式的FETCH語句把游標(biāo)當(dāng)前行的結(jié)果送到SQLDA。(動態(tài)FETCH語句和靜態(tài)FETCH語句的不同是:靜態(tài)FETCH語句規(guī)定了用主變量接收數(shù)據(jù);而動態(tài)FETCH語句是用SQLDA接收數(shù)據(jù)。)并把游標(biāo)指向下一行結(jié)果集。
            8)、CLOSE語句關(guān)閉游標(biāo)。
            具體程序如下:

            exec sql include sqlca;
            exec sql include sqlda;
            ...
            /*input_ descriptor是通過SQLDA傳遞參數(shù),output_descriptor是通過SQLDA返回列數(shù)據(jù)*/
            SQLDA *input_descriptor, *output_descriptor;
            CS_SMALLINT small;
            CS_CHAR character[20];
            /*申請空間*/
            input_descriptor = (SQLDA *)malloc(SYB_SQLDA_SIZE(3));
            /*設(shè)置參數(shù)的最大個數(shù)*/
            input_descriptor->sqlda_sqln = 3;
            /*申請空間*/
            output_descriptor = (SQLDA *)malloc(SYB_SQLDA_SIZE(3));
            /*設(shè)置列數(shù)的最大值*/
            output_descriptor->sqlda_sqln = 3;
            *p_retcode = CS_SUCCEED;
            /*連接數(shù)據(jù)庫服務(wù)器*/
            exec sql connect "sa" identified by password;
            /* 創(chuàng)建一張example表,并插入一些例子數(shù)據(jù),用于演示SQLDA的使用*/
            exec sql drop table example;
            exec sql create table example (fruit char(30), number int);
            exec sql insert example values ('tangerine', 1);
            exec sql insert example values ('pomegranate', 2);
            exec sql insert example values ('banana', 3);
            /* 準(zhǔn)備和描述查詢語句*/
            exec sql prepare statement from
                     "select fruit from example where number = ?";
            /*describe語句的作用是,將查詢所需要的參數(shù)信息存放在input_descriptor中*/
            exec sql describe input statement using descriptor input_descriptor;
            /*設(shè)置SQLDA中指向參數(shù)數(shù)據(jù)的地址信息(sqldata)和數(shù)據(jù)長度(sqlda_sqllen)*/
            input_descriptor->sqlda_column[0].sqlda_datafmt.datatype =CS_SMALLINT_TYPE;
            input_descriptor->sqlda_column[0].sqlda_sqldata = &small;
            input_descriptor->sqlda_column[0].sqlda_sqllen = sizeof(small);
            small = 2;
            /*將查詢語句的列信息存放在output_descriptor中*/
            exec sql describe output statement using descriptor output_descriptor;
            if (output_descriptor->sqlda_sqld != 1 ||
            output_descriptor->sqlda_column[0].sqlda_datafmt.datatype !=
            CS_CHAR_TYPE)
            FAIL;
            else
            printf("first describe output \n");
            /*設(shè)置存放列數(shù)據(jù)的地址信息*/
            output_descriptor->sqlda_column[0].sqlda_sqldata = character;
            output_descriptor->sqlda_column[0].sqlda_datafmt.maxlength = 20;
            /*通過input_descriptor將輸入?yún)?shù)帶入查詢語句,并將結(jié)果通過output_descriptor帶出*/
            exec sql execute statement into descriptor output_descriptor \
            using descriptor input_descriptor;
            /*打印結(jié)果---單行結(jié)果*/
            printf("expected pomegranate, got %s\n",character);
            /*釋放申請的內(nèi)存空間*/
            exec sql deallocate prepare statement;
            /* 多行結(jié)果示例。對多行查詢語句做準(zhǔn)備和描述操作*/
            exec sql prepare statement from \
            "select number from example where fruit = ?";
            /*為多行結(jié)果聲明游標(biāo)*/
            exec sql declare c cursor for statement;

            exec sql describe input statement using descriptor input_descriptor;
            /*設(shè)置查詢的參數(shù)地址信息*/
            input_descriptor->sqlda_column->sqlda_sqldata = character;
            input_descriptor->sqlda_column->sqlda_datafmt.maxlength =CS_NULLTERM;
            /*設(shè)置參數(shù)值為banana,也可以提示用戶輸入這些信息*/
            strcpy(character, "banana");
            input_descriptor->sqlda_column->sqlda_sqllen = CS_NULLTERM;
            /*打開游標(biāo)*/
            exec sql open c using descriptor input_descriptor;
            /*設(shè)置輸出列的信息*/
            exec sql describe output statement using descriptor output_descriptor;
            /*設(shè)置存放數(shù)據(jù)的地址信息*/
            output_descriptor->sqlda_column->sqlda_sqldata = character;
            output_descriptor->sqlda_column->sqlda_datafmt.datatype =CS_CHAR_TYPE;
            output_descriptor->sqlda_column->sqlda_datafmt.maxlength = 20;
            output_descriptor->sqlda_column->sqlda_sqllen = 20;
            output_descriptor->sqlda_column->sqlda_datafmt.format =
            (CS_FMT_NULLTERM | CS_FMT_PADBLANK);
            exec sql fetch c into descriptor output_descriptor;
            /*打印列的數(shù)據(jù)*/
            printf("expected pomegranate, got %s\n", character);
            exec sql commit work;
            ……….
              上面這個例子是典型的動態(tài)查詢程序。該程序中演示了PREPARE語句和DESCRIBE語句的處理方式,以及為程序中檢索到的數(shù)據(jù)分配空間。要注意程序中如何設(shè)置sqlda_column結(jié)構(gòu)中的的各個變量。這個程序也演示了OPEN、FETCH和CLOSE語句在動態(tài)查詢中的應(yīng)用。值得注意的是,F(xiàn)ETCH語句只使用了SQLDA,不使用主變量。由于程序中預(yù)先申請了sqlda_column結(jié)構(gòu)中的SQLDATA空間,所以DBMS知道將查詢到的數(shù)據(jù)保存在何處。該程序還考慮了查詢數(shù)據(jù)為NULL的處理。
              值得注意的是,SQDA結(jié)構(gòu)不是SQL標(biāo)準(zhǔn)。每個數(shù)據(jù)庫廠商的實現(xiàn)方式有可能不同。

            四、DESCRIBE語句
             該語句只有動態(tài)SQL才有。該語句是在PREPARE語句之后,在OPEN語句之前使用。該語句的作用是,設(shè)置SQLDA中的描述信息,如:列名、數(shù)據(jù)類型和長度等。DESCRIBE語句的語法為:
            DESCRIBE 語句名 INTO 描述符名
                如:exec sql describe output statement using descriptor output_descriptor;。
            在執(zhí)行DESCRIBE前,用戶必須給出SQLDA中的SQLN的值(表示最多有多少列),該值也說明了SQLDA中最多有多少個sqlda_column結(jié)構(gòu)。然后,執(zhí)行DESCRIBE語句,該語句填充每一個sqlda_column結(jié)構(gòu)。每個sqlda_column結(jié)構(gòu)中的相應(yīng)列為:
            lSd_datafmt結(jié)構(gòu):列名等信息。
            lSd_sqllen列:給出列的長度。
              注意,sd_sqldata列不填充。由程序在FETCH語句之前,給出數(shù)據(jù)緩沖器地址和指示符地址。
            <!--[if !supportLineBreakNewLine]-->
            下邊的話,給出兩個例子吧,方便對上邊講到的東西做個對比:

            1)、TELECOM程序
              該程序是模擬電信費用查詢。


            #include <stdio.h>
            #include <stdlib.h>
            #include <string.h>
            #if defined ( DB2 )
            #define SQLNOTFOUND 100
            #include <sql.h>
            #elif defined ( ORA7 )
            #define SQLNOTFOUND 1403
            #endif

            #if defined (SYBASE)
            #define SQLNOTFOUND 100
            #endif


            EXEC SQL INCLUDE sqlca;

             
            EXEC SQL BEGIN DECLARE SECTION;
               char user[30];
               char passwd[30];
            char Usr_name[61];
            char Dev_no[9]; 
            long Call_flg;
            char Called_arno[11];
            char Called_no[15];
            char Call_dat[21];
            double Call_dur;  
            double Call_rate;  
            double Call_fee;  
            double Add_fee;
            char as_dev_no[9];
            EXEC SQL END DECLARE SECTION;
            void main(){
            char statusbuf[1024], s[30];
            /*連接到SQL SERVER服務(wù)器*/
            printf("\nplease enter your userid ");
            gets(user);
            printf("\npassword ");
            gets(passwd);
            exec sql connect :user identified by :passwd;
            exec sql use pubs2;
            /*輸入想要查詢的電話號碼*/
               printf("\nPlease enter the telephone number:");
            gets(as_dev_no );
              /*聲明游標(biāo)*/
            EXEC SQL DECLARE c1 CURSOR FOR
            SELECT bas_infot.Usr_name, auto10a_list.Dev_no, auto10a_list.Call_flg, auto10a_list.Called_arno, auto10a_list.Called_no
            , auto10a_list.Call_dat, auto10a_list.Call_dur, auto10a_list.Call_rate, auto10a_list.Call_fee,    
            FROM auto10a_list, bas_infot
            WHERE ( auto10a_list.Dev_no = bas_infot.Dev_no ) AND auto10a_list.Dev_no = :as_dev_no;
            /*打開游標(biāo),指向查詢相關(guān)電話信息的結(jié)果集*/
            EXEC SQL OPEN c1;  /* :rk.2:erk. */
            do{
            /*取出一行數(shù)據(jù)到各個變量*/
            EXEC SQL FETCH c1 INTO
            :Usr_name, :Dev_no, :Call_flg, :Called_arno, :Called_no, :Call_dat, :Call_dur, :Call_rate, :Call_fee, :Add_fee;

            if( (sqlca.sqlcode == SQLNOTFOUND) || (sqlca.sqlcode <0) )
            break;
               /*顯示數(shù)據(jù)*/
            printf("%s,%s,%d,%s,%s,%s,%7.0f,%8.3f,%7.2f,%6.2f\n"
            , Usr_name, Dev_no, Call_flg, Called_arno, Called_no, Call_dat, Call_dur, Call_rate, Call_fee, Add_fee );
            }while(1);
            EXEC SQL CLOSE c1; 
            EXEC SQL DEALLOCATE CURSOR c1;
            Exec sql disconnect all;
               return (0);
            }
            2)、 ADHOC程序
            該程序的功能是:用戶輸入任意SQL語句,并執(zhí)行和打印結(jié)果。


            #include <stdio.h>
            #include <stdlib.h>
            #include <string.h>
            /* Defines for BINDING */
            /*初試化SQLDA*/
            int init_da (SQLDA **DAPointer, int DAsqln);
            /*為存放列數(shù)據(jù)的sd_column結(jié)構(gòu)申請空間*/
            int alloc_host_vars (SQLDA *sqldaPointer);
            /*釋放SQLDA所申請的空間*/
            void free_da (SQLDA *sqldaPointer);
            /*獲取列名信息*/
            char * readColName (SQLDA *sqldaPointer, short sd_columnIndex, char * buffer);
            /*獲取列數(shù)據(jù)*/
            char * readCol (SQLDA *sqldaPointer, short sd_columnIndex, char * buffer);
            #ifdef __cplusplus
            }
            #endif
            /*定義最大列數(shù)*/
            #define MAX_COLUMNS255

            #define MAX_CHAR_FOR_DOUBLE20
            #define MAX_CHAR_FOR_LONG15
            #define MAX_CHAR_FOR_DATETIME30
            #define MAX_CHAR_FOR_DEFAULT100
            EXEC SQL INCLUDE SQLCA ;
            EXEC SQL INCLUDE SQLDA ;

            #define SQLSTATE sqlca.sqlstate
            #define SQLCODE sqlca.sqlcode
            /*處理SQL語句*/
            int process_statement( char * ) ;
            int main() {
              int rc ;
              char st[1024];
              char tmpstr[1024];
            /*獲得SQL語句*/
            printf("Please enter the any sql statement:");
              gets( st);
              /* 處理該語句 */
              rc = process_statement( st ) ;
            /*打印處理結(jié)果*/
              printf( "%d", rc);
              printf("the sqlcode is %d",SQLCODE);
            }
            /******************************************************************************
            * FUNCTION : process_statement
            * 處理sql  語句
            *****************************************************************************/
            int process_statement ( char * sqlInput ) {

              int counter = 0 ;
              SQLDA * sqldaPointer ;
              short sqlda_d ; /* Total columns */
              short idx;
              char buffer[4096];
              char varname[1024];
              char colnamelist[4096];
              EXEC SQL BEGIN DECLARE SECTION ;
                 char st[1024] ;
              EXEC SQL END DECLARE SECTION ;
              strcpy( st, sqlInput ) ;
              /* 為SQLDA結(jié)構(gòu)申請空間" */
              if (init_da( &sqldaPointer, MAX_COLUMNS ) == -1)
            {
                    return -1;
            }
            /*準(zhǔn)備SQL語句*/
              EXEC SQL PREPARE statement1 from :st ;
              if (SQLCODE < 0)
            {
                    free_da(sqldaPointer);
                return SQLCODE;
                }
            /*獲取查詢列的信息到SQLDA結(jié)構(gòu)*/
              EXEC SQL DESCRIBE statement1 USING DESCRIPTOR sqldaPointer ;
            /* 如果SQLCODE為0,則表示為SELECT語句 */
              if ( SQLCODE != 0 ) {
            free_da(sqldaPointer);
            return SQLCODE;
              } /* end if */
              sqlda_d = sqldaPointer->sd_sqld ;
              if ( sqlda_d > 0 ) {
                 /* 為存放列數(shù)據(jù)的sd_column結(jié)構(gòu)申請空間 */
                 if (alloc_host_vars( sqldaPointer ) == -1)
            {free_da(sqldaPointer);
            return -1;
            }
                 /*聲明游標(biāo)*/
                 EXEC SQL DECLARE pcurs CURSOR FOR statement1 ;
                /打開游標(biāo)*/
                 EXEC SQL OPEN pcurs ;
                 if (SQLCODE < 0)
                 return SQLCODE;
                 /*取一行數(shù)據(jù)到SQLDA結(jié)構(gòu)*/
                 EXEC SQL FETCH pcurs INTO DESCRIPTOR sqldaPointer;
                 if (SQLCODE < 0)
            {
             EXEC SQL CLOSE pcurs ;
             return SQLCODE;
                   }
                 /*顯示列標(biāo)題 */
                 colnamelist[0] = 0;
                 for ( idx=0; idx< sqlda_d; idx++)
            { strcat(colnamelist, readColName(sqldaPointer, idx, buffer));
             if (idx < sqlda_d -1)
            strcat(colnamelist, ",");
            }
                 /* 顯示行數(shù)據(jù)*/
                 while ( SQLCODE == 0 ) {
                  counter++ ;
                    for ( idx=0; idx< sqlda_d; idx++)     
                     printf("%s",readCol(sqldaPointer, idx, buffer));
                EXEC SQL FETCH pcurs INTO DESCRIPTOR sqldaPointer ;
                 }  /* endwhile */
                /*關(guān)閉游標(biāo)*/
                 EXEC SQL CLOSE pcurs ;
             EXEC SQL DEALLOCATE CURSOR pcurs;
                 /* 釋放為SQLDA申請的空間 */
                 free_da( sqldaPointer ) ;
              } else { /* 不是SELECT語句*/
                 EXEC SQL EXECUTE statement1 ;
                 free_da( sqldaPointer ) ;
                 if (SQLCODE < 0)
            return SQLCODE;
              }  /* end if */
              return( 0 ) ;
            }     /* end of program : ADHOC.CP */

            /******************************************************************************* PROCEDURE : init_da
            *為SQLDA分配空間。使用SQLDASIZE 獲得SQLDA的大小。如果返回-1,則表示分配
            *空間不成功。
            ******************************************************************************/
            int init_da (SQLDA **DAPointer, int DAsqln) {
            int idx;
              *DAPointer = (SQLDA *)malloc(SYB_SQLDA_SIZE(DAsqln));
              if (*DAPointer == NULL)
                 return (-1);
              memset (*DAPointer, '\0', SYB_SQLDA_SIZE(DAsqln));
              (*DAPointer)->sd_sqln = DAsqln;
              (*DAPointer)->sd_sqld = 0;
              return 0;
            }
            /******************************************************************************* FUNCTION : alloc_host_vars
            *為存放列數(shù)據(jù)的sd_column結(jié)構(gòu)申請空間。如果返回-1,則表示不能獲得足夠內(nèi)存。
            ******************************************************************************/
            int alloc_host_vars (SQLDA *sqldaPointer) {
              short idx;
             
              for (idx = 0; idx < sqldaPointer->sd_sqld; idx++) {
                 switch (sqldaPointer->sd_column[idx].sd_datafmt.datatype ) {
            case CS_CHAR_TYPE:
            case CS_VARCHAR_TYPE:
            sqldaPointer->sd_column[idx].sd_datafmt.datatype = CS_CHAR_TYPE;
             sqldaPointer->sd_column[idx].sd_sqldata = (char *) malloc (sqldaPointer->sd_column[idx].sd_sqllen + 1 );
            sqldaPointer->sd_column[idx].sd_sqllen ++;
            sqldaPointer->sd_column[idx].sd_datafmt.format = CS_FMT_NULLTERM;
            break;

            case CS_TINYINT_TYPE:
            case CS_SMALLINT_TYPE:
            case CS_INT_TYPE:
            case CS_VOID_TYPE:
            case CS_USHORT_TYPE:
            sqldaPointer->sd_column[idx].sd_datafmt.datatype = CS_CHAR_TYPE;
             sqldaPointer->sd_column[idx].sd_sqldata = (char *) malloc (MAX_CHAR_FOR_LONG);
            sqldaPointer->sd_column[idx].sd_sqllen = MAX_CHAR_FOR_LONG;
            sqldaPointer->sd_column[idx].sd_datafmt.format = CS_FMT_NULLTERM;
            break;

            case CS_REAL_TYPE:
            case CS_FLOAT_TYPE:
            case CS_BIT_TYPE:
            case CS_MONEY_TYPE:
            case CS_MONEY4_TYPE:
            sqldaPointer->sd_column[idx].sd_datafmt.datatype = CS_CHAR_TYPE;
            sqldaPointer->sd_column[idx].sd_sqldata = (char *) malloc (MAX_CHAR_FOR_DOUBLE);
            sqldaPointer->sd_column[idx].sd_sqllen = MAX_CHAR_FOR_DOUBLE;
            sqldaPointer->sd_column[idx].sd_datafmt.format = CS_FMT_NULLTERM;
            break;

            case CS_DATETIME_TYPE:
            case CS_DATETIME4_TYPE:
            sqldaPointer->sd_column[idx].sd_datafmt.datatype = CS_CHAR_TYPE;
            sqldaPointer->sd_column[idx].sd_sqldata = (char *) malloc (MAX_CHAR_FOR_DATETIME);
            sqldaPointer->sd_column[idx].sd_sqllen = MAX_CHAR_FOR_DATETIME;
            sqldaPointer->sd_column[idx].sd_datafmt.format = CS_FMT_NULLTERM;
            break;

            case CS_NUMERIC_TYPE:
            case CS_DECIMAL_TYPE:
            sqldaPointer->sd_column[idx].sd_datafmt.datatype = CS_CHAR_TYPE;
            sqldaPointer->sd_column[idx].sd_sqldata = (char *) malloc (sqldaPointer->sd_column[idx].sd_datafmt.precision + 3 );
            sqldaPointer->sd_column[idx].sd_sqllen = sqldaPointer->sd_column[idx].sd_datafmt.precision + 3;
            sqldaPointer->sd_column[idx].sd_datafmt.format = CS_FMT_NULLTERM;
            break;

            default:
            sqldaPointer->sd_column[idx].sd_datafmt.datatype = CS_CHAR_TYPE;
             sqldaPointer->sd_column[idx].sd_sqldata = (char *) malloc (MAX_CHAR_FOR_DEFAULT);
            sqldaPointer->sd_column[idx].sd_sqllen = MAX_CHAR_FOR_DEFAULT;
            sqldaPointer->sd_column[idx].sd_datafmt.format = CS_FMT_NULLTERM;
            break;
                 } /* endswitch */
                 if (sqldaPointer->sd_column[idx].sd_sqldata == NULL) {
            return (-1);
                 }
              } /* endfor */
             return 0;
            }
            /*******************************************************************************  FUNCTION : free_da
            *  釋放SQLDA申請的空間。
            ******************************************************************************/
            void free_da (SQLDA *sqldaPointer) {
              short idx;
              for (idx = 0; idx < sqldaPointer->sd_sqld; idx++) {
                 free (sqldaPointer->sd_column[idx].sd_sqldata);
              } /* endfor */
              free (sqldaPointer);
            }
            /******************************************************************************* PROCEDURE : readColName
            * 返回列名
            ******************************************************************************/
            char * readColName (SQLDA *sqldaPointer, short sd_columnIndex, char * buffer) {
              strcpy(buffer, sqldaPointer->sd_column[sd_columnIndex].sd_datafmt.name);
              return buffer;
            }
            /******************************************************************************* PROCEDURE : readCol
            * 返回列數(shù)據(jù)。
            ******************************************************************************/
            char * readCol (SQLDA *sqldaPointer, short sd_columnIndex, char * buffer){
            short numBytes;
              short idx, ind ;            /* Array idx variables */
              /* Variables for decoding packed decimal data */
              char tmpstr[1024];
              short collen;
              char *dataptr;
               /* 檢查是否為NULL */
              if ( sqldaPointer->sd_column[sd_columnIndex].sd_sqlind )
                 { buffer[0] = 0;
                   return buffer;
                 }
              /*返回列數(shù)據(jù)到buffer變量*/
              strcpy( buffer, (char *) sqldaPointer->sd_column[ sd_columnIndex ].sd_sqldata);
              return buffer;
            }
            /* COMMENT OUT OFF */


            <!--[endif]-->
            <!--[if !supportLineBreakNewLine]--><!--[endif]-->


            http://rickya.bokee.com/viewdiary.14009093.html

            99久久无色码中文字幕人妻| 亚洲嫩草影院久久精品| 99久久精品国产一区二区蜜芽| 久久精品国产久精国产果冻传媒 | 久久精品国产亚洲AV蜜臀色欲 | 久久这里只精品99re66| 久久青青国产| 久久亚洲精品无码播放| 久久精品国产WWW456C0M| 久久精品无码专区免费| 久久久久国产日韩精品网站| 久久久久成人精品无码| 久久婷婷色香五月综合激情| 亚洲精品乱码久久久久久| 久久精品亚洲AV久久久无码| 亚洲精品无码久久久久去q| 久久久无码精品亚洲日韩蜜臀浪潮| 色偷偷偷久久伊人大杳蕉| 久久精品国产99久久久| 99久久精品国产毛片| 亚洲国产成人久久综合野外| 久久WWW免费人成一看片| 久久水蜜桃亚洲av无码精品麻豆 | 国产91久久精品一区二区| 久久精品国产免费| 国产69精品久久久久APP下载| 亚洲色婷婷综合久久| 久久亚洲国产精品一区二区| 日本免费久久久久久久网站| 青青草原综合久久大伊人| 99精品国产在热久久无毒不卡| 久久精品成人一区二区三区| 国内精品久久久久影院薰衣草 | 国产精品久久午夜夜伦鲁鲁| 亚洲国产天堂久久综合网站| 色婷婷久久久SWAG精品| 99久久精品费精品国产一区二区| 久久一本综合| 国产精品VIDEOSSEX久久发布| 久久精品亚洲AV久久久无码| 国产一区二区精品久久岳|