1 /*--------
2 * Module: parse.c
3 *
4 * Description: This module contains routines related to parsing SQL
5 * statements. This can be useful for two reasons:
6 *
7 * 1. So the query does not actually have to be executed
8 * to return data about it
9 *
10 * 2. To be able to return information about precision,
11 * nullability, aliases, etc. in the functions
12 * SQLDescribeCol and SQLColAttributes. Currently,
13 * Postgres doesn't return any information about
14 * these things in a query.
15 *
16 * Classes: none
17 *
18 * API functions: none
19 *
20 * Comments: See "readme.txt" for copyright and license information.
21 *--------
22 */
23 /* Multibyte support Eiji Tokuya 2001-03-15 */
24
25 #include "psqlodbc.h"
26
27 #include <stdio.h>
28 #include <string.h>
29 #include <ctype.h>
30
31 #include "statement.h"
32 #include "connection.h"
33 #include "qresult.h"
34 #include "pgtypes.h"
35 #include "pgapifunc.h"
36 #include "catfunc.h"
37
38 #include "multibyte.h"
39 #include "misc.h"
40
41 #define FLD_INCR 32
42 #define TAB_INCR 8
43 #define COLI_INCR 16
44 #define COLI_RECYCLE 128
45
46 static const char *getNextToken(int ccsc, char escape_in_literal, const char *s, char *token, int smax, char *delim, char *quote, char *dquote, char *numeric);
47 static void getColInfo(COL_INFO *col_info, FIELD_INFO *fi, int k);
48 static char searchColInfo(COL_INFO *col_info, FIELD_INFO *fi);
49 static BOOL getColumnsInfo(ConnectionClass *, TABLE_INFO *, OID, StatementClass *);
50
FI_precision(const FIELD_INFO * fi)51 Int4 FI_precision(const FIELD_INFO *fi)
52 {
53 OID ftype;
54
55 if (!fi) return -1;
56 ftype = FI_type(fi);
57 switch (ftype)
58 {
59 case PG_TYPE_NUMERIC:
60 return fi->column_size;
61 case PG_TYPE_DATETIME:
62 case PG_TYPE_TIMESTAMP_NO_TMZONE:
63 return fi->decimal_digits;
64 }
65 return 0;
66 }
FI_scale(const FIELD_INFO * fi)67 Int4 FI_scale(const FIELD_INFO *fi)
68 {
69 OID ftype;
70
71 if (!fi) return -1;
72 ftype = FI_type(fi);
73 switch (ftype)
74 {
75 case PG_TYPE_NUMERIC:
76 return fi->decimal_digits;
77 }
78 return 0;
79 }
80
81 static const char *
getNextToken(int ccsc,char escape_ch,const char * s,char * token,int smax,char * delim,char * quote,char * dquote,char * numeric)82 getNextToken(
83 int ccsc, /* client encoding */
84 char escape_ch,
85 const char *s, char *token, int smax, char *delim, char *quote, char *dquote, char *numeric)
86 {
87 size_t out = 0;
88 size_t taglen;
89 char in_quote, in_dollar_quote, in_escape;
90 const UCHAR *tag, *tagend;
91 encoded_str encstr;
92 char escape_in_literal;
93 const UCHAR *tstr = (const UCHAR *) s;
94 UCHAR tchar, qc;
95
96 if (smax <= 1)
97 return NULL;
98
99 smax--;
100
101 /* skip leading delimiters */
102 while (isspace(*tstr) || *tstr == ',')
103 {
104 /* MYLOG(0, "skipping '%c'\n", *tstr); */
105 tstr++;
106 }
107
108 if (*tstr == '\0')
109 {
110 token[0] = '\0';
111 return NULL;
112 }
113
114 if (quote)
115 *quote = FALSE;
116 if (dquote)
117 *dquote = FALSE;
118 if (numeric)
119 *numeric = FALSE;
120
121 encoded_str_constr(&encstr, ccsc, (const char *) tstr);
122 /* get the next token */
123 for (tchar = encoded_nextchar(&encstr); tchar && out < smax; tstr++, tchar = encoded_nextchar(&encstr))
124 {
125 if (MBCS_NON_ASCII(encstr))
126 {
127 token[out++] = tchar;
128 continue;
129 }
130 if (isspace(tchar) || tchar == ',')
131 break;
132 /* Handle quoted stuff */
133 in_quote = in_dollar_quote = FALSE;
134 taglen = 0;
135 tag = NULL;
136 escape_in_literal = '\0';
137 if (out == 0)
138 {
139 qc = tchar;
140 if (qc == DOLLAR_QUOTE)
141 {
142 in_quote = in_dollar_quote = TRUE;
143 tag = tstr;
144 taglen = 1;
145 if (tagend = (const UCHAR *) strchr((const char *) tstr + 1, DOLLAR_QUOTE), NULL != tagend)
146 taglen = tagend - tstr + 1;
147 tstr += (taglen - 1);
148 encoded_position_shift(&encstr, taglen - 1);
149 if (quote)
150 *quote = TRUE;
151 }
152 else if (qc == LITERAL_QUOTE)
153 {
154 in_quote = TRUE;
155 if (quote)
156 *quote = TRUE;
157 escape_in_literal = escape_ch;
158 if (!escape_in_literal)
159 {
160 if (LITERAL_EXT == tstr[-1])
161 escape_in_literal = ESCAPE_IN_LITERAL;
162 }
163 }
164 else if (qc == IDENTIFIER_QUOTE)
165 {
166 in_quote = TRUE;
167 if (dquote)
168 *dquote = TRUE;
169 }
170 } /* out == 0 */
171 if (in_quote) /* dquote, dollar_quote */
172 {
173 in_escape = FALSE;
174 for (tstr++, tchar = encoded_nextchar(&encstr); tchar != '\0' && out != smax; tstr++, tchar = encoded_nextchar(&encstr))
175 {
176 if (MBCS_NON_ASCII(encstr))
177 {
178 token[out++] = tchar;
179 continue;
180 }
181 if (in_escape)
182 in_escape = FALSE;
183 else if (tchar == qc)
184 {
185 if (!in_dollar_quote)
186 {
187 /*
188 * Peek at the next byte to see if this is a '' or
189 * "", i.e a quote character that has been escaped
190 * by doubling it.
191 */
192 if (tstr[1] == qc)
193 {
194 tstr++;
195 tchar = encoded_nextchar(&encstr);
196 }
197 else
198 break;
199 }
200 else if (strncmp((const char *) tstr, (const char *) tag, taglen) == 0)
201 {
202 tstr += (taglen - 1);
203 tchar = encoded_position_shift(&encstr, taglen - 1);
204 break;
205 }
206 token[out++] = tchar;
207 }
208 else if (LITERAL_QUOTE == qc && tchar == escape_in_literal)
209 {
210 in_escape = TRUE;
211 }
212 else
213 {
214 token[out++] = tchar;
215 }
216 } /* for */
217 if (tchar == qc)
218 tstr++;
219 break;
220 } /* in_quote */
221
222 /* Check for numeric literals */
223 if (out == 0 && isdigit(tchar))
224 {
225 if (numeric)
226 *numeric = TRUE;
227 token[out++] = tchar;
228 tstr++;
229 while ((isalnum(*tstr) || *tstr == '.') && out < smax)
230 {
231 token[out++] = *tstr;
232 tstr++;
233 }
234
235 break;
236 }
237
238 if (ispunct(tchar) && tchar != '_')
239 {
240 MYLOG(0, "got ispunct: s[] = '%c'\n", tchar);
241
242 if (out == 0)
243 {
244 token[out++] = tchar;
245 tstr++;
246 }
247 break;
248 }
249
250 if (out < smax)
251 token[out++] = tchar;
252 } /* for */
253
254 /* MYLOG(0, "done -- s[] = '%c'\n", *tstr); */
255
256 token[out] = '\0';
257
258 /* find the delimiter */
259 while (isspace(*tstr))
260 tstr++;
261
262 /* return the most priority delimiter */
263 if (*tstr == ',')
264 {
265 if (delim)
266 *delim = *tstr;
267 }
268 else if (*tstr == '\0')
269 {
270 if (delim)
271 *delim = '\0';
272 }
273 else
274 {
275 if (delim)
276 *delim = ' ';
277 }
278
279 /* skip trailing blanks */
280 while (isspace(*tstr))
281 tstr++;
282
283 return (const char *) tstr;
284 }
285
286 static void
getColInfo(COL_INFO * col_info,FIELD_INFO * fi,int k)287 getColInfo(COL_INFO *col_info, FIELD_INFO *fi, int k)
288 {
289 char *str;
290
291 MYLOG(DETAIL_LOG_LEVEL, "entering non-manual result\n");
292 fi->dquote = TRUE;
293 STR_TO_NAME(fi->column_name, QR_get_value_backend_text(col_info->result, k, COLUMNS_COLUMN_NAME));
294
295 fi->columntype = (OID) QR_get_value_backend_int(col_info->result, k, COLUMNS_FIELD_TYPE, NULL);
296 fi->column_size = QR_get_value_backend_int(col_info->result, k, COLUMNS_PRECISION, NULL);
297 fi->length = QR_get_value_backend_int(col_info->result, k, COLUMNS_LENGTH, NULL);
298 if (str = QR_get_value_backend_text(col_info->result, k, COLUMNS_SCALE), str)
299 fi->decimal_digits = atoi(str);
300 else
301 fi->decimal_digits = -1;
302 fi->nullable = QR_get_value_backend_int(col_info->result, k, COLUMNS_NULLABLE, NULL);
303 fi->display_size = QR_get_value_backend_int(col_info->result, k, COLUMNS_DISPLAY_SIZE, NULL);
304 fi->auto_increment = QR_get_value_backend_int(col_info->result, k, COLUMNS_AUTO_INCREMENT, NULL);
305 }
306
307
308 static char
searchColInfo(COL_INFO * col_info,FIELD_INFO * fi)309 searchColInfo(COL_INFO *col_info, FIELD_INFO *fi)
310 {
311 int k,
312 cmp, attnum, atttypmod;
313 OID basetype;
314 const char *col;
315
316 MYLOG(DETAIL_LOG_LEVEL, "entering num_cols=" FORMAT_ULEN " col=%s\n", QR_get_num_cached_tuples(col_info->result), PRINT_NAME(fi->column_name));
317 if (fi->attnum < 0)
318 return FALSE;
319 for (k = 0; k < QR_get_num_cached_tuples(col_info->result); k++)
320 {
321 if (fi->attnum > 0)
322 {
323 attnum = QR_get_value_backend_int(col_info->result, k, COLUMNS_PHYSICAL_NUMBER, NULL);
324 if (basetype = (OID) strtoul(QR_get_value_backend_text(col_info->result, k, COLUMNS_BASE_TYPEID), NULL, 10), 0 == basetype)
325 basetype = (OID) strtoul(QR_get_value_backend_text(col_info->result, k, COLUMNS_FIELD_TYPE), NULL, 10);
326 atttypmod = QR_get_value_backend_int(col_info->result, k, COLUMNS_ATTTYPMOD, NULL);
327 MYLOG(DETAIL_LOG_LEVEL, "%d attnum=%d\n", k, attnum);
328 if (attnum == fi->attnum &&
329 basetype == fi->basetype &&
330 atttypmod == fi->typmod)
331 {
332 getColInfo(col_info, fi, k);
333 MYLOG(0, "PARSE: searchColInfo by attnum=%d\n", attnum);
334 return TRUE;
335 }
336 }
337 else if (NAME_IS_VALID(fi->column_name))
338 {
339 col = QR_get_value_backend_text(col_info->result, k, COLUMNS_COLUMN_NAME);
340 MYLOG(DETAIL_LOG_LEVEL, "%d col=%s\n", k, col);
341 if (fi->dquote)
342 cmp = strcmp(col, GET_NAME(fi->column_name));
343 else
344 cmp = stricmp(col, GET_NAME(fi->column_name));
345 if (!cmp)
346 {
347 if (!fi->dquote)
348 STR_TO_NAME(fi->column_name, col);
349 getColInfo(col_info, fi, k);
350
351 MYLOG(0, "PARSE: \n");
352 return TRUE;
353 }
354 }
355 }
356
357 return FALSE;
358 }
359
360 /*
361 * lower the unquoted name
362 */
363 static
lower_the_name(char * name,ConnectionClass * conn,BOOL dquote)364 void lower_the_name(char *name, ConnectionClass *conn, BOOL dquote)
365 {
366 if (!dquote)
367 {
368 char *ptr;
369 encoded_str encstr;
370 make_encoded_str(&encstr, conn, name);
371
372 /* lower case table name */
373 for (ptr = name; *ptr; ptr++)
374 {
375 encoded_nextchar(&encstr);
376 if (!MBCS_NON_ASCII(encstr))
377 *ptr = tolower((UCHAR) *ptr);
378 }
379 }
380 }
381
382 /*
383 * Check relhasoids(before PG12), relhssubclass and get some relevant information.
384 */
CheckPgClassInfo(StatementClass * stmt)385 BOOL CheckPgClassInfo(StatementClass *stmt)
386 {
387 const COL_INFO *coli;
388 int table_info;
389 TABLE_INFO *ti;
390 BOOL hasoids = FALSE, hassubclass =FALSE, keyFound = FALSE;
391
392 MYLOG(0, "Entering\n");
393 if (0 != SC_checked_hasoids(stmt))
394 return TRUE;
395 if (!stmt->ti || !stmt->ti[0])
396 return FALSE;
397 ti = stmt->ti[0];
398 MYLOG(DETAIL_LOG_LEVEL, "ti->col_info=%p\n", ti->col_info);
399 if (TI_checked_hasoids(ti))
400 ;
401 else if (coli = ti->col_info, NULL != coli)
402 {
403 table_info = coli->table_info;
404 if (0 == (table_info & TBINFO_HASSUBCLASS))
405 {
406 TI_set_has_no_subclass(ti);
407 }
408 else
409 {
410 hassubclass = TRUE;
411 TI_set_hassubclass(ti);
412 STR_TO_NAME(ti->bestitem, TABLEOID_NAME);
413 STRX_TO_NAME(ti->bestqual, "\"" TABLEOID_NAME "\" = %u");
414 }
415 if (!hassubclass)
416 {
417 if (0 == (table_info & TBINFO_HASOIDS))
418 {
419 TI_set_has_no_oids(ti);
420 }
421 else
422 {
423 hasoids = TRUE;
424 TI_set_hasoids(ti);
425 STR_TO_NAME(ti->bestitem, OID_NAME);
426 STRX_TO_NAME(ti->bestqual, "\"" OID_NAME "\" = %u");
427 }
428 }
429 ti->table_oid = coli->table_oid;
430 if (!hasoids && !hassubclass)
431 {
432 QResultClass *res = coli->result;
433 int num_tuples = res ? QR_get_num_cached_tuples(res) : -1;
434
435 if (num_tuples > 0)
436 {
437 int i;
438
439 for (i = 0; i < num_tuples; i++)
440 {
441 if (QR_get_value_backend_int(res, i, COLUMNS_AUTO_INCREMENT, NULL) != 0&&
442 QR_get_value_backend_int(res, i, COLUMNS_FIELD_TYPE, NULL) == PG_TYPE_INT4)
443 {
444 char query[512];
445
446 STR_TO_NAME(ti->bestitem, QR_get_value_backend_text(res, i, COLUMNS_COLUMN_NAME));
447 SPRINTF_FIXED(query, "\"%s\" = %%d", SAFE_NAME(ti->bestitem));
448 STRX_TO_NAME(ti->bestqual, query);
449 break;
450 }
451 }
452 }
453 }
454 TI_set_hasoids_checked(ti);
455 }
456 else
457 return FALSE;
458
459 stmt->num_key_fields = PG_NUM_NORMAL_KEYS;
460 if (TI_has_subclass(ti))
461 keyFound = FALSE;
462 else if (TI_has_oids(ti))
463 keyFound = TRUE;
464 else if (NAME_IS_NULL(ti->bestqual))
465 {
466 keyFound = TRUE;
467 stmt->num_key_fields--;
468 }
469 else
470 keyFound = TRUE;
471 MYLOG(DETAIL_LOG_LEVEL, "subclass=%d oids=%d bestqual=%s keyFound=%d num_key_fields=%d\n", TI_has_subclass(ti), TI_has_oids(ti), PRINT_NAME(ti->bestqual), keyFound, stmt->num_key_fields);
472
473 SC_set_checked_hasoids(stmt, keyFound);
474
475 return TRUE;
476 }
477
increaseNtab(StatementClass * stmt,const char * func)478 static BOOL increaseNtab(StatementClass *stmt, const char *func)
479 {
480 TABLE_INFO **ti = stmt->ti, *wti;
481
482 if (!(stmt->ntab % TAB_INCR))
483 {
484 SC_REALLOC_return_with_error(ti, TABLE_INFO *, (stmt->ntab + TAB_INCR) * sizeof(TABLE_INFO *), stmt, "PGAPI_AllocStmt failed in parse_statement for TABLE_INFO", FALSE);
485 stmt->ti = ti;
486 }
487 wti = ti[stmt->ntab] = (TABLE_INFO *) malloc(sizeof(TABLE_INFO));
488 if (wti == NULL)
489 {
490 SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for TABLE_INFO(2).", func);
491 return FALSE;
492 }
493
494 TI_Constructor(wti, SC_get_conn(stmt));
495 stmt->ntab++;
496 return TRUE;
497 }
498
setNumFields(IRDFields * irdflds,size_t numFields)499 static void setNumFields(IRDFields *irdflds, size_t numFields)
500 {
501 FIELD_INFO **fi = irdflds->fi;
502 size_t nfields = irdflds->nfields;
503
504 if (numFields < nfields)
505 {
506 int i;
507
508 for (i = (int) numFields; i < (int) nfields; i++)
509 {
510 if (fi[i])
511 fi[i]->flag = 0;
512 }
513 }
514 irdflds->nfields = (UInt4) numFields;
515 }
516
SC_initialize_cols_info(StatementClass * stmt,BOOL DCdestroy,BOOL parseReset)517 void SC_initialize_cols_info(StatementClass *stmt, BOOL DCdestroy, BOOL parseReset)
518 {
519 IRDFields *irdflds = SC_get_IRDF(stmt);
520
521 /* Free the parsed table information */
522 if (stmt->ti)
523 {
524 TI_Destructor(stmt->ti, stmt->ntab);
525 free(stmt->ti);
526 stmt->ti = NULL;
527 }
528 stmt->ntab = 0;
529 if (DCdestroy) /* Free the parsed field information */
530 DC_Destructor((DescriptorClass *) SC_get_IRD(stmt));
531 else
532 setNumFields(irdflds, 0);
533 if (parseReset)
534 {
535 stmt->parse_status = STMT_PARSE_NONE;
536 SC_reset_updatable(stmt);
537 }
538 }
539
allocateFields(IRDFields * irdflds,size_t sizeRequested)540 static BOOL allocateFields(IRDFields *irdflds, size_t sizeRequested)
541 {
542 FIELD_INFO **fi = irdflds->fi;
543 size_t alloc_size, incr_size;
544
545 if (sizeRequested <= irdflds->allocated)
546 return TRUE;
547 alloc_size = (0 != irdflds->allocated ? irdflds->allocated : FLD_INCR);
548 for (; alloc_size < sizeRequested; alloc_size *= 2)
549 ;
550 incr_size = sizeof(FIELD_INFO *) * (alloc_size - irdflds->allocated);
551
552 fi = (FIELD_INFO **) realloc(fi, alloc_size * sizeof(FIELD_INFO *));
553 if (!fi)
554 {
555 irdflds->fi = NULL;
556 irdflds->allocated = irdflds->nfields = 0;
557 return FALSE;
558 }
559 memset(&fi[irdflds->allocated], 0, incr_size);
560 irdflds->fi = fi;
561 irdflds->allocated = (SQLSMALLINT) alloc_size;
562
563 return TRUE;
564 }
565
566 /*
567 * This function may not be called but when it is called ...
568 */
xxxxx(StatementClass * stmt,FIELD_INFO * fi,QResultClass * res,int i)569 static void xxxxx(StatementClass *stmt, FIELD_INFO *fi, QResultClass *res, int i)
570 {
571 STR_TO_NAME(fi->column_alias, QR_get_fieldname(res, i));
572 fi->basetype = QR_get_field_type(res, i);
573 if (0 == fi->columntype)
574 fi->columntype = fi->basetype;
575 if (fi->attnum < 0)
576 {
577 fi->nullable = FALSE;
578 fi->updatable = FALSE;
579 }
580 else if (fi->attnum > 0)
581 {
582 int unknowns_as = 0;
583 int type = pg_true_type(SC_get_conn(stmt), fi->columntype, fi->basetype);
584
585 fi->nullable = TRUE; /* probably ? */
586 fi->column_size = pgtype_column_size(stmt, type, i, unknowns_as);
587 fi->length = pgtype_buffer_length(stmt, type, i, unknowns_as);
588 fi->decimal_digits = pgtype_decimal_digits(stmt, type, i);
589 fi->display_size = pgtype_display_size(stmt, type, i, unknowns_as);
590 }
591
592 if (NAME_IS_NULL(fi->column_name))
593 {
594 switch (fi->attnum)
595 {
596 case CTID_ATTNUM:
597 STR_TO_NAME(fi->column_name, "ctid");
598 break;
599 case OID_ATTNUM:
600 STR_TO_NAME(fi->column_name, OID_NAME);
601 break;
602 case XMIN_ATTNUM:
603 STR_TO_NAME(fi->column_name, XMIN_NAME);
604 break;
605 }
606 }
607 }
608
609 /*
610 * SQLColAttribute tries to set the FIELD_INFO (using protocol 3).
611 */
612 static BOOL
ColAttSet(StatementClass * stmt,TABLE_INFO * rti)613 ColAttSet(StatementClass *stmt, TABLE_INFO *rti)
614 {
615 CSTR func = "ColAttSet";
616 QResultClass *res = SC_get_ExecdOrParsed(stmt);
617 IRDFields *irdflds = SC_get_IRDF(stmt);
618 COL_INFO *col_info = NULL;
619 FIELD_INFO **fi, *wfi;
620 OID reloid = 0;
621 Int2 attid;
622 int i, num_fields;
623 BOOL fi_reuse, updatable, call_xxxxx;
624
625 MYLOG(0, "entering\n");
626
627 if (reloid = rti->table_oid, 0 == reloid)
628 return FALSE;
629 if (0 != (rti->flags & TI_COLATTRIBUTE))
630 return TRUE;
631 col_info = rti->col_info;
632 if (!QR_command_maybe_successful(res))
633 return FALSE;
634 if (num_fields = QR_NumPublicResultCols(res), num_fields <= 0)
635 return FALSE;
636 fi = irdflds->fi;
637 if (num_fields > (int) irdflds->allocated)
638 {
639 if (!allocateFields(irdflds, num_fields))
640 return FALSE;
641 fi = irdflds->fi;
642 }
643 setNumFields(irdflds, num_fields);
644 updatable = TI_is_updatable(rti);
645 MYLOG(0, "updatable=%d tab=%d fields=%d", updatable, stmt->ntab, num_fields);
646 if (updatable)
647 {
648 if (1 > stmt->ntab)
649 updatable = FALSE;
650 }
651 MYPRINTF(0, "->%d\n", updatable);
652 for (i = 0; i < num_fields; i++)
653 {
654 if (reloid == (OID) QR_get_relid(res, i))
655 {
656 if (wfi = fi[i], NULL == wfi)
657 {
658 wfi = (FIELD_INFO *) malloc(sizeof(FIELD_INFO));
659 if (wfi == NULL)
660 {
661 SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Couldn't allocate memory for field info.", func);
662 return FALSE;
663 }
664 fi_reuse = FALSE;
665 fi[i] = wfi;
666 }
667 else if (FI_is_applicable(wfi))
668 continue;
669 else
670 fi_reuse = TRUE;
671 FI_Constructor(wfi, fi_reuse);
672 attid = (Int2) QR_get_attid(res, i);
673 wfi->attnum = attid;
674 wfi->basetype = QR_get_field_type(res, i);
675 wfi->typmod = QR_get_atttypmod(res, i);
676 call_xxxxx = TRUE;
677 if (searchColInfo(col_info, wfi))
678 {
679 STR_TO_NAME(wfi->column_alias, QR_get_fieldname(res, i));
680 wfi->basetype = QR_get_field_type(res, i);
681 wfi->updatable = updatable;
682 call_xxxxx = FALSE;
683 }
684 else
685 {
686 if (attid > 0)
687 {
688 if (getColumnsInfo(NULL, rti, reloid, stmt) &&
689 searchColInfo(col_info, wfi))
690 {
691 STR_TO_NAME(wfi->column_alias, QR_get_fieldname(res, i));
692 wfi->basetype = QR_get_field_type(res, i);
693 wfi->updatable = updatable;
694 call_xxxxx= FALSE;
695 }
696 }
697 }
698 if (call_xxxxx)
699 xxxxx(stmt, wfi, res, i);
700 wfi->ti = rti;
701 wfi->flag |= FIELD_COL_ATTRIBUTE;
702 }
703 }
704 if (stmt->updatable < 0)
705 {
706 if (stmt->ntab > 1)
707 updatable = FALSE;
708 SC_set_updatable(stmt, updatable);
709 }
710
711 rti->flags |= TI_COLATTRIBUTE;
712 return TRUE;
713 }
714
715 static BOOL
getCOLIfromTable(ConnectionClass * conn,pgNAME * schema_name,pgNAME table_name,COL_INFO ** coli)716 getCOLIfromTable(ConnectionClass *conn, pgNAME *schema_name, pgNAME table_name,
717 COL_INFO **coli)
718 {
719 int colidx;
720 BOOL found = FALSE;
721
722 *coli = NULL;
723 if (NAME_IS_NULL(table_name))
724 return TRUE;
725 if (NAME_IS_NULL(*schema_name))
726 {
727 const char *curschema = CC_get_current_schema(conn);
728 /*
729 * Though current_schema() doesn't have
730 * much sense in PostgreSQL, we first
731 * check the current_schema() when no
732 * explicit schema name is specified.
733 */
734 if (curschema)
735 {
736 for (colidx = 0; colidx < conn->ntables; colidx++)
737 {
738 if (!NAMEICMP(conn->col_info[colidx]->table_name, table_name) &&
739 !stricmp(SAFE_NAME(conn->col_info[colidx]->schema_name), curschema))
740 {
741 MYLOG(0, "FOUND col_info table='%s' current schema='%s'\n", PRINT_NAME(table_name), curschema);
742 found = TRUE;
743 STR_TO_NAME(*schema_name, curschema);
744 break;
745 }
746 }
747 }
748 if (!found)
749 {
750 QResultClass *res;
751 char token[256], relcnv[128];
752 BOOL tblFound = FALSE;
753
754 /*
755 * We also have to check as follows.
756 */
757 SPRINTF_FIXED(token,
758 "select nspname from pg_namespace n, pg_class c"
759 " where c.relnamespace=n.oid and c.oid='%s'::regclass",
760 identifierEscape((const SQLCHAR *) SAFE_NAME(table_name), SQL_NTS, conn, relcnv, sizeof(relcnv), TRUE));
761 res = CC_send_query(conn, token, NULL, READ_ONLY_QUERY, NULL);
762 if (QR_command_maybe_successful(res))
763 {
764 if (QR_get_num_total_tuples(res) == 1)
765 {
766 tblFound = TRUE;
767 STR_TO_NAME(*schema_name, QR_get_value_backend_text(res, 0, 0));
768 }
769 }
770 QR_Destructor(res);
771 if (!tblFound)
772 return FALSE;
773 }
774 }
775 if (!found && NAME_IS_VALID(*schema_name))
776 {
777 for (colidx = 0; colidx < conn->ntables; colidx++)
778 {
779 if (!NAMEICMP(conn->col_info[colidx]->table_name, table_name) &&
780 !NAMEICMP(conn->col_info[colidx]->schema_name, *schema_name))
781 {
782 MYLOG(0, "FOUND col_info table='%s' schema='%s'\n", PRINT_NAME(table_name), PRINT_NAME(*schema_name));
783 found = TRUE;
784 break;
785 }
786 }
787 }
788 *coli = found ? conn->col_info[colidx] : NULL;
789 return TRUE; /* success */
790 }
791
792 static BOOL
getColumnsInfo(ConnectionClass * conn,TABLE_INFO * wti,OID greloid,StatementClass * stmt)793 getColumnsInfo(ConnectionClass *conn, TABLE_INFO *wti, OID greloid, StatementClass *stmt)
794 {
795 BOOL found = FALSE;
796 RETCODE result;
797 HSTMT hcol_stmt = NULL;
798 StatementClass *col_stmt;
799 QResultClass *res;
800
801 MYLOG(0, "entering Getting PG_Columns for table %u(%s)\n", greloid, PRINT_NAME(wti->table_name));
802
803 if (NULL == conn)
804 conn = SC_get_conn(stmt);
805 result = PGAPI_AllocStmt(conn, &hcol_stmt, 0);
806 if (!SQL_SUCCEEDED(result))
807 {
808 if (stmt)
809 SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for columns.", __FUNCTION__);
810 goto cleanup;
811 }
812
813 col_stmt = (StatementClass *) hcol_stmt;
814
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 = PGAPI_Columns(hcol_stmt, NULL, 0,
821 (SQLCHAR *) SAFE_NAME(wti->schema_name), SQL_NTS,
822 (SQLCHAR *) SAFE_NAME(wti->table_name), SQL_NTS,
823 NULL, 0,
824 PODBC_NOT_SEARCH_PATTERN, 0, 0);
825
826 MYLOG(0, " Past PG_Columns\n");
827 res = SC_get_ExecdOrParsed(col_stmt);
828 if (SQL_SUCCEEDED(result)
829 && res != NULL && QR_get_num_cached_tuples(res) > 0)
830 {
831 BOOL coli_exist = FALSE;
832 COL_INFO *coli = NULL, *ccoli = NULL, *tcoli;
833 int k;
834 time_t acctime = 0;
835
836 MYLOG(0, " Success\n");
837 if (greloid != 0)
838 {
839 for (k = 0; k < conn->ntables; k++)
840 {
841 tcoli = conn->col_info[k];
842 if (tcoli->table_oid == greloid)
843 {
844 coli = tcoli;
845 coli_exist = TRUE;
846 break;
847 }
848 }
849 }
850 if (!coli_exist)
851 {
852 for (k = 0; k < conn->ntables; k++)
853 {
854 tcoli = conn->col_info[k];
855 if (0 < tcoli->refcnt)
856 continue;
857 if ((0 == tcoli->table_oid &&
858 NAME_IS_NULL(tcoli->table_name)) ||
859 strnicmp(SAFE_NAME(tcoli->schema_name), "pg_temp_", 8) == 0)
860 {
861 coli = tcoli;
862 coli_exist = TRUE;
863 break;
864 }
865 if (NULL == ccoli ||
866 tcoli->acc_time < acctime)
867 {
868 ccoli = tcoli;
869 acctime = tcoli->acc_time;
870 }
871 }
872 if (!coli_exist &&
873 NULL != ccoli &&
874 conn->ntables >= COLI_RECYCLE)
875 {
876 coli_exist = TRUE;
877 coli = ccoli;
878 }
879 }
880 if (coli_exist)
881 {
882 free_col_info_contents(coli);
883 }
884 else
885 {
886 if (conn->ntables >= conn->coli_allocated)
887 {
888 Int2 new_alloc;
889 COL_INFO **col_info;
890
891 new_alloc = conn->coli_allocated * 2;
892 if (new_alloc <= conn->ntables)
893 new_alloc = COLI_INCR;
894 MYLOG(0, "PARSE: Allocating col_info at ntables=%d\n", conn->ntables);
895
896 col_info = (COL_INFO **) realloc(conn->col_info, new_alloc * sizeof(COL_INFO *));
897 if (!col_info)
898 {
899 if (stmt)
900 SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for col_info.", __FUNCTION__);
901 goto cleanup;
902 }
903 conn->col_info = col_info;
904 conn->coli_allocated = new_alloc;
905 }
906
907 MYLOG(0, "PARSE: malloc at conn->col_info[%d]\n", conn->ntables);
908 coli = conn->col_info[conn->ntables] = (COL_INFO *) malloc(sizeof(COL_INFO));
909 }
910 if (!coli)
911 {
912 if (stmt)
913 SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for col_info(2).", __FUNCTION__);
914 goto cleanup;
915 }
916 col_info_initialize(coli);
917
918 coli->result = res;
919 if (res && QR_get_num_cached_tuples(res) > 0)
920 {
921 int num_tuples = QR_get_num_cached_tuples(res);
922 int i;
923
924 if (!greloid)
925 greloid = (OID) strtoul(QR_get_value_backend_text(res, 0, COLUMNS_TABLE_OID), NULL, 10);
926 if (!wti->table_oid)
927 wti->table_oid = greloid;
928 if (NAME_IS_NULL(wti->schema_name))
929 STR_TO_NAME(wti->schema_name,
930 QR_get_value_backend_text(res, 0, COLUMNS_SCHEMA_NAME));
931 if (NAME_IS_NULL(wti->table_name))
932 STR_TO_NAME(wti->table_name,
933 QR_get_value_backend_text(res, 0, COLUMNS_TABLE_NAME));
934 for (i = 0; i < num_tuples; i++)
935 {
936 if (NULL != QR_get_value_backend_text(res, 0, COLUMNS_TABLE_INFO))
937 {
938 coli->table_info = QR_get_value_backend_int(res, 0, COLUMNS_TABLE_INFO, NULL);
939 break;
940 }
941 }
942 }
943 MYLOG(DETAIL_LOG_LEVEL, "#2 %p->table_name=%s(%u)\n", wti, PRINT_NAME(wti->table_name), wti->table_oid);
944 /*
945 * Store the table name and the SQLColumns result
946 * structure
947 */
948 if (NAME_IS_VALID(wti->schema_name))
949 {
950 NAME_TO_NAME(coli->schema_name, wti->schema_name);
951 }
952 else
953 NULL_THE_NAME(coli->schema_name);
954 NAME_TO_NAME(coli->table_name, wti->table_name);
955 coli->table_oid = wti->table_oid;
956
957 /*
958 * The connection will now free the result structures, so
959 * make sure that the statement doesn't free it
960 */
961 SC_init_Result(col_stmt);
962
963 if (!coli_exist)
964 conn->ntables++;
965
966 if (res && QR_get_num_cached_tuples(res) > 0)
967 MYLOG(DETAIL_LOG_LEVEL, "oid item == %s\n", (const char *) QR_get_value_backend_text(res, 0, 3));
968
969 MYLOG(0, "Created col_info table='%s', ntables=%d\n", PRINT_NAME(wti->table_name), conn->ntables);
970 /* Associate a table from the statement with a SQLColumn info */
971 found = TRUE;
972 coli->refcnt++;
973 wti->col_info = coli;
974 }
975 cleanup:
976 if (hcol_stmt)
977 PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
978 return found;
979 }
980
getCOLIfromTI(const char * func,ConnectionClass * conn,StatementClass * stmt,const OID reloid,TABLE_INFO ** pti)981 BOOL getCOLIfromTI(const char *func, ConnectionClass *conn, StatementClass *stmt, const OID reloid, TABLE_INFO **pti)
982 {
983 BOOL colatt = FALSE, found = FALSE;
984 OID greloid = reloid;
985 TABLE_INFO *wti = *pti;
986 COL_INFO *coli;
987
988 MYLOG(DETAIL_LOG_LEVEL, "entering reloid=%u ti=%p\n", reloid, wti);
989 if (!conn)
990 conn = SC_get_conn(stmt);
991 if (!wti) /* SQLColAttribute case */
992 {
993 int i;
994
995 if (0 == greloid)
996 return FALSE;
997 if (!stmt)
998 return FALSE;
999 colatt = TRUE;
1000 for (i = 0; i < stmt->ntab; i++)
1001 {
1002 if (stmt->ti[i]->table_oid == greloid)
1003 {
1004 wti = stmt->ti[i];
1005 break;
1006 }
1007 }
1008 if (!wti)
1009 {
1010 MYLOG(DETAIL_LOG_LEVEL, "before increaseNtab\n");
1011 if (!increaseNtab(stmt, func))
1012 return FALSE;
1013 wti = stmt->ti[stmt->ntab - 1];
1014 wti->table_oid = greloid;
1015 }
1016 *pti = wti;
1017 }
1018 MYLOG(DETAIL_LOG_LEVEL, "fi=%p greloid=%d col_info=%p\n", wti, greloid, wti->col_info);
1019 if (0 == greloid)
1020 greloid = wti->table_oid;
1021 if (NULL != wti->col_info)
1022 {
1023 found = TRUE;
1024 goto cleanup;
1025 }
1026 if (greloid != 0)
1027 {
1028 int colidx;
1029
1030 for (colidx = 0; colidx < conn->ntables; colidx++)
1031 {
1032 if (conn->col_info[colidx]->table_oid == greloid)
1033 {
1034 MYLOG(0, "FOUND col_info table=%ul\n", greloid);
1035 found = TRUE;
1036 wti->col_info = conn->col_info[colidx];
1037 wti->col_info->refcnt++;
1038 break;
1039 }
1040 }
1041 }
1042 else
1043 {
1044 if (!getCOLIfromTable(conn, &wti->schema_name, wti->table_name, &coli))
1045 {
1046 if (stmt)
1047 {
1048 SC_set_parse_status(stmt, STMT_PARSE_FATAL);
1049 SC_set_error(stmt, STMT_EXEC_ERROR, "Table not found", func);
1050 SC_reset_updatable(stmt);
1051 }
1052 return FALSE;
1053 }
1054 else if (NULL != coli)
1055 {
1056 found = TRUE;
1057 coli->refcnt++;
1058 wti->col_info = coli;
1059 }
1060 }
1061 if (found)
1062 goto cleanup;
1063 else if (0 != greloid || NAME_IS_VALID(wti->table_name))
1064 found = getColumnsInfo(conn, wti, greloid, stmt);
1065 cleanup:
1066 if (found)
1067 {
1068 QResultClass *res = wti->col_info->result;
1069
1070 if (res && QR_get_num_cached_tuples(res) > 0)
1071 {
1072 if (!greloid)
1073 greloid = (OID) strtoul(QR_get_value_backend_text(res, 0, COLUMNS_TABLE_OID), NULL, 10);
1074 if (!wti->table_oid)
1075 wti->table_oid = greloid;
1076 if (NAME_IS_NULL(wti->schema_name))
1077 STR_TO_NAME(wti->schema_name,
1078 QR_get_value_backend_text(res, 0, COLUMNS_SCHEMA_NAME));
1079 if (NAME_IS_NULL(wti->table_name))
1080 STR_TO_NAME(wti->table_name,
1081 QR_get_value_backend_text(res, 0, COLUMNS_TABLE_NAME));
1082 }
1083 MYLOG(DETAIL_LOG_LEVEL, "#1 %p->table_name=%s(%u)\n", wti, PRINT_NAME(wti->table_name), wti->table_oid);
1084 if (colatt /* SQLColAttribute case */
1085 && 0 == (wti->flags & TI_COLATTRIBUTE))
1086 {
1087 if (stmt)
1088 ColAttSet(stmt, wti);
1089 }
1090 wti->col_info->acc_time = SC_get_time(stmt);
1091 }
1092 else if (!colatt && stmt)
1093 SC_set_parse_status(stmt, STMT_PARSE_FATAL);
1094 MYLOG(DETAIL_LOG_LEVEL, "leaving returns %d\n", found);
1095 return found;
1096 }
1097
1098 SQLRETURN
SC_set_SS_columnkey(StatementClass * stmt)1099 SC_set_SS_columnkey(StatementClass *stmt)
1100 {
1101 IRDFields *irdflds = SC_get_IRDF(stmt);
1102 FIELD_INFO **fi = irdflds->fi, *tfi;
1103 size_t nfields = irdflds->nfields;
1104 HSTMT pstmt = NULL;
1105 SQLRETURN ret = SQL_SUCCESS;
1106 BOOL contains_key = FALSE;
1107 int i;
1108
1109 MYLOG(DETAIL_LOG_LEVEL, "entering fields=" FORMAT_SIZE_T " ntab=%d\n", nfields, stmt->ntab);
1110 if (!fi) return ret;
1111 if (0 >= nfields) return ret;
1112 for (i = 0; i < stmt->ntab; i++)
1113 {
1114 TABLE_INFO **ti = stmt->ti, *oneti;
1115 ConnectionClass *conn = SC_get_conn(stmt);
1116 OID internal_asis_type = SQL_C_CHAR;
1117 char keycolnam[MAX_INFO_STRING];
1118 SQLLEN keycollen;
1119
1120 ret = PGAPI_AllocStmt(conn, &pstmt, 0);
1121 if (!SQL_SUCCEEDED(ret))
1122 return ret;
1123 oneti = ti[i];
1124 ret = PGAPI_PrimaryKeys(pstmt, NULL, 0, NULL, 0, NULL, 0, oneti->table_oid);
1125 if (!SQL_SUCCEEDED(ret))
1126 goto cleanup;
1127 #ifdef UNICODE_SUPPORT
1128 if (CC_is_in_unicode_driver(conn))
1129 internal_asis_type = INTERNAL_ASIS_TYPE;
1130 #endif /* UNICODE_SUPPORT */
1131 ret = PGAPI_BindCol(pstmt, 4, internal_asis_type, keycolnam, MAX_INFO_STRING, &keycollen);
1132 if (!SQL_SUCCEEDED(ret))
1133 goto cleanup;
1134 contains_key = TRUE;
1135 ret = PGAPI_Fetch(pstmt);
1136 while (SQL_SUCCEEDED(ret))
1137 {
1138 int i; // different from i of outer loop
1139
1140 for (i = 0; i < nfields; i++)
1141 {
1142 if (tfi = fi[i], NULL == tfi)
1143 continue;
1144 if (!FI_is_applicable(tfi))
1145 continue;
1146 if (oneti == tfi->ti &&
1147 strcmp(keycolnam, SAFE_NAME(tfi->column_name)) == 0)
1148 {
1149 MYLOG(DETAIL_LOG_LEVEL, "key %s found at %p\n", keycolnam, fi + i);
1150 tfi->columnkey = TRUE;
1151 break;
1152 }
1153 }
1154 if (i >= nfields)
1155 {
1156 MYLOG(0, "%s not found\n", keycolnam);
1157 break;
1158 }
1159 ret = PGAPI_Fetch(pstmt);
1160 }
1161 if (SQL_SUCCEEDED(ret))
1162 contains_key = FALSE;
1163 else if (SQL_NO_DATA_FOUND != ret)
1164 goto cleanup;
1165 ret = SQL_SUCCESS;
1166 }
1167 MYLOG(DETAIL_LOG_LEVEL, "contains_key=%d\n", contains_key);
1168 for (i = 0; i < nfields; i++)
1169 {
1170 if (tfi = fi[i], NULL == tfi)
1171 continue;
1172 if (!FI_is_applicable(tfi))
1173 continue;
1174 if (!contains_key || tfi->columnkey < 0)
1175 tfi->columnkey = FALSE;
1176 }
1177 cleanup:
1178 if (pstmt)
1179 PGAPI_FreeStmt(pstmt, SQL_DROP);
1180 return ret;
1181 }
1182
include_alias_wo_as(const char * token,const char * btoken)1183 static BOOL include_alias_wo_as(const char *token, const char *btoken)
1184 {
1185 MYLOG(0, "alias ? token=%s btoken=%s\n", token, btoken);
1186 if ('\0' == btoken[0])
1187 return FALSE;
1188 else if (0 == stricmp(")", token))
1189 return FALSE;
1190 else if (0 == stricmp("as", btoken) ||
1191 0 == stricmp("and", btoken) ||
1192 0 == stricmp("or", btoken) ||
1193 0 == stricmp("not", btoken) ||
1194 0 == stricmp(",", btoken))
1195 return FALSE;
1196 else
1197 {
1198 CSTR ops = "+-*/%^|!@&#~<>=.";
1199 const char *cptr, *optr;
1200
1201 for (cptr = btoken; *cptr; cptr++)
1202 {
1203 for (optr = ops; *optr; optr++)
1204 {
1205 if (*optr != *cptr)
1206 return TRUE;
1207 }
1208 }
1209 }
1210
1211 return FALSE;
1212 }
1213
insert_as_to_the_statement(char * stmt,const char ** pptr,const char ** ptr)1214 static char *insert_as_to_the_statement(char *stmt, const char **pptr, const char **ptr)
1215 {
1216 size_t stsize = strlen(stmt), ppos = *pptr - stmt, remsize = stsize - ppos;
1217 const int ins_size = 3;
1218 char *newstmt = realloc(stmt, stsize + ins_size + 1);
1219
1220 if (newstmt)
1221 {
1222 char *sptr = newstmt + ppos;
1223 memmove(sptr + ins_size, sptr, remsize + 1);
1224 sptr[0] = 'a';
1225 sptr[1] = 's';
1226 sptr[2] = ' ';
1227 *ptr = sptr + (*ptr - *pptr) + ins_size;
1228 *pptr = sptr + ins_size;
1229 }
1230
1231 return newstmt;
1232 }
1233
1234 #define TOKEN_SIZE 256
1235 static char
parse_the_statement(StatementClass * stmt,BOOL check_hasoids,BOOL sqlsvr_check)1236 parse_the_statement(StatementClass *stmt, BOOL check_hasoids, BOOL sqlsvr_check)
1237 {
1238 CSTR func = "parse_the_statement";
1239 char delimdsp[2], token[TOKEN_SIZE], stoken[TOKEN_SIZE], btoken[TOKEN_SIZE];
1240 char delim,
1241 quote,
1242 dquote,
1243 numeric,
1244 unquoted;
1245 const char *ptr;
1246 const char *pptr = NULL;
1247 char in_select = FALSE,
1248 in_distinct = FALSE,
1249 in_on = FALSE,
1250 in_from = FALSE,
1251 in_where = FALSE,
1252 in_table = FALSE,
1253 out_table = TRUE;
1254 char in_field = FALSE,
1255 in_expr = FALSE,
1256 in_func = FALSE,
1257 in_dot = FALSE,
1258 in_as = FALSE;
1259 int j,
1260 i,
1261 k = 0,
1262 n,
1263 blevel = 0, old_blevel, subqlevel = 0,
1264 tbl_blevel = 0, allocated_size = -1, new_size,
1265 nfields;
1266 FIELD_INFO **fi, *wfi;
1267 TABLE_INFO **ti, *wti;
1268 char parse = FALSE;
1269 po_ind_t join_info = STMT_HAS_NO_JOIN;
1270 ConnectionClass *conn = SC_get_conn(stmt);
1271 IRDFields *irdflds;
1272 BOOL updatable = TRUE, column_has_alias = FALSE, fupdatable;
1273
1274 MYLOG(0, "entering...\n");
1275
1276 if (SC_parsed_status(stmt) != STMT_PARSE_NONE)
1277 {
1278 if (check_hasoids)
1279 CheckPgClassInfo(stmt);
1280 return TRUE;
1281 }
1282 nfields = 0;
1283 wfi = NULL;
1284 wti = NULL;
1285 ptr = stmt->statement;
1286 if (sqlsvr_check)
1287 {
1288 irdflds = NULL;
1289 fi = NULL;
1290 ti = NULL;
1291 }
1292 else
1293 {
1294 SC_set_updatable(stmt, FALSE);
1295 irdflds = SC_get_IRDF(stmt);
1296 fi = irdflds->fi;
1297 ti = stmt->ti;
1298
1299 allocated_size = irdflds->allocated;
1300 SC_initialize_cols_info(stmt, FALSE, TRUE);
1301 stmt->from_pos = -1;
1302 stmt->where_pos = -1;
1303 }
1304 #define return DONT_CALL_RETURN_FROM_HERE???
1305
1306 delim = '\0';
1307 token[0] = '\0';
1308 while (pptr = (const char *) ptr, (delim != ',') ? STRCPY_FIXED(btoken, token) : (btoken[0] = '\0', 0), (ptr = getNextToken(conn->ccsc, CC_get_escape(conn), pptr, token, sizeof(token), &delim, "e, &dquote, &numeric)) != NULL)
1309 {
1310 unquoted = !(quote || dquote);
1311
1312 if (delim)
1313 {
1314 delimdsp[0] = delim;
1315 delimdsp[1] = '\0';
1316 }
1317 else
1318 delimdsp[0] = '\0';
1319 MYLOG(0, "unquoted=%d, quote=%d, dquote=%d, numeric=%d, delim='%s', token='%s', ptr='%s'\n", unquoted, quote, dquote, numeric, delimdsp, token, ptr);
1320
1321 old_blevel = blevel;
1322 if (unquoted && blevel == 0)
1323 {
1324 if (in_select)
1325 {
1326 if (!stricmp(token, "distinct"))
1327 {
1328 in_distinct = TRUE;
1329 updatable = FALSE;
1330
1331 MYLOG(0, "DISTINCT\n");
1332 continue;
1333 }
1334 else if (!stricmp(token, "into"))
1335 {
1336 in_select = FALSE;
1337 MYLOG(0, "INTO\n");
1338 stmt->statement_type = STMT_TYPE_CREATE;
1339 SC_set_parse_status(stmt, STMT_PARSE_FATAL);
1340 goto cleanup;
1341 }
1342 else if (!stricmp(token, "from"))
1343 {
1344 if (sqlsvr_check)
1345 {
1346 parse = TRUE;
1347 goto cleanup;
1348 }
1349 in_select = FALSE;
1350 in_from = TRUE;
1351 if (stmt->from_pos < 0 &&
1352 (!strnicmp(pptr, "from", 4)))
1353 {
1354 MYLOG(0, "First From\n");
1355 stmt->from_pos = pptr - stmt->statement;
1356 }
1357 else
1358 MYLOG(0, "FROM\n");
1359 continue;
1360 }
1361 } /* in_select && unquoted && blevel == 0 */
1362 else if ((!stricmp(token, "where") ||
1363 !stricmp(token, "union") ||
1364 !stricmp(token, "intersect") ||
1365 !stricmp(token, "except") ||
1366 !stricmp(token, "order") ||
1367 !stricmp(token, "group") ||
1368 !stricmp(token, "having")))
1369 {
1370 in_from = FALSE;
1371 in_where = TRUE;
1372
1373 if (stmt->where_pos < 0)
1374 stmt->where_pos = pptr - stmt->statement;
1375 MYLOG(0, "%s...\n", token);
1376 if (stricmp(token, "where") &&
1377 stricmp(token, "order"))
1378 {
1379 updatable = FALSE;
1380 break;
1381 }
1382 continue;
1383 }
1384 } /* unquoted && blevel == 0 */
1385 /* check the change of blevel etc */
1386 if (unquoted)
1387 {
1388 if (!stricmp(token, "select"))
1389 {
1390 stoken[0] = '\0';
1391 if (0 == blevel)
1392 {
1393 in_select = TRUE;
1394 MYLOG(0, "SELECT\n");
1395 continue;
1396 }
1397 else
1398 {
1399 MYLOG(0, "SUBSELECT\n");
1400 if (0 == subqlevel)
1401 subqlevel = blevel;
1402 }
1403 }
1404 else if (token[0] == '(')
1405 {
1406 blevel++;
1407 MYLOG(0, "blevel++ -> %d\n", blevel);
1408 /* aggregate function ? */
1409 if (stoken[0] && updatable && 0 == subqlevel)
1410 {
1411 if (stricmp(stoken, "count") == 0 ||
1412 stricmp(stoken, "sum") == 0 ||
1413 stricmp(stoken, "avg") == 0 ||
1414 stricmp(stoken, "max") == 0 ||
1415 stricmp(stoken, "min") == 0 ||
1416 stricmp(stoken, "variance") == 0 ||
1417 stricmp(stoken, "stddev") == 0)
1418 updatable = FALSE;
1419 }
1420 }
1421 else if (token[0] == ')')
1422 {
1423 blevel--;
1424 MYLOG(0, "blevel-- = %d\n", blevel);
1425 if (blevel < subqlevel)
1426 subqlevel = 0;
1427 }
1428 if (blevel >= old_blevel && ',' != delim)
1429 STRCPY_FIXED(stoken, token);
1430 else
1431 stoken[0] = '\0';
1432 }
1433 if (in_select)
1434 {
1435 MYLOG(0, "blevel=%d btoken=%s in_dot=%d in_field=%d tbname=%s\n", blevel, btoken, in_dot, in_field, wfi ? SAFE_NAME(wfi->column_alias) : "<null>");
1436 if (0 == blevel &&
1437 sqlsvr_check &&
1438 dquote &&
1439 '\0' != btoken[0] &&
1440 !in_dot &&
1441 in_field &&
1442 (!column_has_alias))
1443 {
1444 if (include_alias_wo_as(token, btoken))
1445 {
1446 char *news;
1447
1448 column_has_alias = TRUE;
1449 if (NULL != wfi)
1450 STRX_TO_NAME(wfi->column_alias, token);
1451 news = insert_as_to_the_statement(stmt->statement, &pptr, &ptr);
1452 if (news != stmt->statement)
1453 {
1454 free(stmt->statement);
1455 stmt->statement = news;
1456 }
1457 }
1458 }
1459 if (in_expr || in_func)
1460 {
1461 /* just eat the expression */
1462 MYLOG(0, "in_expr=%d or func=%d\n", in_expr, in_func);
1463
1464 if (blevel == 0)
1465 {
1466 if (delim == ',')
1467 {
1468 MYLOG(0, "**** Got comma in_expr/func\n");
1469 in_func = FALSE;
1470 in_expr = FALSE;
1471 in_field = FALSE;
1472 }
1473 else if (unquoted && !stricmp(token, "as"))
1474 {
1475 MYLOG(0, "got AS in_expr\n");
1476 in_func = FALSE;
1477 in_expr = FALSE;
1478 in_as = TRUE;
1479 in_field = TRUE;
1480 }
1481 }
1482 continue;
1483 } /* (in_expr || in_func) && in_select */
1484
1485 if (in_distinct)
1486 {
1487 MYLOG(0, "in distinct\n");
1488
1489 if (unquoted && !stricmp(token, "on"))
1490 {
1491 in_on = TRUE;
1492 MYLOG(0, "got on\n");
1493 continue;
1494 }
1495 if (in_on)
1496 {
1497 in_distinct = FALSE;
1498 in_on = FALSE;
1499 continue; /* just skip the unique on field */
1500 }
1501 MYLOG(0, "done distinct\n");
1502 in_distinct = FALSE;
1503 } /* in_distinct */
1504
1505 if (!in_field)
1506 {
1507 BOOL fi_reuse = FALSE;
1508
1509 if (!token[0])
1510 continue;
1511
1512 column_has_alias = FALSE;
1513 if (!sqlsvr_check)
1514 {
1515 /* if (!(irdflds->nfields % FLD_INCR)) */
1516 if (irdflds->nfields >= allocated_size)
1517 {
1518 MYLOG(0, "reallocing at nfld=%d\n", irdflds->nfields);
1519 new_size = irdflds->nfields + 1;
1520 if (!allocateFields(irdflds, new_size))
1521 {
1522 SC_set_parse_status(stmt, STMT_PARSE_FATAL);
1523 SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for FIELD_INFO.", func);
1524 goto cleanup;
1525 }
1526 fi = irdflds->fi;
1527 allocated_size = irdflds->allocated;
1528 }
1529
1530 wfi = fi[irdflds->nfields];
1531 if (NULL != wfi)
1532 fi_reuse = TRUE;
1533 else
1534 wfi = fi[irdflds->nfields] = (FIELD_INFO *) malloc(sizeof(FIELD_INFO));
1535 if (NULL == wfi)
1536 {
1537 SC_set_parse_status(stmt, STMT_PARSE_FATAL);
1538 SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for FIELD_INFO(2).", func);
1539 goto cleanup;
1540 }
1541
1542 /* Initialize the field info */
1543 FI_Constructor(wfi, fi_reuse);
1544 wfi->flag = FIELD_PARSING;
1545 }
1546
1547 /* double quotes are for qualifiers */
1548 if (dquote && NULL != wfi)
1549 wfi->dquote = TRUE;
1550
1551 if (quote)
1552 {
1553 if (NULL != wfi)
1554 {
1555 wfi->quote = TRUE;
1556 wfi->column_size = (int) strlen(token);
1557 }
1558 }
1559 else if (numeric)
1560 {
1561 MYLOG(0, "**** got numeric: nfld = %d\n", nfields);
1562 if (NULL != wfi)
1563 wfi->numeric = TRUE;
1564 }
1565 else if (0 == old_blevel && blevel > 0)
1566 { /* expression */
1567 MYLOG(0, "got EXPRESSION\n");
1568 if (NULL != wfi)
1569 wfi->expr = TRUE;
1570 in_expr = TRUE;
1571 /* continue; */
1572 }
1573 else if (NULL != wfi)
1574 {
1575 STRX_TO_NAME(wfi->column_name, token);
1576 NULL_THE_NAME(wfi->before_dot);
1577 }
1578 if (NULL != wfi)
1579 MYLOG(0, "got field='%s', dot='%s'\n", PRINT_NAME(wfi->column_name), PRINT_NAME(wfi->before_dot));
1580
1581 if (delim == ',')
1582 MYLOG(0, "comma (1)\n");
1583 else
1584 in_field = TRUE;
1585 nfields++;
1586 if (NULL != irdflds)
1587 irdflds->nfields++;
1588 continue;
1589 } /* !in_field */
1590
1591 /*
1592 * We are in a field now
1593 */
1594 if (!sqlsvr_check)
1595 wfi = fi[irdflds->nfields - 1];
1596 if (in_dot)
1597 {
1598 if (NULL != wfi)
1599 {
1600 if (NAME_IS_VALID(wfi->before_dot))
1601 {
1602 MOVE_NAME(wfi->schema_name, wfi->before_dot);
1603 }
1604 MOVE_NAME(wfi->before_dot, wfi->column_name);
1605 STRX_TO_NAME(wfi->column_name, token);
1606 }
1607
1608 if (delim == ',')
1609 {
1610 MYLOG(0, "in_dot: got comma\n");
1611 in_field = FALSE;
1612 }
1613 in_dot = FALSE;
1614 continue;
1615 }
1616
1617 if (in_as)
1618 {
1619 column_has_alias = TRUE;
1620 if (NULL != wfi)
1621 {
1622 STRX_TO_NAME(wfi->column_alias, token);
1623 MYLOG(0, "alias for field '%s' is '%s'\n", PRINT_NAME(wfi->column_name), PRINT_NAME(wfi->column_alias));
1624 }
1625 in_as = FALSE;
1626 in_field = FALSE;
1627
1628 if (delim == ',')
1629 MYLOG(0, "comma(2)\n");
1630 continue;
1631 }
1632
1633 /* Function */
1634 if (0 == old_blevel && blevel > 0)
1635 {
1636 in_dot = FALSE;
1637 in_func = TRUE;
1638 if (NULL != wfi)
1639 {
1640 wfi->func = TRUE;
1641
1642 /*
1643 * name will have the function name -- maybe useful some
1644 * day
1645 */
1646 MYLOG(0, "**** got function = '%s'\n", PRINT_NAME(wfi->column_name));
1647 }
1648 continue;
1649 }
1650
1651 if (token[0] == '.')
1652 {
1653 in_dot = TRUE;
1654 MYLOG(0, "got dot\n");
1655 continue;
1656 }
1657
1658 in_dot = FALSE;
1659 if (!stricmp(token, "as"))
1660 {
1661 in_as = TRUE;
1662 MYLOG(0, "got AS\n");
1663 continue;
1664 }
1665
1666 /* otherwise, it's probably an expression */
1667 if (!column_has_alias)
1668 {
1669 in_expr = TRUE;
1670 if (NULL != wfi)
1671 {
1672 wfi->expr = TRUE;
1673 NULL_THE_NAME(wfi->column_name);
1674 wfi->column_size = 0;
1675 }
1676 MYLOG(0, "*** setting expression\n");
1677 }
1678 else
1679 MYLOG(0, "*** may be an alias for a field\n");
1680 if (0 == blevel && ',' == delim)
1681 {
1682 in_expr = in_func = in_field = FALSE;
1683 }
1684 } /* in_select end */
1685
1686 if (in_from || in_where)
1687 {
1688 if (token[0] == ';') /* end of the first command */
1689 {
1690 in_select = in_from = in_where = in_table = FALSE;
1691 break;
1692 }
1693 }
1694 if (in_from)
1695 {
1696 switch (token[0])
1697 {
1698 case '\0':
1699 continue;
1700 case ',':
1701 out_table = TRUE;
1702 continue;
1703 }
1704 if (out_table && !in_table) /* new table */
1705 {
1706 BOOL is_table_name, is_subquery;
1707
1708 in_dot = FALSE;
1709 join_info = STMT_HAS_NO_JOIN;
1710 if (!dquote)
1711 {
1712 if (token[0] == '(' ||
1713 token[0] == ')')
1714 continue;
1715 }
1716
1717 if (sqlsvr_check)
1718 wti = NULL;
1719 else
1720 {
1721 if (!increaseNtab(stmt, func))
1722 {
1723 SC_set_parse_status(stmt, STMT_PARSE_FATAL);
1724 goto cleanup;
1725 }
1726
1727 ti = stmt->ti;
1728 wti = ti[stmt->ntab - 1];
1729 }
1730 is_table_name = TRUE;
1731 is_subquery = FALSE;
1732 if (dquote)
1733 ;
1734 else if (0 == stricmp(token, "select"))
1735 {
1736 MYLOG(0, "got subquery lvl=%d\n", blevel);
1737 is_table_name = FALSE;
1738 is_subquery = TRUE;
1739 }
1740 else if ('(' == ptr[0])
1741 {
1742 MYLOG(0, "got srf? = '%s'\n", token);
1743 is_table_name = FALSE;
1744 }
1745 if (NULL != wti)
1746 {
1747 if (is_table_name)
1748 {
1749 STRX_TO_NAME(wti->table_name, token);
1750 lower_the_name(GET_NAME(wti->table_name), conn, dquote);
1751 MYLOG(0, "got table = '%s'\n", PRINT_NAME(wti->table_name));
1752 }
1753 else
1754 {
1755 NULL_THE_NAME(wti->table_name);
1756 TI_no_updatable(wti);
1757 }
1758 }
1759
1760 if (0 == blevel && delim == ',')
1761 {
1762 out_table = TRUE;
1763 MYLOG(0, "more than 1 tables\n");
1764 }
1765 else
1766 {
1767 out_table = FALSE;
1768 in_table = TRUE;
1769 if (is_subquery)
1770 tbl_blevel = blevel - 1;
1771 else
1772 tbl_blevel = blevel;
1773 }
1774 continue;
1775 }
1776 if (blevel > tbl_blevel)
1777 continue;
1778 /* out_table is FALSE here */
1779 if (!dquote && !in_dot)
1780 {
1781 if (')' == token[0])
1782 continue;
1783 if (stricmp(token, "LEFT") == 0 ||
1784 stricmp(token, "RIGHT") == 0 ||
1785 stricmp(token, "OUTER") == 0 ||
1786 stricmp(token, "FULL") == 0)
1787 {
1788 join_info = STMT_HAS_OUTER_JOIN;
1789 in_table = FALSE;
1790 continue;
1791 }
1792 else if (stricmp(token, "INNER") == 0 ||
1793 stricmp(token, "CROSS") == 0)
1794 {
1795 join_info = STMT_HAS_INNER_JOIN;
1796 in_table = FALSE;
1797 continue;
1798 }
1799 else if (stricmp(token, "JOIN") == 0)
1800 {
1801 in_table = FALSE;
1802 out_table = TRUE;
1803 if (join_info == STMT_HAS_OUTER_JOIN)
1804 {
1805 SC_set_outer_join(stmt);
1806 }
1807 else
1808 {
1809 SC_set_inner_join(stmt);
1810 }
1811 join_info = STMT_HAS_NO_JOIN;
1812 continue;
1813 }
1814 }
1815 join_info = STMT_HAS_NO_JOIN;
1816 if (in_table)
1817 {
1818 if (!sqlsvr_check)
1819 wti = ti[stmt->ntab - 1];
1820 if (in_dot)
1821 {
1822 if (NULL != wfi)
1823 {
1824 MOVE_NAME(wti->schema_name, wti->table_name);
1825 STRX_TO_NAME(wti->table_name, token);
1826 lower_the_name(GET_NAME(wti->table_name), conn, dquote);
1827 }
1828 in_dot = FALSE;
1829 continue;
1830 }
1831 if (strcmp(token, ".") == 0)
1832 {
1833 in_dot = TRUE;
1834 continue;
1835 }
1836 if (dquote || stricmp(token, "as"))
1837 {
1838 if (!dquote)
1839 {
1840 if (stricmp(token, "ON") == 0)
1841 {
1842 in_table = FALSE;
1843 continue;
1844 }
1845 }
1846 if (NULL != wti)
1847 {
1848 STRX_TO_NAME(wti->table_alias, token);
1849 MYLOG(0, "alias for table '%s' is '%s'\n", PRINT_NAME(wti->table_name), PRINT_NAME(wti->table_alias));
1850 }
1851 in_table = FALSE;
1852 if (delim == ',')
1853 {
1854 out_table = TRUE;
1855 MYLOG(0, "more than 1 tables\n");
1856 }
1857 }
1858 }
1859 } /* in_from */
1860 }
1861
1862 /*
1863 * Resolve any possible field names with tables
1864 */
1865
1866 parse = TRUE;
1867 if (sqlsvr_check)
1868 goto cleanup;
1869
1870 /* Resolve field names with tables */
1871 for (i = 0; i < (int) irdflds->nfields; i++)
1872 {
1873 wfi = fi[i];
1874 if (wfi->func || wfi->expr || wfi->numeric)
1875 {
1876 wfi->ti = NULL;
1877 wfi->columntype = wfi->basetype = (OID) 0;
1878 parse = FALSE;
1879 continue;
1880 }
1881 else if (wfi->quote)
1882 { /* handle as text */
1883 wfi->ti = NULL;
1884
1885 /*
1886 * wfi->type = PG_TYPE_TEXT; wfi->column_size = 0; the
1887 * following may be better
1888 */
1889 wfi->basetype = PG_TYPE_UNKNOWN;
1890 if (wfi->column_size == 0)
1891 {
1892 wfi->basetype = PG_TYPE_VARCHAR;
1893 wfi->column_size = 254;
1894 }
1895 wfi->length = wfi->column_size;
1896 continue;
1897 }
1898 /* field name contains the schema name */
1899 else if (NAME_IS_VALID(wfi->schema_name))
1900 {
1901 int matchidx = -1;
1902
1903 for (k = 0; k < stmt->ntab; k++)
1904 {
1905 wti = ti[k];
1906 if (!NAMEICMP(wti->table_name, wfi->before_dot))
1907 {
1908 if (!NAMEICMP(wti->schema_name, wfi->schema_name))
1909 {
1910 wfi->ti = wti;
1911 break;
1912 }
1913 else if (NAME_IS_NULL(wti->schema_name))
1914 {
1915 if (matchidx < 0)
1916 matchidx = k;
1917 else
1918 {
1919 SC_set_parse_status(stmt, STMT_PARSE_FATAL);
1920 SC_set_error(stmt, STMT_EXEC_ERROR, "duplicated Table name", func);
1921 SC_reset_updatable(stmt);
1922 goto cleanup;
1923 }
1924 }
1925 }
1926 }
1927 if (matchidx >= 0)
1928 wfi->ti = ti[matchidx];
1929 }
1930 /* it's a dot, resolve to table or alias */
1931 else if (NAME_IS_VALID(wfi->before_dot))
1932 {
1933 for (k = 0; k < stmt->ntab; k++)
1934 {
1935 wti = ti[k];
1936 if (!NAMEICMP(wti->table_alias, wfi->before_dot))
1937 {
1938 wfi->ti = wti;
1939 break;
1940 }
1941 else if (!NAMEICMP(wti->table_name, wfi->before_dot))
1942 {
1943 wfi->ti = wti;
1944 break;
1945 }
1946 }
1947 }
1948 else if (stmt->ntab == 1)
1949 wfi->ti = ti[0];
1950 }
1951
1952 MYLOG(0, "--------------------------------------------\n");
1953 MYLOG(0, "nfld=%d, ntab=%d\n", irdflds->nfields, stmt->ntab);
1954 if (0 == stmt->ntab)
1955 {
1956 SC_set_parse_status(stmt, STMT_PARSE_FATAL);
1957 goto cleanup;
1958 }
1959
1960 for (i = 0; i < (int) irdflds->nfields; i++)
1961 {
1962 wfi = fi[i];
1963 MYLOG(0, "Field %d: expr=%d, func=%d, quote=%d, dquote=%d, numeric=%d, name='%s', alias='%s', dot='%s'\n", i, wfi->expr, wfi->func, wfi->quote, wfi->dquote, wfi->numeric, PRINT_NAME(wfi->column_name), PRINT_NAME(wfi->column_alias), PRINT_NAME(wfi->before_dot));
1964 if (wfi->ti)
1965 MYLOG(0, " ----> table_name='%s', table_alias='%s'\n", PRINT_NAME(wfi->ti->table_name), PRINT_NAME(wfi->ti->table_alias));
1966 }
1967
1968 for (i = 0; i < stmt->ntab; i++)
1969 {
1970 wti = ti[i];
1971 MYLOG(0, "Table %d: name='%s', alias='%s'\n", i, PRINT_NAME(wti->table_name), PRINT_NAME(wti->table_alias));
1972 }
1973
1974 /*
1975 * Now save the SQLColumns Info for the parse tables
1976 */
1977
1978 /* Call SQLColumns for each table and store the result */
1979 if (stmt->ntab > 1)
1980 updatable = FALSE;
1981 else if (stmt->from_pos < 0)
1982 updatable = FALSE;
1983 for (i = 0; i < stmt->ntab; i++)
1984 {
1985 /* See if already got it */
1986 wti = ti[i];
1987
1988 if (!getCOLIfromTI(func, NULL, stmt, 0, &wti))
1989 break;
1990 }
1991 if (STMT_PARSE_FATAL == SC_parsed_status(stmt))
1992 {
1993 goto cleanup;
1994 }
1995
1996 MYLOG(0, "Done PG_Columns\n");
1997
1998 /*
1999 * Now resolve the fields to point to column info
2000 */
2001 for (i = 0; i < (int) irdflds->nfields;)
2002 {
2003 wfi = fi[i];
2004 if (wfi->ti)
2005 fupdatable = updatable && TI_is_updatable(wfi->ti);
2006 else
2007 fupdatable = FALSE;
2008 wfi->updatable = fupdatable;
2009 /* Dont worry about functions or quotes */
2010 if (wfi->func || wfi->quote || wfi->numeric)
2011 {
2012 wfi->updatable = FALSE;
2013 i++;
2014 continue;
2015 }
2016
2017 /* Stars get expanded to all fields in the table */
2018 else if (SAFE_NAME(wfi->column_name)[0] == '*')
2019 {
2020 char do_all_tables;
2021 Int2 total_cols,
2022 cols,
2023 increased_cols;
2024
2025 MYLOG(0, "expanding field %d\n", i);
2026
2027 total_cols = 0;
2028
2029 if (wfi->ti) /* The star represents only the qualified
2030 * table */
2031 total_cols = (Int2) QR_get_num_cached_tuples(wfi->ti->col_info->result);
2032
2033 else
2034 { /* The star represents all tables */
2035 /* Calculate the total number of columns after expansion */
2036 for (k = 0; k < stmt->ntab; k++)
2037 total_cols += (Int2) QR_get_num_cached_tuples(ti[k]->col_info->result);
2038 }
2039 increased_cols = total_cols - 1;
2040
2041 /* Allocate some more field pointers if necessary */
2042 new_size = irdflds->nfields + increased_cols;
2043
2044 MYLOG(0, "k=%d, increased_cols=%d, allocated_size=%d, new_size=%d\n", k, increased_cols, allocated_size, new_size);
2045
2046 if (new_size > allocated_size)
2047 {
2048 int new_alloc = new_size;
2049
2050 MYLOG(0, "need more cols: new_alloc = %d\n", new_alloc);
2051 if (!allocateFields(irdflds, new_alloc))
2052 {
2053 SC_set_parse_status(stmt, STMT_PARSE_FATAL);
2054 goto cleanup;
2055 }
2056 fi = irdflds->fi;
2057 allocated_size = irdflds->allocated;
2058 }
2059
2060 /*
2061 * copy any other fields (if there are any) up past the
2062 * expansion
2063 */
2064 for (j = irdflds->nfields - 1; j > i; j--)
2065 {
2066 MYLOG(0, "copying field %d to %d\n", j, increased_cols + j);
2067 fi[increased_cols + j] = fi[j];
2068 }
2069 MYLOG(0, "done copying fields\n");
2070
2071 /* Set the new number of fields */
2072 irdflds->nfields += increased_cols;
2073 MYLOG(0, "irdflds->nfields now at %d\n", irdflds->nfields);
2074
2075
2076 /* copy the new field info */
2077 do_all_tables = (wfi->ti ? FALSE : TRUE);
2078 wfi = NULL;
2079
2080 for (k = 0; k < (do_all_tables ? stmt->ntab : 1); k++)
2081 {
2082 TABLE_INFO *the_ti = do_all_tables ? ti[k] : fi[i]->ti;
2083
2084 cols = (Int2) QR_get_num_cached_tuples(the_ti->col_info->result);
2085
2086 for (n = 0; n < cols; n++)
2087 {
2088 FIELD_INFO *afi;
2089 BOOL reuse = TRUE;
2090
2091 MYLOG(0, "creating field info: n=%d\n", n);
2092 /* skip malloc (already did it for the Star) */
2093 if (k > 0 || n > 0)
2094 {
2095 MYLOG(0, "allocating field info at %d\n", n + i);
2096 fi[n + i] = (FIELD_INFO *) malloc(sizeof(FIELD_INFO));
2097 if (fi[n + i] == NULL)
2098 {
2099 SC_set_parse_status(stmt, STMT_PARSE_FATAL);
2100 goto cleanup;
2101 }
2102 reuse = FALSE;
2103 }
2104 afi = fi[n + i];
2105 /* Initialize the new space (or the * field) */
2106 FI_Constructor(afi, reuse);
2107 afi->ti = the_ti;
2108
2109 MYLOG(0, "about to copy at %d\n", n + i);
2110
2111 getColInfo(the_ti->col_info, afi, n);
2112 afi->updatable = fupdatable;
2113
2114 MYLOG(0, "done copying\n");
2115 }
2116
2117 i += cols;
2118 MYLOG(0, "i now at %d\n", i);
2119 }
2120 }
2121
2122 /*
2123 * We either know which table the field was in because it was
2124 * qualified with a table name or alias -OR- there was only 1
2125 * table.
2126 */
2127 else if (wfi->ti)
2128 {
2129 if (!searchColInfo(fi[i]->ti->col_info, wfi))
2130 {
2131 parse = FALSE;
2132 wfi->updatable = FALSE;
2133 }
2134 i++;
2135 }
2136
2137 /* Don't know the table -- search all tables in "from" list */
2138 else
2139 {
2140 for (k = 0; k < stmt->ntab; k++)
2141 {
2142 if (searchColInfo(ti[k]->col_info, wfi))
2143 {
2144 wfi->ti = ti[k]; /* now know the table */
2145 break;
2146 }
2147 }
2148 if (k >= stmt->ntab)
2149 {
2150 parse = FALSE;
2151 wfi->updatable = FALSE;
2152 }
2153 i++;
2154 }
2155 }
2156
2157 if (check_hasoids && updatable)
2158 CheckPgClassInfo(stmt);
2159 SC_set_parse_status(stmt, parse ? STMT_PARSE_COMPLETE : STMT_PARSE_INCOMPLETE);
2160 for (i = 0; i < (int) irdflds->nfields; i++)
2161 {
2162 wfi = fi[i];
2163 wfi->flag &= ~FIELD_PARSING;
2164 if (0 != wfi->columntype || 0 != wfi->basetype)
2165 wfi->flag |= FIELD_PARSED_OK;
2166 }
2167
2168 if (updatable)
2169 {
2170 if (stmt->ntab > 1)
2171 updatable = FALSE;
2172 }
2173 SC_set_updatable(stmt, updatable);
2174 cleanup:
2175 #undef return
2176 if (!sqlsvr_check && STMT_PARSE_FATAL == SC_parsed_status(stmt))
2177 {
2178 SC_initialize_cols_info(stmt, FALSE, FALSE);
2179 parse = FALSE;
2180 }
2181
2182 MYLOG(0, "laving parse=%d, parse_status=%d\n", parse, SC_parsed_status(stmt));
2183 return parse;
2184 }
2185
2186 char
parse_statement(StatementClass * stmt,BOOL check_hasoids)2187 parse_statement(StatementClass *stmt, BOOL check_hasoids)
2188 {
2189 return parse_the_statement(stmt, check_hasoids, FALSE);
2190 }
2191
2192 char
parse_sqlsvr(StatementClass * stmt)2193 parse_sqlsvr(StatementClass *stmt)
2194 {
2195 return parse_the_statement(stmt, FALSE, TRUE);
2196 }
2197