青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Prayer

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

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


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

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

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

一、動(dòng)態(tài)修改
方法1和方法2完成動(dòng)態(tài)修改。對(duì)于方法1,表示要執(zhí)行一個(gè)完整的T-SQL語句,該語句沒有宿主變量,不是一個(gè)查詢語句。因?yàn)闆]有宿主變量來帶入不同的參數(shù),所以不能通過方法1來重復(fù)執(zhí)行修改語句。具體語法為:
exec sql [at connection_name] execute immediate
{: host_variable | string};
其中,host_variable和string是存放完整T-SQL語句。
例:提示用戶輸入被更新書的條件,然后組合成為一個(gè)完整的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;
對(duì)于方法2,可以執(zhí)行一個(gè)包含輸入宿主變量的動(dòng)態(tài)修改語句。該方法要使用PREPARE語句和EXECUTE語句。PREPARE語句是動(dòng)態(tài)SQL語句獨(dú)有的語句。其語法為:
   PREPARE 語句名  FROM 宿主變量|字符串
該語句接收含有SQL語句串的宿主變量,并把該語句送到DBMS。DBMS編譯語句并生成執(zhí)行計(jì)劃。在語句串中包含一個(gè)“?”表明參數(shù),當(dāng)執(zhí)行語句時(shí),DBMS需要參數(shù)來替代這些“?”。PREPRARE執(zhí)行的結(jié)果是,DBMS用語句名標(biāo)志準(zhǔn)備后的語句。SQL SERVER編譯后的語句以臨時(shí)存儲(chǔ)過程的形式存放在緩沖區(qū)中。語句名類似于游標(biāo)名,是一個(gè)SQL標(biāo)識(shí)符。在執(zhí)行SQL語句時(shí),EXECUTE語句后面是這個(gè)語句名。請(qǐng)看下面這個(gè)例子:
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;
}
  在這個(gè)例子中,prep_stat是語句名,prep宿主變量的值是一個(gè)INSERT語句,包含了三個(gè)參數(shù)(3個(gè)“?”)。PREPARE的作用是,DBMS編譯這個(gè)語句并生成執(zhí)行計(jì)劃,并把語句名標(biāo)志這個(gè)準(zhǔn)備后的語句。值得注意的是,PREPARE中的語句名的作用范圍為整個(gè)程序,所以不允許在同一個(gè)程序中使用相同的語句名在多個(gè)PREPARE語句中。
   EXECUTE語句是動(dòng)態(tài)SQL獨(dú)有的語句。它的語法如下:
EXECUTE 語句名 USING  宿主變量 | DESCRIPTOR 描述符名
請(qǐng)看上面這個(gè)例子中的“EXEC SQL EXECUTE prep_stat USING :name, :car, :num;”語句,它的作用是,請(qǐng)求DBMS執(zhí)行PREPARE語句準(zhǔn)備好的語句。當(dāng)要執(zhí)行的動(dòng)態(tài)語句中包含一個(gè)或多個(gè)參數(shù)標(biāo)志時(shí),在EXECUTE語句必須為每一個(gè)參數(shù)提供值,如::name、:car和:num。這樣的話,EXECUTE語句用宿主變量值逐一代替準(zhǔn)備語句中的參數(shù)標(biāo)志(“?”),從而,為動(dòng)態(tài)執(zhí)行語句提供了輸入值。
使用主變量提供值,USING子句中的主變量數(shù)必須同動(dòng)態(tài)語句中的參數(shù)標(biāo)志數(shù)一致,而且每一個(gè)主變量的數(shù)據(jù)類型必須同相應(yīng)參數(shù)所需的數(shù)據(jù)類型相一致。各主變量也可以有一個(gè)伴隨主變量的指示符變量。當(dāng)處理EXECUTE語句時(shí),如果指示符變量包含一個(gè)負(fù)值,就把NULL值賦予相應(yīng)的參數(shù)標(biāo)志。除了使用主變量為參數(shù)提供值,也可以通過SQLDA提供值(關(guān)于這個(gè),后邊會(huì)講到)。

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

使用動(dòng)態(tài)游標(biāo)可以完成方法3。
   游標(biāo)分為靜態(tài)游標(biāo)和動(dòng)態(tài)游標(biāo)兩類。對(duì)于靜態(tài)游標(biāo),在定義游標(biāo)時(shí)就已經(jīng)確定了完整的SELECT語句。在SELECT語句中可以包含主變量來接收輸入值。當(dāng)執(zhí)行游標(biāo)的OPEN語句時(shí),主變量的值被放入SELECT語句。在OPEN語句中,不用指定主變量,因?yàn)樵贒ECLARE CURSOR語句中已經(jīng)放置了主變量。請(qǐ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;
動(dòng)態(tài)游標(biāo)和靜態(tài)游標(biāo)不同。以下是動(dòng)態(tài)游標(biāo)使用的句法:
1)、聲明游標(biāo):
 對(duì)于動(dòng)態(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;
值得注意的是,聲明動(dòng)態(tài)游標(biāo)是一個(gè)可執(zhí)行語句,應(yīng)該在PREPARE語句后執(zhí)行。
2)、打開游標(biāo)
完整語法為:OPEN 游標(biāo)名 [USING 主變量名 | DESCRIPTOR 描述名]
   在動(dòng)態(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ù)編譯的語句。如果動(dòng)態(tài)查詢正文中包含有一個(gè)或多個(gè)參數(shù)標(biāo)志時(shí),OPEN語句必須為這些參數(shù)提供參數(shù)值。USING子句的作用就是規(guī)定參數(shù)值。可以使用主變量提供參數(shù)值,也可以通過描述名(即SQLDA)提供參數(shù)值。如:EXEC SQL OPEN author_cursor USING :szLastName;。
3)、取一行值
   FETCH語法為:FETCH 游標(biāo)名 INTO USING DESCRIPTOR 描述符名。
動(dòng)態(tài)FETCH語句的作用是,把游標(biāo)移到下一行,并把這一行的各列值送到SQLDA中。注意的是,靜態(tài)FETCH語句的作用是用主變量表接收查詢到的列值。在方法3中,使用的是靜態(tài)FETCH語句獲得值。動(dòng)態(tài)FETCH語句只在方法4中使用。
4)、關(guān)閉游標(biāo)
如:EXEC SQL CLOSE c1;
關(guān)閉游標(biāo)的同時(shí),會(huì)釋放由游標(biāo)添加的鎖和放棄未處理的數(shù)據(jù)。在關(guān)閉游標(biāo)前,該游標(biāo)必須已經(jīng)聲明和打開。另外,程序終止時(shí),系統(tǒng)會(huì)自動(dòng)關(guān)閉所有打開的游標(biāo)。
總之,在動(dòng)態(tài)游標(biāo)的DECLARE CURSOR語句中不包含SELECT語句。而是,定義了在PREPARE中的語句名,用PREPARE語句規(guī)定與查詢相關(guān)的語句名稱。當(dāng)PREPARE語句中的語句包含了參數(shù),那么在OPEN語句中必須指定提供參數(shù)值的主變量或SQLDA。動(dòng)態(tài)DECLARE CURSOR語句是一個(gè)可執(zhí)行語句。該子句必須在OPEN、FETCH、CLOSE語句之前使用。請(qǐng)看下面這個(gè)例子,描述了完成方法3的五個(gè)步驟: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;
………
 下面是一個(gè)實(shí)現(xiàn)方法3的實(shí)際例子。提示用戶輸入排序的條件,并把符合條件的書信息顯示出來。
……
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; /* 可以提示用戶輸入這個(gè)值*/
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

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

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

下面我們來看一個(gè)具體的例子。這個(gè)例子是通過output_descriptor查詢數(shù)據(jù)庫中的數(shù)據(jù),是通過input_descriptor傳遞參數(shù)。這個(gè)例子的作用是,模擬一個(gè)動(dòng)態(tài)查詢,并顯示查詢結(jié)果。動(dòng)態(tài)查詢的執(zhí)行過程如下:
1)、如同構(gòu)造動(dòng)態(tài)UPDATE語句或DELETE語句的方法一樣,程序在緩沖器中構(gòu)造一個(gè)有效的SELECT語句。
2)、程序用PREPARE語句把動(dòng)態(tài)查詢語句送到DBMS,DBMS準(zhǔn)備、確認(rèn)和優(yōu)化語句,并生成一個(gè)應(yīng)用計(jì)劃。
3)、動(dòng)態(tài)DECLARE CURSOR語句說明查詢游標(biāo),動(dòng)態(tài)DECLARE CURSOR語句規(guī)定與動(dòng)態(tài)SELECT語句有關(guān)的語句名稱。如:例子中的statement。
4)、程序用DESCRIBE語句請(qǐng)求DBMS提供SQLDA中描述信息,即告訴程序有多少列查詢結(jié)果、各列名稱、數(shù)據(jù)類型和長度。DESCRIBE語句只用于動(dòng)態(tài)查詢。具體見下一節(jié)。
5)、為SQLDA申請(qǐng)存放一列查詢結(jié)果的存儲(chǔ)塊(即:sqldata指向的數(shù)據(jù)區(qū)),也為SQLDA的列的指示符變量申請(qǐng)空間。程序把數(shù)據(jù)區(qū)地址和指示符變量地址送入SQLDA,以告訴DBMS向何處回送查詢結(jié)果。
6)、動(dòng)態(tài)格式的OPEN語句。即打開存放查詢到的數(shù)據(jù)集(動(dòng)態(tài)SELECT語句產(chǎn)生的數(shù)據(jù))的第一行。
7)、動(dòng)態(tài)格式的FETCH語句把游標(biāo)當(dāng)前行的結(jié)果送到SQLDA。(動(dòng)態(tài)FETCH語句和靜態(tài)FETCH語句的不同是:靜態(tài)FETCH語句規(guī)定了用主變量接收數(shù)據(jù);而動(dòng)態(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];
/*申請(qǐng)空間*/
input_descriptor = (SQLDA *)malloc(SYB_SQLDA_SIZE(3));
/*設(shè)置參數(shù)的最大個(gè)數(shù)*/
input_descriptor->sqlda_sqln = 3;
/*申請(qǐng)空間*/
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);
/*釋放申請(qǐng)的內(nèi)存空間*/
exec sql deallocate prepare statement;
/* 多行結(jié)果示例。對(duì)多行查詢語句做準(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;
……….
  上面這個(gè)例子是典型的動(dòng)態(tài)查詢程序。該程序中演示了PREPARE語句和DESCRIBE語句的處理方式,以及為程序中檢索到的數(shù)據(jù)分配空間。要注意程序中如何設(shè)置sqlda_column結(jié)構(gòu)中的的各個(gè)變量。這個(gè)程序也演示了OPEN、FETCH和CLOSE語句在動(dòng)態(tài)查詢中的應(yīng)用。值得注意的是,F(xiàn)ETCH語句只使用了SQLDA,不使用主變量。由于程序中預(yù)先申請(qǐng)了sqlda_column結(jié)構(gòu)中的SQLDATA空間,所以DBMS知道將查詢到的數(shù)據(jù)保存在何處。該程序還考慮了查詢數(shù)據(jù)為NULL的處理。
  值得注意的是,SQDA結(jié)構(gòu)不是SQL標(biāo)準(zhǔn)。每個(gè)數(shù)據(jù)庫廠商的實(shí)現(xiàn)方式有可能不同。

四、DESCRIBE語句
 該語句只有動(dòng)態(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中最多有多少個(gè)sqlda_column結(jié)構(gòu)。然后,執(zhí)行DESCRIBE語句,該語句填充每一個(gè)sqlda_column結(jié)構(gòu)。每個(gè)sqlda_column結(jié)構(gòu)中的相應(yīng)列為:
lSd_datafmt結(jié)構(gòu):列名等信息。
lSd_sqllen列:給出列的長度。
  注意,sd_sqldata列不填充。由程序在FETCH語句之前,給出數(shù)據(jù)緩沖器地址和指示符地址。
<!--[if !supportLineBreakNewLine]-->
下邊的話,給出兩個(gè)例子吧,方便對(duì)上邊講到的東西做個(gè)對(duì)比:

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


#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;
/*輸入想要查詢的電話號(hào)碼*/
   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ù)到各個(gè)變量*/
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)申請(qǐng)空間*/
int alloc_host_vars (SQLDA *sqldaPointer);
/*釋放SQLDA所申請(qǐng)的空間*/
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)申請(qǐng)空間" */
  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)申請(qǐng)空間 */
     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申請(qǐng)的空間 */
     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)申請(qǐng)空間。如果返回-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申請(qǐng)的空間。
******************************************************************************/
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

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            久久精品国产第一区二区三区| 国产欧美一区二区三区另类精品| 亚洲福利免费| 欧美在线啊v一区| 亚洲一区二区综合| 亚洲一区二区三区欧美| 亚洲一区二区动漫| 西西裸体人体做爰大胆久久久| 亚洲综合精品一区二区| 欧美一区二区三区在| 久久欧美中文字幕| 欧美亚洲在线观看| 亚洲国产精品美女| 日韩午夜剧场| 亚洲一区亚洲| 久久久久久国产精品一区| 老司机午夜精品视频在线观看| 久久久久久夜精品精品免费| 亚洲电影免费观看高清完整版在线观看 | 欧美另类高清视频在线| 欧美喷水视频| 国产精品自拍小视频| **欧美日韩vr在线| 亚洲图片在线| 久久综合久色欧美综合狠狠| 亚洲国产一区二区三区高清| 亚洲一区二区精品在线观看| 欧美与黑人午夜性猛交久久久| 免费影视亚洲| 国产精品一级二级三级| 亚洲激情社区| 久久国产精品99久久久久久老狼| 亚洲一区二区在线播放| 亚洲欧美久久| 欧美国产精品劲爆| 国产午夜一区二区三区| 日韩一二三在线视频播| 狼狼综合久久久久综合网| 一本高清dvd不卡在线观看| 久久亚洲综合| 国产日韩欧美麻豆| 亚洲视频免费在线| 亚洲大片av| 久久久久久夜| 国产精品捆绑调教| 日韩午夜视频在线观看| 久久久久久日产精品| 亚洲少妇中出一区| 欧美另类一区| 亚洲麻豆av| 欧美韩日视频| 裸体一区二区三区| 影音先锋中文字幕一区| 久久超碰97中文字幕| 亚洲一级高清| 国产精品乱码| 午夜精品久久久久久99热软件| 亚洲激情av| 欧美激情第4页| 亚洲国内自拍| 欧美护士18xxxxhd| 麻豆91精品91久久久的内涵| 亚洲精品一区二区三区樱花 | av成人天堂| 欧美精品久久一区| 亚洲欧洲精品一区二区三区| 欧美国产视频在线| 欧美激情成人在线| 中文亚洲免费| 在线一区亚洲| 国产精品一区二区黑丝| 午夜精品久久久久久久男人的天堂 | 国产精品卡一卡二| 午夜精品一区二区三区在线| 一区二区三区福利| 国产精品试看| 久久九九电影| 美女91精品| 在线视频精品一区| 亚洲一区免费看| 国产一区白浆| 亚洲福利视频专区| 欧美色网一区二区| 性18欧美另类| 久久久免费精品视频| 亚洲人成在线播放网站岛国| 亚洲人成久久| 国产日韩精品视频一区| 鲁大师影院一区二区三区| 欧美xart系列高清| 亚洲欧美大片| 久久天天躁狠狠躁夜夜爽蜜月 | 亚洲午夜性刺激影院| 一区电影在线观看| 国产一区自拍视频| 亚洲国产欧美久久| 国产精品色网| 亚洲国产va精品久久久不卡综合| 欧美午夜精品久久久久久久| 久久蜜桃精品| 欧美午夜精品伦理| 男女激情久久| 国产精品专区h在线观看| 欧美激情视频一区二区三区在线播放 | 久久九九免费视频| 在线视频欧美日韩精品| 欧美在线免费观看| 亚洲视频在线观看网站| 久久亚洲精品一区二区| 亚洲一区二区三区四区在线观看| 久久国内精品视频| 亚洲综合国产| 欧美国产视频在线观看| 亚洲人久久久| 欧美一区二区三区四区在线| 日韩午夜免费视频| 久久久高清一区二区三区| 免费看黄裸体一级大秀欧美| 日韩视频免费看| 中文欧美日韩| 亚洲精品日韩一| 久久精品国产99精品国产亚洲性色| 亚洲一区二区av电影| 久久综合国产精品台湾中文娱乐网| 亚洲香蕉在线观看| 欧美日韩情趣电影| 亚洲国产成人av好男人在线观看| 国产综合激情| 午夜精品国产| 欧美一区二粉嫩精品国产一线天| 欧美精品九九| 亚洲黄色一区| 9国产精品视频| 欧美精品在线一区二区| 最新成人在线| 亚洲美女毛片| 欧美精品一区在线观看| 亚洲二区在线| 亚洲黄色三级| 欧美精品乱人伦久久久久久 | 久久综合网络一区二区| 国产欧美韩国高清| 午夜精品免费在线| 久久久噜噜噜久久久| 国产亚洲欧美另类一区二区三区| 亚洲一区免费在线观看| 午夜精品福利一区二区蜜股av| 欧美日韩视频在线一区二区 | 久久一区二区三区四区| 国产精品系列在线| 香蕉成人伊视频在线观看| 久久久激情视频| 精品动漫3d一区二区三区| 久久久国产精品一区二区三区| 久久只有精品| 亚洲看片免费| 国产精品日日做人人爱| 欧美一区在线直播| 亚洲福利国产| 新67194成人永久网站| 韩国三级电影一区二区| 蜜臀av一级做a爰片久久 | 久热爱精品视频线路一| 一区二区视频免费完整版观看| 久久偷看各类wc女厕嘘嘘偷窃| 亚洲国产福利在线| 亚洲综合第一页| 一区二区视频免费完整版观看| 欧美激情按摩| 香蕉久久一区二区不卡无毒影院 | 欧美黄色影院| 亚洲综合国产| 亚洲国产清纯| 国产精品美女在线| 噜噜噜久久亚洲精品国产品小说| 欧美一区二区啪啪| 狠狠色伊人亚洲综合成人| 欧美成人精品| 亚洲伊人第一页| 亚洲国产精品va在线看黑人| 午夜精品福利一区二区蜜股av| 亚洲第一页在线| 国产精品久久久一区麻豆最新章节| 久久偷看各类wc女厕嘘嘘偷窃| 99re热这里只有精品视频| 久久精品国产99| 一区二区三区产品免费精品久久75| 国产精品一区三区| 欧美理论电影网| 久久精品视频一| 亚洲在线一区二区| 亚洲精品资源美女情侣酒店| 久久久精品999| 销魂美女一区二区三区视频在线| 亚洲精品一二三| 亚洲福利视频一区二区| 国产日韩欧美综合一区| 欧美日韩色婷婷| 欧美国产一区二区| 老巨人导航500精品|