PageRenderTime 56ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/vxodbc/parse.cc

http://versaplex.googlecode.com/
C++ | 1866 lines | 1607 code | 149 blank | 110 comment | 468 complexity | 936065d4a7ea02a2daef4faf4c212ddc MD5 | raw file
Possible License(s): LGPL-2.0
  1. /*
  2. * Description: This module contains routines related to parsing SQL
  3. * statements. This can be useful for two reasons:
  4. *
  5. * 1. So the query does not actually have to be executed
  6. * to return data about it
  7. *
  8. * 2. To be able to return information about precision,
  9. * nullability, aliases, etc. in the functions
  10. * SQLDescribeCol and SQLColAttributes. Currently,
  11. * Postgres doesn't return any information about
  12. * these things in a query.
  13. */
  14. /* Multibyte support Eiji Tokuya 2001-03-15 */
  15. #include "psqlodbc.h"
  16. #include <stdio.h>
  17. #include <string.h>
  18. #include <ctype.h>
  19. #include "statement.h"
  20. #include "connection.h"
  21. #include "qresult.h"
  22. #include "pgtypes.h"
  23. #include "pgapifunc.h"
  24. #include "catfunc.h"
  25. #include "multibyte.h"
  26. #define FLD_INCR 32
  27. #define TAB_INCR 8
  28. #define COLI_INCR 16
  29. static char *getNextToken(int ccsc, char escape_in_literal, char *s,
  30. char *token, int smax, char *delim,
  31. char *quote, char *dquote, char *numeric);
  32. static void getColInfo(COL_INFO * col_info, FIELD_INFO * fi, int k);
  33. static char searchColInfo(COL_INFO * col_info, FIELD_INFO * fi);
  34. Int4 FI_precision(const FIELD_INFO * fi)
  35. {
  36. OID ftype;
  37. if (!fi)
  38. return -1;
  39. ftype = FI_type(fi);
  40. switch (ftype)
  41. {
  42. case PG_TYPE_NUMERIC:
  43. return fi->column_size;
  44. }
  45. return 0;
  46. }
  47. Int4 FI_scale(const FIELD_INFO * fi)
  48. {
  49. OID ftype;
  50. if (!fi)
  51. return -1;
  52. ftype = FI_type(fi);
  53. switch (ftype)
  54. {
  55. case PG_TYPE_NUMERIC:
  56. return fi->decimal_digits;
  57. }
  58. return 0;
  59. }
  60. static char *getNextToken(int ccsc, /* client encoding */
  61. char escape_ch,
  62. char *s, char *token, int smax, char *delim,
  63. char *quote, char *dquote, char *numeric)
  64. {
  65. int i = 0;
  66. int out = 0, taglen;
  67. char qc, in_quote, in_dollar_quote, in_escape;
  68. const char *tag, *tagend;
  69. encoded_str encstr;
  70. char literal_quote = LITERAL_QUOTE, identifier_quote =
  71. IDENTIFIER_QUOTE, dollar_quote =
  72. DOLLAR_QUOTE, escape_in_literal;
  73. if (smax <= 1)
  74. return NULL;
  75. smax--;
  76. /* skip leading delimiters */
  77. while (isspace((UCHAR) s[i]) || s[i] == ',')
  78. {
  79. /* mylog("skipping '%c'\n", s[i]); */
  80. i++;
  81. }
  82. if (s[i] == '\0')
  83. {
  84. token[0] = '\0';
  85. return NULL;
  86. }
  87. if (quote)
  88. *quote = FALSE;
  89. if (dquote)
  90. *dquote = FALSE;
  91. if (numeric)
  92. *numeric = FALSE;
  93. encoded_str_constr(&encstr, ccsc, &s[i]);
  94. /* get the next token */
  95. while (s[i] != '\0' && out < smax)
  96. {
  97. encoded_nextchar(&encstr);
  98. if (ENCODE_STATUS(encstr) != 0)
  99. {
  100. token[out++] = s[i++];
  101. continue;
  102. }
  103. if (isspace((UCHAR) s[i]) || s[i] == ',')
  104. break;
  105. /* Handle quoted stuff */
  106. in_quote = in_dollar_quote = FALSE;
  107. taglen = 0;
  108. tag = NULL;
  109. escape_in_literal = '\0';
  110. if (out == 0)
  111. {
  112. qc = s[i];
  113. if (qc == dollar_quote)
  114. {
  115. in_quote = in_dollar_quote = TRUE;
  116. tag = s + i;
  117. taglen = 1;
  118. if (tagend =
  119. strchr(s + i + 1, dollar_quote), NULL != tagend)
  120. taglen = tagend - s - i + 1;
  121. i += (taglen - 1);
  122. encoded_position_shift(&encstr, taglen - 1);
  123. if (quote)
  124. *quote = TRUE;
  125. } else if (qc == literal_quote)
  126. {
  127. in_quote = TRUE;
  128. if (quote)
  129. *quote = TRUE;
  130. escape_in_literal = escape_ch;
  131. if (!escape_in_literal)
  132. {
  133. if (LITERAL_EXT == s[i - 1])
  134. escape_in_literal = ESCAPE_IN_LITERAL;
  135. }
  136. } else if (qc == identifier_quote)
  137. {
  138. in_quote = TRUE;
  139. if (dquote)
  140. *dquote = TRUE;
  141. }
  142. }
  143. if (in_quote)
  144. {
  145. i++; /* dont return the quote */
  146. in_escape = FALSE;
  147. while (s[i] != '\0' && out != smax)
  148. {
  149. encoded_nextchar(&encstr);
  150. if (ENCODE_STATUS(encstr) != 0)
  151. {
  152. token[out++] = s[i++];
  153. continue;
  154. }
  155. if (in_escape)
  156. in_escape = FALSE;
  157. else if (s[i] == qc)
  158. {
  159. if (!in_dollar_quote)
  160. break;
  161. if (strncmp(s + i, tag, taglen) == 0)
  162. {
  163. i += (taglen - 1);
  164. encoded_position_shift(&encstr, taglen - 1);
  165. break;
  166. }
  167. token[out++] = s[i];
  168. } else if (literal_quote == qc
  169. && s[i] == escape_in_literal)
  170. {
  171. in_escape = TRUE;
  172. } else
  173. {
  174. token[out++] = s[i];
  175. }
  176. i++;
  177. }
  178. if (s[i] == qc)
  179. i++;
  180. break;
  181. }
  182. /* Check for numeric literals */
  183. if (out == 0 && isdigit((UCHAR) s[i]))
  184. {
  185. if (numeric)
  186. *numeric = TRUE;
  187. token[out++] = s[i++];
  188. while (isalnum((UCHAR) s[i]) || s[i] == '.')
  189. token[out++] = s[i++];
  190. break;
  191. }
  192. if (ispunct((UCHAR) s[i]) && s[i] != '_')
  193. {
  194. mylog("got ispunct: s[%d] = '%c'\n", i, s[i]);
  195. if (out == 0)
  196. {
  197. token[out++] = s[i++];
  198. break;
  199. } else
  200. break;
  201. }
  202. if (out != smax)
  203. token[out++] = s[i];
  204. i++;
  205. }
  206. /* mylog("done -- s[%d] = '%c'\n", i, s[i]); */
  207. token[out] = '\0';
  208. /* find the delimiter */
  209. while (isspace((UCHAR) s[i]))
  210. i++;
  211. /* return the most priority delimiter */
  212. if (s[i] == ',')
  213. {
  214. if (delim)
  215. *delim = s[i];
  216. } else if (s[i] == '\0')
  217. {
  218. if (delim)
  219. *delim = '\0';
  220. } else
  221. {
  222. if (delim)
  223. *delim = ' ';
  224. }
  225. /* skip trailing blanks */
  226. while (isspace((UCHAR) s[i]))
  227. i++;
  228. return &s[i];
  229. }
  230. static void getColInfo(COL_INFO * col_info, FIELD_INFO * fi, int k)
  231. {
  232. char *str;
  233. inolog("getColInfo non-manual result\n");
  234. fi->dquote = TRUE;
  235. STR_TO_NAME(fi->column_name,
  236. QR_get_value_backend_text(col_info->result, k,
  237. COLUMNS_COLUMN_NAME));
  238. fi->columntype =
  239. (OID) QR_get_value_backend_int(col_info->result, k,
  240. COLUMNS_FIELD_TYPE, NULL);
  241. fi->column_size =
  242. QR_get_value_backend_int(col_info->result, k, COLUMNS_PRECISION,
  243. NULL);
  244. fi->length =
  245. QR_get_value_backend_int(col_info->result, k, COLUMNS_LENGTH,
  246. NULL);
  247. if (str = (char *)
  248. QR_get_value_backend_text(col_info->result, k, COLUMNS_SCALE),
  249. str)
  250. fi->decimal_digits = atoi(str);
  251. else
  252. fi->decimal_digits = -1;
  253. fi->nullable =
  254. QR_get_value_backend_int(col_info->result, k, COLUMNS_NULLABLE,
  255. NULL);
  256. fi->display_size =
  257. QR_get_value_backend_int(col_info->result, k,
  258. COLUMNS_DISPLAY_SIZE, NULL);
  259. fi->auto_increment =
  260. QR_get_value_backend_int(col_info->result, k,
  261. COLUMNS_AUTO_INCREMENT, NULL);
  262. }
  263. static char searchColInfo(COL_INFO * col_info, FIELD_INFO * fi)
  264. {
  265. int k, cmp, attnum;
  266. const char *col;
  267. inolog("searchColInfo num_cols=%d col=%s\n",
  268. QR_get_num_cached_tuples(col_info->result),
  269. PRINT_NAME(fi->column_name));
  270. if (fi->attnum < 0)
  271. return FALSE;
  272. for (k = 0; k < QR_get_num_cached_tuples(col_info->result); k++)
  273. {
  274. if (fi->attnum > 0)
  275. {
  276. attnum =
  277. QR_get_value_backend_int(col_info->result, k,
  278. COLUMNS_PHYSICAL_NUMBER, NULL);
  279. inolog("searchColInfo %d attnum=%d\n", k, attnum);
  280. if (attnum == fi->attnum)
  281. {
  282. getColInfo(col_info, fi, k);
  283. mylog("PARSE: searchColInfo by attnum=%d\n", attnum);
  284. return TRUE;
  285. }
  286. } else if (NAME_IS_VALID(fi->column_name))
  287. {
  288. col =
  289. QR_get_value_backend_text(col_info->result, k,
  290. COLUMNS_COLUMN_NAME);
  291. inolog("searchColInfo %d col=%s\n", k, col);
  292. if (fi->dquote)
  293. cmp = strcmp(col, GET_NAME(fi->column_name));
  294. else
  295. cmp = stricmp(col, GET_NAME(fi->column_name));
  296. if (!cmp)
  297. {
  298. if (!fi->dquote)
  299. STR_TO_NAME(fi->column_name, col);
  300. getColInfo(col_info, fi, k);
  301. mylog("PARSE: searchColInfo: \n");
  302. return TRUE;
  303. }
  304. }
  305. }
  306. return FALSE;
  307. }
  308. /*
  309. * lower the unquoted name
  310. */
  311. static
  312. void lower_the_name(char *name, ConnectionClass * conn, BOOL dquote)
  313. {
  314. if (!dquote)
  315. {
  316. char *ptr;
  317. encoded_str encstr;
  318. make_encoded_str(&encstr, conn, name);
  319. /* lower case table name */
  320. for (ptr = name; *ptr; ptr++)
  321. {
  322. encoded_nextchar(&encstr);
  323. if (ENCODE_STATUS(encstr) == 0)
  324. *ptr = tolower((UCHAR) * ptr);
  325. }
  326. }
  327. }
  328. static BOOL CheckHasOids(StatementClass * stmt)
  329. {
  330. QResultClass *res;
  331. BOOL hasoids = TRUE, foundKey = FALSE;
  332. char query[512];
  333. ConnectionClass *conn = SC_get_conn(stmt);
  334. TABLE_INFO *ti;
  335. if (0 != SC_checked_hasoids(stmt))
  336. return TRUE;
  337. if (!stmt->ti || !stmt->ti[0])
  338. return FALSE;
  339. ti = stmt->ti[0];
  340. sprintf(query,
  341. "select relhasoids, c.oid from pg_class c, pg_namespace n where relname = '%s' and nspname = '%s' and c.relnamespace = n.oid",
  342. SAFE_NAME(ti->table_name), SAFE_NAME(ti->schema_name));
  343. res =
  344. CC_send_query(conn, query, NULL,
  345. ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN, NULL);
  346. if (QR_command_maybe_successful(res))
  347. {
  348. stmt->num_key_fields = PG_NUM_NORMAL_KEYS;
  349. if (1 == QR_get_num_total_tuples(res))
  350. {
  351. const char *value = QR_get_value_backend_text(res, 0, 0);
  352. if (value && ('f' == *value || '0' == *value))
  353. {
  354. hasoids = FALSE;
  355. TI_set_has_no_oids(ti);
  356. } else
  357. {
  358. TI_set_hasoids(ti);
  359. foundKey = TRUE;
  360. STR_TO_NAME(ti->bestitem, OID_NAME);
  361. strcpy(query, "\"oid\" = %u");
  362. /*strcpy(query, "\"oid\" = %%u"); */
  363. STR_TO_NAME(ti->bestqual, query);
  364. }
  365. TI_set_hasoids_checked(ti);
  366. ti->table_oid =
  367. (OID) strtoul(QR_get_value_backend_text(res, 0, 1),
  368. NULL, 10);
  369. }
  370. QR_Destructor(res);
  371. res = NULL;
  372. if (!hasoids)
  373. {
  374. sprintf(query,
  375. "select a.attname, a.atttypid from pg_index i, pg_attribute a where indrelid=%u and indnatts=1 and indisunique and indexprs is null and indpred is null and i.indrelid = a.attrelid and a.attnum=i.indkey[0] and attnotnull and atttypid in (%d, %d)",
  376. ti->table_oid, PG_TYPE_INT4, PG_TYPE_OID);
  377. res =
  378. CC_send_query(conn, query, NULL,
  379. ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN,
  380. NULL);
  381. if (QR_command_maybe_successful(res)
  382. && QR_get_num_total_tuples(res) > 0)
  383. {
  384. foundKey = TRUE;
  385. STR_TO_NAME(ti->bestitem,
  386. QR_get_value_backend_text(res, 0, 0));
  387. sprintf(query, "\"%s\" = %%", SAFE_NAME(ti->bestitem));
  388. if (PG_TYPE_INT4 ==
  389. (OID) QR_get_value_backend_int(res, 0, 1, NULL))
  390. strcat(query, "d");
  391. else
  392. strcat(query, "u");
  393. STR_TO_NAME(ti->bestqual, query);
  394. } else
  395. {
  396. /* stmt->updatable = FALSE; */
  397. foundKey = TRUE;
  398. stmt->num_key_fields--;
  399. }
  400. }
  401. }
  402. QR_Destructor(res);
  403. SC_set_checked_hasoids(stmt, foundKey);
  404. return TRUE;
  405. }
  406. static BOOL increaseNtab(StatementClass * stmt, const char *func)
  407. {
  408. TABLE_INFO **ti = stmt->ti, *wti;
  409. if (!(stmt->ntab % TAB_INCR))
  410. {
  411. ti = (TABLE_INFO **) realloc(ti,
  412. (stmt->ntab +
  413. TAB_INCR) * sizeof(TABLE_INFO *));
  414. if (!ti)
  415. {
  416. SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
  417. "PGAPI_AllocStmt failed in parse_statement for TABLE_INFO.",
  418. func);
  419. return FALSE;
  420. }
  421. stmt->ti = ti;
  422. }
  423. wti = ti[stmt->ntab] = (TABLE_INFO *) malloc(sizeof(TABLE_INFO));
  424. if (wti == NULL)
  425. {
  426. SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
  427. "PGAPI_AllocStmt failed in parse_statement for TABLE_INFO(2).",
  428. func);
  429. return FALSE;
  430. }
  431. TI_Constructor(wti, SC_get_conn(stmt));
  432. stmt->ntab++;
  433. return TRUE;
  434. }
  435. static void setNumFields(IRDFields * irdflds, size_t numFields)
  436. {
  437. FIELD_INFO **fi = irdflds->fi;
  438. size_t nfields = irdflds->nfields;
  439. if (numFields < nfields)
  440. {
  441. int i;
  442. for (i = (int) numFields; i < (int) nfields; i++)
  443. {
  444. if (fi[i])
  445. fi[i]->flag = 0;
  446. }
  447. }
  448. irdflds->nfields = (UInt4) numFields;
  449. }
  450. void SC_initialize_cols_info(StatementClass * stmt, BOOL DCdestroy,
  451. BOOL parseReset)
  452. {
  453. IRDFields *irdflds = SC_get_IRDF(stmt);
  454. /* Free the parsed table information */
  455. if (stmt->ti)
  456. {
  457. TI_Destructor(stmt->ti, stmt->ntab);
  458. free(stmt->ti);
  459. stmt->ti = NULL;
  460. }
  461. stmt->ntab = 0;
  462. if (DCdestroy) /* Free the parsed field information */
  463. DC_Destructor((DescriptorClass *) SC_get_IRD(stmt));
  464. else
  465. setNumFields(irdflds, 0);
  466. if (parseReset)
  467. {
  468. stmt->parse_status = STMT_PARSE_NONE;
  469. stmt->updatable = FALSE;
  470. }
  471. }
  472. static BOOL allocateFields(IRDFields * irdflds, size_t sizeRequested)
  473. {
  474. FIELD_INFO **fi = irdflds->fi;
  475. size_t alloc_size, incr_size;
  476. if (sizeRequested <= irdflds->allocated)
  477. return TRUE;
  478. alloc_size =
  479. (0 != irdflds->allocated ? irdflds->allocated : FLD_INCR);
  480. for (; alloc_size < sizeRequested; alloc_size *= 2)
  481. ;
  482. incr_size =
  483. sizeof(FIELD_INFO *) * (alloc_size - irdflds->allocated);
  484. fi = (FIELD_INFO **) realloc(fi, alloc_size * sizeof(FIELD_INFO *));
  485. if (!fi)
  486. {
  487. irdflds->fi = NULL;
  488. irdflds->allocated = irdflds->nfields = 0;
  489. return FALSE;
  490. }
  491. memset(&fi[irdflds->allocated], 0, incr_size);
  492. irdflds->fi = fi;
  493. irdflds->allocated = (SQLSMALLINT) alloc_size;
  494. return TRUE;
  495. }
  496. static void xxxxx(FIELD_INFO * fi, QResultClass * res, int i)
  497. {
  498. STR_TO_NAME(fi->column_alias, QR_get_fieldname(res, i));
  499. fi->basetype = QR_get_field_type(res, i);
  500. if (0 == fi->columntype)
  501. fi->columntype = fi->basetype;
  502. if (fi->attnum < 0)
  503. {
  504. fi->nullable = FALSE;
  505. fi->updatable = FALSE;
  506. } else if (fi->attnum > 0)
  507. fi->nullable = TRUE; /* probably ? */
  508. if (NAME_IS_NULL(fi->column_name))
  509. {
  510. switch (fi->attnum)
  511. {
  512. case CTID_ATTNUM:
  513. STR_TO_NAME(fi->column_name, "ctid");
  514. break;
  515. case OID_ATTNUM:
  516. STR_TO_NAME(fi->column_name, OID_NAME);
  517. break;
  518. case XMIN_ATTNUM:
  519. STR_TO_NAME(fi->column_name, "xmin");
  520. break;
  521. }
  522. }
  523. }
  524. /*
  525. * SQLColAttribute tries to set the FIELD_INFO (using protocol 3).
  526. */
  527. static BOOL ColAttSet(StatementClass * stmt, TABLE_INFO * rti)
  528. {
  529. QResultClass *res = SC_get_Curres(stmt);
  530. IRDFields *irdflds = SC_get_IRDF(stmt);
  531. COL_INFO *col_info = NULL;
  532. FIELD_INFO **fi, *wfi;
  533. OID reloid = 0;
  534. Int2 attid;
  535. int i, num_fields;
  536. BOOL fi_reuse, updatable;
  537. mylog("ColAttSet in\n");
  538. if (rti)
  539. {
  540. if (reloid = rti->table_oid, 0 == reloid)
  541. return FALSE;
  542. if (0 != (rti->flags & TI_COLATTRIBUTE))
  543. return TRUE;
  544. col_info = rti->col_info;
  545. }
  546. if (!QR_command_maybe_successful(res))
  547. return FALSE;
  548. if (num_fields = QR_NumPublicResultCols(res), num_fields <= 0)
  549. return FALSE;
  550. fi = irdflds->fi;
  551. if (num_fields > (int) irdflds->allocated)
  552. {
  553. if (!allocateFields(irdflds, num_fields))
  554. return FALSE;
  555. fi = irdflds->fi;
  556. }
  557. setNumFields(irdflds, num_fields);
  558. updatable = rti ? TI_is_updatable(rti) : FALSE;
  559. mylog("updatable=%d tab=%d fields=%d", updatable, stmt->ntab,
  560. num_fields);
  561. if (updatable)
  562. {
  563. if (1 != stmt->ntab)
  564. updatable = FALSE;
  565. else if (SC_has_join(stmt))
  566. updatable = FALSE;
  567. else
  568. {
  569. OID greloid;
  570. for (i = 0; i < num_fields; i++)
  571. {
  572. greloid = QR_get_relid(res, i);
  573. if (0 != greloid && reloid != greloid)
  574. {
  575. updatable = FALSE;
  576. break;
  577. }
  578. }
  579. }
  580. }
  581. mylog("->%d\n", updatable);
  582. for (i = 0; i < num_fields; i++)
  583. {
  584. if (reloid == (OID) QR_get_relid(res, i))
  585. {
  586. if (wfi = fi[i], NULL == wfi)
  587. {
  588. wfi = (FIELD_INFO *) malloc(sizeof(FIELD_INFO));
  589. fi_reuse = FALSE;
  590. fi[i] = wfi;
  591. } else if (FI_is_applicable(wfi))
  592. continue;
  593. else
  594. fi_reuse = TRUE;
  595. FI_Constructor(wfi, fi_reuse);
  596. attid = (Int2) QR_get_attid(res, i);
  597. wfi->attnum = attid;
  598. if (searchColInfo(col_info, wfi))
  599. {
  600. STR_TO_NAME(wfi->column_alias,
  601. QR_get_fieldname(res, i));
  602. wfi->basetype = QR_get_field_type(res, i);
  603. wfi->updatable = updatable;
  604. } else
  605. {
  606. xxxxx(wfi, res, i);
  607. }
  608. wfi->ti = rti;
  609. wfi->flag |= FIELD_COL_ATTRIBUTE;
  610. }
  611. }
  612. if (rti)
  613. rti->flags |= TI_COLATTRIBUTE;
  614. return TRUE;
  615. }
  616. static BOOL
  617. getCOLIfromTable(ConnectionClass * conn, pgNAME * schema_name,
  618. pgNAME table_name, COL_INFO ** coli)
  619. {
  620. int colidx;
  621. BOOL found = FALSE;
  622. *coli = NULL;
  623. if (NAME_IS_NULL(table_name))
  624. return TRUE;
  625. if (conn->schema_support)
  626. {
  627. if (NAME_IS_NULL(*schema_name))
  628. {
  629. const char *curschema = CC_get_current_schema(conn);
  630. /*
  631. * Though current_schema() doesn't have
  632. * much sense in PostgreSQL, we first
  633. * check the current_schema() when no
  634. * explicit schema name was specified.
  635. */
  636. for (colidx = 0; colidx < conn->ntables; colidx++)
  637. {
  638. if (!NAMEICMP
  639. (conn->col_info[colidx]->table_name, table_name)
  640. &&
  641. !stricmp(SAFE_NAME
  642. (conn->col_info[colidx]->schema_name),
  643. curschema))
  644. {
  645. mylog
  646. ("FOUND col_info table='%s' current schema='%s'\n",
  647. PRINT_NAME(table_name), curschema);
  648. found = TRUE;
  649. STR_TO_NAME(*schema_name, curschema);
  650. break;
  651. }
  652. }
  653. if (!found)
  654. {
  655. QResultClass *res;
  656. char token[256];
  657. BOOL tblFound = FALSE;
  658. /*
  659. * We also have to check as follows.
  660. */
  661. sprintf(token,
  662. "select nspname from pg_namespace n, pg_class c"
  663. " where c.relnamespace=n.oid and c.oid='\"%s\"'::regclass",
  664. SAFE_NAME(table_name));
  665. res =
  666. CC_send_query(conn, token, NULL,
  667. ROLLBACK_ON_ERROR |
  668. IGNORE_ABORT_ON_CONN, NULL);
  669. if (QR_command_maybe_successful(res))
  670. {
  671. if (QR_get_num_total_tuples(res) == 1)
  672. {
  673. tblFound = TRUE;
  674. STR_TO_NAME(*schema_name,
  675. QR_get_value_backend_text(res, 0,
  676. 0));
  677. }
  678. }
  679. QR_Destructor(res);
  680. if (!tblFound)
  681. return FALSE;
  682. }
  683. }
  684. if (!found && NAME_IS_VALID(*schema_name))
  685. {
  686. for (colidx = 0; colidx < conn->ntables; colidx++)
  687. {
  688. if (!NAMEICMP
  689. (conn->col_info[colidx]->table_name, table_name)
  690. && !NAMEICMP(conn->col_info[colidx]->schema_name,
  691. *schema_name))
  692. {
  693. mylog("FOUND col_info table='%s' schema='%s'\n",
  694. PRINT_NAME(table_name),
  695. PRINT_NAME(*schema_name));
  696. found = TRUE;
  697. break;
  698. }
  699. }
  700. }
  701. } else
  702. {
  703. for (colidx = 0; colidx < conn->ntables; colidx++)
  704. {
  705. if (!NAMEICMP
  706. (conn->col_info[colidx]->table_name, table_name))
  707. {
  708. mylog("FOUND col_info table='%s'\n", table_name);
  709. found = TRUE;
  710. break;
  711. }
  712. }
  713. }
  714. *coli = found ? conn->col_info[colidx] : NULL;
  715. return TRUE; /* success */
  716. }
  717. BOOL getCOLIfromTI(const char *func, ConnectionClass * conn,
  718. StatementClass * stmt, const OID reloid,
  719. TABLE_INFO ** pti)
  720. {
  721. BOOL colatt = FALSE, found = FALSE;
  722. OID greloid = reloid;
  723. TABLE_INFO *wti = *pti;
  724. COL_INFO *coli;
  725. HSTMT hcol_stmt = NULL;
  726. QResultClass *res;
  727. inolog("getCOLIfromTI reloid=%u ti=%p\n", reloid, wti);
  728. if (!conn)
  729. conn = SC_get_conn(stmt);
  730. if (!wti) /* SQLColAttribute case */
  731. {
  732. int i;
  733. if (0 == greloid)
  734. return FALSE;
  735. colatt = TRUE;
  736. for (i = 0; i < stmt->ntab; i++)
  737. {
  738. if (stmt->ti[i]->table_oid == greloid)
  739. {
  740. wti = stmt->ti[i];
  741. break;
  742. }
  743. }
  744. if (!wti)
  745. {
  746. inolog("before increaseNtab\n");
  747. if (!increaseNtab(stmt, func))
  748. return FALSE;
  749. wti = stmt->ti[stmt->ntab - 1];
  750. wti->table_oid = greloid;
  751. }
  752. *pti = wti;
  753. }
  754. inolog("fi=%p greloid=%d col_info=%p\n", wti, greloid,
  755. wti->col_info);
  756. if (0 == greloid)
  757. greloid = wti->table_oid;
  758. if (NULL != wti->col_info)
  759. {
  760. found = TRUE;
  761. goto cleanup;
  762. }
  763. if (greloid != 0)
  764. {
  765. int colidx;
  766. for (colidx = 0; colidx < conn->ntables; colidx++)
  767. {
  768. if (conn->col_info[colidx]->table_oid == greloid)
  769. {
  770. mylog("FOUND col_info table=%ul\n", greloid);
  771. found = TRUE;
  772. wti->col_info = conn->col_info[colidx];
  773. break;
  774. }
  775. }
  776. } else
  777. {
  778. if (!getCOLIfromTable
  779. (conn, &wti->schema_name, wti->table_name, &coli))
  780. {
  781. if (stmt)
  782. {
  783. SC_set_parse_status(stmt, STMT_PARSE_FATAL);
  784. SC_set_error(stmt, STMT_EXEC_ERROR, "Table not found",
  785. func);
  786. stmt->updatable = FALSE;
  787. }
  788. return FALSE;
  789. } else if (NULL != coli)
  790. {
  791. found = TRUE;
  792. wti->col_info = coli;
  793. }
  794. }
  795. if (found)
  796. goto cleanup;
  797. else if (0 != greloid || NAME_IS_VALID(wti->table_name))
  798. {
  799. RETCODE result;
  800. StatementClass *col_stmt;
  801. mylog("PARSE: Getting PG_Columns for table='%s'\n",
  802. wti->table_name);
  803. result = PGAPI_AllocStmt(conn, &hcol_stmt);
  804. if ((result != SQL_SUCCESS)
  805. && (result != SQL_SUCCESS_WITH_INFO))
  806. {
  807. if (stmt)
  808. SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
  809. "PGAPI_AllocStmt failed in parse_statement for columns.",
  810. func);
  811. goto cleanup;
  812. }
  813. col_stmt = (StatementClass *) hcol_stmt;
  814. col_stmt->internal = TRUE;
  815. if (greloid)
  816. result = PGAPI_Columns(hcol_stmt, NULL, 0,
  817. NULL, 0, NULL, 0, NULL, 0,
  818. PODBC_SEARCH_BY_IDS, greloid, 0);
  819. else
  820. result =
  821. PGAPI_Columns(hcol_stmt, NULL, 0,
  822. (const UCHAR *)SAFE_NAME(wti->schema_name),
  823. SQL_NTS,
  824. (const UCHAR *)SAFE_NAME(wti->table_name),
  825. SQL_NTS, NULL, 0,
  826. PODBC_NOT_SEARCH_PATTERN, 0, 0);
  827. mylog(" Past PG_Columns\n");
  828. res = SC_get_Curres(col_stmt);
  829. if ((SQL_SUCCESS == result || SQL_SUCCESS_WITH_INFO == result)
  830. && res && QR_get_num_cached_tuples(res) > 0)
  831. {
  832. COL_INFO *coli;
  833. mylog(" Success\n");
  834. if (conn->ntables >= conn->coli_allocated)
  835. {
  836. Int2 new_alloc;
  837. new_alloc = conn->coli_allocated * 2;
  838. if (new_alloc <= conn->ntables)
  839. new_alloc = COLI_INCR;
  840. mylog("PARSE: Allocating col_info at ntables=%d\n",
  841. conn->ntables);
  842. conn->col_info =
  843. (COL_INFO **) realloc(conn->col_info,
  844. new_alloc *
  845. sizeof(COL_INFO *));
  846. if (!conn->col_info)
  847. {
  848. if (stmt)
  849. SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
  850. "PGAPI_AllocStmt failed in parse_statement for col_info.",
  851. func);
  852. goto cleanup;
  853. }
  854. conn->coli_allocated = new_alloc;
  855. }
  856. mylog("PARSE: malloc at conn->col_info[%d]\n",
  857. conn->ntables);
  858. coli = conn->col_info[conn->ntables] =
  859. (COL_INFO *) malloc(sizeof(COL_INFO));
  860. if (!coli)
  861. {
  862. if (stmt)
  863. SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
  864. "PGAPI_AllocStmt failed in parse_statement for col_info(2).",
  865. func);
  866. goto cleanup;
  867. }
  868. col_info_initialize(coli);
  869. coli->result = res;
  870. if (res && QR_get_num_cached_tuples(res) > 0)
  871. {
  872. if (!greloid)
  873. greloid =
  874. (OID)
  875. strtoul(QR_get_value_backend_text
  876. (res, 0, COLUMNS_TABLE_OID), NULL, 10);
  877. if (!wti->table_oid)
  878. wti->table_oid = greloid;
  879. if (NAME_IS_NULL(wti->schema_name))
  880. STR_TO_NAME(wti->schema_name,
  881. QR_get_value_backend_text(res, 0,
  882. COLUMNS_SCHEMA_NAME));
  883. if (NAME_IS_NULL(wti->table_name))
  884. STR_TO_NAME(wti->table_name,
  885. QR_get_value_backend_text(res, 0,
  886. COLUMNS_TABLE_NAME));
  887. }
  888. inolog("#2 %p->table_name=%s(%u)\n", wti,
  889. PRINT_NAME(wti->table_name), wti->table_oid);
  890. /*
  891. * Store the table name and the SQLColumns result
  892. * structure
  893. */
  894. if (NAME_IS_VALID(wti->schema_name))
  895. {
  896. NAME_TO_NAME(coli->schema_name, wti->schema_name);
  897. } else
  898. NULL_THE_NAME(coli->schema_name);
  899. NAME_TO_NAME(coli->table_name, wti->table_name);
  900. coli->table_oid = wti->table_oid;
  901. /*
  902. * The connection will now free the result structures, so
  903. * make sure that the statement doesn't free it
  904. */
  905. SC_init_Result(col_stmt);
  906. conn->ntables++;
  907. if (res && QR_get_num_cached_tuples(res) > 0)
  908. inolog("oid item == %s\n",
  909. QR_get_value_backend_text(res, 0, 3));
  910. mylog("Created col_info table='%s', ntables=%d\n",
  911. PRINT_NAME(wti->table_name), conn->ntables);
  912. /* Associate a table from the statement with a SQLColumn info */
  913. found = TRUE;
  914. wti->col_info = coli;
  915. }
  916. }
  917. cleanup:
  918. if (hcol_stmt)
  919. PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
  920. if (found)
  921. {
  922. QResultClass *res = wti->col_info->result;
  923. if (res && QR_get_num_cached_tuples(res) > 0)
  924. {
  925. if (!greloid)
  926. greloid =
  927. (OID)
  928. strtoul(QR_get_value_backend_text
  929. (res, 0, COLUMNS_TABLE_OID), NULL, 10);
  930. if (!wti->table_oid)
  931. wti->table_oid = greloid;
  932. if (NAME_IS_NULL(wti->schema_name))
  933. STR_TO_NAME(wti->schema_name,
  934. QR_get_value_backend_text(res, 0,
  935. COLUMNS_SCHEMA_NAME));
  936. if (NAME_IS_NULL(wti->table_name))
  937. STR_TO_NAME(wti->table_name,
  938. QR_get_value_backend_text(res, 0,
  939. COLUMNS_TABLE_NAME));
  940. }
  941. inolog("#1 %p->table_name=%s(%u)\n", wti,
  942. PRINT_NAME(wti->table_name), wti->table_oid);
  943. if (colatt /* SQLColAttribute case */
  944. && 0 == (wti->flags & TI_COLATTRIBUTE))
  945. {
  946. if (stmt)
  947. ColAttSet(stmt, wti);
  948. }
  949. } else if (!colatt && stmt)
  950. SC_set_parse_status(stmt, STMT_PARSE_FATAL);
  951. inolog("getCOLIfromTI returns %d\n", found);
  952. return found;
  953. }
  954. char parse_statement(StatementClass * stmt, BOOL check_hasoids)
  955. {
  956. CSTR func = "parse_statement";
  957. char token[256], stoken[256];
  958. char delim, quote, dquote, numeric, unquoted;
  959. char *ptr, *pptr = NULL;
  960. char in_select = FALSE,
  961. in_distinct = FALSE,
  962. in_on = FALSE,
  963. in_from = FALSE,
  964. in_where = FALSE, in_table = FALSE, out_table = TRUE;
  965. char in_field = FALSE,
  966. in_expr = FALSE, in_func = FALSE, in_dot = FALSE, in_as = FALSE;
  967. int j,
  968. i,
  969. k = 0,
  970. n,
  971. blevel = 0, old_blevel, subqlevel = 0, allocated_size, new_size;
  972. FIELD_INFO **fi, *wfi;
  973. TABLE_INFO **ti, *wti;
  974. char parse, maybe_join = 0;
  975. ConnectionClass *conn = SC_get_conn(stmt);
  976. IRDFields *irdflds = SC_get_IRDF(stmt);
  977. BOOL updatable = TRUE;
  978. mylog("%s: entering...\n", func);
  979. if (SC_parsed_status(stmt) != STMT_PARSE_NONE)
  980. {
  981. if (check_hasoids)
  982. CheckHasOids(stmt);
  983. return TRUE;
  984. }
  985. stmt->updatable = FALSE;
  986. ptr = stmt->statement;
  987. fi = irdflds->fi;
  988. ti = stmt->ti;
  989. allocated_size = irdflds->allocated;
  990. SC_initialize_cols_info(stmt, FALSE, TRUE);
  991. stmt->from_pos = -1;
  992. stmt->where_pos = -1;
  993. #define return DONT_CALL_RETURN_FROM_HERE???
  994. while (pptr =
  995. ptr, (ptr =
  996. getNextToken(conn->ccsc, CC_get_escape(conn), pptr,
  997. token, sizeof(token), &delim, &quote,
  998. &dquote, &numeric)) != NULL)
  999. {
  1000. unquoted = !(quote || dquote);
  1001. mylog
  1002. ("unquoted=%d, quote=%d, dquote=%d, numeric=%d, delim='%c', token='%s', ptr='%s'\n",
  1003. unquoted, quote, dquote, numeric, delim, token, ptr);
  1004. old_blevel = blevel;
  1005. if (unquoted && blevel == 0)
  1006. {
  1007. if (in_select)
  1008. {
  1009. if (!stricmp(token, "distinct"))
  1010. {
  1011. in_distinct = TRUE;
  1012. updatable = FALSE;
  1013. mylog("DISTINCT\n");
  1014. continue;
  1015. } else if (!stricmp(token, "into"))
  1016. {
  1017. in_select = FALSE;
  1018. mylog("INTO\n");
  1019. stmt->statement_type = STMT_TYPE_CREATE;
  1020. SC_set_parse_status(stmt, STMT_PARSE_FATAL);
  1021. goto cleanup;
  1022. } else if (!stricmp(token, "from"))
  1023. {
  1024. in_select = FALSE;
  1025. in_from = TRUE;
  1026. if (stmt->from_pos < 0 &&
  1027. (!strnicmp(pptr, "from", 4)))
  1028. {
  1029. mylog("First ");
  1030. stmt->from_pos = pptr - stmt->statement;
  1031. }
  1032. mylog("FROM\n");
  1033. continue;
  1034. }
  1035. } /* in_select && unquoted && blevel == 0 */
  1036. else if ((!stricmp(token, "where") ||
  1037. !stricmp(token, "union") ||
  1038. !stricmp(token, "intersect") ||
  1039. !stricmp(token, "except") ||
  1040. !stricmp(token, "order") ||
  1041. !stricmp(token, "group") ||
  1042. !stricmp(token, "having")))
  1043. {
  1044. in_from = FALSE;
  1045. in_where = TRUE;
  1046. if (stmt->where_pos < 0)
  1047. stmt->where_pos = pptr - stmt->statement;
  1048. mylog("%s...\n", token);
  1049. if (stricmp(token, "where") && stricmp(token, "order"))
  1050. {
  1051. updatable = FALSE;
  1052. break;
  1053. }
  1054. continue;
  1055. }
  1056. }
  1057. /* unquoted && blevel == 0 */
  1058. /* check the change of blevel etc */
  1059. if (unquoted)
  1060. {
  1061. if (!stricmp(token, "select"))
  1062. {
  1063. stoken[0] = '\0';
  1064. if (0 == blevel)
  1065. {
  1066. in_select = TRUE;
  1067. mylog("SELECT\n");
  1068. continue;
  1069. } else
  1070. {
  1071. mylog("SUBSELECT\n");
  1072. if (0 == subqlevel)
  1073. subqlevel = blevel;
  1074. }
  1075. } else if (token[0] == '(')
  1076. {
  1077. blevel++;
  1078. mylog("blevel++ = %d\n", blevel);
  1079. /* aggregate function ? */
  1080. if (stoken[0] && updatable && 0 == subqlevel)
  1081. {
  1082. if (stricmp(stoken, "count") == 0 ||
  1083. stricmp(stoken, "sum") == 0 ||
  1084. stricmp(stoken, "avg") == 0 ||
  1085. stricmp(stoken, "max") == 0 ||
  1086. stricmp(stoken, "min") == 0 ||
  1087. stricmp(stoken, "variance") == 0 ||
  1088. stricmp(stoken, "stddev") == 0)
  1089. updatable = FALSE;
  1090. }
  1091. } else if (token[0] == ')')
  1092. {
  1093. blevel--;
  1094. mylog("blevel-- = %d\n", blevel);
  1095. if (blevel < subqlevel)
  1096. subqlevel = 0;
  1097. }
  1098. if (blevel >= old_blevel && ',' != delim)
  1099. strcpy(stoken, token);
  1100. else
  1101. stoken[0] = '\0';
  1102. }
  1103. if (in_select)
  1104. {
  1105. if (in_expr || in_func)
  1106. {
  1107. /* just eat the expression */
  1108. mylog("in_expr=%d or func=%d\n", in_expr, in_func);
  1109. if (blevel == 0)
  1110. {
  1111. if (delim == ',')
  1112. {
  1113. mylog("**** Got comma in_expr/func\n");
  1114. in_func = FALSE;
  1115. in_expr = FALSE;
  1116. in_field = FALSE;
  1117. } else if (unquoted && !stricmp(token, "as"))
  1118. {
  1119. mylog("got AS in_expr\n");
  1120. in_func = FALSE;
  1121. in_expr = FALSE;
  1122. in_as = TRUE;
  1123. in_field = TRUE;
  1124. }
  1125. }
  1126. continue;
  1127. }
  1128. /* (in_expr || in_func) && in_select */
  1129. if (in_distinct)
  1130. {
  1131. mylog("in distinct\n");
  1132. if (unquoted && !stricmp(token, "on"))
  1133. {
  1134. in_on = TRUE;
  1135. mylog("got on\n");
  1136. continue;
  1137. }
  1138. if (in_on)
  1139. {
  1140. in_distinct = FALSE;
  1141. in_on = FALSE;
  1142. continue; /* just skip the unique on field */
  1143. }
  1144. mylog("done distinct\n");
  1145. in_distinct = FALSE;
  1146. }
  1147. /* in_distinct */
  1148. if (!in_field)
  1149. {
  1150. BOOL fi_reuse = FALSE;
  1151. if (!token[0])
  1152. continue;
  1153. /* if (!(irdflds->nfields % FLD_INCR)) */
  1154. if (irdflds->nfields >= allocated_size)
  1155. {
  1156. mylog("reallocing at nfld=%d\n", irdflds->nfields);
  1157. new_size = irdflds->nfields + 1;
  1158. if (!allocateFields(irdflds, new_size))
  1159. {
  1160. SC_set_parse_status(stmt, STMT_PARSE_FATAL);
  1161. SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
  1162. "PGAPI_AllocStmt failed in parse_statement for FIELD_INFO.",
  1163. func);
  1164. goto cleanup;
  1165. }
  1166. fi = irdflds->fi;
  1167. allocated_size = irdflds->allocated;
  1168. }
  1169. wfi = fi[irdflds->nfields];
  1170. if (wfi)
  1171. fi_reuse = TRUE;
  1172. else
  1173. wfi = fi[irdflds->nfields] =
  1174. (FIELD_INFO *) malloc(sizeof(FIELD_INFO));
  1175. if (wfi == NULL)
  1176. {
  1177. SC_set_parse_status(stmt, STMT_PARSE_FATAL);
  1178. SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
  1179. "PGAPI_AllocStmt failed in parse_statement for FIELD_INFO(2).",
  1180. func);
  1181. goto cleanup;
  1182. }
  1183. /* Initialize the field info */
  1184. FI_Constructor(wfi, fi_reuse);
  1185. wfi->flag = FIELD_PARSING;
  1186. /* double quotes are for qualifiers */
  1187. if (dquote)
  1188. wfi->dquote = TRUE;
  1189. if (quote)
  1190. {
  1191. wfi->quote = TRUE;
  1192. wfi->column_size = (int) strlen(token);
  1193. } else if (numeric)
  1194. {
  1195. mylog("**** got numeric: nfld = %d\n",
  1196. irdflds->nfields);
  1197. wfi->numeric = TRUE;
  1198. } else if (0 == old_blevel && blevel > 0)
  1199. { /* expression */
  1200. mylog("got EXPRESSION\n");
  1201. wfi->expr = TRUE;
  1202. in_expr = TRUE;
  1203. /* continue; */
  1204. } else
  1205. {
  1206. STR_TO_NAME(wfi->column_name, token);
  1207. NULL_THE_NAME(wfi->before_dot);
  1208. }
  1209. mylog("got field='%s', dot='%s'\n",
  1210. PRINT_NAME(wfi->column_name),
  1211. PRINT_NAME(wfi->before_dot));
  1212. if (delim == ',')
  1213. mylog("comma (1)\n");
  1214. else
  1215. in_field = TRUE;
  1216. irdflds->nfields++;
  1217. continue;
  1218. }
  1219. /* !in_field */
  1220. /*
  1221. * We are in a field now
  1222. */
  1223. wfi = fi[irdflds->nfields - 1];
  1224. if (in_dot)
  1225. {
  1226. if (NAME_IS_VALID(wfi->before_dot))
  1227. {
  1228. MOVE_NAME(wfi->schema_name, wfi->before_dot);
  1229. }
  1230. MOVE_NAME(wfi->before_dot, wfi->column_name);
  1231. STR_TO_NAME(wfi->column_name, token);
  1232. if (delim == ',')
  1233. {
  1234. mylog("in_dot: got comma\n");
  1235. in_field = FALSE;
  1236. }
  1237. in_dot = FALSE;
  1238. continue;
  1239. }
  1240. if (in_as)
  1241. {
  1242. STR_TO_NAME(wfi->column_alias, token);
  1243. mylog("alias for field '%s' is '%s'\n",
  1244. PRINT_NAME(wfi->column_name),
  1245. PRINT_NAME(wfi->column_alias));
  1246. in_as = FALSE;
  1247. in_field = FALSE;
  1248. if (delim == ',')
  1249. mylog("comma(2)\n");
  1250. continue;
  1251. }
  1252. /* Function */
  1253. if (0 == old_blevel && blevel > 0)
  1254. {
  1255. in_dot = FALSE;
  1256. in_func = TRUE;
  1257. wfi->func = TRUE;
  1258. /*
  1259. * name will have the function name -- maybe useful some
  1260. * day
  1261. */
  1262. mylog("**** got function = '%s'\n",
  1263. PRINT_NAME(wfi->column_name));
  1264. continue;
  1265. }
  1266. if (token[0] == '.')
  1267. {
  1268. in_dot = TRUE;
  1269. mylog("got dot\n");
  1270. continue;
  1271. }
  1272. in_dot = FALSE;
  1273. if (!stricmp(token, "as"))
  1274. {
  1275. in_as = TRUE;
  1276. mylog("got AS\n");
  1277. continue;
  1278. }
  1279. /* otherwise, it's probably an expression */
  1280. in_expr = TRUE;
  1281. wfi->expr = TRUE;
  1282. NULL_THE_NAME(wfi->column_name);
  1283. wfi->column_size = 0;
  1284. mylog("*** setting expression\n");
  1285. }
  1286. /* in_select end */
  1287. if (in_from || in_where)
  1288. {
  1289. if (token[0] == ';') /* end of the first command */
  1290. {
  1291. in_select = in_from = in_where = in_table = FALSE;
  1292. break;
  1293. }
  1294. }
  1295. if (in_from)
  1296. {
  1297. switch (token[0])
  1298. {
  1299. case '\0':
  1300. continue;
  1301. case ',':
  1302. out_table = TRUE;
  1303. continue;
  1304. }
  1305. if (out_table && !in_table) /* new table */
  1306. {
  1307. in_dot = FALSE;
  1308. maybe_join = 0;
  1309. if (!dquote)
  1310. {
  1311. if (token[0] == '(' || token[0] == ')')
  1312. continue;
  1313. }
  1314. if (!increaseNtab(stmt, func))
  1315. {
  1316. SC_set_parse_status(stmt, STMT_PARSE_FATAL);
  1317. goto cleanup;
  1318. }
  1319. ti = stmt->ti;
  1320. wti = ti[stmt->ntab - 1];
  1321. if (dquote || stricmp(token, "select"))
  1322. {
  1323. STR_TO_NAME(wti->table_name, token);
  1324. lower_the_name(GET_NAME(wti->table_name), conn,
  1325. dquote);
  1326. } else
  1327. {
  1328. NULL_THE_NAME(wti->table_name);
  1329. TI_no_updatable(wti);
  1330. }
  1331. mylog("got table = '%s'\n",
  1332. PRINT_NAME(wti->table_name));
  1333. if (0 == blevel && delim == ',')
  1334. {
  1335. out_table = TRUE;
  1336. mylog("more than 1 tables\n");
  1337. } else
  1338. {
  1339. out_table = FALSE;
  1340. in_table = TRUE;
  1341. }
  1342. continue;
  1343. }
  1344. if (0 != blevel)
  1345. continue;
  1346. /* out_table is FALSE here */
  1347. if (!dquote && !in_dot)
  1348. {
  1349. if (')' == token[0])
  1350. continue;
  1351. if (stricmp(token, "LEFT") == 0 ||
  1352. stricmp(token, "RIGHT") == 0 ||
  1353. stricmp(token, "OUTER") == 0 ||
  1354. stricmp(token, "FULL") == 0)
  1355. {
  1356. maybe_join = 1;
  1357. in_table = FALSE;
  1358. continue;
  1359. } else if (stricmp(token, "INNER") == 0 ||
  1360. stricmp(token, "CROSS") == 0)
  1361. {
  1362. maybe_join = 2;
  1363. in_table = FALSE;
  1364. continue;
  1365. } else if (stricmp(token, "JOIN") == 0)
  1366. {
  1367. in_table = FALSE;
  1368. out_table = TRUE;
  1369. switch (maybe_join)
  1370. {
  1371. case 1:
  1372. SC_set_outer_join(stmt);
  1373. break;
  1374. case 2:
  1375. SC_set_inner_join(stmt);
  1376. break;
  1377. }
  1378. maybe_join = 0;
  1379. continue;
  1380. }
  1381. }
  1382. maybe_join = 0;
  1383. if (in_table)
  1384. {
  1385. wti = ti[stmt->ntab - 1];
  1386. if (in_dot)
  1387. {
  1388. MOVE_NAME(wti->schema_name, wti->table_name);
  1389. STR_TO_NAME(wti->table_name, token);
  1390. lower_the_name(GET_NAME(wti->table_name), conn,
  1391. dquote);
  1392. in_dot = FALSE;
  1393. continue;
  1394. }
  1395. if (strcmp(token, ".") == 0)
  1396. {
  1397. in_dot = TRUE;
  1398. continue;
  1399. }
  1400. if (dquote || stricmp(token, "as"))
  1401. {
  1402. if (!dquote)
  1403. {
  1404. if (stricmp(token, "ON") == 0)
  1405. {
  1406. in_table = FALSE;
  1407. continue;
  1408. }
  1409. }
  1410. STR_TO_NAME(wti->table_alias, token);
  1411. mylog("alias for table '%s' is '%s'\n",
  1412. PRINT_NAME(wti->table_name),
  1413. PRINT_NAME(wti->table_alias));
  1414. in_table = FALSE;
  1415. if (delim == ',')
  1416. {
  1417. out_table = TRUE;
  1418. mylog("more than 1 tables\n");
  1419. }
  1420. }
  1421. }
  1422. } /* in_from */
  1423. }
  1424. /*
  1425. * Resolve any possible field names with tables
  1426. */
  1427. parse = TRUE;
  1428. /* Resolve field names with tables */
  1429. for (i = 0; i < (int) irdflds->nfields; i++)
  1430. {
  1431. wfi = fi[i];
  1432. if (wfi->func || wfi->expr || wfi->numeric)
  1433. {
  1434. wfi->ti = NULL;
  1435. wfi->columntype = wfi->basetype = (OID) 0;
  1436. parse = FALSE;
  1437. continue;
  1438. } else if (wfi->quote)
  1439. { /* handle as text */
  1440. wfi->ti = NULL;
  1441. /*
  1442. * wfi->type = PG_TYPE_TEXT; wfi->column_size = 0; the
  1443. * following may be better
  1444. */
  1445. wfi->basetype = PG_TYPE_UNKNOWN;
  1446. if (wfi->column_size == 0)
  1447. {
  1448. wfi->basetype = PG_TYPE_VARCHAR;
  1449. wfi->column_size = 254;
  1450. }
  1451. wfi->length = wfi->column_size;
  1452. continue;
  1453. }
  1454. /* field name contains the schema name */
  1455. else if (NAME_IS_VALID(wfi->schema_name))
  1456. {
  1457. int matchidx = -1;
  1458. for (k = 0; k < stmt->ntab; k++)
  1459. {
  1460. wti = ti[k];
  1461. if (!NAMEICMP(wti->table_name, wfi->before_dot))
  1462. {
  1463. if (!NAMEICMP(wti->schema_name, wfi->schema_name))
  1464. {
  1465. wfi->ti = wti;
  1466. break;
  1467. } else if (NAME_IS_NULL(wti->schema_name))
  1468. {
  1469. if (matchidx < 0)
  1470. matchidx = k;
  1471. else
  1472. {
  1473. SC_set_parse_status(stmt, STMT_PARSE_FATAL);
  1474. SC_set_error(stmt, STMT_EXEC_ERROR,
  1475. "duplicated Table name", func);
  1476. stmt->updatable = FALSE;
  1477. goto cleanup;
  1478. }
  1479. }
  1480. }
  1481. }
  1482. if (matchidx >= 0)
  1483. wfi->ti = ti[matchidx];
  1484. }
  1485. /* it's a dot, resolve to table or alias */
  1486. else if (NAME_IS_VALID(wfi->before_dot))
  1487. {
  1488. for (k = 0; k < stmt->ntab; k++)
  1489. {
  1490. wti = ti[k];
  1491. if (!NAMEICMP(wti->table_alias, wfi->before_dot))
  1492. {
  1493. wfi->ti = wti;
  1494. break;
  1495. } else if (!NAMEICMP(wti->table_name, wfi->before_dot))
  1496. {
  1497. wfi->ti = wti;
  1498. break;
  1499. }
  1500. }
  1501. } else if (stmt->ntab == 1)
  1502. wfi->ti = ti[0];
  1503. }
  1504. mylog("--------------------------------------------\n");
  1505. mylog("nfld=%d, ntab=%d\n", irdflds->nfields, stmt->ntab);
  1506. if (0 == stmt->ntab)
  1507. {
  1508. SC_set_parse_status(stmt, STMT_PARSE_FATAL);
  1509. goto cleanup;
  1510. }
  1511. for (i = 0; i < (int) irdflds->nfields; i++)
  1512. {
  1513. wfi = fi[i];
  1514. mylog
  1515. ("Field %d: expr=%d, func=%d, quote=%d, dquote=%d, numeric=%d, name='%s', alias='%s', dot='%s'\n",
  1516. i, wfi->expr, wfi->func, wfi->quote, wfi->dquote,
  1517. wfi->numeric, PRINT_NAME(wfi->column_name),
  1518. PRINT_NAME(wfi->column_alias),
  1519. PRINT_NAME(wfi->before_dot));
  1520. if (wfi->ti)
  1521. mylog(" ----> table_name='%s', table_alias='%s'\n",
  1522. PRINT_NAME(wfi->ti->table_name),
  1523. PRINT_NAME(wfi->ti->table_alias));
  1524. }
  1525. for (i = 0; i < stmt->ntab; i++)
  1526. {
  1527. wti = ti[i];
  1528. mylog("Table %d: name='%s', alias='%s'\n", i,
  1529. PRINT_NAME(wti->table_name),
  1530. PRINT_NAME(wti->table_alias));
  1531. }
  1532. /*
  1533. * Now save the SQLColumns Info for the parse tables
  1534. */
  1535. /* Call SQLColumns for each table and store the result */
  1536. if (stmt->ntab > 1)
  1537. updatable = FALSE;
  1538. else if (stmt->from_pos < 0)
  1539. updatable = FALSE;
  1540. for (i = 0; i < stmt->ntab; i++)
  1541. {
  1542. /* See if already got it */
  1543. wti = ti[i];
  1544. if (!getCOLIfromTI(func, NULL, stmt, 0, &wti))
  1545. break;
  1546. }
  1547. if (STMT_PARSE_FATAL == SC_parsed_status(stmt))
  1548. {
  1549. goto cleanup;
  1550. }
  1551. mylog("Done PG_Columns\n");
  1552. /*
  1553. * Now resolve the fields to point to column info
  1554. */
  1555. if (updatable && 1 == stmt->ntab)
  1556. updatable = TI_is_updatable(stmt->ti[0]);
  1557. for (i = 0; i < (int) irdflds->nfields;)
  1558. {
  1559. wfi = fi[i];
  1560. wfi->updatable = updatable;
  1561. /* Dont worry about functions or quotes */
  1562. if (wfi->func || wfi->quote || wfi->numeric)
  1563. {
  1564. wfi->updatable = FALSE;
  1565. i++;
  1566. continue;
  1567. }
  1568. /* Stars get expanded to all fields in the table */
  1569. else if (SAFE_NAME(wfi->column_name)[0] == '*')
  1570. {
  1571. char do_all_tables;
  1572. Int2 total_cols, cols, increased_cols;
  1573. mylog("expanding field %d\n", i);
  1574. total_cols = 0;
  1575. if (wfi->ti) /* The star represents only the qualified
  1576. * table */
  1577. total_cols =
  1578. (Int2) QR_get_num_cached_tuples(wfi->ti->col_info->
  1579. result);
  1580. else
  1581. { /* The star represents all tables */
  1582. /* Calculate the total number of columns after expansion */
  1583. for (k = 0; k < stmt->ntab; k++)
  1584. total_cols +=
  1585. (Int2) QR_get_num_cached_tuples(ti[k]->
  1586. col_info->
  1587. result);
  1588. }
  1589. increased_cols = total_cols - 1;
  1590. /* Allocate some more field pointers if necessary */
  1591. new_size = irdflds->nfields + increased_cols;
  1592. mylog
  1593. ("k=%d, increased_cols=%d, allocated_size=%d, new_size=%d\n",
  1594. k, increased_cols, allocated_size, new_size);
  1595. if (new_size > allocated_size)
  1596. {
  1597. int new_alloc = new_size;
  1598. mylog("need more cols: new_alloc = %d\n", new_alloc);
  1599. if (!allocateFields(irdflds, new_alloc))
  1600. {
  1601. SC_set_parse_status(stmt, STMT_PARSE_FATAL);
  1602. goto cleanup;
  1603. }
  1604. fi = irdflds->fi;
  1605. allocated_size = irdflds->allocated;
  1606. }
  1607. /*
  1608. * copy any other fields (if there are any) up past the
  1609. * expansion
  1610. */
  1611. for (j = irdflds->nfields - 1; j > i; j--)
  1612. {
  1613. mylog("copying field %d to %d\n", j,
  1614. increased_cols + j);
  1615. fi[increased_cols + j] = fi[j];
  1616. }
  1617. mylog("done copying fields\n");
  1618. /* Set the new number of fields */
  1619. irdflds->nfields += increased_cols;
  1620. mylog("irdflds->nfields now at %d\n", irdflds->nfields);
  1621. /* copy the new field info */
  1622. do_all_tables = (wfi->ti ? FALSE : TRUE);
  1623. wfi = NULL;
  1624. for (k = 0; k < (do_all_tables ? stmt->ntab : 1); k++)
  1625. {
  1626. TABLE_INFO *the_ti = do_all_tables ? ti[k] : fi[i]->ti;
  1627. cols =
  1628. (Int2) QR_get_num_cached_tuples(the_ti->col_info->
  1629. result);
  1630. for (n = 0; n < cols; n++)
  1631. {
  1632. FIELD_INFO *afi;
  1633. BOOL reuse = TRUE;
  1634. mylog("creating field info: n=%d\n", n);
  1635. /* skip malloc (already did it for the Star) */
  1636. if (k > 0 || n > 0)
  1637. {
  1638. mylog("allocating field info at %d\n", n + i);
  1639. fi[n + i] =
  1640. (FIELD_INFO *) malloc(sizeof(FIELD_INFO));
  1641. if (fi[n + i] == NULL)
  1642. {
  1643. SC_set_parse_status(stmt, STMT_PARSE_FATAL);
  1644. goto cleanup;
  1645. }
  1646. reuse = FALSE;
  1647. }
  1648. afi = fi[n + i];
  1649. /* Initialize the new space (or the * field) */
  1650. FI_Constructor(afi, reuse);
  1651. afi->ti = the_ti;
  1652. mylog("about to copy at %d\n", n + i);
  1653. getColInfo(the_ti->col_info, afi, n);
  1654. afi->updatable = updatable;
  1655. mylog("done copying\n");
  1656. }
  1657. i += cols;
  1658. mylog("i now at %d\n", i);
  1659. }
  1660. }
  1661. /*
  1662. * We either know which table the field was in because it was
  1663. * qualified with a table name or alias -OR- there was only 1
  1664. * table.
  1665. */
  1666. else if (wfi->ti)
  1667. {
  1668. if (!searchColInfo(fi[i]->ti->col_info, wfi))
  1669. {
  1670. parse = FALSE;
  1671. wfi->updatable = FALSE;
  1672. }
  1673. i++;
  1674. }
  1675. /* Don't know the table -- search all tables in "from" list */
  1676. else
  1677. {
  1678. for (k = 0; k < stmt->ntab; k++)
  1679. {
  1680. if (searchColInfo(ti[k]->col_info, wfi))
  1681. {
  1682. wfi->ti = ti[k]; /* now know the table */
  1683. break;
  1684. }
  1685. }
  1686. if (k >= stmt->ntab)
  1687. {
  1688. parse = FALSE;
  1689. wfi->updatable = FALSE;
  1690. }
  1691. i++;
  1692. }
  1693. }
  1694. if (check_hasoids && updatable)
  1695. CheckHasOids(stmt);
  1696. SC_set_parse_status(stmt,
  1697. parse ? STMT_PARSE_COMPLETE :
  1698. STMT_PARSE_INCOMPLETE);
  1699. for (i = 0; i < (int) irdflds->nfields; i++)
  1700. {
  1701. wfi = fi[i];
  1702. wfi->flag &= ~FIELD_PARSING;
  1703. if (0 != wfi->columntype || 0 != wfi->basetype)
  1704. wfi->flag |= FIELD_PARSED_OK;
  1705. }
  1706. stmt->updatable = updatable;
  1707. cleanup:
  1708. #undef return
  1709. if (STMT_PARSE_FATAL == SC_parsed_status(stmt))
  1710. {
  1711. SC_initialize_cols_info(stmt, FALSE, FALSE);
  1712. parse = FALSE;
  1713. }
  1714. mylog("done parse_statement: parse=%d, parse_status=%d\n", parse,
  1715. SC_parsed_status(stmt));
  1716. return parse;
  1717. }