📄 esql-c资料(完全版)三_unix_操作系统_网络学院_天新网.htm
字号:
<BR>#include <sqlca.h> <BR>main() <BR>{ emp_number =
7499;<BR>/* 处理错误*/ <BR>EXEC SQL WHENEVER SQLERROR do
sql_error("Oracle error");<BR>/* 连接到Oracle数据库*/ <BR>EXEC SQL CONNECT
:userid; <BR>printf("Connected.\n"); <BR>/* 声明游标 */ <BR>EXEC SQL
DECLARE emp_cursor CURSOR FOR <BR>SELECT ename FROM emp WHERE deptno
= :dept_number; <BR>printf("Department number? ");
<BR>gets(temp);<BR>dept_number = atoi(temp); <BR>/* 打开游标*/ <BR>EXEC
SQL OPEN emp_cursor; <BR>printf("Employee Name\n");
<BR>printf("-------------\n");<BR>/* 循环处理每一行数据,如果无数据,则退出*/<BR>EXEC
SQL WHENEVER NOT FOUND DO break;<BR>while (1) <BR>{ <BR>EXEC SQL
FETCH emp_cursor INTO :emp_name; <BR>printf("%s\n", emp_name); <BR>}
<BR>EXEC SQL CLOSE emp_cursor; <BR>EXEC SQL COMMIT WORK RELEASE;
<BR>exit(0); <BR>}<BR>/错误处理程序*/<BR>void sql_error(msg)<BR>char
*msg;<BR>{<BR>char buf[500];<BR>int buflen, msglen;<BR>EXEC SQL
WHENEVER SQLERROR CONTINUE; <BR>EXEC SQL ROLLBACK WORK RELEASE;
<BR>buflen = sizeof (buf);<BR>sqlglm(buf, &buflen,
&msglen);<BR>printf("%s\n", msg); <BR>printf("%*.s\n", msglen,
buf); <BR>exit(1); <BR>}<BR>4.2
嵌入PL/SQL<BR>嵌入PL/SQL和嵌入SQL不同。嵌入PL/SQL提供了很多嵌入SQL不具有的优点,如:更好的性能、更灵活的表达方式。能够自己定义过程和函数。如:<BR>PROCEDURE
create_dept <BR>(new_dname IN CHAR(14), <BR>new_loc IN CHAR(13),
<BR>new_deptno OUT NUMBER(2)) IS <BR>BEGIN <BR>SELECT
deptno_seq.NEXTVAL INTO new_deptno FROM dual; <BR>INSERT INTO dept
VALUES (new_deptno, new_dname, new_loc); <BR>END create_dept;
<BR>其中的IN/OUT,表示参数模式。IN是传递参数值到过程,而OUT是从过程传递参数值到调用者。<BR>但是,如果使用这些扩展的功能,也会造成同其他数据库厂商的嵌入SQL的不兼容。<BR>4.3
动态SQL语句<BR>4.3.1 ORACLE动态SQL语句的一些特点<BR>ORACLE
DBMS进入市场的时间早于DB2,其动态SQL支持是以IBM的system/R原型为基础的。因此,ORACLE支持的动态SQL与IBM的DB2标准有不同。虽然ORACLE和DB2在很大程度上是兼容的,但是在使用参数标志、SQLDA格式及支持数据类型转换等方面都有差异。<BR>DB2中不允许在PREPARE的动态语句中引用宿主变量,而是用问号来标志语句中的参数,然后用EXECUTE或OPEN语句来规定参数值。ORACLE允许用户用宿主变量规定动态语句中的参数。<BR>而且,ORACLE支持的DESCRIBE语句同DB2有一些区别。如:<BR>从已经PREPARE后的动态查询语句中获得对查询结果列的信息的语句为:<BR>EXEC
SQL DESCRIBE SELECT LIST FOR qrystmt INTO
qry_sqlda;<BR>等价于DB2的:<BR>EXEC SQL DESCRIBE qrystmt INTO
qry_sqlda;<BR>从已经PREPARE后的动态查询语句中获得对查询参数的说明的语句为:<BR>EXEC SQL
DESCRIBE BIND LIST FOR qrystmt INTO
qry_sqlda;<BR>该ORACLE语句没有对应的DB2语句。用户只能按照当前需要的参数和SQLDA的结构对SQLDA赋值。然后再在OPEN语句或EXECUTE语句中使用SQLDA结构。<BR>4.3.2
使用动态SQL的四种方法<BR>使用动态SQL,共分成四种方法:
<P>方法 支持的SQL语句
<P>1 该语句不包含宿主变量,该语句不是查询语句<BR>2 该语句包含输入宿主变量 ,该语句不是查询语句<BR>3
包含已知数目的输入宿主变量或列的查询 <BR>4 包含未知数目的输入宿主变量或列的查询 <BR>l方法1:使用EXECUTE
IMMEDIATE命令实现,具体语法为:<BR>EXEC SQL EXECUTE IMMEDIATE { :host_string |
string_literal
};<BR>其中,host_variable和string是存放完整T-SQL语句。<BR>请看下面这个例子。这个例子的作用是执行用户随意输入的合法的SQL语句。<BR>char
dyn_stmt[132]; <BR>... <BR>for (;;) <BR>{ <BR>printf("Enter SQL
statement: "); <BR>gets(dyn_stmt); <BR>if (*dyn_stmt == '\0')
<BR>break; <BR>/* dyn_stmt now contains the text of a SQL statement
*/ <BR>EXEC SQL EXECUTE IMMEDIATE :dyn_stmt; <BR>} <BR>...
<BR>EXECUTE
IMMEDIATE命令的作用是:分析该语句的语法,然后执行该语句。方法1适合于仅仅执行一次的语句。<BR>l方法2:方法支持的语句可以包含输入宿主变量。这个语句首先做PREPARE操作,然后通过EXECUTE执行。PREPARE语句的语法为:<BR>EXEC
SQL PREPARE statement_name FROM { :host_string | string_literal
};<BR>该语句接收含有SQL语句串的宿主变量,并把该语句送到ORACLE。ORACLE编译语句并生成执行计划。在语句串中包含一个“?”表明参数,当执行语句时,ORACLE需要参数来替代这些“?”。PREPRARE执行的结果是,DBMS用语句名标志准备后的语句。在执行SQL语句时,EXECUTE语句后面是这个语句名。EXECUTE语句的语法为:<BR>EXECUTE
语句名 USING 宿主变量 | DESCRIPTOR
描述符名<BR>它的作用是,请求ORACLE执行PREPARE语句准备好的语句。当要执行的动态语句中包含一个或多个参数标志时,在EXECUTE语句必须为每一个参数提供值。这样的话,EXECUTE语句用宿主变量值逐一代替准备语句中的参数标志(“?”或其他占位符),从而,为动态执行语句提供了输入值。<BR>使用主变量提供值,USING子句中的主变量数必须同动态语句中的参数标志数一致,而且每一个主变量的数据类型必须同相应参数所需的数据类型相一致。各主变量也可以有一个伴随主变量的指示符变量。当处理EXECUTE语句时,如果指示符变量包含一个负值,就把NULL值赋予相应的参数标志。除了使用主变量为参数提供值,也可以通过SQLDA提供值。<BR>请看下面这个例子。这个例子的作用是删除用户指定的雇员信息。<BR>...
<BR>int emp_number INTEGER; <BR>char delete_stmt[120],
search_cond[40];; <BR>... <BR>strcpy(delete_stmt, "DELETE FROM EMP
WHERE EMPNO = :n AND "); <BR>printf("Complete the following
statement's search condition--\n"); <BR>printf("%s\n", delete_stmt);
<BR>gets(search_cond); <BR>strcat(delete_stmt, search_cond);
<BR><BR>EXEC SQL PREPARE sql_stmt FROM :delete_stmt; <BR>for (;;)
<BR>{
<P>printf("Enter employee number: "); <BR>gets(temp);<BR>emp_number
= atoi(temp); <BR>if (emp_number == 0) <BR>break; <BR>EXEC SQL
EXECUTE sql_stmt USING :emp_number; <BR>}
<BR>l方法三:是指查询的列数或输入宿主变量数在预编译时已经确定,但是数据库中的对象,如表、列名等信息未确定。这些对象名不能是宿主变量。这时,必须通过以下语句来完成:<BR>PREPARE
statement_name FROM { :host_string | string_literal }; <BR>DECLARE
cursor_name CURSOR FOR statement_name; <BR>OPEN cursor_name [USING
host_variable_list]; <BR>FETCH cursor_name INTO host_variable_list;
<BR>CLOSE cursor_name; <BR>如:下面这个例子演示用方法3完成动态查询:<BR>char
select_stmt[132] =<BR>"SELECT MGR, JOB FROM EMP WHERE SAL <
:salary"; <BR>EXEC SQL PREPARE sql_stmt FROM :select_stmt; <BR>EXEC
SQL DECLARE emp_cursor CURSOR FOR sql_stmt; <BR>EXEC SQL OPEN
emp_cursor USING :salary; <BR>EXEC SQL FETCH emp_cursor INTO
:mgr_number, :job_title; <BR>EXEC SQL CLOSE emp_cursor;
<BR>l方法四:在预编译时,查询的列数或者宿主变量的个数不能确定,因为不知道具体的返回个数,所以不能使用输出宿主变量。这是因为你不知道应该定义多少个宿主变量。这时,就需要SQLDA结构和DESCRIBE命令。SQLDA包含了动态查询的列描述信息。对于输入宿主变量,也可以使用SQLDA来完成不确定的参数说明。要完成方法四,必须通过以下语句来完成:<BR>EXEC
SQL PREPARE statement_name FROM { :host_string | string_literal };
<BR>EXEC SQL DECLARE cursor_name CURSOR FOR statement_name; <BR>EXEC
SQL DESCRIBE BIND VARIABLES FOR statement_name <BR>INTO
bind_descriptor_name; <BR>EXEC SQL OPEN cursor_name <BR>[USING
DESCRIPTOR bind_descriptor_name]; <BR>EXEC SQL DESCRIBE [SELECT LIST
FOR] statement_name <BR>INTO select_descriptor_name; <BR>EXEC SQL
FETCH cursor_name USING DESCRIPTOR select_descriptor_name; <BR>EXEC
SQL CLOSE cursor_name; <BR>在上述语句中,DESCRIBE SELECT
LIST的作用是将PREPARE后的动态查询语句的列名、数据类型、长度等信息保存在SQLDA中。DESCRIBE BIND
VARIABLES的作用是,检查PREPARE后的动态查询语句的每个占位符的名字、数据类型、长度等信息。并将它存放在SQLDA中,然后,使用SQLDA提示用户数据参数值。<BR>值得注意的是,方法之间可以混合使用。如:在一个查询中,列的个数确定,但是查询中的占位符不确定,这时,你可以结合方法3和方法4,即使用方法3的FETCH语句和方法4的OPEN语句,如:EXEC
SQL FETCH emp_cursor INTO host_variable_list;
反之,如果查询中占位符的个数确定,而列数不确定,则你可以使用方法3的OPEN语句,如:EXEC SQL OPEN cursor_name
[USING host_variable_list];
<BR>这里,我们讲解的是嵌入SQL,对于嵌入PL/SQL,有一些区别。简单来说,主要有两点:<BR>l预编译器将PL/SQL块中的所有宿主变量都作为输入宿主变量。<BR>l不能对PL/SQL块使用FETCH命令。<BR>l占位符不用声明,可以是任何名字。如:<BR>INSERT
INTO emp (empno, deptno) VALUES (:e, :d) <BR>DELETE FROM dept WHERE
deptno = :num OR loc = :loc <BR>其中的e、d、num和loc就是占位符。<BR>4.3.3
SQLDA<BR>SQLDA存放了输出数据的信息,或存放了输入数据的信息。可以使用SQLSQLDAAlloc(runtime_context,
size, name_length,
ind_name_length)来分配空间。<BR>SQLDA结构的定义存放在sqlda.h文件中。它的内容为:<BR>struct
SQLDA <BR>{ <BR>long N; /* Descriptor size in number of entr<A
href="http://school.21tx.com/office/ie/" target=_blank>IE</A>s */
<BR>char **V; /*Ptr to Arr of addresses of main variables */
<BR>long *L; /* Ptr to Arr of lengths of buffers */ <BR>short *T; /*
Ptr to Arr of types of buffers */ <BR>short **I; /* Ptr to Arr of
addresses of indicator vars */ <BR>long F; /* Number of variables
found by DESCRIBE */ <BR>char **S; /* Ptr to Arr of variable name
pointers */ <BR>short *M; /* Ptr to Arr of max lengths of var. names
*/ <BR>short *C; /* Ptr to Arr of current lengths of var. names */
<BR>char **X; /* Ptr to Arr of ind. var. name pointers */ <BR>short
*Y; /* Ptr to Arr of max lengths of ind. var. names */ <BR>short *Z;
/* Ptr to Arr of cur lengths of ind. var. names */ <BR>};
<BR>其中,上述变量的含义为:<BR>lN:可以容纳的列的最大数目或参数的最大数目。它对应于DB2的SQLDA的SQLN字段。<BR>lF:当前SQLDA中的实际列数或参数个数。它对应于DB2的SQLDA的SQLD字段。<BR>lT:指明数据类型。它对应于DB2的SQLVAR结构中的SQLTYPE字段。
<P>lV:指向字符数组。该字符数组可能是列的数据,或传送参数的数据。它对应于DB2的SQLVAR结构中的SQLDATA字段。<BR>lL:给出列或参数值的长度。它对应于DB2的SQLVAR结构中的SQLLEN字段。<BR>lI:指向指示符变量,标志数据是否为NULL。它对应于DB2的SQLVAR结构中的SQLIND字段。<BR>lS:指向存放列名或参数名的字符数组。它对应于DB2的SQLVAR结构中的SQLNAME结构的data[]。<BR>lM:指向一个整数,该整数是S的申请长度。在DB2中,SQLVAR结构中的SQLNAME结构的data[30]的大小是固定的,即是30。而ORACLE中是可变的。其大小为M指向的整数。<BR>lC:指向一个整数,该整数是S的实际长度。它对应于DB2的SQLVAR结构中的SQLNAME结构的
length。<BR>lX:指向一个字符数组。该字符数组存放了指示符变量的名称,指示符变量表示传递的参数是否为NULL。DB2中无相应的对应字段。这个缓冲区仅仅供DESCRIBE
BIND
LIST语句使用。<BR>lY:指向一个整数,该整数是X的申请的最大长度。DB2中无相应的对应字段。<BR>lZ:指向一个整数,该整数是X的实际长度。DB2中无相应的对应字段。<BR>ORACLE的数据类型分成两种情况:内部数据类型和外部数据类型。ORACLE的内部数据类型是ORACLE在数据库中存放数据的类型,在使用DESCRIBE
SELECT LIST命令,就返回内部数据类型代码。下表是所有的内部数据类型:
<P>Oracle 内部数据类型 代码
<P>VARCHAR2 1 <BR>NUMBER 2 <BR>LONG 8 <BR>ROWID 11 <BR>DATE 12
<BR>RAW 23 <BR>LONG RAW 24 <BR>CHARACTER (or CHAR) 96 <BR>MLSLABEL
106
<P>外部数据类型是输入宿主变量和输出宿主变量存放数据的类型。DESCRIBE BIND
VARIABLES命令将SQLDA中的数据类型代码置为0。所以,必须在OPEN语句前设置外部数据类型代码,以告诉ORACLE是什么外部数据类型。下表是具体的外部数据类型:
<P>外部数据类型 代码 C数据类型
<P>VARCHAR2 1 char[n] <BR>NUMBER 2 char[n] (n 22) <BR>INTEGER 3 int
<BR>FLOAT 4 float <BR>STRING 5 char[n+1] <BR>VARNUM 6 char[n] (n 22)
<BR>DECIMAL 7 float <BR>LONG 8 char[n] <BR>VARCHAR 9 char[n+2]
<BR>ROWID 11 char[n] <BR>DATE 12 char[n] <BR>VARRAW 15 char[n]
<BR>RAW 23 unsigned char[n] <BR>LONG RAW 24 unsigned char[n]
<BR>UNSIGNED 68 unsigned int <BR>DISPLAY 91 char[n] <BR>LONG VARCHAR
94 char[n+4] <BR>LONG VARRAW 95 unsigned char[n+4] <BR>CHAR 96
char[n] <BR>CHARF 96 char[n] <BR>CHARZ 97 char[n+1] <BR>MLSLABEL 106
char[n]
<P>当ORACLE从用户程序中接收参数值并向用户程序传送查询结果时,就在自己的内部数据格式与它所运行的计算机系统的数据格式之间自动进行数据转换。DESCRIBE
SELECT L
IST命令可以返回ORACLE的内部数据类型。对于字符数据,内部数据类型同外部数据类型是相一致的;而有些内部数据类型对应到外部数据类型后,导致处理复杂化,如:你想将NUMBER数据类型的值处理为C中的FLOAT,那么你可以设置相应的T值为FLOAT(4)和L值为FLOAT的长度。在FETCH时,ORACLE自动在内部数据类型和外部数据类型之间转换。
<P>在DB2的SQLVAR结构中,列的说明信息、数据等存放在一个单独的sqlvar结构中。而在ORACLE数据库中,不存在一个单独的结构来说明每列的信息。而是通过数组的方式实现。如下图所示,描述了1个输入参数,参数名为bonus。假设的最大参数个数为3。
<P>
<P>
<P>
<P>
<P>
<P>
<P>
<P>
<P>
<P>
<P>
<P>
<P>
<P><BR>SQLDA结构<BR>N=3<BR>V<BR>L<BR>T<BR>I<BR>F=1
describe设置<BR>S<BR>N<BR>C<BR>X<BR>Y<BR>Z<BR>图6-5 SQLDA结构示例
<P>下面这个例子是一个adhoc程序。用户输入任何合法的SQL语句(可以带参数),该程序能够处理这个语句,并打印出结果。这个例子非常经典,说明使用SQLDA的两个功能。
<P><BR>#include <stdio.h><BR>#include
<string.h><BR>#include <setjmp.h>
<P>/* 列的最大数目或宿主变量的最大个数*/<BR>#define MAX_ITEMS 40<BR>/*
列名的最大长度或指示符的最大长度*/<BR>#define MAX_VNAME_LEN 30<BR>#define
MAX_INAME_LEN 30<BR>#ifndef NULL<BR>#define NULL 0<BR>#endif
<P>char *dml_commands[] = {"SELECT", "select", "INSERT",
"insert",<BR>"UPDATE", "update", "DELETE", "delete"};<BR>EXEC SQL
BEGIN DECLARE SECTION;<BR>char dyn_statement[1024];<BR>EXEC SQL VAR
dyn_statement IS STRING(1024);<BR>EXEC SQL END DECLARE
SECTION;<BR>EXEC SQL INCLUDE sqlca;<BR>EXEC SQL INCLUDE
sqlda;<BR>SQLDA *bind_dp;<BR>SQLDA *select_dp;<BR>extern SQLDA
*SQLSQLDAAlloc();<BR>extern void sqlnul();
<P>/* Define a buffer to hold longjmp state info. */<BR>jmp_buf
jmp_continue;
<P>/* A global flag for the error routine. */<BR>int parse_flag = 0;
<P>main()<BR>{<BR>int oracle_connect();<BR>int
alloc_descriptors();<BR>int get_dyn_statement();<BR>int
set_bind_variables();<BR>int process_select_list();<BR>int i;
<P>/*连接到数据库 */<BR>if (oracle_connect() != 0)<BR>exit(1);<BR>/*
为SQLDA分配空间*/<BR>if (alloc_descriptors(MAX_ITEMS, MAX_VNAME_LEN,
MAX_INAME_LEN) != 0)<BR>exit(1);<BR>/* 处理SQL 语句*/<BR>for (;;)
<BR>{<BR>i = setjmp(jmp_continue);<BR>/* 获取SQL语句。输入"exit"表示退出
*/<BR>if (get_dyn_statement() != 0)<BR>break;<BR>/*
对该SQL语句做PREPARE操作 */<BR>EXEC SQL WHENEVER SQLERROR DO
sql_error();<BR>parse_flag = 1; /* Set a flag for sql_error().
*/<BR>EXEC SQL PREPARE S FROM :dyn_statement;<BR>parse_flag = 0; /*
Unset the flag. */<BR>/*声明游标*/<BR>EXEC SQL DECLARE C CURSOR FOR
S;<BR>/* 提示用户输入参数值*/<BR>set_bind_variables();<BR>/* 打开游标 */<BR>EXEC
SQL OPEN C USING DESCRIPTOR bind_dp;
<P>/* 处理语句,并输出结果*/<BR>process_select_list();
<P>/*输出处理的行数. */<BR>for (i = 0; i < 8; i++)<BR>{<BR>if
(strncmp(dyn_statement, dml_commands[i], 6) ==
0)<BR>{<BR>printf("\n\n%d row%c
processed.\n",<BR>sqlca.sqlerrd[2],<BR>sqlca.sqlerrd[2] == 1 ? '\0'
: 's');<BR>break;<BR>}<BR>}<BR>} /* end of for(;;)
statement-processing loop */
<P>/* 释放申请的空间*/<BR>for (i = 0; i < MAX_ITEMS; i++)<BR>{ <BR>if
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -