ESQL/C
很多来自网络,自己整理了一下。
☆ 概念
利用高级语言的过程性结构来弥补SQL语言实现复杂应用方面的不足。
嵌入SQL的高级语言称为主语言或宿主语言。
在混合编程中,SQL语句负责操作数据库,高级语言语句负责控制程序流程。
预编译方法:由DBMS的预处理程序对源程序扫描,识别出SQL语句,把它们转换成主语言调用语句,以使主语言编译器能识别它,最后由主语言编译器将整个源程序编译成目标码。
嵌入SQL的高级语言称为主语言或宿主语言。
在混合编程中,SQL语句负责操作数据库,高级语言语句负责控制程序流程。
预编译方法:由DBMS的预处理程序对源程序扫描,识别出SQL语句,把它们转换成主语言调用语句,以使主语言编译器能识别它,最后由主语言编译器将整个源程序编译成目标码。
☆ 嵌入式SQL的一般形式
所有的嵌入式SQL语句都必须加前缀EXEC SQL
在C语言中: EXEC SQL <SQL语句>
例如:EXEC SQL DROP TABLE Student ;
在C语言中: EXEC SQL <SQL语句>
例如:EXEC SQL DROP TABLE Student ;
☆ 嵌入式SQL与主语言的通信
向主语言传递SQL语句执行状态信息,使语言能够据此信息控制程序流程,用SQL通信区(SQLCA【SQL Communication Area】)实现。
主语言向SQL语句提供参数,主要用主变量(Host Variable)实现;
将SQL语句查询数据库的结果交主语言进一步处理,主要用主变量和游标(Cursor)实现。
主语言向SQL语句提供参数,主要用主变量(Host Variable)实现;
将SQL语句查询数据库的结果交主语言进一步处理,主要用主变量和游标(Cursor)实现。
☆ SQL通信区
SQLCA中有一个存放每次执行SQL语句后返回代码的变量SQLCODE。
每次执行完SQL语句后都应该测试一下SQLCODE的值,以了解该SQL语句执行情况并做相应处理,如果SQLCODE等于预定的常量SUCCESS,则表示SQL语句成功,否则在SQLCODE中存放错误代码。
SQLCA(SQL Communication Access) 系由系统提供之系统记录架构,作为back end与 front end 之间沟通之用,当发生 I/O 状态时,系统会记录该状态于SQLCA 中,front end 即可依据其其内容得知 I/O 运作是否成功,再决定往后执行的步骤。SQLCA 为系统定义之 GLOBAL变量,以下为其架构并介绍其内容与用途:
DEFINE SQLCA RECORD
SQLCODE INTEGER ,
SQLERRM CHAR( 71 ) ,
SQLERRP CHAR( 8 ) ,
SQLERRD ARRAY [ 6 ] OF INTEGER ,
SQLAWARN CHAR( 8 )
END RECORD
.SQLCODE :表示 I/O 的结果
0 表示 I/O 成功
100 表示 NOTFOUND
< 0 表示 I/O 失败
.SQLERRM :保留未用
.SQLERRP :保留未用
.SQLERRD :为一个含有6个INTEGER数组
SQLERRD [ 1 ] :保留未用
SQLERRD [ 2 ] :新增时 SERIAL 字段所传回之值
SQLERRD [ 3 ] :处理资料的笔数
SQLERRD [ 4 ] :查询时预估的 CPU COST
SQLERRD [ 5 ] :SQL指令之错误位移
SQLERRD [ 6 ] :最后一个 ROWID 值
.SQLAWARN :为一个含有8个字符的字符串,以记录I/O时产生的警告讯息。若正确无误,则相对应之字符设定为空白,否则会被设定为 " W " 。
SQLAWARN [ 1 ] :若第2至第8字符中任意一个被设成 " W " ,则此字符亦为 " W " ,否则为空白。
SQLAWARN [ 2 ] :若资料太长而被截掉时,会被设成 " W " 。
SQLAWARN [ 3 ] :若 aggregate function(如 SUM,AVG,MAX,MIN) 处理时遇到 NULL 值,则会被设成 " W " 。
SQLAWARN [ 4 ] :若查询时,若欲查询的字段数目和 INTO 之变量数目不合时,会被设成 " W " 。
SQLAWARN [ 5 ] :如转换 float 成 integer 时,则会被设成 " W " 。
SQLAWARN [ 6 ] :保留未用
SQLAWARN [ 7 ] :保留未用
SQLAWARN [ 8 ] :保留未用
每次执行完SQL语句后都应该测试一下SQLCODE的值,以了解该SQL语句执行情况并做相应处理,如果SQLCODE等于预定的常量SUCCESS,则表示SQL语句成功,否则在SQLCODE中存放错误代码。
SQLCA(SQL Communication Access) 系由系统提供之系统记录架构,作为back end与 front end 之间沟通之用,当发生 I/O 状态时,系统会记录该状态于SQLCA 中,front end 即可依据其其内容得知 I/O 运作是否成功,再决定往后执行的步骤。SQLCA 为系统定义之 GLOBAL变量,以下为其架构并介绍其内容与用途:
DEFINE SQLCA RECORD
SQLCODE INTEGER ,
SQLERRM CHAR( 71 ) ,
SQLERRP CHAR( 8 ) ,
SQLERRD ARRAY [ 6 ] OF INTEGER ,
SQLAWARN CHAR( 8 )
END RECORD
.SQLCODE :表示 I/O 的结果
0 表示 I/O 成功
100 表示 NOTFOUND
< 0 表示 I/O 失败
.SQLERRM :保留未用
.SQLERRP :保留未用
.SQLERRD :为一个含有6个INTEGER数组
SQLERRD [ 1 ] :保留未用
SQLERRD [ 2 ] :新增时 SERIAL 字段所传回之值
SQLERRD [ 3 ] :处理资料的笔数
SQLERRD [ 4 ] :查询时预估的 CPU COST
SQLERRD [ 5 ] :SQL指令之错误位移
SQLERRD [ 6 ] :最后一个 ROWID 值
.SQLAWARN :为一个含有8个字符的字符串,以记录I/O时产生的警告讯息。若正确无误,则相对应之字符设定为空白,否则会被设定为 " W " 。
SQLAWARN [ 1 ] :若第2至第8字符中任意一个被设成 " W " ,则此字符亦为 " W " ,否则为空白。
SQLAWARN [ 2 ] :若资料太长而被截掉时,会被设成 " W " 。
SQLAWARN [ 3 ] :若 aggregate function(如 SUM,AVG,MAX,MIN) 处理时遇到 NULL 值,则会被设成 " W " 。
SQLAWARN [ 4 ] :若查询时,若欲查询的字段数目和 INTO 之变量数目不合时,会被设成 " W " 。
SQLAWARN [ 5 ] :如转换 float 成 integer 时,则会被设成 " W " 。
SQLAWARN [ 6 ] :保留未用
SQLAWARN [ 7 ] :保留未用
SQLAWARN [ 8 ] :保留未用
☆ 主变量
一个主变量既可是输入主变量也可是输出主变量。
主变量必须在SQL语句EXEC SQL BEGIN DECLARE SECTION与EXEC SQL END DECLARE SECTION之间进行说明。
例如:
EXEC SQL BEGIN DECLARE SECTION ;
int i = 0 ;
EXEC SQL END DECLARE SECTION ;
SQL语句的主变量名前要加冒号作为标志。
在SQL语句之外,主变量直接引用,不须加冒号。
主变量必须在SQL语句EXEC SQL BEGIN DECLARE SECTION与EXEC SQL END DECLARE SECTION之间进行说明。
例如:
EXEC SQL BEGIN DECLARE SECTION ;
int i = 0 ;
EXEC SQL END DECLARE SECTION ;
SQL语句的主变量名前要加冒号作为标志。
在SQL语句之外,主变量直接引用,不须加冒号。
☆ 使用游标查询
EXEC
SQL
DECLARE
cur
CURSOR
FOR
select
name,sex
from
student
where
no
like
:no;
//
定义游标
EXEC SQL OPEN cur; // 打开游标
for (;;){
EXEC SQL fetch cur into :name,:sex; // 推进游标
if (sqlca.sqlcode == 100 ) // 没有满足条件的数据
break ;
// 操作数据
}
EXEC SQL close cur; // 关闭游标
EXEC SQL free cur; // 释放游标
EXEC SQL OPEN cur; // 打开游标
for (;;){
EXEC SQL fetch cur into :name,:sex; // 推进游标
if (sqlca.sqlcode == 100 ) // 没有满足条件的数据
break ;
// 操作数据
}
EXEC SQL close cur; // 关闭游标
EXEC SQL free cur; // 释放游标
☆ 使用事务
事务的三个常用操作:开始事务(
BEGIN
WORK
),提交事务(
COMMIT
WORK
),回滚(
ROLLBACK
WORK
),
例如:
EXEC SQL BEGIN WORK ;
…… // 数据库操作
if (sqlca.sqlcode < 0 )
EXEC SQL ROLLBACK WORK ;
else
EXEC SQL COMMIT WORK ;
例如:
EXEC SQL BEGIN WORK ;
…… // 数据库操作
if (sqlca.sqlcode < 0 )
EXEC SQL ROLLBACK WORK ;
else
EXEC SQL COMMIT WORK ;
☆ CURRENT形式的UPDATE语句和DELETE语句
UPDATE和DELETE语句都是集合操作,如果只想修改或删除其中的某个记录,则需要用带游标的SELECT语句查出所有满足条件记录,从中进一步找出要修改或删除的记录,然后用CURRENT形式的UPDATE和DELETE语句处理。
用DELCARE语句说明游标。如果是为CURRENT形式的UPDATE语句作准备,则SELECT语句中要用 FOR UPDATE OF<列名>用来指明查询出的数据在指定列是可修改的。如果是为CURRENT形式的DELETE语句作准备,则不必使用上述子句。
检查该记录是否为该修改或删除的记录。如果是,则修改或删除之。这时UPDATE和DELETE语句中要用子句 WHERE CURRENT OF<游标名>,表示修改或删除的是最近一次取出的记录,即游标指针指向的记录。
例如:
char yn ;
EXEC SQL BEGIN DELCARE SECTION ;
char Sno [ 20 ] , Sname [ 20 ] , NEWSname [ 20 ] ;
EXEC SQL END DECLARE SECTION ;
EXEC SQL DECLARE cur CURSOR FOR SELECT Sno , Sname FROM Student WHERE Sno like ' 01 %' FOR UPDATE OF Sname ;
EXEC SQL OPEN cur
while( 1 ) { /*用循环结构逐条处理结果集中的记录*/
EXEC SQL FETCH cur INTO :Sno , :Sname ;
if(sqlca.sqlcode == 100 )
break ; /*若查询结果处理完或出现错误,则退出循环*/
printf( " no=%s,name=%s " , Sno , Sname) ;
printf( " UPDATE Name(y/n)? " ) ; /*问用户是否需要修改*/
scanf( " %c " , &yn) ;
if(yn = 'y' or yn = 'Y') /*需要修改*/
{
printf( " INPUT NEW Name: " ) ;
scanf( " %d " , &NEWSname) ;
EXEC SQL UPDATE Student SET Sname = :NEWSname WHERE CURRENT OF cur ;
} ;
} ;
EXEC SQL CLOSE cur ;
用DELCARE语句说明游标。如果是为CURRENT形式的UPDATE语句作准备,则SELECT语句中要用 FOR UPDATE OF<列名>用来指明查询出的数据在指定列是可修改的。如果是为CURRENT形式的DELETE语句作准备,则不必使用上述子句。
检查该记录是否为该修改或删除的记录。如果是,则修改或删除之。这时UPDATE和DELETE语句中要用子句 WHERE CURRENT OF<游标名>,表示修改或删除的是最近一次取出的记录,即游标指针指向的记录。
例如:
char yn ;
EXEC SQL BEGIN DELCARE SECTION ;
char Sno [ 20 ] , Sname [ 20 ] , NEWSname [ 20 ] ;
EXEC SQL END DECLARE SECTION ;
EXEC SQL DECLARE cur CURSOR FOR SELECT Sno , Sname FROM Student WHERE Sno like ' 01 %' FOR UPDATE OF Sname ;
EXEC SQL OPEN cur
while( 1 ) { /*用循环结构逐条处理结果集中的记录*/
EXEC SQL FETCH cur INTO :Sno , :Sname ;
if(sqlca.sqlcode == 100 )
break ; /*若查询结果处理完或出现错误,则退出循环*/
printf( " no=%s,name=%s " , Sno , Sname) ;
printf( " UPDATE Name(y/n)? " ) ; /*问用户是否需要修改*/
scanf( " %c " , &yn) ;
if(yn = 'y' or yn = 'Y') /*需要修改*/
{
printf( " INPUT NEW Name: " ) ;
scanf( " %d " , &NEWSname) ;
EXEC SQL UPDATE Student SET Sname = :NEWSname WHERE CURRENT OF cur ;
} ;
} ;
EXEC SQL CLOSE cur ;
☆ 数据类型
1
、SQL与C数据类型的对应简单类型
SQL C
CHAR(n) char (n + 1 )
CHARCTER(n) char *
SMALLINT short
INTERGER int
SMALLFLOAT float
FLOAT / DOUBLE double
SERIAL long int
DATE long int
VARCHAR string
2 、数据类型转换
转换类型 转换后
FLOAT DECIMAL( 16 )
SMALLFLOAT DECIMAL( 8 )
INTERGER DECIMAL( 10 , 0 )
SAMLLINT DECIMAL( 5 , 0 )
SQL C
CHAR(n) char (n + 1 )
CHARCTER(n) char *
SMALLINT short
INTERGER int
SMALLFLOAT float
FLOAT / DOUBLE double
SERIAL long int
DATE long int
VARCHAR string
2 、数据类型转换
转换类型 转换后
FLOAT DECIMAL( 16 )
SMALLFLOAT DECIMAL( 8 )
INTERGER DECIMAL( 10 , 0 )
SAMLLINT DECIMAL( 5 , 0 )
☆ 有关CHAR类型的函数
1
、以空值结尾的串的操作函数
rdownshift( char * s) 把一个字符串中的所有字母转换成小写形式。
rupshift( char * s) 把一个字符串中的所有字母转换成大写形式。
stcat( char * s, char * dest) 把一个字符串同另一个字符串相连接。
stcmpr( char * s1, char * s2) 比较两个字符串。
stcopy( char * from, char * to) 把一个字符串拷贝到另一个字符串。
stleng( char * string ) 统计字符串的长度。
2 、定长串的操作函数
bycmpr( char byte1, byte2, rpt len) 比较两组连续的字节内存块。
bycopy( char * from, char * to, int len) 把一块内存的内容拷贝到另一块内存。
byfill( char * to, int len, char ch) 用字符填充指定的内存块。
byleng( char from, int count) 统计有效字符的数目。有效字符是指字符串去除了末尾空格所剩的字符。
3 、字符串操作函数
ldchar( char * from, int num, char * to) 拷贝定长串到空值结尾的串。
stchar( char * from, char * to, int num) 拷贝空值结尾的串到定长串。
4 、字符串函数简单数值转换
rstod( char * str, double * dblval) 把以空值结束的字符串转换成C的double型
rstoi( char * str, int * intval) 把以空值结束的字符串转换成C的int类型。
rstol( char * str, long * lngval) 把以空值结束的字符串转换成C的long类型。
rdownshift( char * s) 把一个字符串中的所有字母转换成小写形式。
rupshift( char * s) 把一个字符串中的所有字母转换成大写形式。
stcat( char * s, char * dest) 把一个字符串同另一个字符串相连接。
stcmpr( char * s1, char * s2) 比较两个字符串。
stcopy( char * from, char * to) 把一个字符串拷贝到另一个字符串。
stleng( char * string ) 统计字符串的长度。
2 、定长串的操作函数
bycmpr( char byte1, byte2, rpt len) 比较两组连续的字节内存块。
bycopy( char * from, char * to, int len) 把一块内存的内容拷贝到另一块内存。
byfill( char * to, int len, char ch) 用字符填充指定的内存块。
byleng( char from, int count) 统计有效字符的数目。有效字符是指字符串去除了末尾空格所剩的字符。
3 、字符串操作函数
ldchar( char * from, int num, char * to) 拷贝定长串到空值结尾的串。
stchar( char * from, char * to, int num) 拷贝空值结尾的串到定长串。
4 、字符串函数简单数值转换
rstod( char * str, double * dblval) 把以空值结束的字符串转换成C的double型
rstoi( char * str, int * intval) 把以空值结束的字符串转换成C的int类型。
rstol( char * str, long * lngval) 把以空值结束的字符串转换成C的long类型。
☆ DATE类型的函数
1
、创建内部日期
rdefmtdate( long * jdate, char * frmt char * str) 生成具有确定格式的日期字符串。(str字符串和fmt必须按月、日、年的同一顺序)
返回代码:0操作成功; - 1204在str参数中有非法的月份; - 1206在str参数中有非法的日期; - 1209由于str中没有包含年、月、日各部分间的定界符,str的长度必须准确定义为6或8个字节长; - 1212fmt中没有包含年、月、日部分。
fmt和str的有效组合
fmt str
" mmddyy " " DEC 25th 1997 "
" mmm.dd.yyyy " " dec 25 1997 "
" mmm.dd.yyyy " " DEC-25-1997 "
" mmm.dd.yyyy " " 12251997 "
" mmm.dd.yyyy " " 12/25/1997 "
" yy/mm/dd " " 97/12/25 "
" yy/mm/dd " " 1997,December, 25th "
" yy/mm/dd " " In the year 1997, the month of December, its 25th day "
" dd-mm-yy " " This 25th day of December, 1997 "
rmdyjul( short mdy[ 3 ], long * jdate) 用三个短整数生成一个内部日期这三个整数是有关年、月、日的数字值。(年必须以完整的形式表达)
返回代码:0操作成功。 - 1204在mdy[ 2 ]中有非法年份。 - 1205在mdy[ 1 ]中有非法月份。 - 1206在mdy[ 0 ]中有非法日期。
rstrdate( char * str, long * jdate) 将一个字符串日期转换成一内部格式的日期。
rtoday( long * jdate) 从系统日期创建一个内部日期值。
2 、从内部日期转换成其他类型
rfmtdate(ling jdate, char * fmt, char * str) 从内部格式的日期类型值创建格式化的字符串。返回代码:0操作成功。 - 1210内部日期不能被转换成月 - 日 - 年格式。 - 1211程序存储溢出,即存储分配错误。
rjulmdy( long jdate, short mdy[ 3 ]) 从一个内部日期生成一个含有3个短整数的数组对应内部日期的月、日、年。
rdatestr( long jdate, char * str) 从一个内部日期值创建缺省的日期字符串。
rdayofweek( long jdate) 给定一内部格式表示的日期,此函数返回所对应的星期中的某一天。
rleapyear( int year) 用来判断给定的年份是否为闰年。 返回值:TRUE( 1 )是闰年;FALSE( 0 )不是闰年
rdefmtdate( long * jdate, char * frmt char * str) 生成具有确定格式的日期字符串。(str字符串和fmt必须按月、日、年的同一顺序)
返回代码:0操作成功; - 1204在str参数中有非法的月份; - 1206在str参数中有非法的日期; - 1209由于str中没有包含年、月、日各部分间的定界符,str的长度必须准确定义为6或8个字节长; - 1212fmt中没有包含年、月、日部分。
fmt和str的有效组合
fmt str
" mmddyy " " DEC 25th 1997 "
" mmm.dd.yyyy " " dec 25 1997 "
" mmm.dd.yyyy " " DEC-25-1997 "
" mmm.dd.yyyy " " 12251997 "
" mmm.dd.yyyy " " 12/25/1997 "
" yy/mm/dd " " 97/12/25 "
" yy/mm/dd " " 1997,December, 25th "
" yy/mm/dd " " In the year 1997, the month of December, its 25th day "
" dd-mm-yy " " This 25th day of December, 1997 "
rmdyjul( short mdy[ 3 ], long * jdate) 用三个短整数生成一个内部日期这三个整数是有关年、月、日的数字值。(年必须以完整的形式表达)
返回代码:0操作成功。 - 1204在mdy[ 2 ]中有非法年份。 - 1205在mdy[ 1 ]中有非法月份。 - 1206在mdy[ 0 ]中有非法日期。
rstrdate( char * str, long * jdate) 将一个字符串日期转换成一内部格式的日期。
rtoday( long * jdate) 从系统日期创建一个内部日期值。
2 、从内部日期转换成其他类型
rfmtdate(ling jdate, char * fmt, char * str) 从内部格式的日期类型值创建格式化的字符串。返回代码:0操作成功。 - 1210内部日期不能被转换成月 - 日 - 年格式。 - 1211程序存储溢出,即存储分配错误。
rjulmdy( long jdate, short mdy[ 3 ]) 从一个内部日期生成一个含有3个短整数的数组对应内部日期的月、日、年。
rdatestr( long jdate, char * str) 从一个内部日期值创建缺省的日期字符串。
rdayofweek( long jdate) 给定一内部格式表示的日期,此函数返回所对应的星期中的某一天。
rleapyear( int year) 用来判断给定的年份是否为闰年。 返回值:TRUE( 1 )是闰年;FALSE( 0 )不是闰年
☆ 简单数值类型的格式化函数
rfmtdouble(
double
dbval,
char
*
fmt,
char
*
str) 将双精度格式化为指定的模板格式。
rfmtlong( double longval, char * fmt, char * str) 将长整型值格式化为指定的模板格式。
可以构成格式模板串的字符:
* 以星号代替空格。
& 以0代替空格。
#代表一个数字或空格的位置。
< 左调整,显示一个逗号,仅当左边有数字时才显示。
.显示一个小数点,一个格式模板串只能有一个小数点。
- 显示负号,当数字为负的时候显示。
+ 显示正号,当数字为正的时候显示。
(显示一个负号,同(一起显示负值。
)显示一个负号,同)一起显示负值。
$显示美元符号。
rfmtlong( double longval, char * fmt, char * str) 将长整型值格式化为指定的模板格式。
可以构成格式模板串的字符:
* 以星号代替空格。
& 以0代替空格。
#代表一个数字或空格的位置。
< 左调整,显示一个逗号,仅当左边有数字时才显示。
.显示一个小数点,一个格式模板串只能有一个小数点。
- 显示负号,当数字为负的时候显示。
+ 显示正号,当数字为正的时候显示。
(显示一个负号,同(一起显示负值。
)显示一个负号,同)一起显示负值。
$显示美元符号。
☆ 处理空值的数值类型函数
risnull(
int
type,
char
*
c) 检查C变量是否为空值。
rsetnull( int type, char * c) 给C变量置空值。
rsetnull( int type, char * c) 给C变量置空值。
☆ 其他函数
typalign(
int
pos,
int
type) 返回一具有指定数据类型变量的下一个位置。
rtypmsize( int sqltype, int sqllen) 返回你必须分配在存储单元中的指定的C或RDSQLD的字节数。
rtyname( int sqltype) 返回一包含指定RDSQL类型名的以空结尾的串。
rtypwidth( int sqltype, intsqllen) 返回一具有RDSQL类型的值转换为一字符类型时避免截取所需的最小字符数。
rtypmsize( int sqltype, int sqllen) 返回你必须分配在存储单元中的指定的C或RDSQLD的字节数。
rtyname( int sqltype) 返回一包含指定RDSQL类型名的以空结尾的串。
rtypwidth( int sqltype, intsqllen) 返回一具有RDSQL类型的值转换为一字符类型时避免截取所需的最小字符数。