分享
 
 
 

ESQL/C资料(完全版)四

王朝mssql·作者佚名  2006-11-24
窄屏简体版  字體: |||超大  

5.3 嵌入SQL的处理过程

INFORMIX的预编译器为esql。嵌入SQL包含一些组件:嵌入SQL的库文件,提供访问数据库服务器、操作各种数据类型、出错信息的处理等函数。嵌入SQL的头文件(UNIX环境:$INFORMIXDIR/incl/esql下,WINDOWS环境:%INFORMIXDIR%\incl\esql下),提供程序用的数据结构、常数和宏的定义信息。Esql是预编译器。UNIX系统下,是finderr程序获得INFORMIX的错误信息,WINDOWS平台下是find error获得错误信息。还有一些GLS locale文件,提供一些特定的locale信息。在WINDOWS平台下,还有另外一些文件,如:setnet32、ilogin、regcopy、esqlmf程序。

创建嵌入SQL/C的程序的一般步骤:程序的后缀可以是.ec或.ecp。

1、定义宿主变量。

2、访问数据库。

3、操作。

4、完成后,使用esql命令来预编译。如:esql demo1.ec。在预编译后,程序中只有C语言语句,它们都可以为C语言的编译器所识别。所以,可以按照一般的方法进行编译和连接,但在将SQL语句转换以后,在C语言程序中,又引入了许多一般的C语言系统所没有的结构、变量和函数,因此应该设置INCLUDE和LIB的设置。最后生成的可执行文件。

5.4 动态SQL语言

所谓静态SQL的编程方法,就是指在预编译时SQL语句已经基本确定,即访问的表或视图名、访问的列等信息已经确定。但是,有时整个SQL语句要到执行的时候才能确定下来,而且SQL语句所访问的对象也要到执行时才能确定。这就需要通过动态SQL语句完成。动态SQL语句的处理步骤是:

1、组合SQL语句。

2、PREPARE。PREPARE语句是动态SQL语句独有的语句。其语法为:

PREPARE 语句名 FROM 宿主变量|字符串

该语句接收含有SQL语句串的宿主变量,并把该语句送到DBMS。DBMS编译语句并生成执行计划。在语句串中包含一个“?”表明参数,当执行语句时,DBMS需要参数来替代这些“?”。PREPRARE执行的结果是,DBMS用语句名标志编译后的语句。在执行SQL语句时,EXECUTE语句后面是这个语句名。请看下面这个例子:

EXEC SQL prepare slct_id from

'select company from customer where customer_num = ?';

可以通过SQLCA检查PREPARE操作是否成功。

3、EXECUTE或OPEN。

EXECUTE语句的语法如下:

EXECUTE 语句名 USING 宿主变量 | DESCRIPTOR 描述符名

它的作用是,请求DBMS执行PREPARE语句准备好的语句。当要执行的动态语句中包含一个或多个参数标志时,在EXECUTE语句必须为每一个参数提供值。这样的话,EXECUTE语句用宿主变量值逐一代替准备语句中的参数标志(“?”),从而,为动态执行语句提供了输入值。

如果是多行查询,则使用游标,使用OPEN USING语句传递参数;如果是单行查询,则使用SELECT INTO。如果是修改数据:则使用EXECUTE USING语句。如果知道参数个数,就可以使用宿主变量。如果不知道参数个数,则必须使用DESCRIBE语句。下表总结了动态SQL语句的处理方法:

语句类型是否有输入参数执行的方法

INSERT、DELETE、UPDATE没有EXECUTE

INSERT、DELETE、UPDATE有(数据类型和个数确定)EXECUTE …USING

INSERT、DELETE、UPDATE有(数据类型和个数不确定)EXECUTE...USINGSQL DESCRIPTOR或EXECUTE...USINGDESCRIPTOR

SELECT(返回多行)无OPEN

SELECT(返回多行)有(数据类型和个数确定)OPEN…USING

SELECT(返回多行)有(数据类型和个数不确定)OPEN...USINGSQL DESCRIPTOR或OPEN...USINGDESCRIPTOR

SELECT(返回一行)无EXECUTE...INTO

SELECT(返回一行,但是返回的数据类型和个数不确定)无EXECUTE...INTODESCRIPTOR或EXECUTE...INTOSQL DESCRIPTOR

SELECT(返回一行)有EXECUTE...INTO...USING

SELECT(返回一行,但是返回的数据类型和个数不确定)有EXECUTE...INTO...USING SQLDESCRIPTOR或EXECUTE...INTO...USINGDESCRIPTOR 4、释放资源。

5.4.1 SQLDA

可以通过SQLDA为嵌入SQL语句提供输入数据和从嵌入SQ语句中输出数据。理解SQLDA的结构是理解动态SQL的关键。

我们知道,动态SQL语句在编译时可能不知道有多少列信息。在嵌入SQL语句中,这些不确定的数据是通过SQLDA完成的。SQLDA的结构非常灵活,在该结构的固定部分,指明了多少列等信息(如下图中的sqld=2,表示为两列信息),在该结构的后面,有一个可变长的结构(SQLVAR结构),说明每列的信息。

SQLDA结构

Sqld=2

sqlvar

Desc_name

Desc_occ

Desc_next

Sqltype=500

Sqllen

sqldata

…..

Sqltype=501

Sqllen

Sqldata

….. 图6-6 SQLDA结构示例

具体SQLDA的结构在sqlda.h中定义,是:

struct sqlvar_struct

{

short sqltype;/* variable type*/

short sqllen;/* length in bytes*/

char *sqldata;/* pointer to data*/

short *sqlind;/* pointer to indicator*/

char *sqlname;/* variable name*/

char *sqlformat;/* reserved for future use */

short sqlitype;/* ind variable type*/

short sqlilen;/* ind length in bytes*/

char *sqlidata;/* ind data pointer*/

}; struct sqlda

{

short sqld;

struct sqlvar_struct *sqlvar;

char desc_name[19];/* descriptor name */

short desc_occ;/* size of sqlda structure */

struct sqlda *desc_next;/* pointer to next sqlda struct */

}; #endif /* _SQLDA */

从上面这个定义看出,SQLDA是一种由三个不同部分组成的可变长数据结构。位于SQLDA开端的sqldaid用于标志该SQLDA描述了多少列的信息;而后是一个或多个sqlvar结构 ,用于标志列数据。当用SQLDA把参数送到执行语句时,每一个参数都是一个sqlvar结构;当用SQLDA返回输出列信息时,每一列都是一个sqlvar结构。第三部分是SQLDA结构的描述信息部分。具体每个元素的含义为:

lSqld。目前使用的sqlvar结构的个数。即输出列的个数。

lSqlvar。指向sqlvar_struct结构。 即指向描述第一列信息的sqlvar结构。

lDesc_name。Sqlda的名称。

lDesc_occ。Sqlda结构的大小。

lDesc_next。指向下一个SQLDA结构。

lSqltype。代表参数或列的数据类型。它是一个整数数据类型代码。具体每个整数的含义见第二节。

l Sqllen。代表传送数据的长度。如:2,即代表二字节整数。如果是字符串,则该数据为字符串中的字符数量。

lSqldata。指向数据的地址。注意,仅仅是一个地址。

lSqlind。代表是否为NULL。如果该列不允许为NULL,则该字段不赋值;如果该列允许为NULL,则:该字段若为0,表示数据值不为NULL,若为-1,表示数据值为NULL。

lSqlname。代表列名或变量名。它是一个结构。包含length和data。Length是名字的长度;data是名字。

lSqlformat。保留为以后使用。

lSqlitype。指定用户定义的指示符变量的数据类型。

lSqlilen。指定用户定义的指示符变量的长度。

lSqlidata。指向用户定义的指示符变量所存放的数据。 下面这个ADHOC程序非常经典,演示了SQLDA的作用。模拟一个不确定的查询,然后通过SQLDA来获得数据,并打印出来。

EXEC SQL include locator.h;

EXEC SQL include sqltypes.h;

#define BLOBSIZE 32276;

main()

{

int i = 0;

int row_count;

/**** Step 1: 声明一个SQLDA结构,来存放查询的数据 ********/

struct sqlda *da_ptr;

/*连接到数据库服务器*/

EXEC SQL connect to 'stores7';

if ( SQLCODE < 0 )

{ printf("CONNECT failed: %d\n", SQLCODE)

exit(0);

}

/* 创建一个临时表,模拟一个不确定列和表的环境*/

EXEC SQL create table blob_tab (int_col integer, blob_col byte);

/* load_db函数是往blob_tab表插入数据,读者不用关心它的代码*/

load_db();

/* PREPARE查询语句 */

EXEC SQL prepare selct_id 'select * from tab1';

/* Step 2: 使用describe函数完成两个功能:一是为sqlda分配空间, 二是获取语句信息,并存放在SQLDA结构中。*/

EXEC SQL describe selct_id into da_ptr;

/* Step 3: 初试化sqlda结构,如:为列分配空间,改变数据类型等。*/

row_size = init_sqlda(da_ptr, 0);

/* 为PREPARE的SELECT语句声明和打开游标*/

EXEC SQL declare curs for selct_id;

EXEC SQL open curs;

while (1)

{

/* Step 4: 执行fetch操作,将一行数据存放在sqlda结构中*/

EXEC SQL fetch curs using descriptor da_ptr;

/* 是否到达最后一行?,若是,则退出。 */

if ( SQLCODE == SQLNOTFOUND )

break;

/* Step 5: 从SQLDA中打印数据,使用sqlca.sqlerrd[2]来获得查询的行数*/

printf("\n===============\n");

printf("FETCH %d\n", i++);

printf("===============");

print_sqlda(da_ptr, ((FetArrSize == 0) ? 1 : sqlca.sqlerrd[2]));

/* Step 6: 循环执行FETCH,直到处理完所有的行(SQLCODE为SQLNOTFOUND)*/

}

/* Step 7: 释放申请的内存空间,如游标、SQLDA、创建的临时表等*/

EXEC SQL free selct_id;

EXEC SQL close curs;

EXEC SQL free curs;

free_sqlda(da_ptr);

cleanup_db();

}

/************************************************************************

* 函数: init_sqlda()

* 作用: 为SQLDA申请空间

* 返回值: 0 正确,否则有错误

************************************************************************/

int init_sqlda(in_da, print)

struct sqlda *in_da;

int print;

{

int i, j, row_size=0, msglen=0, num_to_alloc;

struct sqlvar_struct *col_ptr;

loc_t *temp_loc;

char *type;

if (print)

printf("columns: %d. ", in_da->sqld);

/* Step 1: 获得一行数据的长度 */

for (i = 0, col_ptr = in_da->sqlvar; i < in_da->sqld; i++, col_ptr++)

/* msglen变量存放查询数据的所有列的长度和。*/

msglen += col_ptr->sqllen; /* get database sizes */

/* 为col_ptr->sqllen 重新赋值,该值是在C下的大小。如:在数据库中的字符串,在C中应该多一个字节空间来存放NULL的结束符。*/

col_ptr->sqllen = rtypmsize(col_ptr->sqltype, col_ptr->sqllen);

/*row_size变量存放了在C程序中的所有列的长度和。这个值是应用程序为存放一行数据所需要申请的内存空间*/

row_size += col_ptr->sqllen;

}

if (print) printf("Total row size = %d\n", row_size);

/* Step 2: 设置FetArrSize值*/

if (FetArrSize == -1) /* if FetArrSize not yet initialized */

{

if (FetBufSize == 0) /* if FetBufSize not set */

FetBufSize = 4096; /* default FetBufSize */

FetArrSize = FetBufSize/msglen;

}

num_to_alloc = (FetArrSize == 0)? 1: FetArrSize;

/* 设置sqlvar_struct结构中的数据类型为相应的C的数据类型*/

for (i = 0, col_ptr = in_da->sqlvar; i < in_da->sqld; i++, col_ptr++)

{

switch(col_ptr->sqltype)

{

case SQLCHAR:

type = "char ";

col_ptr->sqltype = CCHARTYPE;

break;

case SQLINT:

type = "int ";

col_ptr->sqltype = CINTTYPE;

break;

case SQLBYTES:

case SQLTEXT:

if (col_ptr->sqltype == SQLBYTES)

type = "blob ";

else

type = "text ";

col_ptr->sqltype = CLOCATORTYPE;

/* Step 3 :只有数据类型为TEXT 和BLOB时,才执行。为存放TEXT 或BYTE列数据申请空间*/

temp_loc = (loc_t *)malloc(col_ptr->sqllen * num_to_alloc);

if (!temp_loc)

{

fprintf(stderr, "blob sqldata malloc failed\n");

return(-1);

}

col_ptr->sqldata = (char *)temp_loc;

/* Step 4:只有数据类型为TEXT 和BLOB时,才执行。初试化loc_t结构*/

byfill(temp_loc, col_ptr->sqllen*num_to_alloc ,0);

for (j = 0; j< num_to_alloc; j++, temp_loc++)

{

temp_loc->loc_loctype = LOCMEMORY;

temp_loc->loc_bufsize = BLOBSIZE;

temp_loc->loc_buffer = (char *)malloc(BLOBSIZE);

if (!temp_loc->loc_buffer)

{

fprintf(stderr, "loc_buffer malloc failed\n");

return(-1);

}

temp_loc->loc_oflags = 0; /* clear flag */

} /* end for */

break;

default: /* 其他数据类型*/

fprintf(stderr, "not yet handled(%d)!\n", col_ptr->sqltype);

return(-1);

} /* switch */

/* Step 5: 为指示符变量申请空间*/

col_ptr->sqlind =

(short *) malloc(sizeof(short) * num_to_alloc);

if (!col_ptr->sqlind)

{

printf("indicator malloc failed\n");

return -1;

/* Step 6 :为存放非TEXT 和BLOB的数据类型的sqldata申请空间.注意的是,申请的地址是(char *),在输出数据时,要按照相应的数据类型做转换。*/

if (col_ptr->sqltype != CLOCATORTYPE)

{

col_ptr->sqldata = (char *) malloc(col_ptr->sqllen * num_to_alloc);

if (!col_ptr->sqldata)

{

printf("sqldata malloc failed\n");

return -1;

}

if (print)

printf("column %3d, type = %s(%3d), len=%d\n", i+1, type,

col_ptr->sqltype, col_ptr->sqllen);

} /* end for */

return msglen;

}

/***********

[1] [2] [3] [4] [5] 下一页

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有