dynfull.e 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. /*
  2. * Program type: Embedded Dynamic SQL
  3. *
  4. * Description:
  5. * This program prompts for and executes unknown SQL statements.
  6. * The contents of this file are subject to the Interbase Public
  7. * License Version 1.0 (the "License"); you may not use this file
  8. * except in compliance with the License. You may obtain a copy
  9. * of the License at http://www.Inprise.com/IPL.html
  10. *
  11. * Software distributed under the License is distributed on an
  12. * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
  13. * or implied. See the License for the specific language governing
  14. * rights and limitations under the License.
  15. *
  16. * The Original Code was created by Inprise Corporation
  17. * and its predecessors. Portions created by Inprise Corporation are
  18. * Copyright (C) Inprise Corporation.
  19. *
  20. * All Rights Reserved.
  21. * Contributor(s): ______________________________________.
  22. */
  23. #include "example.h"
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <time.h>
  28. #include <ctype.h>
  29. #include <ibase.h>
  30. #include "align.h"
  31. #define MAXLEN 1024
  32. #define EOFIND -1
  33. void process_statement (XSQLDA **sqlda, char *query);
  34. void print_column (XSQLVAR *var);
  35. int get_statement (char *buf);
  36. typedef struct vary2 {
  37. short vary_length;
  38. char vary_string [1];
  39. } VARY2;
  40. #ifndef ISC_INT64_FORMAT
  41. /* Define a format string for printf. Printing of 64-bit integers
  42. is not standard between platforms */
  43. #if (defined(_MSC_VER) && defined(WIN32))
  44. #define ISC_INT64_FORMAT "I64"
  45. #else
  46. #define ISC_INT64_FORMAT "ll"
  47. #endif
  48. #endif
  49. EXEC SQL
  50. SET SQL DIALECT 3;
  51. EXEC SQL
  52. SET DATABASE db = COMPILETIME "employee.fdb";
  53. int main(int argc, char** argv)
  54. {
  55. char query[MAXLEN];
  56. XSQLDA *sqlda;
  57. char db_name[128];
  58. if (argc < 2)
  59. {
  60. printf("Enter the database name: ");
  61. gets(db_name);
  62. }
  63. else
  64. strcpy(db_name, *(++argv));
  65. EXEC SQL
  66. CONNECT :db_name AS db;
  67. if (SQLCODE)
  68. {
  69. printf("Could not open database %s\n", db_name);
  70. return(1);
  71. }
  72. /*
  73. * Allocate enough space for 20 fields.
  74. * If more fields get selected, re-allocate SQLDA later.
  75. */
  76. sqlda = (XSQLDA *) malloc(XSQLDA_LENGTH (20));
  77. sqlda->sqln = 20;
  78. sqlda->version = 1;
  79. /*
  80. * Process SQL statements.
  81. */
  82. while (get_statement(query))
  83. {
  84. process_statement(&sqlda, query);
  85. }
  86. EXEC SQL
  87. DISCONNECT db;
  88. return(0);
  89. }
  90. void process_statement(XSQLDA** sqldap, char* query)
  91. {
  92. int buffer[MAXLEN];
  93. XSQLVAR *var;
  94. XSQLDA *sqlda;
  95. short num_cols, i;
  96. short length, alignment, type, offset;
  97. sqlda = *sqldap;
  98. EXEC SQL
  99. WHENEVER SQLERROR GO TO Error;
  100. /* Start a transaction for each statement */
  101. EXEC SQL
  102. SET TRANSACTION;
  103. EXEC SQL
  104. PREPARE q INTO SQL DESCRIPTOR sqlda FROM :query;
  105. EXEC SQL
  106. DESCRIBE q INTO SQL DESCRIPTOR sqlda;
  107. /*
  108. * Execute a non-select statement.
  109. */
  110. if (!sqlda->sqld)
  111. {
  112. EXEC SQL
  113. EXECUTE q;
  114. EXEC SQL
  115. COMMIT;
  116. return ;
  117. }
  118. /*
  119. * Process select statements.
  120. */
  121. num_cols = sqlda->sqld;
  122. /* Need more room. */
  123. if (sqlda->sqln < num_cols)
  124. {
  125. free(sqlda);
  126. sqlda = (XSQLDA *) malloc(XSQLDA_LENGTH (num_cols));
  127. sqlda->sqln = num_cols;
  128. sqlda->sqld = num_cols;
  129. sqlda->version = 1;
  130. EXEC SQL
  131. DESCRIBE q INTO SQL DESCRIPTOR sqlda;
  132. num_cols = sqlda->sqld;
  133. }
  134. /* Open the cursor. */
  135. EXEC SQL
  136. DECLARE c CURSOR FOR q;
  137. EXEC SQL
  138. OPEN c;
  139. /*
  140. * Set up SQLDA.
  141. */
  142. for (var = sqlda->sqlvar, offset = 0, i = 0; i < num_cols; var++, i++)
  143. {
  144. length = alignment = var->sqllen;
  145. type = var->sqltype & ~1;
  146. if (type == SQL_TEXT)
  147. alignment = 1;
  148. else if (type == SQL_VARYING)
  149. {
  150. /* Allow space for vary's strlen & space to insert
  151. a null byte for printing */
  152. length += sizeof (short) + 1;
  153. alignment = sizeof (short);
  154. }
  155. offset = FB_ALIGN(offset, alignment);
  156. var->sqldata = (char*) buffer + offset;
  157. offset += length;
  158. offset = FB_ALIGN(offset, sizeof (short));
  159. var->sqlind = (short*) ((char*) buffer + offset);
  160. offset += sizeof (short);
  161. }
  162. /*
  163. * Print rows.
  164. */
  165. while (SQLCODE == 0)
  166. {
  167. EXEC SQL
  168. FETCH c USING SQL DESCRIPTOR sqlda;
  169. if (SQLCODE == 100)
  170. break;
  171. for (i = 0; i < num_cols; i++)
  172. {
  173. print_column(&sqlda->sqlvar[i]);
  174. }
  175. printf("\n");
  176. }
  177. EXEC SQL
  178. CLOSE c;
  179. EXEC SQL
  180. COMMIT;
  181. return;
  182. Error:
  183. EXEC SQL
  184. WHENEVER SQLERROR CONTINUE;
  185. printf("Statement failed. SQLCODE = %d\n", SQLCODE);
  186. fflush (stdout);
  187. isc_print_status(gds__status);
  188. EXEC SQL
  189. ROLLBACK;
  190. return;
  191. }
  192. /*
  193. * Print column's data.
  194. */
  195. void print_column(XSQLVAR* var)
  196. {
  197. short dtype;
  198. char data[MAXLEN], *p;
  199. char blob_s[20], date_s[25];
  200. VARY2 *vary2;
  201. short len;
  202. struct tm times;
  203. ISC_QUAD bid;
  204. dtype = var->sqltype & ~1;
  205. p = data;
  206. if ((var->sqltype & 1) && (*var->sqlind < 0))
  207. {
  208. switch (dtype)
  209. {
  210. case SQL_TEXT:
  211. case SQL_VARYING:
  212. len = var->sqllen;
  213. break;
  214. case SQL_SHORT:
  215. len = 6;
  216. if (var->sqlscale > 0) len += var->sqlscale;
  217. break;
  218. case SQL_LONG:
  219. len = 11;
  220. if (var->sqlscale > 0) len += var->sqlscale;
  221. break;
  222. case SQL_INT64:
  223. len = 21;
  224. if (var->sqlscale > 0) len += var->sqlscale;
  225. break;
  226. case SQL_FLOAT:
  227. len = 15;
  228. break;
  229. case SQL_DOUBLE:
  230. len = 24;
  231. break;
  232. case SQL_TIMESTAMP:
  233. len = 24;
  234. break;
  235. case SQL_TYPE_DATE:
  236. len = 10;
  237. break;
  238. case SQL_TYPE_TIME:
  239. len = 13;
  240. break;
  241. case SQL_BLOB:
  242. case SQL_ARRAY:
  243. default:
  244. len = 17;
  245. break;
  246. }
  247. if ((dtype == SQL_TEXT) || (dtype == SQL_VARYING))
  248. sprintf(p, "%-*s ", len, "NULL");
  249. else
  250. sprintf(p, "%*s ", len, "NULL");
  251. }
  252. else
  253. {
  254. switch (dtype)
  255. {
  256. case SQL_TEXT:
  257. sprintf(p, "%.*s ", var->sqllen, var->sqldata);
  258. break;
  259. case SQL_VARYING:
  260. vary2 = (VARY2*) var->sqldata;
  261. vary2->vary_string[vary2->vary_length] = '\0';
  262. sprintf(p, "%-*s ", var->sqllen, vary2->vary_string);
  263. break;
  264. case SQL_SHORT:
  265. case SQL_LONG:
  266. case SQL_INT64:
  267. {
  268. ISC_INT64 value;
  269. short field_width;
  270. short dscale;
  271. switch (dtype)
  272. {
  273. case SQL_SHORT:
  274. value = (ISC_INT64) *(short *) var->sqldata;
  275. field_width = 6;
  276. break;
  277. case SQL_LONG:
  278. value = (ISC_INT64) *(int *) var->sqldata;
  279. field_width = 11;
  280. break;
  281. case SQL_INT64:
  282. value = (ISC_INT64) *(ISC_INT64 *) var->sqldata;
  283. field_width = 21;
  284. break;
  285. }
  286. dscale = var->sqlscale;
  287. if (dscale < 0)
  288. {
  289. ISC_INT64 tens;
  290. short i;
  291. tens = 1;
  292. for (i = 0; i > dscale; i--)
  293. tens *= 10;
  294. if (value >= 0)
  295. sprintf (p, "%*" ISC_INT64_FORMAT "d.%0*" ISC_INT64_FORMAT "d",
  296. field_width - 1 + dscale,
  297. (ISC_INT64) value / tens,
  298. -dscale,
  299. (ISC_INT64) value % tens);
  300. else if ((value / tens) != 0)
  301. sprintf (p, "%*" ISC_INT64_FORMAT "d.%0*" ISC_INT64_FORMAT "d",
  302. field_width - 1 + dscale,
  303. (ISC_INT64) (value / tens),
  304. -dscale,
  305. (ISC_INT64) -(value % tens));
  306. else
  307. sprintf (p, "%*s.%0*" ISC_INT64_FORMAT "d",
  308. field_width - 1 + dscale,
  309. "-0",
  310. -dscale,
  311. (ISC_INT64) -(value % tens));
  312. }
  313. else if (dscale)
  314. sprintf (p, "%*" ISC_INT64_FORMAT "d%0*d",
  315. field_width,
  316. (ISC_INT64) value,
  317. dscale, 0);
  318. else
  319. sprintf (p, "%*" ISC_INT64_FORMAT "d%",
  320. field_width,
  321. (ISC_INT64) value);
  322. }
  323. break;
  324. case SQL_FLOAT:
  325. sprintf(p, "%15g ", *(float *) (var->sqldata));
  326. break;
  327. case SQL_DOUBLE:
  328. sprintf(p, "%24g ", *(double *) (var->sqldata));
  329. break;
  330. case SQL_TIMESTAMP:
  331. isc_decode_timestamp((ISC_TIMESTAMP *)var->sqldata, &times);
  332. sprintf(date_s, "%04d-%02d-%02d %02d:%02d:%02d.%04d",
  333. times.tm_year + 1900,
  334. times.tm_mon+1,
  335. times.tm_mday,
  336. times.tm_hour,
  337. times.tm_min,
  338. times.tm_sec,
  339. ((ISC_TIMESTAMP *)var->sqldata)->timestamp_time % 10000);
  340. sprintf(p, "%*s ", 24, date_s);
  341. break;
  342. case SQL_TYPE_DATE:
  343. isc_decode_sql_date((ISC_DATE *)var->sqldata, &times);
  344. sprintf(date_s, "%04d-%02d-%02d",
  345. times.tm_year + 1900,
  346. times.tm_mon+1,
  347. times.tm_mday);
  348. sprintf(p, "%*s ", 10, date_s);
  349. break;
  350. case SQL_TYPE_TIME:
  351. isc_decode_sql_time((ISC_TIME *)var->sqldata, &times);
  352. sprintf(date_s, "%02d:%02d:%02d.%04d",
  353. times.tm_hour,
  354. times.tm_min,
  355. times.tm_sec,
  356. (*((ISC_TIME *)var->sqldata)) % 10000);
  357. sprintf(p, "%*s ", 13, date_s);
  358. break;
  359. case SQL_BLOB:
  360. case SQL_ARRAY:
  361. bid = *(ISC_QUAD *) var->sqldata;
  362. sprintf(blob_s, "%08x:%08x", bid.gds_quad_high, bid.gds_quad_low);
  363. sprintf(p, "%17s ", blob_s);
  364. break;
  365. default:
  366. break;
  367. }
  368. }
  369. while (*p)
  370. {
  371. putchar(*p++);
  372. }
  373. }
  374. /*
  375. * Prompt for and get input.
  376. * Statements are terminated by a semicolon.
  377. */
  378. int get_statement(char* buf)
  379. {
  380. short c;
  381. char *p;
  382. int cnt;
  383. p = buf;
  384. cnt = 0;
  385. printf("SQL> ");
  386. for (;;)
  387. {
  388. if ((c = getchar()) == EOFIND)
  389. return 0;
  390. if (c == '\n')
  391. {
  392. /* accept "quit" or "exit" to terminate application */
  393. if (!strncmp(buf, "exit;", 5))
  394. return 0;
  395. if (!strncmp(buf, "quit;", 5))
  396. return 0;
  397. /* Search back through any white space looking for ';'.*/
  398. while (cnt && isspace(*(p - 1)))
  399. {
  400. p--;
  401. cnt--;
  402. }
  403. if (*(p - 1) == ';')
  404. {
  405. *p++ = '\0';
  406. return 1;
  407. }
  408. *p++ = ' ';
  409. printf("CON> ");
  410. }
  411. else
  412. *p++ = c;
  413. cnt++;
  414. }
  415. }