📄 esql-c资料(完全版)四_unix_操作系统_网络学院_天新网.htm
字号:
usCallType,<BR>unsigned short usSection,<BR>unsigned short
usSqldaInId,<BR>unsigned short usSqlDaOutId,<BR>unsigned short
usSqlTextLen,<BR>char far *lpszSQLText);
<P>short ESQLAPI _loadds sqlacall(<BR>unsigned short
usCallType,<BR>unsigned short usSection,<BR>unsigned short
usSqldaInId,<BR>unsigned short usSqlDaOutId,<BR>void far *spare);
<P>short ESQLAPI _loadds sqladloc(<BR>unsigned short
usSqldaInId,<BR>void far *spare);
<P>short ESQLAPI _loadds sqlasets(<BR>unsigned short
cbSqlText,<BR>void far *lpvSqlText,<BR>void far *spare);
<P>short ESQLAPI _loadds sqlasetv(<BR>unsigned short
usSqldaInId,<BR>unsigned short sqlvar_index,<BR>unsigned short
sqltype,<BR>unsigned short sqllen,<BR>void far *sqldata,<BR>void far
*sqlind,<BR>void far *spare);
<P>short ESQLAPI _loadds sqlastop(<BR>void far *spare);
<P>short ESQLAPI _loadds sqlastrt(<BR>void far *pid,<BR>void far
*spare,<BR>void far *sqlca);
<P>short ESQLAPI _loadds sqlausda(<BR>unsigned short
sqldaId,<BR>void far *lpvSqlDa,<BR>void far *spare);
<P>extern struct tag_sqlca far sql_sqlca;<BR>extern struct tag_sqlca
far *sqlca;<BR>struct sqla_program_id2 { <BR>unsigned short length;
<BR>unsigned short rp_rel_num; <BR>unsigned short db_rel_num;
<BR>unsigned short bf_rel_num; <BR>unsigned char sqluser[30];
<BR>unsigned char sqlusername[30];<BR>unsigned char planname[256];
<BR>unsigned char contoken[8]; <BR>unsigned char buffer[8]; <BR>};
<BR>static struct sqla_program_id2 program_id = <BR>{340,2,0,0,"
","","demo","VVVLKcBo"," "};<BR>static void far* pid =
&program_id;<BR>#line 1 "demo.sqc"
<P>main()
<P>{<BR><BR>#line 5<BR>/*<BR>EXEC SQL BEGIN DECLARE
SECTION;<BR>*/<BR>#line 5
<P>char first_name[50];<BR>char last_name[] = "White";<BR><BR>#line
8<BR>/*<BR>EXEC SQL END DECLARE SECTION;<BR>*/<BR>#line 8
<P><BR><BR>#line 10<BR>/*<BR>EXEC SQL CONNECT TO YANGZH.pubs<BR>USER
sa.password;<BR>*/<BR>#line 11
<P>#line 10<BR>{<BR>#line 10<BR>sqlastrt((void far *)pid, (void far
*)0, (struct tag_sqlca far *)sqlca);<BR>#line 10<BR>sqlxcall(30, 1,
0, 0, 42, (char far *)" CONNECT TO YANGZH.pubs USER sa.password
");<BR>#line 10<BR>SQLCODE = sqlca->sqlcode;<BR>#line
10<BR>sqlastop((void far *)0L);<BR>#line 10<BR>}<BR>#line
12<BR><BR>#line 12<BR>/*<BR>EXEC SQL SELECT au_fname INTO
:first_name<BR>from authors where au_lname =
:last_name;<BR>*/<BR>#line 13
<P>#line 12<BR>{<BR>#line 12<BR>sqlastrt((void far *)pid, (void far
*)0, (struct tag_sqlca far *)sqlca);<BR>#line 12<BR>sqlaaloc(1, 1,
2, (void far *)0);<BR>#line 12<BR>sqlasetv(1, 0, 462,(short)
SQLLENMAX(sizeof(first_name)),(void far *)&first_name, (void far
*)0,0L);<BR>#line 12<BR>sqlaaloc(2, 1, 2, (void far *)0);<BR>#line
12<BR>sqlasetv(2, 0, 462, (short) SQLLENMAX(sizeof(last_name)),
(void far *)last_name, (void far *)0, (void far *)0L);<BR>#line
12<BR>sqlxcall(24, 2, 2, 1, 60, (char far *)" SELECT au_fname from
authors where au_lname = @p1 ");<BR>#line 12<BR>SQLCODE =
sqlca->sqlcode;<BR>#line 12<BR>sqlastop((void far *)0L);<BR>#line
12<BR>}<BR>#line 14<BR>printf("first name:
%s\n",first_name);<BR>return (0);<BR>}<BR>long SQLCODE;
<P>从这个程序看出,预编译器的处理方法是,注释了嵌入的SQL语句,用一些特定的函数代替,如sqlxcall。这些函数调用sqlakw32.dll,而sqlakw32.dll调用了DB-Library(ntwdblib.dll)来访问SQL
Server服务器。所以,必须保证应用程序能够访问到sqlakw32.dll、ntwdblib.dll和dbnmpntw.dll。预编译器nsqlprep.exe有很多选项,具体这些选项信息可参见帮助。<BR>l“cl
-o demo.exe e:\mssql7\devtools\lib\sqlakw32.lib
\<BR>e:\mssql7\devtools\lib\caw32.lib
demo.c”的作用是C源程序的编译和链接。cl是编译和链接命令的集成命令,编译的结果是产生demo.obj,在链接时,将C的系统库和SQL
Server提供的库文件(sqlakw32.lib和caw32.lib)同目标文件连接在一起。最后生成demo.exe。也可以使用“SET
LIB=e:\mssql7\devtools\LIB;%LIB%”语句设置库文件的环境信息。<BR>设置SQL
Server相关的头文件和库文件环境信息,也可以执行mssql7\devtools\samples\esqlc\setenv.bat程序完成。<BR>在运行demo.exe程序时,对于每个SQL语句,都调用相应的运行中的服务(如:sqlakw32.dll)。如果该语句是静态SQL语句,那么该服务执行SQL语句或执行一个已编译成功的存储过程(可以在编译时使用/SQLACCESS选项为静态SQL语句创建存储过程);如果该语句是动态SQL语句,那么该服务将SQL语句送到SQL
Server上处理。这个服务调用DB-Library,在客户和服务器之间传递数据。这些数据要么存放在主变量中,要么存放在SQLDA结构中。执行SQL语句的错误信息存放在SQLCA数据结构中。<BR>下图总结了整个处理过程。
<P>6-7
嵌入SQL程序处理过程<BR>一个应用中的静态SQL语句,可以在运行时才发送到服务器端处理(类似动态SQL语句),或者生成执行计划(access
plan)。一个执行计划就是一些存储过程。每个静态SQL语句可以生成一个存储过程。在预编译时,可以创建执行计划。如果在预编译时,服务器不可访问,那么预编译器创建绑定文件(bind
file)。绑定文件就是用来创建执行计划中的存储过程的一些Transact-SQL脚本。在运行应用程序前,你可以通过OSQL执行绑定文件。上面这个例子,在预编译时,未指定“/DB”和“/PASS”选项(用于生成执行计划)也未指定“/BIND”选项(用于生成绑定文件),所以我们生成的应用程序对SQL语句的处理是采用类似动态SQL语句的处理方式,即在运行时才将语句送到服务器端处理。<BR>Nsqlprep.exe编译器的作用是,找出SQL语句,语法分析这些语句,创建执行计划或绑定文件,最终生成C程序。<BR>当然,以上步骤的完整,也可以在VC++(版本2.0以上)集成环境中完成。<BR>6.3
嵌入SQL语句<BR>下表是所有的嵌入式SQL语句,“*”表示嵌入式SQL语句的名字同Transact-SQL语句相同。
<P>BEGIN DECLARE SECTION PREPARE <BR>CLOSE* SELECT INTO* <BR>CONNECT
TO SET ANSI_DEFAULTS <BR>DECLARE CURSOR* SET CONCURRENCY <BR>DELETE
(POSITIONED)* SET CONNECTION <BR>DELETE (SEARCHED)* SET
CURSOR_CLOSE_ON_COMMIT <BR>DESCRIBE SET CURSORTYPE <BR>DISCONNECT
SET FETCHBUFFER <BR>END DECLARE SECTION SET OPTION <BR>EXECUTE* SET
SCROLLOPTION <BR>EXECUTE IMMEDIATE UPDATE (POSITIONED)* <BR>FETCH*
UPDATE (SEARCHED)* <BR>GET CONNECTION WHENEVER <BR>OPEN*
<P>嵌入式SQL语句分为静态SQL语句和动态SQL语句两类。下面我们按照功能讲解这些语句。本节讲解静态SQL语句的作用。动态SQL语句将在下一节讲解。同动态SQL相关的一些语句也在下一节中讲解。<BR>6.3.1
声明嵌入SQL语句中使用的C变量<BR>1)、声明方法<BR>主变量(host
variable)就是在嵌入式SQL语句中引用主语言说明的程序变量(如例1中的last_name[]变量)。如:
<P>EXEC SQL BEGIN DECLARE SECTION;<BR>char first_name[50];<BR>char
last_name[] = "White";<BR>EXEC SQL END DECLARE
SECTION;<BR>…………<BR>EXEC SQL SELECT au_fname INTO
:first_name<BR>from authors where au_lname =
:last_name;<BR>………….<BR>在嵌入式SQL语句中使用主变量前,必须采用BEGIN DECLARE SECTION
和END DECLARE
SECTION之间给主变量说明。这两条语句不是可执行语句,而是预编译程序的说明。主变量是标准的C程序变量。嵌入SQL语句使用主变量来输入数据和输出数据。C程序和嵌入SQL语句都可以访问主变量。<BR>值得注意的是,主变量的长度不能超过30字节。<BR>2)、主变量的数据类型<BR>在以SQL为基础的DBMS支持的数据类型与程序<A
href="http://school.21tx.com/photo/"
target=_blank>设计</A>语言支持的数据类型之间有很大差别。这些差别对主变量影响很大。一方面,主变量是一个用程序设计语言的数据类型说明并用程序设计语言处理的程序变量;另一方面,在嵌入SQL语句中用主变量保存数据库数据。所以,在嵌入SQL语句中,必须映射C数据类型为合适的SQL
Server数据类型。必须慎重选择主变量的数据类型。在SQL
SERVER中,很多数据类型都能够自动转换。请看下面这个例子:<BR>EXEC SQL BEGIN DECLARE
SECTION;<BR>int hostvar1 = 39;<BR>char *hostvar2 =
"telescope";<BR>float hostvar3 = 355.95;<BR>EXEC SQL END DECLARE
SECTION;
<P>EXEC SQL UPDATE inventory<BR>SET department = :hostvar1<BR>WHERE
part_num = "4572-3";
<P>EXEC SQL UPDATE inventory<BR>SET prod_descrip =
:hostvar2<BR>WHERE part_num = "4572-3";
<P>EXEC SQL UPDATE inventory<BR>SET price = :hostvar3<BR>WHERE
part_num =
"4572-3";<BR>在第一个update语句中,department列为smallint数据类型(integer
),所以应该把hostvar1定义为int数据类型(integer)。这样的话,从C到SQL
Server的hostvar1可以直接映射。在第二个update语句中,prod_descip列为varchar数据类型,所以应该把hostvar2定义为字符数组。这样的话,从C到SQL
Server的hostvar2可以从字符数组映射为varchar数据类型。在第三个update语句中,price列为money数据类型。在C语言中,没有相应的数据类型,所以用户可以把hostvar3定义为C的浮点变量或字符数据类型。SQL
Server可以自动将浮点变量转换为money数据类型(输入数据),或将money数据类型转换为浮点变量(输出数据)。<BR>注意的是,如果数据类型为字符数组,那么SQL
Server会在数据后面填充空格,直到填满该变量的声明长度。<BR>在ESQL/C中,不支持所有的unicode数据类型(如:nvarchar、nchar和ntext)。对于非unicode数据类型,除了datetime、smalldatetime、money和smallmoney外(decimal和numeric数据类型部分情况下不支持),都可以相互转换。<BR>下表列出了C的数据类型和datetime、smalldatetime、money、smallmoney、decimal和numeric数据类型的一些转换关系:<BR>C数据类型分配的SQL
Server数据类型Datetime或smalldatetimeMoney或smallmoneyDecimal或numeric<BR>shortSmallint不可以不可以不可以<BR>IntSmallint不可以不可以不可以<BR>LongInt不可以不可以不可以<BR>FloatReal不可以不可以不可以<BR>DoubleFloat不可以不可以不可以<BR>CharCarchar[X]可以可以可以<BR>Void
*pBinary(2)可以可以可以<BR>Char
bytetinyint不可以不可以不可以<BR>因为C没有date或time数据类型,所以SQL
Server的date或time列将被转换为字符。缺省情况下,使用以下转换格式:mm dd yyyy hh:mm:ss[am |
pm]。你也可以使用字符数据格式将C的字符数据存放到SQL
Server的date列上。你也可以使用Transact-SQL中的convert语句来转换数据类型。如:SELECT
CONVERT(char, date, 8) FROM sales。
<P>3)、主变量和NULL<BR>大多数程序设计语言(如C)都不支持NULL。所以对NULL的处理,一定要在SQL中完成。我们可以使用主机指示符变量(host
indicator
variable)来解决这个问题。在嵌入式SQL语句中,主变量和指示符变量共同规定一个单独的SQL类型值。如:<BR>EXEC SQL
SELECT price INTO :price:price_nullflag FROM titles <BR>WHERE au_id
=
"mc3026"<BR>其中,price是主变量,price_nullflag是指示符变量。指示符变量共有两类值:<BR>l-1。表示主变量应该假设为NULL。(注意:主变量的实际值是一个无关值,不予考虑)。<BR>l>0。表示主变量包含了有效值。该指示变量存放了该主变量数据的最大长度。<BR>所以,上面这个例子的含义是:如果不存在mc3026写的书,那么price_nullflag为-1,表示price为NULL;如果存在,则price为实际的价格。<BR>下面我们再看一个update的例子:<BR>EXEC
SQL UPDATE closeoutsale<BR>SET temp_price = :saleprice
:saleprice_null, listprice =
:oldprice;<BR>如果saleprice_null是-1,则上述语句等价为:<BR>EXEC SQL UPDATE
closeoutsale<BR>SET temp_price = null, listprice =
:oldprice;<BR>我们也可以在指示符变量前面加上“INDICATOR”关键字,表示后面的变量为指示符变量。如:<BR>EXEC
SQL UPDATE closeoutsale<BR>SET temp_price = :saleprice INDICATOR
:saleprice_null;<BR>值得注意的是,不能在WHERE语句后面使用指示符变量。如:<BR>EXEC SQL DELETE
FROM closeoutsale<BR>WHERE temp_price = :saleprice
:saleprice_null;<BR>你可以使用下面语句来完成上述功能:<BR>if (saleprice_null ==
-1)<BR>{<BR>EXEC SQL DELETE FROM closeoutsale<BR>WHERE temp_price IS
null;<BR>}<BR>else<BR>{<BR>EXEC SQL DELETE FROM
closeoutsale<BR>WHERE temp_price = :saleprice;<BR>}
<P>为了便于识别主变量,当嵌入式SQL语句中出现主变量时,必须在变量名称前标上冒号(:)。冒号的作用是,告诉预编译器,这是个主变量而不是表名或列名。<BR>6.3.2
连接数据库<BR>在程序中,使用“CONNECT TO”语句来连接数据库。该语句的完整语法为:<BR>CONNECT TO
{[server_name.]database_name} [AS connection_name] USER
[login[.password] | $integrated]
<BR>其中,<BR>lserver_name为服务器名。如省略,则为本地服务器名。<BR>ldatabase_name为数据库名。<BR>lconnection_name为连接名。可省略。如果你仅仅使用一个连接,那么无需指定连接名。可以使用SET
CONNECTION来使用不同的连接。<BR>llogin为登录名。<BR>lpassword为密码。<BR>在上例中的“ EXEC
SQL CONNECT TO YANGZH.pubs USER sa.password;
”,服务器是YANGZH,数据库为pubs,登录名为sa,密码为password。缺省的超时时间为10秒。如果指定连接的服务器没有响应这个连接请求,或者连接超时,那么系统会返回错误信息。我们可以使用“SET
OPTION”命令设置连接超时的时间值。<BR>在嵌入SQL语句中,使用DISCONNECT语句断开数据库的连接。其语法为:<BR>DISCONNECT
[connection_name | ALL |
CURRENT]<BR>其中,connection_name为连接名。ALL表示断开所有的连接。CURRENT表示断开当前连接。请看下面这些例子来理解CONNECT和DISCONNECT语句。
<P>EXEC SQL CONNECT TO caffe.pubs AS caffe1 USER sa;<BR>EXEC SQL
CONNECT TO latte.pubs AS latte1 USER sa;<BR>EXEC SQL SET CONNECTION
caffe1;<BR>EXEC SQL SELECT name FROM sysobjects INTO :name;<BR>EXEC
SQL SET CONNECTION latte1;<BR>EXEC SQL SELECT name FROM sysobjects
INTO :name;<BR>EXEC SQL DISCONNECT caffe1;<BR>EXEC SQL DISCONNECT
latte1;<BR>在上面这个例子中,第一个select 语句查询在caffe服务器上的pubs
数据库。第二个SELECT语句查询在latte服务器上的pubs数据库。当然,你也可以使用“EXEC SQL DISCONNECT
ALL; ”来断开所有的连接。<BR>6.3.3 数据的查询和修改<BR>可以使用SELECT
INTO语句查询数据,并将数据存放在主变量中。如上例中的:<BR>EXEC SQL SELECT au_fname INTO
:first_name<BR>from authors where au_lname =
:last_name;<BR>使用DELETE语句删除数据。其语法类似于Transact-SQL中的DELETE语法。如:<BR>EXEC
SQL DELETE FROM authors WHERE au_lname =
'White'<BR>使用UPDATE语句可以更新数据。其语法就是Transact-SQL中的UPDATE语法。如:<BR>`EXEC
SQL UPDATE authors SET au_fname = 'Fred' WHERE au_lname =
'White'<BR>使用INSERT语句可以插入新数据。其语法就是Transact-SQL中的INSERT语法。如:<BR>EXEC
SQL INSERT INTO homesales (seller_name,
sale_price)<BR>real_estate('Jane Doe',
180000.00);<BR>多行数据的查询和修改请参见下一节——游标。<BR>6.3.4
游标的使用<BR>用嵌入式SQL语句查询数据分成两类情况。一类是单行结果,一类是多行结果。对于单行结果,可以使用SELECT
INTO语句;对于多行结果,你必须使用cursor(游标)来完成。游标(Cursor)是一个与SELECT语句相关联的符号名,它使用户可逐行访问由SQL
Server返回的结果集。先请看下面这个例子,这个例子的作用是逐行打印staff表的id、name、dept、
job、years、salary和comm的值。
<P>EXEC SQL DECLARE C1 CURSOR FOR<BR>SELECT id, name, dept, job,
years, salary, comm FROM staff;
<P>EXEC SQL OPEN c1;
<P>while (SQLCODE == 0)<BR>{<BR>/* SQLCODE will be zero if data is
successfully fetched */
<P>EXEC SQL FETCH c1 INTO :id, :name, :dept, :job, :years, :salary,
:comm;<BR>if (SQLCODE == 0)<BR>printf("%4d %12s %10d %10s %2d %8d
%8d",<BR>id, name, dept, job, years, salary, comm);<BR>}<BR>EXEC SQL
CLOSE c1;
<P>从上例看出,你首先应该定义游标结果集,即
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -