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

Prayer

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

關于動態SQL

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

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


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

方法     支持的SQL語句                                      實現方法

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

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

二、動態游標

使用動態游標可以完成方法3。
   游標分為靜態游標和動態游標兩類。對于靜態游標,在定義游標時就已經確定了完整的SELECT語句。在SELECT語句中可以包含主變量來接收輸入值。當執行游標的OPEN語句時,主變量的值被放入SELECT語句。在OPEN語句中,不用指定主變量,因為在DECLARE CURSOR語句中已經放置了主變量。請看下面靜態游標的例子:
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;
動態游標和靜態游標不同。以下是動態游標使用的句法:
1)、聲明游標:
 對于動態游標,在DECLARE CURSOR語句中不包含SELECT語句。而是,定義了在PREPARE中的語句名,PREPARE語句規定與查詢相關的語句名稱。具體語法為:
exec sql [at connection_name] declare cursor_name
cursor for statement_name;
如:EXEC SQL DECLARE author_cursor CURSOR FOR select_statement;
值得注意的是,聲明動態游標是一個可執行語句,應該在PREPARE語句后執行。
2)、打開游標
完整語法為:OPEN 游標名 [USING 主變量名 | DESCRIPTOR 描述名]
   在動態游標中,OPEN語句的作用是使DBMS定位相關的游標在第一行查詢結果前。當OPEN語句成功執行完畢后,游標處于打開狀態,并為FETCH語句做準備。OPEN語句執行一條由PREPARE語句預編譯的語句。如果動態查詢正文中包含有一個或多個參數標志時,OPEN語句必須為這些參數提供參數值。USING子句的作用就是規定參數值。可以使用主變量提供參數值,也可以通過描述名(即SQLDA)提供參數值。如:EXEC SQL OPEN author_cursor USING :szLastName;。
3)、取一行值
   FETCH語法為:FETCH 游標名 INTO USING DESCRIPTOR 描述符名。
動態FETCH語句的作用是,把游標移到下一行,并把這一行的各列值送到SQLDA中。注意的是,靜態FETCH語句的作用是用主變量表接收查詢到的列值。在方法3中,使用的是靜態FETCH語句獲得值。動態FETCH語句只在方法4中使用。
4)、關閉游標
如:EXEC SQL CLOSE c1;
關閉游標的同時,會釋放由游標添加的鎖和放棄未處理的數據。在關閉游標前,該游標必須已經聲明和打開。另外,程序終止時,系統會自動關閉所有打開的游標。
總之,在動態游標的DECLARE CURSOR語句中不包含SELECT語句。而是,定義了在PREPARE中的語句名,用PREPARE語句規定與查詢相關的語句名稱。當PREPARE語句中的語句包含了參數,那么在OPEN語句中必須指定提供參數值的主變量或SQLDA。動態DECLARE CURSOR語句是一個可執行語句。該子句必須在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;
………
 下面是一個實現方法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

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


             SQLDA結構
Sd_Sqld=2
Sd_column
……


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

                          
  具體SQLDA的結構在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是一種由兩個不同部分組成的可變長數據結構。從位于SQLDA開端的sd_sqln到sd_sqld為固定部分,用于標志該SQLDA,并規定這一特定的SQLDA的長度。而后是一個或多個sd_column結構 ,用于標志列數據或參數。當用SQLDA把參數送到執行語句時,每一個參數都是一個sd_column結構;當用SQLDA返回輸出列信息時,每一列都是一個sd_column 結構。具體每個元素的含義為:
lSd_Sqln。分配的sd_column結構的個數。等價于可以允許的最大輸入參數的個數或輸出列的個數。
lSd_Sqld。目前使用的sd_column結構的個數。
lSd_column[].sd_datafmt。標志同列相關的CS_DATAFMT結構。
lSd_column[].sd_Sqldata。指向數據的地址。注意,僅僅是一個地址。
lSd_column[].sd_sqllen。sd_sqldata指向的數據的長度。
lSd_column[].sd_Sqlind。代表是否為NULL。如果該列不允許為NULL,則該字段不賦值;如果該列允許為NULL,則:該字段若為0,表示數據值不為NULL,若為-1,表示數據值為NULL。
lSd_column[].sd_sqlmore。保留為將來使用。

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

exec sql include sqlca;
exec sql include sqlda;
...
/*input_ descriptor是通過SQLDA傳遞參數,output_descriptor是通過SQLDA返回列數據*/
SQLDA *input_descriptor, *output_descriptor;
CS_SMALLINT small;
CS_CHAR character[20];
/*申請空間*/
input_descriptor = (SQLDA *)malloc(SYB_SQLDA_SIZE(3));
/*設置參數的最大個數*/
input_descriptor->sqlda_sqln = 3;
/*申請空間*/
output_descriptor = (SQLDA *)malloc(SYB_SQLDA_SIZE(3));
/*設置列數的最大值*/
output_descriptor->sqlda_sqln = 3;
*p_retcode = CS_SUCCEED;
/*連接數據庫服務器*/
exec sql connect "sa" identified by password;
/* 創建一張example表,并插入一些例子數據,用于演示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);
/* 準備和描述查詢語句*/
exec sql prepare statement from
         "select fruit from example where number = ?";
/*describe語句的作用是,將查詢所需要的參數信息存放在input_descriptor中*/
exec sql describe input statement using descriptor input_descriptor;
/*設置SQLDA中指向參數數據的地址信息(sqldata)和數據長度(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");
/*設置存放列數據的地址信息*/
output_descriptor->sqlda_column[0].sqlda_sqldata = character;
output_descriptor->sqlda_column[0].sqlda_datafmt.maxlength = 20;
/*通過input_descriptor將輸入參數帶入查詢語句,并將結果通過output_descriptor帶出*/
exec sql execute statement into descriptor output_descriptor \
using descriptor input_descriptor;
/*打印結果---單行結果*/
printf("expected pomegranate, got %s\n",character);
/*釋放申請的內存空間*/
exec sql deallocate prepare statement;
/* 多行結果示例。對多行查詢語句做準備和描述操作*/
exec sql prepare statement from \
"select number from example where fruit = ?";
/*為多行結果聲明游標*/
exec sql declare c cursor for statement;

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

四、DESCRIBE語句
 該語句只有動態SQL才有。該語句是在PREPARE語句之后,在OPEN語句之前使用。該語句的作用是,設置SQLDA中的描述信息,如:列名、數據類型和長度等。DESCRIBE語句的語法為:
DESCRIBE 語句名 INTO 描述符名
    如:exec sql describe output statement using descriptor output_descriptor;。
在執行DESCRIBE前,用戶必須給出SQLDA中的SQLN的值(表示最多有多少列),該值也說明了SQLDA中最多有多少個sqlda_column結構。然后,執行DESCRIBE語句,該語句填充每一個sqlda_column結構。每個sqlda_column結構中的相應列為:
lSd_datafmt結構:列名等信息。
lSd_sqllen列:給出列的長度。
  注意,sd_sqldata列不填充。由程序在FETCH語句之前,給出數據緩沖器地址和指示符地址。
<!--[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服務器*/
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 );
  /*聲明游標*/
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;
/*打開游標,指向查詢相關電話信息的結果集*/
EXEC SQL OPEN c1;  /* :rk.2:erk. */
do{
/*取出一行數據到各個變量*/
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;
   /*顯示數據*/
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語句,并執行和打印結果。


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Defines for BINDING */
/*初試化SQLDA*/
int init_da (SQLDA **DAPointer, int DAsqln);
/*為存放列數據的sd_column結構申請空間*/
int alloc_host_vars (SQLDA *sqldaPointer);
/*釋放SQLDA所申請的空間*/
void free_da (SQLDA *sqldaPointer);
/*獲取列名信息*/
char * readColName (SQLDA *sqldaPointer, short sd_columnIndex, char * buffer);
/*獲取列數據*/
char * readCol (SQLDA *sqldaPointer, short sd_columnIndex, char * buffer);
#ifdef __cplusplus
}
#endif
/*定義最大列數*/
#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 ) ;
/*打印處理結果*/
  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結構申請空間" */
  if (init_da( &sqldaPointer, MAX_COLUMNS ) == -1)
{
        return -1;
}
/*準備SQL語句*/
  EXEC SQL PREPARE statement1 from :st ;
  if (SQLCODE < 0)
{
        free_da(sqldaPointer);
    return SQLCODE;
    }
/*獲取查詢列的信息到SQLDA結構*/
  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 ) {
     /* 為存放列數據的sd_column結構申請空間 */
     if (alloc_host_vars( sqldaPointer ) == -1)
{free_da(sqldaPointer);
return -1;
}
     /*聲明游標*/
     EXEC SQL DECLARE pcurs CURSOR FOR statement1 ;
    /打開游標*/
     EXEC SQL OPEN pcurs ;
     if (SQLCODE < 0)
     return SQLCODE;
     /*取一行數據到SQLDA結構*/
     EXEC SQL FETCH pcurs INTO DESCRIPTOR sqldaPointer;
     if (SQLCODE < 0)
{
 EXEC SQL CLOSE pcurs ;
 return SQLCODE;
       }
     /*顯示列標題 */
     colnamelist[0] = 0;
     for ( idx=0; idx< sqlda_d; idx++)
{ strcat(colnamelist, readColName(sqldaPointer, idx, buffer));
 if (idx < sqlda_d -1)
strcat(colnamelist, ",");
}
     /* 顯示行數據*/
     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 */
    /*關閉游標*/
     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
*為存放列數據的sd_column結構申請空間。如果返回-1,則表示不能獲得足夠內存。
******************************************************************************/
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
* 返回列數據。
******************************************************************************/
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;
     }
  /*返回列數據到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>
            亚洲宅男天堂在线观看无病毒| 久久精品国产一区二区三区| 国产日韩欧美中文| 国产一区二区三区成人欧美日韩在线观看 | 欧美成人亚洲| 亚洲二区精品| 亚洲五月六月| 美女视频黄免费的久久| 国产精品视频免费一区| 亚洲免费激情| 欧美国产日产韩国视频| 99精品视频免费在线观看| 久久伊人一区二区| 国产日产欧美一区| 一二美女精品欧洲| 欧美护士18xxxxhd| 久久久一二三| 欧美色精品在线视频| 亚洲高清在线观看| 久久视频一区| 欧美一区国产在线| 国产欧美亚洲日本| 亚洲综合精品| 亚洲国产另类精品专区| 久久婷婷丁香| 韩国成人理伦片免费播放| 小黄鸭精品密入口导航| 一本色道久久综合狠狠躁篇怎么玩| 美女视频黄a大片欧美| 亚洲国产美女精品久久久久∴| 久久精品观看| 久久精品成人| 在线观看欧美一区| 蜜桃av综合| 欧美电影免费观看| 尤物精品国产第一福利三区 | 国产精品家教| 亚洲视频第一页| 亚洲精品国产精品久久清纯直播 | 在线中文字幕一区| 99视频一区二区三区| 欧美日本二区| 中国成人黄色视屏| 日韩视频免费| 欧美视频不卡中文| 亚洲你懂的在线视频| 亚洲一级特黄| 国产日韩欧美一二三区| 亚洲天堂男人| 亚洲欧美在线免费观看| 国产在线一区二区三区四区| 久久婷婷丁香| 欧美激情网友自拍| 亚洲视频免费| 午夜综合激情| 国产日韩精品一区二区| 美女91精品| 欧美精品成人一区二区在线观看| 夜夜嗨av一区二区三区网站四季av | 久久久久欧美| 欧美激情在线狂野欧美精品| 亚洲一区图片| 久久国产色av| 99人久久精品视频最新地址| 亚洲高清免费在线| 欧美亚洲成人免费| 久久噜噜亚洲综合| 欧美日韩不卡| 久久久久一区二区| 欧美一区网站| 99日韩精品| 久久成人一区二区| 宅男66日本亚洲欧美视频 | 最近中文字幕日韩精品 | 久久午夜电影| 久久综合伊人77777蜜臀| 制服丝袜激情欧洲亚洲| 在线中文字幕不卡| 一区二区三区在线观看欧美| 久久精品综合网| 日韩视频永久免费观看| 久久天堂精品| 久久久久久久网| 一区二区日韩免费看| 老司机aⅴ在线精品导航| 欧美激情第一页xxx| 欧美在线日韩| 欧美日韩成人综合在线一区二区 | 久久婷婷综合激情| 亚洲在线一区二区三区| 欧美性猛交xxxx乱大交退制版| 欧美黄色一区二区| 亚洲成人在线视频网站| 久久国产日韩| 久久精品人人做人人爽| 国产精品国产亚洲精品看不卡15| 91久久亚洲| 日韩午夜av电影| 欧美日本一道本| 亚洲乱码国产乱码精品精98午夜| 亚洲日本一区二区| 欧美国产日韩一区二区在线观看 | 亚洲国产精品尤物yw在线观看| 亚洲高清不卡在线观看| 免费观看亚洲视频大全| 亚洲日本va在线观看| 女仆av观看一区| 欧美高清在线视频| 99国产精品视频免费观看一公开 | 亚洲欧洲一二三| 欧美成人精品福利| 亚洲国产高清一区二区三区| 亚洲精品一区二区三区在线观看| 欧美激情精品久久久久久| 日韩视频免费观看高清在线视频 | 欧美色一级片| 亚洲图片你懂的| 久久久久久999| 亚洲精品久久久久久一区二区| 欧美不卡在线视频| 在线一区二区三区四区五区| 久久精品在线| 亚洲乱码一区二区| 国产美女精品| 美女尤物久久精品| 国产精品99久久久久久久久| 久久九九精品| 亚洲最黄网站| 国产亚洲成av人在线观看导航| 久久亚洲国产成人| 亚洲国产一区二区三区高清| 一区二区三区国产在线观看| 国产亚洲欧美另类中文| 久久夜精品va视频免费观看| 一区二区三区精密机械公司| 久久乐国产精品| 一二三四社区欧美黄| 国产女优一区| 99国产精品久久久久久久成人热| 国内久久视频| 欧美一区二粉嫩精品国产一线天| 蜜臀av一级做a爰片久久 | 亚洲影院高清在线| 亚洲成在线观看| 国产麻豆一精品一av一免费| 麻豆精品网站| 午夜精品短视频| 亚洲激情av| 欧美诱惑福利视频| 艳女tv在线观看国产一区| 极品av少妇一区二区| 欧美激情久久久| 久久久999精品视频| 亚洲淫片在线视频| 亚洲欧洲久久| 久久综合狠狠综合久久综合88| 亚洲视频图片小说| 亚洲国产综合在线看不卡| 国产欧美日韩一区二区三区在线观看 | 亚洲国产美女| 老妇喷水一区二区三区| 亚洲欧美综合国产精品一区| 久久久亚洲精品一区二区三区 | 在线视频免费在线观看一区二区| 国内精品视频在线播放| 国产精品美女在线观看| 欧美区二区三区| 欧美成人免费视频| 久久天天躁狠狠躁夜夜av| 欧美一区二区三区在| 亚洲欧美日韩久久精品| 这里只有精品丝袜| 一区二区三区|亚洲午夜| 亚洲美女免费精品视频在线观看| 欧美黄色aaaa| 亚洲国产精品成人久久综合一区| 久久亚洲私人国产精品va| 久久国产色av| 久久精品欧美日韩| 久久福利电影| 久久精品一区二区三区四区| 久久久久久久久久久久久9999| 欧美一区二区福利在线| 午夜精品美女自拍福到在线 | 久久精品毛片| 久久久久久久久蜜桃| 久久九九国产| 麻豆成人在线播放| 欧美国产第二页| 欧美日韩精品高清| 国产精品免费网站| 黑丝一区二区三区| 亚洲电影在线看| 99v久久综合狠狠综合久久| 一区二区精品在线| 亚洲免费在线观看视频| 久久激情综合网| 亚洲国产精品久久人人爱蜜臀| 性欧美video另类hd性玩具| 亚洲人成网站精品片在线观看|