ANSI实现动态 sql
1 2 /* 包含C头文件 */ 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <string.h> 6 7 /* 包含SQLCA头文件 */ 8 #include <sqlca.h> 9 10 /* 定义绑定变量值和 选择列表项值的最大长度 11 * 绑定变量:即在SQL语句中输入的“&”占位符。 12 */ 13 #define MAX_VAR_LEN 30 14 15 /* 定义选择列表项名的最大长度 */ 16 #define MAX_NAME_LEN 31 17 18 19 /* 定义宿主变量 */ 20 exec sql begin declare section; 21 char *usrname = "scott"; 22 char *passwd = "11"; 23 char *serverid = "orcl"; 24 char sql_stat[100]; 25 char current_date[20]; 26 exec sql end declare section; 27 28 void sql_error(void); 29 void connet(void); 30 void process_input(void); 31 void process_output(void); 32 33 int main(void) 34 { 35 /* 安装错误处理句柄 */ 36 exec sql whenever sqlerror do sql_error(); 37 38 /* 连接到数据库 */ 39 connet(); 40 41 /* 42 * 分配输入描述区和输出描述区 43 * Ansi定义了该套标准,proc程序开发者按标准实现了它 44 * 这两条语句在proc编译的时候会开辟对应大小的存储空间 45 */ 46 exec sql allocate descriptor 'input_descriptor'; //用来存储输入的宿主变量 47 exec sql allocate descriptor 'output_descriptor'; //用来缓存数据库端返回的结果集 48 49 for( ; ; ) 50 { 51 printf("\n请输入动态SQL语句(EXIT:退出):\n"); 52 gets(sql_stat); 53 54 /* EXIT(exit)->退出 */ 55 if(0 == strncmp(sql_stat , "EXIT" , 4) || 0 == strncmp(sql_stat , "exit" , 4)) 56 break; 57 58 /* 准备动态SQL语句 */ 59 exec sql prepare s from :sql_stat; 60 61 /* 定义游标 */ 62 exec sql declare c cursor for s; 63 64 /* 处理绑定变量 , 即处理占位符 “&” */ 65 process_input(); 66 67 /* 68 * 打开游标成功 意寓着结果已经被保存到输出描述区了。 69 * select语句:处理查询结果 70 * 其他SQL语句:执行 71 */ 72 exec sql open c using descriptor 'input_descriptor'; 73 if(0 == strncmp(sql_stat , "SELECT" , 6) , 0 == strncmp(sql_stat , "select" , 6)) 74 { 75 process_output(); 76 } 77 /* 关闭游标 */ 78 exec sql close c; 79 } 80 81 /* 释放输入描述区和输出描述区 */ 82 exec sql deallocate descriptor 'input_descriptor'; 83 exec sql deallocate descriptor 'output_descriptor'; 84 85 /* 提交事务,断开连接 */ 86 exec sql commit work release; 87 puts("谢谢使用ANSI动态SQL!\n"); 88 89 return 0; 90 } 91 92 void sql_error(void) 93 { 94 /* 显示SQL错误号、错误描述 */ 95 printf("%.*s\n" , sqlca.sqlerrm.sqlerrml , sqlca.sqlerrm.sqlerrmc); 96 exit(1); 97 } 98 99 void process_input(void) 100 { 101 int i; 102 103 /* 定义宿主变量 */ 104 exec sql begin declare section; 105 int input_count; 106 int input_type ; 107 int input_len; 108 char input_buffer[MAX_VAR_LEN]; 109 char name[MAX_NAME_LEN]; 110 int occurs; 111 exec sql end declare section; 112 113 /* 绑定变量->输入描述区 */ 114 exec sql describe input s using descriptor 'input_descriptor'; 115 116 /* 取得绑定变量个数 */ 117 exec sql get descriptor 'input_descriptor' :input_count = count; 118 119 /* 循环处理绑定变量名 */ 120 for(i = 0 ; i != input_count ; ++i) 121 { 122 occurs = i + 1; 123 124 /* 取得绑定变量名 */ 125 exec sql get descriptor 'input_descriptor' value :occurs :name = name; 126 printf("请输入%s的值:" , name); 127 gets(input_buffer); 128 129 /* 以NULL结尾 */ 130 input_len = strlen(input_buffer); 131 input_buffer[input_len] = '\0'; 132 133 /* 设置绑定变量类型、长度和值 */ 134 input_type = 1; 135 exec sql set descriptor 'input_descriptor' value :occurs 136 type = :input_type , length = :input_len , data = :input_buffer; 137 } 138 } 139 140 void process_output(void) 141 { 142 int i; 143 144 // 定义宿主变量 145 EXEC SQL BEGIN DECLARE SECTION ; 146 int output_count; 147 int output_type; 148 int output_len; 149 char output_buffer[MAX_VAR_LEN]; 150 short output_indicator; 151 char name[MAX_NAME_LEN]; 152 int occurs; 153 EXEC SQL END DECLARE SECTION ; 154 155 // 选择列表项->输出描述区 156 exec sql describe output s using descriptor 'output_descriptor'; 157 158 //取得选择列表项个数 159 exec sql get descriptor 'output_descriptor' :output_count = count; 160 161 //循环处理选择列表项(即列名,或者叫表头) 162 163 output_type = 12; //设置类型为变长字符串varchar 164 165 for(i = 0 ; i != output_count ; ++i) 166 { 167 occurs = i + 1; 168 169 output_len = MAX_VAR_LEN; 170 171 // 设置选择列表项的类型和长度(设置每一列,按照varchar类型进行显示) 172 exec sql set descriptor 'output_descriptor' value :occurs 173 type = :output_type , length = :output_len; 174 175 //取得选择列表项的名称并输出 176 exec sql get descriptor 'output_descriptor' value :occurs :name = name; 177 178 //显示选择列表项名称 179 printf("\t%s" , name); 180 } 181 printf("\n"); 182 183 // 提取数据完毕->退出循环 184 exec sql whenever not found do break; 185 186 // 循环处理选择列表项数据 187 for( ; ; ) 188 { 189 // 行数据-> fetch into 利用游标从输出描述区读取数据。 190 exec sql fetch c into descriptor 'output_descriptor'; 191 192 // 循环处理每列数据 193 for(i = 0 ; i < output_count ; ++i) 194 { 195 occurs = i + 1; 196 197 // 取得列数据和指示变量值 198 exec sql get descriptor 'output_descriptor' VALUE :occurs 199 :output_buffer = DATA , :output_indicator = INDICATOR; 200 201 //输出列数据 202 if(-1 == output_indicator) 203 printf("\t%s", " "); 204 else 205 printf("\t%s" , output_buffer); 206 } 207 printf("\n"); 208 } 209 } 210 211 void connet(void) 212 { 213 int ret = 0; 214 //连接数据库 215 EXEC SQL CONNECT:usrname IDENTIFIED BY:passwd USING:serverid ; 216 if (sqlca.sqlcode != 0) 217 { 218 ret = sqlca.sqlcode; 219 printf("sqlca.sqlcode: err:%d \n", sqlca.sqlcode); 220 return ; 221 } else { 222 printf("connect ok...\n"); 223 } 224 }
1.ASNI 与 ORACLE 实现动态sql的最大区别就在于不用关心描述区的动态扩容,因为ASNI已经封装好了接口,直接调用就成。
2.也是主要分为两部分:输出描述区和输入描述区。两个区的作用同ORACLE 功能一样。
* 分配输入描述区和输出描述区
* Ansi 定义了该套标准,proc 程序开发者按标准实现了它
* 这两条语句在 proc 编译的时候会开辟对应大小的存储空间
*/
exec sql allocate descriptor 'input_descriptor'; //用来存储输入的宿主变量
exec sql allocate descriptor 'output_descriptor'; //用来缓存数据库端返回的结果集
路之遥