业精于勤,荒于嬉
全部博文(763)
分类: DB2/Informix
2008-04-27 20:45:25
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.39s<..", data);
else
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);
}