📄 esqlc方面的资料.txt
字号:
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;
………..
2.4.3 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
…..
图6-2 SQLDA结构示例
具体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标准。每个数据库厂商的实现方式有可能不同。
2.4.4 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语句之前,给出数据缓冲器地址和指示符地址。
2.5 两个例子程序
2.5.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 SQLNOTFOUND100
#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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -