Merge commit 'origin/master'
[versaplex.git] / vxodbc / parse.cc
blobb2a931ffe538b8f9671a8de7ed10b1b8010ad69b
1 /*
2 * Description: This module contains routines related to parsing SQL
3 * statements. This can be useful for two reasons:
5 * 1. So the query does not actually have to be executed
6 * to return data about it
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.
14 /* Multibyte support Eiji Tokuya 2001-03-15 */
16 #include "psqlodbc.h"
18 #include <stdio.h>
19 #include <string.h>
20 #include <ctype.h>
22 #include "statement.h"
23 #include "connection.h"
24 #include "qresult.h"
25 #include "pgtypes.h"
26 #include "pgapifunc.h"
27 #include "catfunc.h"
29 #include "multibyte.h"
31 #define FLD_INCR 32
32 #define TAB_INCR 8
33 #define COLI_INCR 16
35 static char *getNextToken(int ccsc, char escape_in_literal, char *s,
36 char *token, int smax, char *delim,
37 char *quote, char *dquote, char *numeric);
38 static void getColInfo(COL_INFO * col_info, FIELD_INFO * fi, int k);
39 static char searchColInfo(COL_INFO * col_info, FIELD_INFO * fi);
41 Int4 FI_precision(const FIELD_INFO * fi)
43 OID ftype;
45 if (!fi)
46 return -1;
47 ftype = FI_type(fi);
48 switch (ftype)
50 case PG_TYPE_NUMERIC:
51 return fi->column_size;
53 return 0;
56 Int4 FI_scale(const FIELD_INFO * fi)
58 OID ftype;
60 if (!fi)
61 return -1;
62 ftype = FI_type(fi);
63 switch (ftype)
65 case PG_TYPE_NUMERIC:
66 return fi->decimal_digits;
68 return 0;
71 static char *getNextToken(int ccsc, /* client encoding */
72 char escape_ch,
73 char *s, char *token, int smax, char *delim,
74 char *quote, char *dquote, char *numeric)
76 int i = 0;
77 int out = 0, taglen;
78 char qc, in_quote, in_dollar_quote, in_escape;
79 const char *tag, *tagend;
80 encoded_str encstr;
81 char literal_quote = LITERAL_QUOTE, identifier_quote =
82 IDENTIFIER_QUOTE, dollar_quote =
83 DOLLAR_QUOTE, escape_in_literal;
85 if (smax <= 1)
86 return NULL;
88 smax--;
90 /* skip leading delimiters */
91 while (isspace((UCHAR) s[i]) || s[i] == ',')
93 /* mylog("skipping '%c'\n", s[i]); */
94 i++;
97 if (s[i] == '\0')
99 token[0] = '\0';
100 return NULL;
103 if (quote)
104 *quote = FALSE;
105 if (dquote)
106 *dquote = FALSE;
107 if (numeric)
108 *numeric = FALSE;
110 encoded_str_constr(&encstr, ccsc, &s[i]);
111 /* get the next token */
112 while (s[i] != '\0' && out < smax)
114 encoded_nextchar(&encstr);
115 if (ENCODE_STATUS(encstr) != 0)
117 token[out++] = s[i++];
118 continue;
120 if (isspace((UCHAR) s[i]) || s[i] == ',')
121 break;
122 /* Handle quoted stuff */
123 in_quote = in_dollar_quote = FALSE;
124 taglen = 0;
125 tag = NULL;
126 escape_in_literal = '\0';
127 if (out == 0)
129 qc = s[i];
130 if (qc == dollar_quote)
132 in_quote = in_dollar_quote = TRUE;
133 tag = s + i;
134 taglen = 1;
135 if (tagend =
136 strchr(s + i + 1, dollar_quote), NULL != tagend)
137 taglen = tagend - s - i + 1;
138 i += (taglen - 1);
139 encoded_position_shift(&encstr, taglen - 1);
140 if (quote)
141 *quote = TRUE;
142 } else if (qc == literal_quote)
144 in_quote = TRUE;
145 if (quote)
146 *quote = TRUE;
147 escape_in_literal = escape_ch;
148 if (!escape_in_literal)
150 if (LITERAL_EXT == s[i - 1])
151 escape_in_literal = ESCAPE_IN_LITERAL;
153 } else if (qc == identifier_quote)
155 in_quote = TRUE;
156 if (dquote)
157 *dquote = TRUE;
160 if (in_quote)
162 i++; /* dont return the quote */
163 in_escape = FALSE;
164 while (s[i] != '\0' && out != smax)
166 encoded_nextchar(&encstr);
167 if (ENCODE_STATUS(encstr) != 0)
169 token[out++] = s[i++];
170 continue;
172 if (in_escape)
173 in_escape = FALSE;
174 else if (s[i] == qc)
176 if (!in_dollar_quote)
177 break;
178 if (strncmp(s + i, tag, taglen) == 0)
180 i += (taglen - 1);
181 encoded_position_shift(&encstr, taglen - 1);
182 break;
184 token[out++] = s[i];
185 } else if (literal_quote == qc
186 && s[i] == escape_in_literal)
188 in_escape = TRUE;
189 } else
191 token[out++] = s[i];
193 i++;
195 if (s[i] == qc)
196 i++;
197 break;
200 /* Check for numeric literals */
201 if (out == 0 && isdigit((UCHAR) s[i]))
203 if (numeric)
204 *numeric = TRUE;
205 token[out++] = s[i++];
206 while (isalnum((UCHAR) s[i]) || s[i] == '.')
207 token[out++] = s[i++];
209 break;
212 if (ispunct((UCHAR) s[i]) && s[i] != '_')
214 mylog("got ispunct: s[%d] = '%c'\n", i, s[i]);
216 if (out == 0)
218 token[out++] = s[i++];
219 break;
220 } else
221 break;
224 if (out != smax)
225 token[out++] = s[i];
227 i++;
230 /* mylog("done -- s[%d] = '%c'\n", i, s[i]); */
232 token[out] = '\0';
234 /* find the delimiter */
235 while (isspace((UCHAR) s[i]))
236 i++;
238 /* return the most priority delimiter */
239 if (s[i] == ',')
241 if (delim)
242 *delim = s[i];
243 } else if (s[i] == '\0')
245 if (delim)
246 *delim = '\0';
247 } else
249 if (delim)
250 *delim = ' ';
253 /* skip trailing blanks */
254 while (isspace((UCHAR) s[i]))
255 i++;
257 return &s[i];
260 static void getColInfo(COL_INFO * col_info, FIELD_INFO * fi, int k)
262 char *str;
264 inolog("getColInfo non-manual result\n");
265 fi->dquote = TRUE;
266 STR_TO_NAME(fi->column_name,
267 QR_get_value_backend_text(col_info->result, k,
268 COLUMNS_COLUMN_NAME));
270 fi->columntype =
271 (OID) QR_get_value_backend_int(col_info->result, k,
272 COLUMNS_FIELD_TYPE, NULL);
273 fi->column_size =
274 QR_get_value_backend_int(col_info->result, k, COLUMNS_PRECISION,
275 NULL);
276 fi->length =
277 QR_get_value_backend_int(col_info->result, k, COLUMNS_LENGTH,
278 NULL);
279 if (str = (char *)
280 QR_get_value_backend_text(col_info->result, k, COLUMNS_SCALE),
281 str)
282 fi->decimal_digits = atoi(str);
283 else
284 fi->decimal_digits = -1;
285 fi->nullable =
286 QR_get_value_backend_int(col_info->result, k, COLUMNS_NULLABLE,
287 NULL);
288 fi->display_size =
289 QR_get_value_backend_int(col_info->result, k,
290 COLUMNS_DISPLAY_SIZE, NULL);
291 fi->auto_increment =
292 QR_get_value_backend_int(col_info->result, k,
293 COLUMNS_AUTO_INCREMENT, NULL);
297 static char searchColInfo(COL_INFO * col_info, FIELD_INFO * fi)
299 int k, cmp, attnum;
300 const char *col;
302 inolog("searchColInfo num_cols=%d col=%s\n",
303 QR_get_num_cached_tuples(col_info->result),
304 PRINT_NAME(fi->column_name));
305 if (fi->attnum < 0)
306 return FALSE;
307 for (k = 0; k < QR_get_num_cached_tuples(col_info->result); k++)
309 if (fi->attnum > 0)
311 attnum =
312 QR_get_value_backend_int(col_info->result, k,
313 COLUMNS_PHYSICAL_NUMBER, NULL);
314 inolog("searchColInfo %d attnum=%d\n", k, attnum);
315 if (attnum == fi->attnum)
317 getColInfo(col_info, fi, k);
318 mylog("PARSE: searchColInfo by attnum=%d\n", attnum);
319 return TRUE;
321 } else if (NAME_IS_VALID(fi->column_name))
323 col =
324 QR_get_value_backend_text(col_info->result, k,
325 COLUMNS_COLUMN_NAME);
326 inolog("searchColInfo %d col=%s\n", k, col);
327 if (fi->dquote)
328 cmp = strcmp(col, GET_NAME(fi->column_name));
329 else
330 cmp = stricmp(col, GET_NAME(fi->column_name));
331 if (!cmp)
333 if (!fi->dquote)
334 STR_TO_NAME(fi->column_name, col);
335 getColInfo(col_info, fi, k);
337 mylog("PARSE: searchColInfo: \n");
338 return TRUE;
343 return FALSE;
347 * lower the unquoted name
349 static
350 void lower_the_name(char *name, ConnectionClass * conn, BOOL dquote)
352 if (!dquote)
354 char *ptr;
355 encoded_str encstr;
356 make_encoded_str(&encstr, conn, name);
358 /* lower case table name */
359 for (ptr = name; *ptr; ptr++)
361 encoded_nextchar(&encstr);
362 if (ENCODE_STATUS(encstr) == 0)
363 *ptr = tolower((UCHAR) * ptr);
368 static BOOL CheckHasOids(StatementClass * stmt)
370 QResultClass *res;
371 BOOL hasoids = TRUE, foundKey = FALSE;
372 char query[512];
373 ConnectionClass *conn = SC_get_conn(stmt);
374 TABLE_INFO *ti;
376 if (0 != SC_checked_hasoids(stmt))
377 return TRUE;
378 if (!stmt->ti || !stmt->ti[0])
379 return FALSE;
380 ti = stmt->ti[0];
381 sprintf(query,
382 "select relhasoids, c.oid from pg_class c, pg_namespace n where relname = '%s' and nspname = '%s' and c.relnamespace = n.oid",
383 SAFE_NAME(ti->table_name), SAFE_NAME(ti->schema_name));
384 res =
385 CC_send_query(conn, query, NULL,
386 ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN, NULL);
387 if (QR_command_maybe_successful(res))
389 stmt->num_key_fields = PG_NUM_NORMAL_KEYS;
390 if (1 == QR_get_num_total_tuples(res))
392 const char *value = QR_get_value_backend_text(res, 0, 0);
393 if (value && ('f' == *value || '0' == *value))
395 hasoids = FALSE;
396 TI_set_has_no_oids(ti);
397 } else
399 TI_set_hasoids(ti);
400 foundKey = TRUE;
401 STR_TO_NAME(ti->bestitem, OID_NAME);
402 strcpy(query, "\"oid\" = %u");
403 /*strcpy(query, "\"oid\" = %%u"); */
404 STR_TO_NAME(ti->bestqual, query);
406 TI_set_hasoids_checked(ti);
407 ti->table_oid =
408 (OID) strtoul(QR_get_value_backend_text(res, 0, 1),
409 NULL, 10);
411 QR_Destructor(res);
412 res = NULL;
413 if (!hasoids)
415 sprintf(query,
416 "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)",
417 ti->table_oid, PG_TYPE_INT4, PG_TYPE_OID);
418 res =
419 CC_send_query(conn, query, NULL,
420 ROLLBACK_ON_ERROR | IGNORE_ABORT_ON_CONN,
421 NULL);
422 if (QR_command_maybe_successful(res)
423 && QR_get_num_total_tuples(res) > 0)
425 foundKey = TRUE;
426 STR_TO_NAME(ti->bestitem,
427 QR_get_value_backend_text(res, 0, 0));
428 sprintf(query, "\"%s\" = %%", SAFE_NAME(ti->bestitem));
429 if (PG_TYPE_INT4 ==
430 (OID) QR_get_value_backend_int(res, 0, 1, NULL))
431 strcat(query, "d");
432 else
433 strcat(query, "u");
434 STR_TO_NAME(ti->bestqual, query);
435 } else
437 /* stmt->updatable = FALSE; */
438 foundKey = TRUE;
439 stmt->num_key_fields--;
443 QR_Destructor(res);
444 SC_set_checked_hasoids(stmt, foundKey);
445 return TRUE;
448 static BOOL increaseNtab(StatementClass * stmt, const char *func)
450 TABLE_INFO **ti = stmt->ti, *wti;
452 if (!(stmt->ntab % TAB_INCR))
454 ti = (TABLE_INFO **) realloc(ti,
455 (stmt->ntab +
456 TAB_INCR) * sizeof(TABLE_INFO *));
457 if (!ti)
459 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
460 "PGAPI_AllocStmt failed in parse_statement for TABLE_INFO.",
461 func);
462 return FALSE;
464 stmt->ti = ti;
466 wti = ti[stmt->ntab] = (TABLE_INFO *) malloc(sizeof(TABLE_INFO));
467 if (wti == NULL)
469 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
470 "PGAPI_AllocStmt failed in parse_statement for TABLE_INFO(2).",
471 func);
472 return FALSE;
475 TI_Constructor(wti, SC_get_conn(stmt));
476 stmt->ntab++;
477 return TRUE;
480 static void setNumFields(IRDFields * irdflds, size_t numFields)
482 FIELD_INFO **fi = irdflds->fi;
483 size_t nfields = irdflds->nfields;
485 if (numFields < nfields)
487 int i;
489 for (i = (int) numFields; i < (int) nfields; i++)
491 if (fi[i])
492 fi[i]->flag = 0;
495 irdflds->nfields = (UInt4) numFields;
498 void SC_initialize_cols_info(StatementClass * stmt, BOOL DCdestroy,
499 BOOL parseReset)
501 IRDFields *irdflds = SC_get_IRDF(stmt);
503 /* Free the parsed table information */
504 if (stmt->ti)
506 TI_Destructor(stmt->ti, stmt->ntab);
507 free(stmt->ti);
508 stmt->ti = NULL;
510 stmt->ntab = 0;
511 if (DCdestroy) /* Free the parsed field information */
512 DC_Destructor((DescriptorClass *) SC_get_IRD(stmt));
513 else
514 setNumFields(irdflds, 0);
515 if (parseReset)
517 stmt->parse_status = STMT_PARSE_NONE;
518 stmt->updatable = FALSE;
522 static BOOL allocateFields(IRDFields * irdflds, size_t sizeRequested)
524 FIELD_INFO **fi = irdflds->fi;
525 size_t alloc_size, incr_size;
527 if (sizeRequested <= irdflds->allocated)
528 return TRUE;
529 alloc_size =
530 (0 != irdflds->allocated ? irdflds->allocated : FLD_INCR);
531 for (; alloc_size < sizeRequested; alloc_size *= 2)
533 incr_size =
534 sizeof(FIELD_INFO *) * (alloc_size - irdflds->allocated);
536 fi = (FIELD_INFO **) realloc(fi, alloc_size * sizeof(FIELD_INFO *));
537 if (!fi)
539 irdflds->fi = NULL;
540 irdflds->allocated = irdflds->nfields = 0;
541 return FALSE;
543 memset(&fi[irdflds->allocated], 0, incr_size);
544 irdflds->fi = fi;
545 irdflds->allocated = (SQLSMALLINT) alloc_size;
547 return TRUE;
550 static void xxxxx(FIELD_INFO * fi, QResultClass * res, int i)
552 STR_TO_NAME(fi->column_alias, QR_get_fieldname(res, i));
553 fi->basetype = QR_get_field_type(res, i);
554 if (0 == fi->columntype)
555 fi->columntype = fi->basetype;
556 if (fi->attnum < 0)
558 fi->nullable = FALSE;
559 fi->updatable = FALSE;
560 } else if (fi->attnum > 0)
561 fi->nullable = TRUE; /* probably ? */
563 if (NAME_IS_NULL(fi->column_name))
565 switch (fi->attnum)
567 case CTID_ATTNUM:
568 STR_TO_NAME(fi->column_name, "ctid");
569 break;
570 case OID_ATTNUM:
571 STR_TO_NAME(fi->column_name, OID_NAME);
572 break;
573 case XMIN_ATTNUM:
574 STR_TO_NAME(fi->column_name, "xmin");
575 break;
581 * SQLColAttribute tries to set the FIELD_INFO (using protocol 3).
583 static BOOL ColAttSet(StatementClass * stmt, TABLE_INFO * rti)
585 QResultClass *res = SC_get_Curres(stmt);
586 IRDFields *irdflds = SC_get_IRDF(stmt);
587 COL_INFO *col_info = NULL;
588 FIELD_INFO **fi, *wfi;
589 OID reloid = 0;
590 Int2 attid;
591 int i, num_fields;
592 BOOL fi_reuse, updatable;
594 mylog("ColAttSet in\n");
595 if (rti)
597 if (reloid = rti->table_oid, 0 == reloid)
598 return FALSE;
599 if (0 != (rti->flags & TI_COLATTRIBUTE))
600 return TRUE;
601 col_info = rti->col_info;
603 if (!QR_command_maybe_successful(res))
604 return FALSE;
605 if (num_fields = QR_NumPublicResultCols(res), num_fields <= 0)
606 return FALSE;
607 fi = irdflds->fi;
608 if (num_fields > (int) irdflds->allocated)
610 if (!allocateFields(irdflds, num_fields))
611 return FALSE;
612 fi = irdflds->fi;
614 setNumFields(irdflds, num_fields);
615 updatable = rti ? TI_is_updatable(rti) : FALSE;
616 mylog("updatable=%d tab=%d fields=%d", updatable, stmt->ntab,
617 num_fields);
618 if (updatable)
620 if (1 != stmt->ntab)
621 updatable = FALSE;
622 else if (SC_has_join(stmt))
623 updatable = FALSE;
624 else
626 OID greloid;
628 for (i = 0; i < num_fields; i++)
630 greloid = QR_get_relid(res, i);
631 if (0 != greloid && reloid != greloid)
633 updatable = FALSE;
634 break;
639 mylog("->%d\n", updatable);
640 for (i = 0; i < num_fields; i++)
642 if (reloid == (OID) QR_get_relid(res, i))
644 if (wfi = fi[i], NULL == wfi)
646 wfi = (FIELD_INFO *) malloc(sizeof(FIELD_INFO));
647 fi_reuse = FALSE;
648 fi[i] = wfi;
649 } else if (FI_is_applicable(wfi))
650 continue;
651 else
652 fi_reuse = TRUE;
653 FI_Constructor(wfi, fi_reuse);
654 attid = (Int2) QR_get_attid(res, i);
655 wfi->attnum = attid;
656 if (searchColInfo(col_info, wfi))
658 STR_TO_NAME(wfi->column_alias,
659 QR_get_fieldname(res, i));
660 wfi->basetype = QR_get_field_type(res, i);
661 wfi->updatable = updatable;
662 } else
664 xxxxx(wfi, res, i);
666 wfi->ti = rti;
667 wfi->flag |= FIELD_COL_ATTRIBUTE;
670 if (rti)
671 rti->flags |= TI_COLATTRIBUTE;
672 return TRUE;
675 static BOOL
676 getCOLIfromTable(ConnectionClass * conn, pgNAME * schema_name,
677 pgNAME table_name, COL_INFO ** coli)
679 int colidx;
680 BOOL found = FALSE;
682 *coli = NULL;
683 if (NAME_IS_NULL(table_name))
684 return TRUE;
685 if (conn->schema_support)
687 if (NAME_IS_NULL(*schema_name))
689 const char *curschema = CC_get_current_schema(conn);
691 * Though current_schema() doesn't have
692 * much sense in PostgreSQL, we first
693 * check the current_schema() when no
694 * explicit schema name was specified.
696 for (colidx = 0; colidx < conn->ntables; colidx++)
698 if (!NAMEICMP
699 (conn->col_info[colidx]->table_name, table_name)
701 !stricmp(SAFE_NAME
702 (conn->col_info[colidx]->schema_name),
703 curschema))
705 mylog
706 ("FOUND col_info table='%s' current schema='%s'\n",
707 PRINT_NAME(table_name), curschema);
708 found = TRUE;
709 STR_TO_NAME(*schema_name, curschema);
710 break;
713 if (!found)
715 QResultClass *res;
716 char token[256];
717 BOOL tblFound = FALSE;
720 * We also have to check as follows.
722 sprintf(token,
723 "select nspname from pg_namespace n, pg_class c"
724 " where c.relnamespace=n.oid and c.oid='\"%s\"'::regclass",
725 SAFE_NAME(table_name));
726 res =
727 CC_send_query(conn, token, NULL,
728 ROLLBACK_ON_ERROR |
729 IGNORE_ABORT_ON_CONN, NULL);
730 if (QR_command_maybe_successful(res))
732 if (QR_get_num_total_tuples(res) == 1)
734 tblFound = TRUE;
735 STR_TO_NAME(*schema_name,
736 QR_get_value_backend_text(res, 0,
737 0));
740 QR_Destructor(res);
741 if (!tblFound)
742 return FALSE;
745 if (!found && NAME_IS_VALID(*schema_name))
747 for (colidx = 0; colidx < conn->ntables; colidx++)
749 if (!NAMEICMP
750 (conn->col_info[colidx]->table_name, table_name)
751 && !NAMEICMP(conn->col_info[colidx]->schema_name,
752 *schema_name))
754 mylog("FOUND col_info table='%s' schema='%s'\n",
755 PRINT_NAME(table_name),
756 PRINT_NAME(*schema_name));
757 found = TRUE;
758 break;
762 } else
764 for (colidx = 0; colidx < conn->ntables; colidx++)
766 if (!NAMEICMP
767 (conn->col_info[colidx]->table_name, table_name))
769 mylog("FOUND col_info table='%s'\n", table_name);
770 found = TRUE;
771 break;
775 *coli = found ? conn->col_info[colidx] : NULL;
776 return TRUE; /* success */
779 BOOL getCOLIfromTI(const char *func, ConnectionClass * conn,
780 StatementClass * stmt, const OID reloid,
781 TABLE_INFO ** pti)
783 BOOL colatt = FALSE, found = FALSE;
784 OID greloid = reloid;
785 TABLE_INFO *wti = *pti;
786 COL_INFO *coli;
787 HSTMT hcol_stmt = NULL;
788 QResultClass *res;
790 inolog("getCOLIfromTI reloid=%u ti=%p\n", reloid, wti);
791 if (!conn)
792 conn = SC_get_conn(stmt);
793 if (!wti) /* SQLColAttribute case */
795 int i;
796 if (0 == greloid)
797 return FALSE;
798 colatt = TRUE;
799 for (i = 0; i < stmt->ntab; i++)
801 if (stmt->ti[i]->table_oid == greloid)
803 wti = stmt->ti[i];
804 break;
807 if (!wti)
809 inolog("before increaseNtab\n");
810 if (!increaseNtab(stmt, func))
811 return FALSE;
812 wti = stmt->ti[stmt->ntab - 1];
813 wti->table_oid = greloid;
815 *pti = wti;
817 inolog("fi=%p greloid=%d col_info=%p\n", wti, greloid,
818 wti->col_info);
819 if (0 == greloid)
820 greloid = wti->table_oid;
821 if (NULL != wti->col_info)
823 found = TRUE;
824 goto cleanup;
826 if (greloid != 0)
828 int colidx;
830 for (colidx = 0; colidx < conn->ntables; colidx++)
832 if (conn->col_info[colidx]->table_oid == greloid)
834 mylog("FOUND col_info table=%ul\n", greloid);
835 found = TRUE;
836 wti->col_info = conn->col_info[colidx];
837 break;
840 } else
842 if (!getCOLIfromTable
843 (conn, &wti->schema_name, wti->table_name, &coli))
845 if (stmt)
847 SC_set_parse_status(stmt, STMT_PARSE_FATAL);
848 SC_set_error(stmt, STMT_EXEC_ERROR, "Table not found",
849 func);
850 stmt->updatable = FALSE;
852 return FALSE;
853 } else if (NULL != coli)
855 found = TRUE;
856 wti->col_info = coli;
859 if (found)
860 goto cleanup;
861 else if (0 != greloid || NAME_IS_VALID(wti->table_name))
863 RETCODE result;
864 StatementClass *col_stmt;
866 mylog("PARSE: Getting PG_Columns for table='%s'\n",
867 wti->table_name);
869 result = PGAPI_AllocStmt(conn, &hcol_stmt);
870 if ((result != SQL_SUCCESS)
871 && (result != SQL_SUCCESS_WITH_INFO))
873 if (stmt)
874 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
875 "PGAPI_AllocStmt failed in parse_statement for columns.",
876 func);
877 goto cleanup;
880 col_stmt = (StatementClass *) hcol_stmt;
881 col_stmt->internal = TRUE;
883 if (greloid)
884 result = PGAPI_Columns(hcol_stmt, NULL, 0,
885 NULL, 0, NULL, 0, NULL, 0,
886 PODBC_SEARCH_BY_IDS, greloid, 0);
887 else
888 result =
889 PGAPI_Columns(hcol_stmt, NULL, 0,
890 (const UCHAR *)SAFE_NAME(wti->schema_name),
891 SQL_NTS,
892 (const UCHAR *)SAFE_NAME(wti->table_name),
893 SQL_NTS, NULL, 0,
894 PODBC_NOT_SEARCH_PATTERN, 0, 0);
896 mylog(" Past PG_Columns\n");
897 res = SC_get_Curres(col_stmt);
898 if ((SQL_SUCCESS == result || SQL_SUCCESS_WITH_INFO == result)
899 && res && QR_get_num_cached_tuples(res) > 0)
901 COL_INFO *coli;
903 mylog(" Success\n");
904 if (conn->ntables >= conn->coli_allocated)
906 Int2 new_alloc;
908 new_alloc = conn->coli_allocated * 2;
909 if (new_alloc <= conn->ntables)
910 new_alloc = COLI_INCR;
911 mylog("PARSE: Allocating col_info at ntables=%d\n",
912 conn->ntables);
914 conn->col_info =
915 (COL_INFO **) realloc(conn->col_info,
916 new_alloc *
917 sizeof(COL_INFO *));
918 if (!conn->col_info)
920 if (stmt)
921 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
922 "PGAPI_AllocStmt failed in parse_statement for col_info.",
923 func);
924 goto cleanup;
926 conn->coli_allocated = new_alloc;
929 mylog("PARSE: malloc at conn->col_info[%d]\n",
930 conn->ntables);
931 coli = conn->col_info[conn->ntables] =
932 (COL_INFO *) malloc(sizeof(COL_INFO));
933 if (!coli)
935 if (stmt)
936 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
937 "PGAPI_AllocStmt failed in parse_statement for col_info(2).",
938 func);
939 goto cleanup;
941 col_info_initialize(coli);
943 coli->result = res;
944 if (res && QR_get_num_cached_tuples(res) > 0)
946 if (!greloid)
947 greloid =
948 (OID)
949 strtoul(QR_get_value_backend_text
950 (res, 0, COLUMNS_TABLE_OID), NULL, 10);
951 if (!wti->table_oid)
952 wti->table_oid = greloid;
953 if (NAME_IS_NULL(wti->schema_name))
954 STR_TO_NAME(wti->schema_name,
955 QR_get_value_backend_text(res, 0,
956 COLUMNS_SCHEMA_NAME));
957 if (NAME_IS_NULL(wti->table_name))
958 STR_TO_NAME(wti->table_name,
959 QR_get_value_backend_text(res, 0,
960 COLUMNS_TABLE_NAME));
962 inolog("#2 %p->table_name=%s(%u)\n", wti,
963 PRINT_NAME(wti->table_name), wti->table_oid);
965 * Store the table name and the SQLColumns result
966 * structure
968 if (NAME_IS_VALID(wti->schema_name))
970 NAME_TO_NAME(coli->schema_name, wti->schema_name);
971 } else
972 NULL_THE_NAME(coli->schema_name);
973 NAME_TO_NAME(coli->table_name, wti->table_name);
974 coli->table_oid = wti->table_oid;
977 * The connection will now free the result structures, so
978 * make sure that the statement doesn't free it
980 SC_init_Result(col_stmt);
982 conn->ntables++;
984 if (res && QR_get_num_cached_tuples(res) > 0)
985 inolog("oid item == %s\n",
986 QR_get_value_backend_text(res, 0, 3));
988 mylog("Created col_info table='%s', ntables=%d\n",
989 PRINT_NAME(wti->table_name), conn->ntables);
990 /* Associate a table from the statement with a SQLColumn info */
991 found = TRUE;
992 wti->col_info = coli;
995 cleanup:
996 if (hcol_stmt)
997 PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
998 if (found)
1000 QResultClass *res = wti->col_info->result;
1002 if (res && QR_get_num_cached_tuples(res) > 0)
1004 if (!greloid)
1005 greloid =
1006 (OID)
1007 strtoul(QR_get_value_backend_text
1008 (res, 0, COLUMNS_TABLE_OID), NULL, 10);
1009 if (!wti->table_oid)
1010 wti->table_oid = greloid;
1011 if (NAME_IS_NULL(wti->schema_name))
1012 STR_TO_NAME(wti->schema_name,
1013 QR_get_value_backend_text(res, 0,
1014 COLUMNS_SCHEMA_NAME));
1015 if (NAME_IS_NULL(wti->table_name))
1016 STR_TO_NAME(wti->table_name,
1017 QR_get_value_backend_text(res, 0,
1018 COLUMNS_TABLE_NAME));
1020 inolog("#1 %p->table_name=%s(%u)\n", wti,
1021 PRINT_NAME(wti->table_name), wti->table_oid);
1022 if (colatt /* SQLColAttribute case */
1023 && 0 == (wti->flags & TI_COLATTRIBUTE))
1025 if (stmt)
1026 ColAttSet(stmt, wti);
1028 } else if (!colatt && stmt)
1029 SC_set_parse_status(stmt, STMT_PARSE_FATAL);
1030 inolog("getCOLIfromTI returns %d\n", found);
1031 return found;
1034 char parse_statement(StatementClass * stmt, BOOL check_hasoids)
1036 CSTR func = "parse_statement";
1037 char token[256], stoken[256];
1038 char delim, quote, dquote, numeric, unquoted;
1039 char *ptr, *pptr = NULL;
1040 char in_select = FALSE,
1041 in_distinct = FALSE,
1042 in_on = FALSE,
1043 in_from = FALSE,
1044 in_where = FALSE, in_table = FALSE, out_table = TRUE;
1045 char in_field = FALSE,
1046 in_expr = FALSE, in_func = FALSE, in_dot = FALSE, in_as = FALSE;
1047 int j,
1049 k = 0,
1051 blevel = 0, old_blevel, subqlevel = 0, allocated_size, new_size;
1052 FIELD_INFO **fi, *wfi;
1053 TABLE_INFO **ti, *wti;
1054 char parse, maybe_join = 0;
1055 ConnectionClass *conn = SC_get_conn(stmt);
1056 IRDFields *irdflds = SC_get_IRDF(stmt);
1057 BOOL updatable = TRUE;
1059 mylog("%s: entering...\n", func);
1061 if (SC_parsed_status(stmt) != STMT_PARSE_NONE)
1063 if (check_hasoids)
1064 CheckHasOids(stmt);
1065 return TRUE;
1067 stmt->updatable = FALSE;
1068 ptr = stmt->statement;
1069 fi = irdflds->fi;
1070 ti = stmt->ti;
1072 allocated_size = irdflds->allocated;
1073 SC_initialize_cols_info(stmt, FALSE, TRUE);
1074 stmt->from_pos = -1;
1075 stmt->where_pos = -1;
1076 #define return DONT_CALL_RETURN_FROM_HERE???
1078 while (pptr =
1079 ptr, (ptr =
1080 getNextToken(conn->ccsc, CC_get_escape(conn), pptr,
1081 token, sizeof(token), &delim, &quote,
1082 &dquote, &numeric)) != NULL)
1084 unquoted = !(quote || dquote);
1086 mylog
1087 ("unquoted=%d, quote=%d, dquote=%d, numeric=%d, delim='%c', token='%s', ptr='%s'\n",
1088 unquoted, quote, dquote, numeric, delim, token, ptr);
1090 old_blevel = blevel;
1091 if (unquoted && blevel == 0)
1093 if (in_select)
1095 if (!stricmp(token, "distinct"))
1097 in_distinct = TRUE;
1098 updatable = FALSE;
1100 mylog("DISTINCT\n");
1101 continue;
1102 } else if (!stricmp(token, "into"))
1104 in_select = FALSE;
1105 mylog("INTO\n");
1106 stmt->statement_type = STMT_TYPE_CREATE;
1107 SC_set_parse_status(stmt, STMT_PARSE_FATAL);
1108 goto cleanup;
1109 } else if (!stricmp(token, "from"))
1111 in_select = FALSE;
1112 in_from = TRUE;
1113 if (stmt->from_pos < 0 &&
1114 (!strnicmp(pptr, "from", 4)))
1116 mylog("First ");
1117 stmt->from_pos = pptr - stmt->statement;
1120 mylog("FROM\n");
1121 continue;
1123 } /* in_select && unquoted && blevel == 0 */
1124 else if ((!stricmp(token, "where") ||
1125 !stricmp(token, "union") ||
1126 !stricmp(token, "intersect") ||
1127 !stricmp(token, "except") ||
1128 !stricmp(token, "order") ||
1129 !stricmp(token, "group") ||
1130 !stricmp(token, "having")))
1132 in_from = FALSE;
1133 in_where = TRUE;
1135 if (stmt->where_pos < 0)
1136 stmt->where_pos = pptr - stmt->statement;
1137 mylog("%s...\n", token);
1138 if (stricmp(token, "where") && stricmp(token, "order"))
1140 updatable = FALSE;
1141 break;
1143 continue;
1146 /* unquoted && blevel == 0 */
1147 /* check the change of blevel etc */
1148 if (unquoted)
1150 if (!stricmp(token, "select"))
1152 stoken[0] = '\0';
1153 if (0 == blevel)
1155 in_select = TRUE;
1156 mylog("SELECT\n");
1157 continue;
1158 } else
1160 mylog("SUBSELECT\n");
1161 if (0 == subqlevel)
1162 subqlevel = blevel;
1164 } else if (token[0] == '(')
1166 blevel++;
1167 mylog("blevel++ = %d\n", blevel);
1168 /* aggregate function ? */
1169 if (stoken[0] && updatable && 0 == subqlevel)
1171 if (stricmp(stoken, "count") == 0 ||
1172 stricmp(stoken, "sum") == 0 ||
1173 stricmp(stoken, "avg") == 0 ||
1174 stricmp(stoken, "max") == 0 ||
1175 stricmp(stoken, "min") == 0 ||
1176 stricmp(stoken, "variance") == 0 ||
1177 stricmp(stoken, "stddev") == 0)
1178 updatable = FALSE;
1180 } else if (token[0] == ')')
1182 blevel--;
1183 mylog("blevel-- = %d\n", blevel);
1184 if (blevel < subqlevel)
1185 subqlevel = 0;
1187 if (blevel >= old_blevel && ',' != delim)
1188 strcpy(stoken, token);
1189 else
1190 stoken[0] = '\0';
1192 if (in_select)
1194 if (in_expr || in_func)
1196 /* just eat the expression */
1197 mylog("in_expr=%d or func=%d\n", in_expr, in_func);
1199 if (blevel == 0)
1201 if (delim == ',')
1203 mylog("**** Got comma in_expr/func\n");
1204 in_func = FALSE;
1205 in_expr = FALSE;
1206 in_field = FALSE;
1207 } else if (unquoted && !stricmp(token, "as"))
1209 mylog("got AS in_expr\n");
1210 in_func = FALSE;
1211 in_expr = FALSE;
1212 in_as = TRUE;
1213 in_field = TRUE;
1216 continue;
1218 /* (in_expr || in_func) && in_select */
1219 if (in_distinct)
1221 mylog("in distinct\n");
1223 if (unquoted && !stricmp(token, "on"))
1225 in_on = TRUE;
1226 mylog("got on\n");
1227 continue;
1229 if (in_on)
1231 in_distinct = FALSE;
1232 in_on = FALSE;
1233 continue; /* just skip the unique on field */
1235 mylog("done distinct\n");
1236 in_distinct = FALSE;
1238 /* in_distinct */
1239 if (!in_field)
1241 BOOL fi_reuse = FALSE;
1243 if (!token[0])
1244 continue;
1246 /* if (!(irdflds->nfields % FLD_INCR)) */
1247 if (irdflds->nfields >= allocated_size)
1249 mylog("reallocing at nfld=%d\n", irdflds->nfields);
1250 new_size = irdflds->nfields + 1;
1251 if (!allocateFields(irdflds, new_size))
1253 SC_set_parse_status(stmt, STMT_PARSE_FATAL);
1254 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
1255 "PGAPI_AllocStmt failed in parse_statement for FIELD_INFO.",
1256 func);
1257 goto cleanup;
1259 fi = irdflds->fi;
1260 allocated_size = irdflds->allocated;
1263 wfi = fi[irdflds->nfields];
1264 if (wfi)
1265 fi_reuse = TRUE;
1266 else
1267 wfi = fi[irdflds->nfields] =
1268 (FIELD_INFO *) malloc(sizeof(FIELD_INFO));
1269 if (wfi == NULL)
1271 SC_set_parse_status(stmt, STMT_PARSE_FATAL);
1272 SC_set_error(stmt, STMT_NO_MEMORY_ERROR,
1273 "PGAPI_AllocStmt failed in parse_statement for FIELD_INFO(2).",
1274 func);
1275 goto cleanup;
1278 /* Initialize the field info */
1279 FI_Constructor(wfi, fi_reuse);
1280 wfi->flag = FIELD_PARSING;
1282 /* double quotes are for qualifiers */
1283 if (dquote)
1284 wfi->dquote = TRUE;
1286 if (quote)
1288 wfi->quote = TRUE;
1289 wfi->column_size = (int) strlen(token);
1290 } else if (numeric)
1292 mylog("**** got numeric: nfld = %d\n",
1293 irdflds->nfields);
1294 wfi->numeric = TRUE;
1295 } else if (0 == old_blevel && blevel > 0)
1296 { /* expression */
1297 mylog("got EXPRESSION\n");
1298 wfi->expr = TRUE;
1299 in_expr = TRUE;
1300 /* continue; */
1301 } else
1303 STR_TO_NAME(wfi->column_name, token);
1304 NULL_THE_NAME(wfi->before_dot);
1306 mylog("got field='%s', dot='%s'\n",
1307 PRINT_NAME(wfi->column_name),
1308 PRINT_NAME(wfi->before_dot));
1310 if (delim == ',')
1311 mylog("comma (1)\n");
1312 else
1313 in_field = TRUE;
1314 irdflds->nfields++;
1315 continue;
1318 /* !in_field */
1320 * We are in a field now
1322 wfi = fi[irdflds->nfields - 1];
1323 if (in_dot)
1325 if (NAME_IS_VALID(wfi->before_dot))
1327 MOVE_NAME(wfi->schema_name, wfi->before_dot);
1329 MOVE_NAME(wfi->before_dot, wfi->column_name);
1330 STR_TO_NAME(wfi->column_name, token);
1332 if (delim == ',')
1334 mylog("in_dot: got comma\n");
1335 in_field = FALSE;
1337 in_dot = FALSE;
1338 continue;
1341 if (in_as)
1343 STR_TO_NAME(wfi->column_alias, token);
1344 mylog("alias for field '%s' is '%s'\n",
1345 PRINT_NAME(wfi->column_name),
1346 PRINT_NAME(wfi->column_alias));
1347 in_as = FALSE;
1348 in_field = FALSE;
1350 if (delim == ',')
1351 mylog("comma(2)\n");
1352 continue;
1355 /* Function */
1356 if (0 == old_blevel && blevel > 0)
1358 in_dot = FALSE;
1359 in_func = TRUE;
1360 wfi->func = TRUE;
1363 * name will have the function name -- maybe useful some
1364 * day
1366 mylog("**** got function = '%s'\n",
1367 PRINT_NAME(wfi->column_name));
1368 continue;
1371 if (token[0] == '.')
1373 in_dot = TRUE;
1374 mylog("got dot\n");
1375 continue;
1378 in_dot = FALSE;
1379 if (!stricmp(token, "as"))
1381 in_as = TRUE;
1382 mylog("got AS\n");
1383 continue;
1386 /* otherwise, it's probably an expression */
1387 in_expr = TRUE;
1388 wfi->expr = TRUE;
1389 NULL_THE_NAME(wfi->column_name);
1390 wfi->column_size = 0;
1391 mylog("*** setting expression\n");
1393 /* in_select end */
1394 if (in_from || in_where)
1396 if (token[0] == ';') /* end of the first command */
1398 in_select = in_from = in_where = in_table = FALSE;
1399 break;
1402 if (in_from)
1404 switch (token[0])
1406 case '\0':
1407 continue;
1408 case ',':
1409 out_table = TRUE;
1410 continue;
1412 if (out_table && !in_table) /* new table */
1414 in_dot = FALSE;
1415 maybe_join = 0;
1416 if (!dquote)
1418 if (token[0] == '(' || token[0] == ')')
1419 continue;
1422 if (!increaseNtab(stmt, func))
1424 SC_set_parse_status(stmt, STMT_PARSE_FATAL);
1425 goto cleanup;
1428 ti = stmt->ti;
1429 wti = ti[stmt->ntab - 1];
1430 if (dquote || stricmp(token, "select"))
1432 STR_TO_NAME(wti->table_name, token);
1433 lower_the_name(GET_NAME(wti->table_name), conn,
1434 dquote);
1435 } else
1437 NULL_THE_NAME(wti->table_name);
1438 TI_no_updatable(wti);
1440 mylog("got table = '%s'\n",
1441 PRINT_NAME(wti->table_name));
1443 if (0 == blevel && delim == ',')
1445 out_table = TRUE;
1446 mylog("more than 1 tables\n");
1447 } else
1449 out_table = FALSE;
1450 in_table = TRUE;
1452 continue;
1454 if (0 != blevel)
1455 continue;
1456 /* out_table is FALSE here */
1457 if (!dquote && !in_dot)
1459 if (')' == token[0])
1460 continue;
1461 if (stricmp(token, "LEFT") == 0 ||
1462 stricmp(token, "RIGHT") == 0 ||
1463 stricmp(token, "OUTER") == 0 ||
1464 stricmp(token, "FULL") == 0)
1466 maybe_join = 1;
1467 in_table = FALSE;
1468 continue;
1469 } else if (stricmp(token, "INNER") == 0 ||
1470 stricmp(token, "CROSS") == 0)
1472 maybe_join = 2;
1473 in_table = FALSE;
1474 continue;
1475 } else if (stricmp(token, "JOIN") == 0)
1477 in_table = FALSE;
1478 out_table = TRUE;
1479 switch (maybe_join)
1481 case 1:
1482 SC_set_outer_join(stmt);
1483 break;
1484 case 2:
1485 SC_set_inner_join(stmt);
1486 break;
1488 maybe_join = 0;
1489 continue;
1492 maybe_join = 0;
1493 if (in_table)
1495 wti = ti[stmt->ntab - 1];
1496 if (in_dot)
1498 MOVE_NAME(wti->schema_name, wti->table_name);
1499 STR_TO_NAME(wti->table_name, token);
1500 lower_the_name(GET_NAME(wti->table_name), conn,
1501 dquote);
1502 in_dot = FALSE;
1503 continue;
1505 if (strcmp(token, ".") == 0)
1507 in_dot = TRUE;
1508 continue;
1510 if (dquote || stricmp(token, "as"))
1512 if (!dquote)
1514 if (stricmp(token, "ON") == 0)
1516 in_table = FALSE;
1517 continue;
1520 STR_TO_NAME(wti->table_alias, token);
1521 mylog("alias for table '%s' is '%s'\n",
1522 PRINT_NAME(wti->table_name),
1523 PRINT_NAME(wti->table_alias));
1524 in_table = FALSE;
1525 if (delim == ',')
1527 out_table = TRUE;
1528 mylog("more than 1 tables\n");
1532 } /* in_from */
1536 * Resolve any possible field names with tables
1539 parse = TRUE;
1541 /* Resolve field names with tables */
1542 for (i = 0; i < (int) irdflds->nfields; i++)
1544 wfi = fi[i];
1545 if (wfi->func || wfi->expr || wfi->numeric)
1547 wfi->ti = NULL;
1548 wfi->columntype = wfi->basetype = (OID) 0;
1549 parse = FALSE;
1550 continue;
1551 } else if (wfi->quote)
1552 { /* handle as text */
1553 wfi->ti = NULL;
1556 * wfi->type = PG_TYPE_TEXT; wfi->column_size = 0; the
1557 * following may be better
1559 wfi->basetype = PG_TYPE_UNKNOWN;
1560 if (wfi->column_size == 0)
1562 wfi->basetype = PG_TYPE_VARCHAR;
1563 wfi->column_size = 254;
1565 wfi->length = wfi->column_size;
1566 continue;
1568 /* field name contains the schema name */
1569 else if (NAME_IS_VALID(wfi->schema_name))
1571 int matchidx = -1;
1573 for (k = 0; k < stmt->ntab; k++)
1575 wti = ti[k];
1576 if (!NAMEICMP(wti->table_name, wfi->before_dot))
1578 if (!NAMEICMP(wti->schema_name, wfi->schema_name))
1580 wfi->ti = wti;
1581 break;
1582 } else if (NAME_IS_NULL(wti->schema_name))
1584 if (matchidx < 0)
1585 matchidx = k;
1586 else
1588 SC_set_parse_status(stmt, STMT_PARSE_FATAL);
1589 SC_set_error(stmt, STMT_EXEC_ERROR,
1590 "duplicated Table name", func);
1591 stmt->updatable = FALSE;
1592 goto cleanup;
1597 if (matchidx >= 0)
1598 wfi->ti = ti[matchidx];
1600 /* it's a dot, resolve to table or alias */
1601 else if (NAME_IS_VALID(wfi->before_dot))
1603 for (k = 0; k < stmt->ntab; k++)
1605 wti = ti[k];
1606 if (!NAMEICMP(wti->table_alias, wfi->before_dot))
1608 wfi->ti = wti;
1609 break;
1610 } else if (!NAMEICMP(wti->table_name, wfi->before_dot))
1612 wfi->ti = wti;
1613 break;
1616 } else if (stmt->ntab == 1)
1617 wfi->ti = ti[0];
1620 mylog("--------------------------------------------\n");
1621 mylog("nfld=%d, ntab=%d\n", irdflds->nfields, stmt->ntab);
1622 if (0 == stmt->ntab)
1624 SC_set_parse_status(stmt, STMT_PARSE_FATAL);
1625 goto cleanup;
1628 for (i = 0; i < (int) irdflds->nfields; i++)
1630 wfi = fi[i];
1631 mylog
1632 ("Field %d: expr=%d, func=%d, quote=%d, dquote=%d, numeric=%d, name='%s', alias='%s', dot='%s'\n",
1633 i, wfi->expr, wfi->func, wfi->quote, wfi->dquote,
1634 wfi->numeric, PRINT_NAME(wfi->column_name),
1635 PRINT_NAME(wfi->column_alias),
1636 PRINT_NAME(wfi->before_dot));
1637 if (wfi->ti)
1638 mylog(" ----> table_name='%s', table_alias='%s'\n",
1639 PRINT_NAME(wfi->ti->table_name),
1640 PRINT_NAME(wfi->ti->table_alias));
1643 for (i = 0; i < stmt->ntab; i++)
1645 wti = ti[i];
1646 mylog("Table %d: name='%s', alias='%s'\n", i,
1647 PRINT_NAME(wti->table_name),
1648 PRINT_NAME(wti->table_alias));
1652 * Now save the SQLColumns Info for the parse tables
1655 /* Call SQLColumns for each table and store the result */
1656 if (stmt->ntab > 1)
1657 updatable = FALSE;
1658 else if (stmt->from_pos < 0)
1659 updatable = FALSE;
1660 for (i = 0; i < stmt->ntab; i++)
1662 /* See if already got it */
1663 wti = ti[i];
1665 if (!getCOLIfromTI(func, NULL, stmt, 0, &wti))
1666 break;
1668 if (STMT_PARSE_FATAL == SC_parsed_status(stmt))
1670 goto cleanup;
1673 mylog("Done PG_Columns\n");
1676 * Now resolve the fields to point to column info
1678 if (updatable && 1 == stmt->ntab)
1679 updatable = TI_is_updatable(stmt->ti[0]);
1680 for (i = 0; i < (int) irdflds->nfields;)
1682 wfi = fi[i];
1683 wfi->updatable = updatable;
1684 /* Dont worry about functions or quotes */
1685 if (wfi->func || wfi->quote || wfi->numeric)
1687 wfi->updatable = FALSE;
1688 i++;
1689 continue;
1692 /* Stars get expanded to all fields in the table */
1693 else if (SAFE_NAME(wfi->column_name)[0] == '*')
1695 char do_all_tables;
1696 Int2 total_cols, cols, increased_cols;
1698 mylog("expanding field %d\n", i);
1700 total_cols = 0;
1702 if (wfi->ti) /* The star represents only the qualified
1703 * table */
1704 total_cols =
1705 (Int2) QR_get_num_cached_tuples(wfi->ti->col_info->
1706 result);
1708 else
1709 { /* The star represents all tables */
1710 /* Calculate the total number of columns after expansion */
1711 for (k = 0; k < stmt->ntab; k++)
1712 total_cols +=
1713 (Int2) QR_get_num_cached_tuples(ti[k]->
1714 col_info->
1715 result);
1717 increased_cols = total_cols - 1;
1719 /* Allocate some more field pointers if necessary */
1720 new_size = irdflds->nfields + increased_cols;
1722 mylog
1723 ("k=%d, increased_cols=%d, allocated_size=%d, new_size=%d\n",
1724 k, increased_cols, allocated_size, new_size);
1726 if (new_size > allocated_size)
1728 int new_alloc = new_size;
1730 mylog("need more cols: new_alloc = %d\n", new_alloc);
1731 if (!allocateFields(irdflds, new_alloc))
1733 SC_set_parse_status(stmt, STMT_PARSE_FATAL);
1734 goto cleanup;
1736 fi = irdflds->fi;
1737 allocated_size = irdflds->allocated;
1741 * copy any other fields (if there are any) up past the
1742 * expansion
1744 for (j = irdflds->nfields - 1; j > i; j--)
1746 mylog("copying field %d to %d\n", j,
1747 increased_cols + j);
1748 fi[increased_cols + j] = fi[j];
1750 mylog("done copying fields\n");
1752 /* Set the new number of fields */
1753 irdflds->nfields += increased_cols;
1754 mylog("irdflds->nfields now at %d\n", irdflds->nfields);
1757 /* copy the new field info */
1758 do_all_tables = (wfi->ti ? FALSE : TRUE);
1759 wfi = NULL;
1761 for (k = 0; k < (do_all_tables ? stmt->ntab : 1); k++)
1763 TABLE_INFO *the_ti = do_all_tables ? ti[k] : fi[i]->ti;
1765 cols =
1766 (Int2) QR_get_num_cached_tuples(the_ti->col_info->
1767 result);
1769 for (n = 0; n < cols; n++)
1771 FIELD_INFO *afi;
1772 BOOL reuse = TRUE;
1774 mylog("creating field info: n=%d\n", n);
1775 /* skip malloc (already did it for the Star) */
1776 if (k > 0 || n > 0)
1778 mylog("allocating field info at %d\n", n + i);
1779 fi[n + i] =
1780 (FIELD_INFO *) malloc(sizeof(FIELD_INFO));
1781 if (fi[n + i] == NULL)
1783 SC_set_parse_status(stmt, STMT_PARSE_FATAL);
1784 goto cleanup;
1786 reuse = FALSE;
1788 afi = fi[n + i];
1789 /* Initialize the new space (or the * field) */
1790 FI_Constructor(afi, reuse);
1791 afi->ti = the_ti;
1793 mylog("about to copy at %d\n", n + i);
1795 getColInfo(the_ti->col_info, afi, n);
1796 afi->updatable = updatable;
1798 mylog("done copying\n");
1801 i += cols;
1802 mylog("i now at %d\n", i);
1807 * We either know which table the field was in because it was
1808 * qualified with a table name or alias -OR- there was only 1
1809 * table.
1811 else if (wfi->ti)
1813 if (!searchColInfo(fi[i]->ti->col_info, wfi))
1815 parse = FALSE;
1816 wfi->updatable = FALSE;
1818 i++;
1821 /* Don't know the table -- search all tables in "from" list */
1822 else
1824 for (k = 0; k < stmt->ntab; k++)
1826 if (searchColInfo(ti[k]->col_info, wfi))
1828 wfi->ti = ti[k]; /* now know the table */
1829 break;
1832 if (k >= stmt->ntab)
1834 parse = FALSE;
1835 wfi->updatable = FALSE;
1837 i++;
1841 if (check_hasoids && updatable)
1842 CheckHasOids(stmt);
1843 SC_set_parse_status(stmt,
1844 parse ? STMT_PARSE_COMPLETE :
1845 STMT_PARSE_INCOMPLETE);
1846 for (i = 0; i < (int) irdflds->nfields; i++)
1848 wfi = fi[i];
1849 wfi->flag &= ~FIELD_PARSING;
1850 if (0 != wfi->columntype || 0 != wfi->basetype)
1851 wfi->flag |= FIELD_PARSED_OK;
1854 stmt->updatable = updatable;
1855 cleanup:
1856 #undef return
1857 if (STMT_PARSE_FATAL == SC_parsed_status(stmt))
1859 SC_initialize_cols_info(stmt, FALSE, FALSE);
1860 parse = FALSE;
1863 mylog("done parse_statement: parse=%d, parse_status=%d\n", parse,
1864 SC_parsed_status(stmt));
1865 return parse;