5.1 一个简单的入门例子
例1、查询customer表中所有lname的第一个字符小于C的顾客信息。
#include /*定义两个常量*/
EXEC SQL define FNAME_LEN 15;
EXEC SQL define LNAME_LEN 15;
main()
{
/*声明宿主变量*/
EXEC SQL BEGIN DECLARE SECTION;
char fname[ FNAME_LEN + 1 ];
char lname[ LNAME_LEN + 1 ];
EXEC SQL END DECLARE SECTION;
printf( "DEMO1 Sample ESQL Program running.\n\n");
/*出错处理,如果返回错误信息,则停止该程序*/
EXEC SQL WHENEVER ERROR STOP;
/*连接到stores7数据库*/
EXEC SQL connect to 'stores7';
/*声明一个游标*/
EXEC SQL DECLARE democursor cursor for
select fname, lname
into :fname, :lname
from customer
where lname < 'C';
/*打开游标*/
EXEC SQL open democursor;
/*如果SQLSTATE不等于“00”,那么表示到达了数据集的尾部(02),或者产生了错误(大于02)*/
for (;;)
{
EXEC SQL fetchdemocursor;
if (strncmp(SQLSTATE, "00", 2) != 0)
break;
printf("%s %s\n",fname, lname);
}
/*打印错误信息*/
if (strncmp(SQLSTATE, "02", 2) != 0)
printf("SQLSTATE after fetch is %s\n", SQLSTATE);
/*关闭游标*/
EXEC SQL close democursor;
/*释放游标占用的资源*/
EXEC SQL free democursor;
/*断开数据库服务器的连接*/EXEC SQL disconnect current;printf("\nDEMO1 Sample Program over.\n\n");
}
从上面这个例子,我们看出嵌入SQL的基本特点是:
1、每条嵌入式SQL语句都用EXEC SQL开始,表明它是一条SQL语句。这也是告诉预编译器在EXEC SQL和“;”之间是嵌入SQL语句。
2、如果一条嵌入式SQL语句占用多行,在C程序中可以用续行符“\”,在Fortran中必须有续行符。其他语言也有相应规定。
3、每一条嵌入SQL语句都有结束符号,如:在C中是“;”。
4、嵌入SQL语句的关键字不区分大小写。
5、可以使用“/*….*/”来添加注释。
从上面这个例子看出,INFORMIX数据库的嵌入SQL语句的格式同其他数据库基本相同。但是,它也有它自己本身的一些特点。本节把重点放在INFORMIX数据库所独有的一些语句或处理方式。
5.2 宿主变量
宿主变量就是在嵌入式SQL语句中引用主语言说明的程序变量。如:
EXEC SQL connect to :hostvar;
1)、定义宿主变量
方法1:采用BEGIN DECLARE SECTION 和END DECLARE SECTION之间给主变量说明。如:
EXEC SQL BEGIN DECLARE SECTION;
char fname[ FNAME_LEN + 1 ];
char lname[ LNAME_LEN + 1 ];
EXEC SQL END DECLARE SECTION;
方法2:在每个变量的数据类型前加上“$”。如:
$int hostint;
$double hostdbl;
ESQL/C对宿主变量的大小写敏感。但是,ESQL/C的关键字、语句标志符、游标名大小写不敏感。在SQL语句中,除了使用“:”来标志宿主变量外,还可以使用“$”。当然,“:”是ANSI标准。如:EXEC SQL connect to $hostvar。对于注释,可以使用“--”,也可以使用标准的“/*…*/”。
2)、宿主变量和NULL
方法1:使用指示符变量。
方法2:使用函数risnull()和rsetnull()。
3)、指示符变量
大多数程序设计语言(如C)都不支持NULL。所以对NULL的处理,一定要在SQL中完成。我们可以使用主机指示符变量来解决这个问题。在嵌入式SQL语句中,宿主变量和指示符变量共同规定一个单独的SQL类型值。指示变量和前面宿主变量之间用一个空格相分隔。如:
EXEC SQL select lname, company
into :name INDICATOR :nameind, :comp INDICATOR :compind
nameind是name变量的指示符,而compind是comp变量的指示符。
可以通过以下三种方法使用指示符变量:
方法1、使用INDICATOR关键字。
:hostvar INDICATOR :indvar
方法2、
:hostvar :indvar
方法3、使用$符号。
$hostvar $indvar。
无论采用哪种方法,都是实现指示符变量的作用。即:当宿主变量hostvar应该返回NULL时,指示符变量为-1。当宿主变量hostvar应该返回不是NULL而且无需截断时,指示符变量为0。当返回值太大而需要截断时,指示符变量是截断前数据的长度。SQLSTATE会返回01004错误信息。请看下面这个例子:
EXEC SQL BEGIN DECLARE SECTION;
char name[16];
char comp[20];
short nameind;
short compind;
EXEC SQL END DECLARE SECTION;
EXEC SQL select lname, company
into :name INDICATOR :nameind, :comp INDICATOR :compind
from customer
where customer_num = 105;
如果对应105的company为NULL,则compind小于0,如果lname的结果大于15个字节,那么name包含前15个字符。
4)、宿主变量的数据类型
INFROMIX ESQ/C的宿主变量数据类型除了标准C的数据类型外,可以是它自己定义的数据类型。如:
lvarchar数据类型
EXEC SQL BEGIN DECLARE SECTION;
varchar varc_name[n + 1];
EXEC SQL END DECLARE SECTION;
lint8数据类型
EXEC SQL BEGIN DECLARE SECTION;
int8 int8_var1;
ifx_int8_t int8_var2;
EXEC SQL BEGIN DECLARE SECTION;
lfixchar数据类型EXEC SQL BEGIN DECLARE SECTION;
boolean flag;
fixchar my_boolflag;
int id;
EXEC SQL END DECLARE SECTION;
lDecimal数据类型
#define DECSIZE 16
struct decimal
{
short dec_exp;
short dec_pos;
short dec_ndgts;
char dec_dgts[DECSIZE];
};
typedef struct decimal dec_t;
lDatetime数据类型EXEC SQL include datetime;
EXEC SQL BEGIN DECLARE SECTION;
datetime year; /* will cause an error */
datetime year to day year, today; /* ambiguous */
EXEC SQL END DECLARE SECTION;
lInterval hour等数据类型EXEC SQL BEGIN DECLARE SECTION;
interval day(3) to day accrued_leave, leave_taken;
interval hour to second race_length;
interval scheduled;
EXEC SQL END DECLARE SECTION;
l其他数据类型
EXEC SQL BEGIN DECLARE SECTION;
loc_t my_simple_lo;
EXEC SQL END DECLARE SECTION;
my_simole_lo.loc_loctype = LOCMEMORY;
l在INFORMIX数据库中,'\0'表示为NULL。如:
id = 1;
flag = '\0'; /* valid boolean assignment to FALSE */
EXEC SQL insert into table2 values (:id, :flag); /* inserts FALSE */
在以SQL为基础的DBMS支持的数据类型与程序设计语言支持的数据类型之间有很大差别。如果你通过宿主变量从数据库取值,或者通过宿主变量向数据库插入值,都存在数据类型转换的问题。
下表列出了C的数据类型、ESQL/C定义的数据类型和SQL数据类型的兼容关系:
SQL数据类型 ESQL/C定义的数据类型 C的数据类型
BOOLEAN boolean
BYTE loc_t
CHAR(n)
CHARACTER(n) fixchar [n] 或string [n+1] char [n + 1] 或 char *
DATE date 4-byte integer
DATETIME datetime或ordtime_t
DECIMAL decimal或dec_t
DEC decimal或dec_t
NUMERIC decimal或dec_t
MONEY decimal或dec_t
FLOAT double
DOUBLE double
PRECISION double
INT8 int8或ifx_int8_t
INTEGER 4-byte integer
INT 4-byte integer
INTERVAL interval or intrvl_t
LVARCHAR lvarchar char [n + 1] orchar *
NCHAR(n) fixchar [n] orstring [n+1] char [n + 1] orchar *
NVARCHAR(m) varchar[m+1] orstring [m+1] char [m+1]
SERIAL 4-byte integer
SERIAL8 int8 or ifx_int8_t
SMALLFLOAT float
REAL float
SMALLINT 2-byte integer
TEXT loc_t
VARCHAR(m,x) varchar[m+1] or string [m+1] char d[m+1]
BLOB ifx_lo_t
CLOB ifx_lo_t
LIST(e) collection
MULTISET(e) collection
Opaque data type lvarchar,fixed binary或var binary
ROW(...) row
SET(e) collection
下表是INFORMIX数据库服务器支持的数据类型和类型代码:
SQL数据类型 类型代码 类型代码值
CHAR SQLCHAR 0
SMALLINT SQLSMINT 1
INTEGER SQLINT 2
FLOAT SQLFLOAT 3
SMALLFLOAT SQLSMFLOAT 4
DECIMAL SQLDECIMAL 5
SERIAL SQLSERIAL 6
DATE SQLDATE 7
MONEY SQLMONEY 8
DATETIME SQLDTIME 10
BYTE SQLBYTES 11
TEXT SQLTEXT 12
VARCHAR SQLVCHAR 13
INTERVAL SQLINTERVAL 14
NCHAR SQLNCHAR 15
NVARCHAR SQLNVCHAR 16
INT8 SQLINT8 17
SERIAL8 SQLSERIAL8 18
LVARCHAR SQLLVARCHAR 43
BOOLEAN SQLBOOL 45
SET SQLSET 19
MULTISET SQLMULTISET 20
LIST SQLLIST 21
ROW SQLROW 22
Varying-length
opaqueType SQLUDTVAR 40
Fixed-length
opaque type SQLUDTFIXED 41
SENDRECV
(client-side only) SQLSENDRECV 44
下表是ESQL/C定义的数据类型和类型代码,这些定义存放在各个头文件中。
ESQL/C数据类型 类型代码 类型代码值
char CCHARTYPE 100
short int CSHORTTYPE 101
int4 CINTTYPE 102
long CLONGTYPE 103
float CFLOATTYPE 104
double CDOUBLETYPE 105
dec_t或decimal CDECIMALTYPE 107
fixchar CFIXCHARTYPE 108
string CSTRINGTYPE 109
date CDATETYPE 110
dec_t或decimal CMONEYTYPE 111
datetime或dtime_t CDTIMETYPE 112
loc_t CLOCATORTYPE 113
varchar CVCHARTYPE 114
intrvl_t 或interval CINVTYPE 115
char CFILETYPE 116
int8 CINT8TYPE 117
collection (Universal
Data Option) CCOLTYPE 118
lvarchar CLVCHARTYPE 119
fixed binary CFIXBINTYPE 120
var binary (Universal
Data Option) CVARBINTYPE 121
boolean CBOOLTYPE 122
row (Universal Data
Option) CROWTYPE 123
INFORMIX的ESQL/C提供了很多函数来处理数据类型,这些函数的参数就是ESQL/C定义的数据类型。如:dectoasc()的作用是转换数据类型是decimal的值为ASCII。
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语句提供输入数据和从嵌入SQL语句中输出数据。理解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;
}
/************************************************************************
* 函数: print_sqlda
* 作用: 打印存放在SQLDA结构中的数据。
************************************************************************/
void print_sqlda(sqlda, count)
struct sqlda *sqlda;
int count;
{
void *data;
int i, j;
loc_t *temp_loc;
struct sqlvar_struct *col_ptr;
char *type;
char buffer[512];
int ind;
char i1, i2;
/* 打印列数 (sqld) 和行数*/
printf("\nsqld: %d, fetch-array elements: %d.\n", sqlda->sqld, count);
/* 外循环:针对每一行数据循环处理 */
for (j = 0; j < count; j ++)
{
if (count > 1)
{
printf("record[%4d]:\n", j);
printf("col | type | id | len | ind | rin | data ");
printf("| value\n");
printf("--------------------------------------------");
printf("------------------\n");
}
/* 内循环: 针对每一列数据处理*/
for (i = 0, col_ptr = sqlda->sqlvar; i < sqlda->sqld;
i++, col_ptr++)
{
data = col_ptr->sqldata + (j*col_ptr->sqllen);
switch (col_ptr->sqltype)
{
case CFIXCHARTYPE:
case CCHARTYPE:
type = "char";
if (col_ptr->sqllen > 40)
sprintf(buffer, " %39.39selse
sprintf(buffer, "%*.*s", col_ptr->sqllen,
col_ptr->sqllen, data);
break;
case CINTTYPE:
type = "int";
sprintf(buffer, " %d", *(int *) data);
break;
case CLOCATORTYPE:
type = "byte";
temp_loc = (loc_t *)(col_ptr->sqldata +
(j * sizeof(loc_t)));
sprintf(buffer, " buf ptr: %p, buf sz: %d,
blob sz: %d", temp_loc->loc_buffer,
temp_loc->loc_bufsize, temp_loc->loc_size);
break;
default:
type = "??????";
sprintf(buffer, " type not implemented: ",
"can't print %d", col_ptr->sqltype);
break;
} /* end switch */
i1 = (col_ptr->sqlind==NULL) ? 'X' :
(((col_ptr->sqlind)[j] != 0) ? 'T' : 'F');
i2 = (risnull(col_ptr->sqltype, data)) ? 'T' : 'F';
printf("%3d | %-6.6s | %3d | %3d | %c | %c | ",
i, type, col_ptr->sqltype, col_ptr->sqllen, i1, i2);
printf("%8p |%s\n", data, buffer);
} /* end for (i=0...) */
} /* end for (j=0...) */
}
/************************************************************************
* 函数: free_sqlda
* 作用: 释放以下对象申请的内存空间
* o loc_buffer memory (used by TEXT & BYTE)
* o sqldata memory
* o sqlda structure
************************************************************************/
void free_sqlda(sqlda)
struct sqlda *sqlda;
{
int i,j, num_to_dealloc;
struct sqlvar_struc *col_ptr;
loc_t *temp_loc;
for (i = 0, col_ptr = sqlda->sqlvar; i < sqlda->sqld;
i++, col_ptr++)
{
if ( col_ptr->sqltype = CLOCATORTYPE )
{
/* Free memory for blob buffer of each element in fetch array */
num_to_dealloc = (FetArrSize == 0)? 1: FetArrSize;
temp_loc = (loc_t *) col_ptr->sqldata;
for (j = 0; j< num_to_dealloc; j++, temp_loc++)
free(temp_loc->loc_buffer);
}
/* Free memory for sqldata (contains fetch array) */
free(col_ptr->sqldata);
}
/* Free memory for sqlda structure */
free(sqlda);
}