PageRenderTime 38ms CodeModel.GetById 11ms RepoModel.GetById 1ms app.codeStats 0ms

/tags/2.3.0/Drivers/Postgre7.1/parse.c

#
C | 790 lines | 558 code | 160 blank | 72 comment | 205 complexity | cba600660a9f45cf75e655c2897c99ae MD5 | raw file
Possible License(s): LGPL-2.1, AGPL-1.0
  1. /* Module: parse.c
  2. *
  3. * Description: This module contains routines related to parsing SQL statements.
  4. * This can be useful for two reasons:
  5. *
  6. * 1. So the query does not actually have to be executed to return data about it
  7. *
  8. * 2. To be able to return information about precision, nullability, aliases, etc.
  9. * in the functions SQLDescribeCol and SQLColAttributes. Currently, Postgres
  10. * doesn't return any information about these things in a query.
  11. *
  12. * Classes: none
  13. *
  14. * API functions: none
  15. *
  16. * Comments: See "notice.txt" for copyright and license information.
  17. *
  18. */
  19. #include <config.h>
  20. #include <stdio.h>
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include <ctype.h>
  24. #include "statement.h"
  25. #include "connection.h"
  26. #include "qresult.h"
  27. #include "pgtypes.h"
  28. #ifndef WIN32
  29. #ifndef HAVE_STRICMP
  30. #define stricmp(s1,s2) strcasecmp(s1,s2)
  31. #define strnicmp(s1,s2,n) strncasecmp(s1,s2,n)
  32. #endif
  33. #endif
  34. #define FLD_INCR 32
  35. #define TAB_INCR 8
  36. #define COL_INCR 16
  37. char *getNextToken(char *s, char *token, int smax, char *delim, char *quote, char *dquote, char *numeric);
  38. void getColInfo(COL_INFO *col_info, FIELD_INFO *fi, int k);
  39. char searchColInfo(COL_INFO *col_info, FIELD_INFO *fi);
  40. char *
  41. getNextToken(char *s, char *token, int smax, char *delim, char *quote, char *dquote, char *numeric)
  42. {
  43. int i = 0;
  44. int out = 0;
  45. char qc, in_escape = FALSE;
  46. if (smax <= 1)
  47. return NULL;
  48. smax--;
  49. /* skip leading delimiters */
  50. while (isspace((unsigned char) s[i]) || s[i] == ',') {
  51. /* mylog("skipping '%c'\n", s[i]); */
  52. i++;
  53. }
  54. if (s[0] == '\0') {
  55. token[0] = '\0';
  56. return NULL;
  57. }
  58. if (quote) *quote = FALSE;
  59. if (dquote) *dquote = FALSE;
  60. if (numeric) *numeric = FALSE;
  61. /* get the next token */
  62. while ( ! isspace((unsigned char) s[i]) && s[i] != ',' &&
  63. s[i] != '\0' && out != smax) {
  64. /* Handle quoted stuff */
  65. if ( out == 0 && (s[i] == '\"' || s[i] == '\'')) {
  66. qc = s[i];
  67. if (qc == '\"') {
  68. if (dquote) *dquote = TRUE;
  69. }
  70. if (qc == '\'') {
  71. if (quote) *quote = TRUE;
  72. }
  73. i++; /* dont return the quote */
  74. while (s[i] != '\0' && out != smax) {
  75. if (s[i] == qc && ! in_escape) {
  76. break;
  77. }
  78. if (s[i] == '\\' && ! in_escape) {
  79. in_escape = TRUE;
  80. }
  81. else {
  82. in_escape = FALSE;
  83. token[out++] = s[i];
  84. }
  85. i++;
  86. }
  87. if (s[i] == qc)
  88. i++;
  89. break;
  90. }
  91. /* Check for numeric literals */
  92. if ( out == 0 && isdigit((unsigned char) s[i])) {
  93. if (numeric) *numeric = TRUE;
  94. token[out++] = s[i++];
  95. while ( isalnum((unsigned char) s[i]) || s[i] == '.')
  96. token[out++] = s[i++];
  97. break;
  98. }
  99. if ( ispunct((unsigned char) s[i]) && s[i] != '_') {
  100. mylog("got ispunct: s[%d] = '%c'\n", i, s[i]);
  101. if (out == 0) {
  102. token[out++] = s[i++];
  103. break;
  104. }
  105. else
  106. break;
  107. }
  108. if (out != smax)
  109. token[out++] = s[i];
  110. i++;
  111. }
  112. /* mylog("done -- s[%d] = '%c'\n", i, s[i]); */
  113. token[out] = '\0';
  114. /* find the delimiter */
  115. while ( isspace((unsigned char) s[i]))
  116. i++;
  117. /* return the most priority delimiter */
  118. if (s[i] == ',') {
  119. if (delim) *delim = s[i];
  120. }
  121. else if (s[i] == '\0') {
  122. if (delim) *delim = '\0';
  123. }
  124. else {
  125. if (delim) *delim = ' ';
  126. }
  127. /* skip trailing blanks */
  128. while ( isspace((unsigned char) s[i])) {
  129. i++;
  130. }
  131. return &s[i];
  132. }
  133. #if 0
  134. QR_set_num_fields(stmt->result, 14);
  135. QR_set_field_info(stmt->result, 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
  136. QR_set_field_info(stmt->result, 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
  137. QR_set_field_info(stmt->result, 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
  138. QR_set_field_info(stmt->result, 3, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
  139. QR_set_field_info(stmt->result, 4, "DATA_TYPE", PG_TYPE_INT2, 2);
  140. QR_set_field_info(stmt->result, 5, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
  141. QR_set_field_info(stmt->result, 6, "PRECISION", PG_TYPE_INT4, 4);
  142. QR_set_field_info(stmt->result, 7, "LENGTH", PG_TYPE_INT4, 4);
  143. QR_set_field_info(stmt->result, 8, "SCALE", PG_TYPE_INT2, 2);
  144. QR_set_field_info(stmt->result, 9, "RADIX", PG_TYPE_INT2, 2);
  145. QR_set_field_info(stmt->result, 10, "NULLABLE", PG_TYPE_INT2, 2);
  146. QR_set_field_info(stmt->result, 11, "REMARKS", PG_TYPE_TEXT, 254);
  147. /* User defined fields */
  148. QR_set_field_info(stmt->result, 12, "DISPLAY_SIZE", PG_TYPE_INT4, 4);
  149. QR_set_field_info(stmt->result, 13, "FIELD_TYPE", PG_TYPE_INT4, 4);
  150. #endif
  151. void
  152. getColInfo(COL_INFO *col_info, FIELD_INFO *fi, int k)
  153. {
  154. if (fi->name[0] == '\0')
  155. strcpy(fi->name, QR_get_value_manual(col_info->result, k, 3));
  156. fi->type = atoi( QR_get_value_manual(col_info->result, k, 13));
  157. fi->precision = atoi( QR_get_value_manual(col_info->result, k, 6));
  158. fi->length = atoi( QR_get_value_manual(col_info->result, k, 7));
  159. fi->nullable = atoi( QR_get_value_manual(col_info->result, k, 10));
  160. fi->display_size = atoi( QR_get_value_manual(col_info->result, k, 12));
  161. }
  162. char
  163. searchColInfo(COL_INFO *col_info, FIELD_INFO *fi)
  164. {
  165. int k;
  166. char *col;
  167. for (k = 0; k < QR_get_num_tuples(col_info->result); k++) {
  168. col = QR_get_value_manual(col_info->result, k, 3);
  169. if ( ! strcmp(col, fi->name)) {
  170. getColInfo(col_info, fi, k);
  171. mylog("PARSE: searchColInfo: \n");
  172. return TRUE;
  173. }
  174. }
  175. return FALSE;
  176. }
  177. char
  178. parse_statement(StatementClass *stmt)
  179. {
  180. static char* const func="parse_statement";
  181. char token[256];
  182. char delim, quote, dquote, numeric, unquoted;
  183. char *ptr;
  184. char in_select = FALSE, in_distinct = FALSE, in_on = FALSE, in_from = FALSE, in_where = FALSE, in_table = FALSE;
  185. char in_field = FALSE, in_expr = FALSE, in_func = FALSE, in_dot = FALSE, in_as = FALSE;
  186. int j, i, k = 0, n, blevel = 0;
  187. FIELD_INFO **fi;
  188. TABLE_INFO **ti;
  189. char parse;
  190. ConnectionClass *conn = stmt->hdbc;
  191. HSTMT hcol_stmt;
  192. StatementClass *col_stmt;
  193. RETCODE result;
  194. mylog("%s: entering...\n", func);
  195. ptr = stmt->statement;
  196. fi = stmt->fi;
  197. ti = stmt->ti;
  198. stmt->nfld = 0;
  199. stmt->ntab = 0;
  200. while ((ptr = getNextToken(ptr, token, sizeof(token), &delim, &quote, &dquote, &numeric)) != NULL) {
  201. unquoted = ! ( quote || dquote );
  202. mylog("unquoted=%d, quote=%d, dquote=%d, numeric=%d, delim='%c', token='%s', ptr='%s'\n", unquoted, quote, dquote, numeric, delim, token, ptr);
  203. if ( unquoted && ! stricmp(token, "select")) {
  204. in_select = TRUE;
  205. mylog("SELECT\n");
  206. continue;
  207. }
  208. if ( unquoted && in_select && ! stricmp(token, "distinct")) {
  209. in_distinct = TRUE;
  210. mylog("DISTINCT\n");
  211. continue;
  212. }
  213. if ( unquoted && ! stricmp(token, "into")) {
  214. in_select = FALSE;
  215. mylog("INTO\n");
  216. continue;
  217. }
  218. if ( unquoted && ! stricmp(token, "from")) {
  219. in_select = FALSE;
  220. in_from = TRUE;
  221. mylog("FROM\n");
  222. continue;
  223. }
  224. if ( unquoted && (! stricmp(token, "where") ||
  225. ! stricmp(token, "union") ||
  226. ! stricmp(token, "order") ||
  227. ! stricmp(token, "group") ||
  228. ! stricmp(token, "having"))) {
  229. in_select = FALSE;
  230. in_from = FALSE;
  231. in_where = TRUE;
  232. mylog("WHERE...\n");
  233. break;
  234. }
  235. if (in_select) {
  236. if ( in_distinct) {
  237. mylog("in distinct\n");
  238. if (unquoted && ! stricmp(token, "on")) {
  239. in_on = TRUE;
  240. mylog("got on\n");
  241. continue;
  242. }
  243. if (in_on) {
  244. in_distinct = FALSE;
  245. in_on = FALSE;
  246. continue; /* just skip the unique on field */
  247. }
  248. mylog("done distinct\n");
  249. in_distinct = FALSE;
  250. }
  251. if ( in_expr || in_func) { /* just eat the expression */
  252. mylog("in_expr=%d or func=%d\n", in_expr, in_func);
  253. if (quote || dquote)
  254. continue;
  255. if (in_expr && blevel == 0 && delim == ',') {
  256. mylog("**** in_expr and Got comma\n");
  257. in_expr = FALSE;
  258. in_field = FALSE;
  259. }
  260. else if (token[0] == '(') {
  261. blevel++;
  262. mylog("blevel++ = %d\n", blevel);
  263. }
  264. else if (token[0] == ')') {
  265. blevel--;
  266. mylog("blevel-- = %d\n", blevel);
  267. if (delim==',') {
  268. in_func = FALSE;
  269. in_expr = FALSE;
  270. in_field = FALSE;
  271. }
  272. }
  273. continue;
  274. }
  275. if ( ! in_field) {
  276. if ( ! token[0])
  277. continue;
  278. if ( ! (stmt->nfld % FLD_INCR)) {
  279. mylog("reallocing at nfld=%d\n", stmt->nfld);
  280. fi = (FIELD_INFO **) realloc(fi, (stmt->nfld + FLD_INCR) * sizeof(FIELD_INFO *));
  281. if ( ! fi) {
  282. stmt->parse_status = STMT_PARSE_FATAL;
  283. return FALSE;
  284. }
  285. stmt->fi = fi;
  286. }
  287. fi[stmt->nfld] = (FIELD_INFO *) malloc( sizeof(FIELD_INFO));
  288. if (fi[stmt->nfld] == NULL) {
  289. stmt->parse_status = STMT_PARSE_FATAL;
  290. return FALSE;
  291. }
  292. /* Initialize the field info */
  293. memset(fi[stmt->nfld], 0, sizeof(FIELD_INFO));
  294. /* double quotes are for qualifiers */
  295. if (dquote)
  296. fi[stmt->nfld]->dquote = TRUE;
  297. if (quote) {
  298. fi[stmt->nfld++]->quote = TRUE;
  299. continue;
  300. }
  301. else if (numeric) {
  302. mylog("**** got numeric: nfld = %d\n", stmt->nfld);
  303. fi[stmt->nfld]->numeric = TRUE;
  304. }
  305. else if (token[0] == '(') { /* expression */
  306. mylog("got EXPRESSION\n");
  307. fi[stmt->nfld++]->expr = TRUE;
  308. in_expr = TRUE;
  309. blevel = 1;
  310. continue;
  311. }
  312. else {
  313. strcpy(fi[stmt->nfld]->name, token);
  314. fi[stmt->nfld]->dot[0] = '\0';
  315. }
  316. mylog("got field='%s', dot='%s'\n", fi[stmt->nfld]->name, fi[stmt->nfld]->dot);
  317. if (delim == ',') {
  318. mylog("comma (1)\n");
  319. }
  320. else {
  321. in_field = TRUE;
  322. }
  323. stmt->nfld++;
  324. continue;
  325. }
  326. /**************************/
  327. /* We are in a field now */
  328. /**************************/
  329. if (in_dot) {
  330. stmt->nfld--;
  331. strcpy(fi[stmt->nfld]->dot, fi[stmt->nfld]->name);
  332. strcpy(fi[stmt->nfld]->name, token);
  333. stmt->nfld++;
  334. in_dot = FALSE;
  335. if (delim == ',') {
  336. mylog("in_dot: got comma\n");
  337. in_field = FALSE;
  338. }
  339. continue;
  340. }
  341. if (in_as) {
  342. stmt->nfld--;
  343. strcpy(fi[stmt->nfld]->alias, token);
  344. mylog("alias for field '%s' is '%s'\n", fi[stmt->nfld]->name, fi[stmt->nfld]->alias);
  345. in_as = FALSE;
  346. in_field = FALSE;
  347. stmt->nfld++;
  348. if (delim == ',') {
  349. mylog("comma(2)\n");
  350. }
  351. continue;
  352. }
  353. /* Function */
  354. if (token[0] == '(') {
  355. in_func = TRUE;
  356. blevel = 1;
  357. fi[stmt->nfld-1]->func = TRUE;
  358. /* name will have the function name -- maybe useful some day */
  359. mylog("**** got function = '%s'\n", fi[stmt->nfld-1]->name);
  360. continue;
  361. }
  362. if (token[0] == '.') {
  363. in_dot = TRUE;
  364. mylog("got dot\n");
  365. continue;
  366. }
  367. if ( ! stricmp(token, "as")) {
  368. in_as = TRUE;
  369. mylog("got AS\n");
  370. continue;
  371. }
  372. /* otherwise, it's probably an expression */
  373. in_expr = TRUE;
  374. fi[stmt->nfld-1]->expr = TRUE;
  375. fi[stmt->nfld-1]->name[0] = '\0';
  376. mylog("*** setting expression\n");
  377. }
  378. if (in_from) {
  379. if ( ! in_table) {
  380. if ( ! token[0])
  381. continue;
  382. if ( ! (stmt->ntab % TAB_INCR)) {
  383. ti = (TABLE_INFO **) realloc(ti, (stmt->ntab + TAB_INCR) * sizeof(TABLE_INFO *));
  384. if ( ! ti) {
  385. stmt->parse_status = STMT_PARSE_FATAL;
  386. return FALSE;
  387. }
  388. stmt->ti = ti;
  389. }
  390. ti[stmt->ntab] = (TABLE_INFO *) malloc(sizeof(TABLE_INFO));
  391. if (ti[stmt->ntab] == NULL) {
  392. stmt->parse_status = STMT_PARSE_FATAL;
  393. return FALSE;
  394. }
  395. ti[stmt->ntab]->alias[0] = '\0';
  396. strcpy(ti[stmt->ntab]->name, token);
  397. mylog("got table = '%s'\n", ti[stmt->ntab]->name);
  398. if (delim == ',') {
  399. mylog("more than 1 tables\n");
  400. }
  401. else {
  402. in_table = TRUE;
  403. }
  404. stmt->ntab++;
  405. continue;
  406. }
  407. strcpy(ti[stmt->ntab-1]->alias, token);
  408. mylog("alias for table '%s' is '%s'\n", ti[stmt->ntab-1]->name, ti[stmt->ntab-1]->alias);
  409. in_table = FALSE;
  410. if (delim == ',') {
  411. mylog("more than 1 tables\n");
  412. }
  413. }
  414. }
  415. /*************************************************/
  416. /* Resolve any possible field names with tables */
  417. /*************************************************/
  418. parse = TRUE;
  419. /* Resolve field names with tables */
  420. for (i = 0; i < stmt->nfld; i++) {
  421. if (fi[i]->func || fi[i]->expr || fi[i]->numeric) {
  422. fi[i]->ti = NULL;
  423. fi[i]->type = -1;
  424. parse = FALSE;
  425. continue;
  426. }
  427. else if (fi[i]->quote) { /* handle as text */
  428. fi[i]->ti = NULL;
  429. fi[i]->type = PG_TYPE_TEXT;
  430. fi[i]->precision = 0;
  431. continue;
  432. }
  433. /* it's a dot, resolve to table or alias */
  434. else if (fi[i]->dot[0]) {
  435. for (k = 0; k < stmt->ntab; k++) {
  436. if ( ! stricmp(ti[k]->name, fi[i]->dot)) {
  437. fi[i]->ti = ti[k];
  438. break;
  439. }
  440. else if ( ! stricmp(ti[k]->alias, fi[i]->dot)) {
  441. fi[i]->ti = ti[k];
  442. break;
  443. }
  444. }
  445. }
  446. else if (stmt->ntab == 1)
  447. fi[i]->ti = ti[0];
  448. }
  449. mylog("--------------------------------------------\n");
  450. mylog("nfld=%d, ntab=%d\n", stmt->nfld, stmt->ntab);
  451. for (i=0; i < stmt->nfld; i++) {
  452. mylog("Field %d: expr=%d, func=%d, quote=%d, dquote=%d, numeric=%d, name='%s', alias='%s', dot='%s'\n", i, fi[i]->expr, fi[i]->func, fi[i]->quote, fi[i]->dquote, fi[i]->numeric, fi[i]->name, fi[i]->alias, fi[i]->dot);
  453. if (fi[i]->ti)
  454. mylog(" ----> table_name='%s', table_alias='%s'\n", fi[i]->ti->name, fi[i]->ti->alias);
  455. }
  456. for (i=0; i < stmt->ntab; i++) {
  457. mylog("Table %d: name='%s', alias='%s'\n", i, ti[i]->name, ti[i]->alias);
  458. }
  459. /******************************************************/
  460. /* Now save the SQLColumns Info for the parse tables */
  461. /******************************************************/
  462. /* Call SQLColumns for each table and store the result */
  463. for (i = 0; i < stmt->ntab; i++) {
  464. /* See if already got it */
  465. char found = FALSE;
  466. for (k = 0; k < conn->ntables; k++) {
  467. if ( ! stricmp(conn->col_info[k]->name, ti[i]->name)) {
  468. mylog("FOUND col_info table='%s'\n", ti[i]->name);
  469. found = TRUE;
  470. break;
  471. }
  472. }
  473. if ( ! found) {
  474. mylog("PARSE: Getting SQLColumns for table[%d]='%s'\n", i, ti[i]->name);
  475. result = PG_SQLAllocStmt( stmt->hdbc, &hcol_stmt);
  476. if((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO)) {
  477. SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "SQLAllocStmt failed in parse_statement for columns.");
  478. stmt->parse_status = STMT_PARSE_FATAL;
  479. return FALSE;
  480. }
  481. col_stmt = (StatementClass *) hcol_stmt;
  482. col_stmt->internal = TRUE;
  483. result = PG_SQLColumns(hcol_stmt, "", 0, "", 0,
  484. ti[i]->name, (SWORD) strlen(ti[i]->name), "", 0);
  485. mylog(" Past SQLColumns\n");
  486. if (result == SQL_SUCCESS) {
  487. mylog(" Success\n");
  488. if ( ! (conn->ntables % COL_INCR)) {
  489. mylog("PARSE: Allocing col_info at ntables=%d\n", conn->ntables);
  490. conn->col_info = (COL_INFO **) realloc(conn->col_info, (conn->ntables + COL_INCR) * sizeof(COL_INFO *));
  491. if ( ! conn->col_info) {
  492. stmt->parse_status = STMT_PARSE_FATAL;
  493. return FALSE;
  494. }
  495. }
  496. mylog("PARSE: malloc at conn->col_info[%d]\n", conn->ntables);
  497. conn->col_info[conn->ntables] = (COL_INFO *) malloc(sizeof(COL_INFO));
  498. if ( ! conn->col_info[conn->ntables]) {
  499. stmt->parse_status = STMT_PARSE_FATAL;
  500. return FALSE;
  501. }
  502. /* Store the table name and the SQLColumns result structure */
  503. strcpy(conn->col_info[conn->ntables]->name, ti[i]->name);
  504. conn->col_info[conn->ntables]->result = col_stmt->result;
  505. /* The connection will now free the result structures, so make
  506. sure that the statement doesn't free it
  507. */
  508. col_stmt->result = NULL;
  509. conn->ntables++;
  510. PG_SQLFreeStmt(hcol_stmt, SQL_DROP);
  511. mylog("Created col_info table='%s', ntables=%d\n", ti[i]->name, conn->ntables);
  512. }
  513. else {
  514. PG_SQLFreeStmt(hcol_stmt, SQL_DROP);
  515. break;
  516. }
  517. }
  518. /* Associate a table from the statement with a SQLColumn info */
  519. ti[i]->col_info = conn->col_info[k];
  520. mylog("associate col_info: i=%d, k=%d\n", i, k);
  521. }
  522. mylog("Done SQLColumns\n");
  523. /******************************************************/
  524. /* Now resolve the fields to point to column info */
  525. /******************************************************/
  526. for (i = 0; i < stmt->nfld;) {
  527. /* Dont worry about functions or quotes */
  528. if (fi[i]->func || fi[i]->quote || fi[i]->numeric) {
  529. i++;
  530. continue;
  531. }
  532. /* Stars get expanded to all fields in the table */
  533. else if (fi[i]->name[0] == '*') {
  534. char do_all_tables;
  535. int total_cols, old_alloc, new_size, cols;
  536. int increased_cols;
  537. mylog("expanding field %d\n", i);
  538. total_cols = 0;
  539. if (fi[i]->ti) /* The star represents only the qualified table */
  540. total_cols = QR_get_num_tuples(fi[i]->ti->col_info->result);
  541. else { /* The star represents all tables */
  542. /* Calculate the total number of columns after expansion */
  543. for (k = 0; k < stmt->ntab; k++) {
  544. total_cols += QR_get_num_tuples(ti[k]->col_info->result);
  545. }
  546. }
  547. increased_cols = total_cols - 1;
  548. /* Allocate some more field pointers if necessary */
  549. /*------------------------------------------------------------- */
  550. old_alloc = ((stmt->nfld - 1) / FLD_INCR + 1) * FLD_INCR;
  551. new_size = stmt->nfld + increased_cols;
  552. mylog("k=%d, increased_cols=%d, old_alloc=%d, new_size=%d\n", k,increased_cols,old_alloc,new_size);
  553. if (new_size > old_alloc) {
  554. int new_alloc = ((new_size / FLD_INCR) + 1) * FLD_INCR;
  555. mylog("need more cols: new_alloc = %d\n", new_alloc);
  556. fi = (FIELD_INFO **) realloc(fi, new_alloc * sizeof(FIELD_INFO *));
  557. if ( ! fi) {
  558. stmt->parse_status = STMT_PARSE_FATAL;
  559. return FALSE;
  560. }
  561. stmt->fi = fi;
  562. }
  563. /*------------------------------------------------------------- */
  564. /* copy any other fields (if there are any) up past the expansion */
  565. for (j = stmt->nfld - 1; j > i; j--) {
  566. mylog("copying field %d to %d\n", j, increased_cols + j);
  567. fi[increased_cols + j] = fi[j];
  568. }
  569. mylog("done copying fields\n");
  570. /*------------------------------------------------------------- */
  571. /* Set the new number of fields */
  572. stmt->nfld += increased_cols;
  573. mylog("stmt->nfld now at %d\n", stmt->nfld);
  574. /*------------------------------------------------------------- */
  575. /* copy the new field info */
  576. do_all_tables = (fi[i]->ti ? FALSE : TRUE);
  577. for (k = 0; k < (do_all_tables ? stmt->ntab : 1); k++) {
  578. TABLE_INFO *the_ti = do_all_tables ? ti[k] : fi[i]->ti;
  579. cols = QR_get_num_tuples(the_ti->col_info->result);
  580. for (n = 0; n < cols; n++) {
  581. mylog("creating field info: n=%d\n", n);
  582. /* skip malloc (already did it for the Star) */
  583. if (k > 0 || n > 0) {
  584. mylog("allocating field info at %d\n", n + i);
  585. fi[n + i] = (FIELD_INFO *) malloc( sizeof(FIELD_INFO));
  586. if (fi[n + i] == NULL) {
  587. stmt->parse_status = STMT_PARSE_FATAL;
  588. return FALSE;
  589. }
  590. }
  591. /* Initialize the new space (or the * field) */
  592. memset(fi[n + i], 0, sizeof(FIELD_INFO));
  593. fi[n + i]->ti = the_ti;
  594. mylog("about to copy at %d\n", n + i);
  595. getColInfo(the_ti->col_info, fi[n + i], n);
  596. mylog("done copying\n");
  597. }
  598. i += cols;
  599. mylog("i now at %d\n", i);
  600. }
  601. /*------------------------------------------------------------- */
  602. }
  603. /* We either know which table the field was in because it was qualified
  604. with a table name or alias -OR- there was only 1 table.
  605. */
  606. else if (fi[i]->ti) {
  607. if ( ! searchColInfo(fi[i]->ti->col_info, fi[i]))
  608. parse = FALSE;
  609. i++;
  610. }
  611. /* Don't know the table -- search all tables in "from" list */
  612. else {
  613. parse = FALSE;
  614. for (k = 0; k < stmt->ntab; k++) {
  615. if ( searchColInfo(ti[k]->col_info, fi[i])) {
  616. fi[i]->ti = ti[k]; /* now know the table */
  617. parse = TRUE;
  618. break;
  619. }
  620. }
  621. i++;
  622. }
  623. }
  624. if ( ! parse)
  625. stmt->parse_status = STMT_PARSE_INCOMPLETE;
  626. else
  627. stmt->parse_status = STMT_PARSE_COMPLETE;
  628. mylog("done parse_statement: parse=%d, parse_status=%d\n", parse, stmt->parse_status);
  629. return parse;
  630. }