~ubuntu-branches/ubuntu/natty/psqlodbc/natty

« back to all changes in this revision

Viewing changes to parse.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2004-05-13 10:47:36 UTC
  • Revision ID: james.westby@ubuntu.com-20040513104736-a530gmn0p3knep89
Tags: upstream-07.03.0200
ImportĀ upstreamĀ versionĀ 07.03.0200

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 "notice.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
 
 
37
#include "multibyte.h"
 
38
 
 
39
#define FLD_INCR        32
 
40
#define TAB_INCR        8
 
41
#define COL_INCR        16
 
42
 
 
43
char       *getNextToken(int ccsc, char *s, char *token, int smax, char *delim, char *quote, char *dquote, char *numeric);
 
44
void            getColInfo(COL_INFO *col_info, FIELD_INFO *fi, int k);
 
45
char            searchColInfo(COL_INFO *col_info, FIELD_INFO *fi);
 
46
 
 
47
Int4 FI_precision(const FIELD_INFO *fi)
 
48
{
 
49
        if (!fi)        return -1;
 
50
        switch (fi->type)
 
51
        {
 
52
                case PG_TYPE_NUMERIC:
 
53
                        return fi->column_size;
 
54
                case PG_TYPE_DATETIME:
 
55
                case PG_TYPE_TIMESTAMP_NO_TMZONE:
 
56
                        return fi->decimal_digits;
 
57
        }
 
58
        return 0;
 
59
}
 
60
Int4 FI_scale(const FIELD_INFO *fi)
 
61
{
 
62
        if (!fi)        return -1;
 
63
        switch (fi->type)
 
64
        {
 
65
                case PG_TYPE_NUMERIC:
 
66
                        return fi->decimal_digits;
 
67
        }
 
68
        return 0;
 
69
}
 
70
 
 
71
char *
 
72
getNextToken(
 
73
        int ccsc, /* client encoding */
 
74
        char *s, char *token, int smax, char *delim, char *quote, char *dquote, char *numeric)
 
75
{
 
76
        int                     i = 0;
 
77
        int                     out = 0;
 
78
        char            qc,
 
79
                                in_escape = FALSE;
 
80
        encoded_str     encstr;
 
81
 
 
82
        if (smax <= 1)
 
83
                return NULL;
 
84
 
 
85
        smax--;
 
86
 
 
87
        /* skip leading delimiters */
 
88
        while (isspace((unsigned char) s[i]) || s[i] == ',')
 
89
        {
 
90
                /* mylog("skipping '%c'\n", s[i]); */
 
91
                i++;
 
92
        }
 
93
 
 
94
        if (s[i] == '\0')
 
95
        {
 
96
                token[0] = '\0';
 
97
                return NULL;
 
98
        }
 
99
 
 
100
        if (quote)
 
101
                *quote = FALSE;
 
102
        if (dquote)
 
103
                *dquote = FALSE;
 
104
        if (numeric)
 
105
                *numeric = FALSE;
 
106
 
 
107
        encoded_str_constr(&encstr, ccsc, &s[i]);
 
108
        /* get the next token */
 
109
        while (s[i] != '\0' && out < smax)
 
110
        {
 
111
                encoded_nextchar(&encstr);
 
112
                if (ENCODE_STATUS(encstr) != 0)
 
113
                {
 
114
                        token[out++] = s[i++];
 
115
                        continue;
 
116
                }
 
117
                if (isspace((unsigned char) s[i]) || s[i] == ',')
 
118
                        break;
 
119
                /* Handle quoted stuff */
 
120
                if (out == 0 && (s[i] == '\"' || s[i] == '\''))
 
121
                {
 
122
                        qc = s[i];
 
123
                        if (qc == '\"')
 
124
                        {
 
125
                                if (dquote)
 
126
                                        *dquote = TRUE;
 
127
                        }
 
128
                        if (qc == '\'')
 
129
                        {
 
130
                                if (quote)
 
131
                                        *quote = TRUE;
 
132
                        }
 
133
 
 
134
                        i++;                            /* dont return the quote */
 
135
                        while (s[i] != '\0' && out != smax)
 
136
                        {
 
137
                                encoded_nextchar(&encstr);
 
138
                                if (ENCODE_STATUS(encstr) != 0)
 
139
                                {
 
140
                                        token[out++] = s[i++];
 
141
                                        continue;
 
142
                                }
 
143
                                if (s[i] == qc && !in_escape)
 
144
                                        break;
 
145
                                if (s[i] == '\\' && !in_escape)
 
146
                                        in_escape = TRUE;
 
147
                                else
 
148
                                {
 
149
                                        in_escape = FALSE;
 
150
                                        token[out++] = s[i];
 
151
                                }
 
152
                                i++;
 
153
                        }
 
154
                        if (s[i] == qc)
 
155
                                i++;
 
156
                        break;
 
157
                }
 
158
 
 
159
                /* Check for numeric literals */
 
160
                if (out == 0 && isdigit((unsigned char) s[i]))
 
161
                {
 
162
                        if (numeric)
 
163
                                *numeric = TRUE;
 
164
                        token[out++] = s[i++];
 
165
                        while (isalnum((unsigned char) s[i]) || s[i] == '.')
 
166
                                token[out++] = s[i++];
 
167
 
 
168
                        break;
 
169
                }
 
170
 
 
171
                if (ispunct((unsigned char) s[i]) && s[i] != '_')
 
172
                {
 
173
                        mylog("got ispunct: s[%d] = '%c'\n", i, s[i]);
 
174
 
 
175
                        if (out == 0)
 
176
                        {
 
177
                                token[out++] = s[i++];
 
178
                                break;
 
179
                        }
 
180
                        else
 
181
                                break;
 
182
                }
 
183
 
 
184
                if (out != smax)
 
185
                        token[out++] = s[i];
 
186
 
 
187
                i++;
 
188
        }
 
189
 
 
190
        /* mylog("done -- s[%d] = '%c'\n", i, s[i]); */
 
191
 
 
192
        token[out] = '\0';
 
193
 
 
194
        /* find the delimiter  */
 
195
        while (isspace((unsigned char) s[i]))
 
196
                i++;
 
197
 
 
198
        /* return the most priority delimiter */
 
199
        if (s[i] == ',')
 
200
        {
 
201
                if (delim)
 
202
                        *delim = s[i];
 
203
        }
 
204
        else if (s[i] == '\0')
 
205
        {
 
206
                if (delim)
 
207
                        *delim = '\0';
 
208
        }
 
209
        else
 
210
        {
 
211
                if (delim)
 
212
                        *delim = ' ';
 
213
        }
 
214
 
 
215
        /* skip trailing blanks  */
 
216
        while (isspace((unsigned char) s[i]))
 
217
                i++;
 
218
 
 
219
        return &s[i];
 
220
}
 
221
 
 
222
 
 
223
#if 0
 
224
QR_set_num_fields(SC_get_Curres(stmt), 14);
 
225
QR_set_field_info(SC_get_Curres(stmt), 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
 
226
QR_set_field_info(SC_get_Curres(stmt), 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
 
227
QR_set_field_info(SC_get_Curres(stmt), 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
 
228
QR_set_field_info(SC_get_Curres(stmt), 3, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
 
229
QR_set_field_info(SC_get_Curres(stmt), 4, "DATA_TYPE", PG_TYPE_INT2, 2);
 
230
QR_set_field_info(SC_get_Curres(stmt), 5, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
 
231
QR_set_field_info(SC_get_Curres(stmt), 6, "PRECISION", PG_TYPE_INT4, 4);
 
232
QR_set_field_info(SC_get_Curres(stmt), 7, "LENGTH", PG_TYPE_INT4, 4);
 
233
QR_set_field_info(SC_get_Curres(stmt), 8, "SCALE", PG_TYPE_INT2, 2);
 
234
QR_set_field_info(SC_get_Curres(stmt), 9, "RADIX", PG_TYPE_INT2, 2);
 
235
QR_set_field_info(SC_get_Curres(stmt), 10, "NULLABLE", PG_TYPE_INT2, 2);
 
236
QR_set_field_info(SC_get_Curres(stmt), 11, "REMARKS", PG_TYPE_TEXT, 254);
 
237
/*      User defined fields */
 
238
QR_set_field_info(SC_get_Curres(stmt), 12, "DISPLAY_SIZE", PG_TYPE_INT4, 4);
 
239
QR_set_field_info(SC_get_Curres(stmt), 13, "FIELD_TYPE", PG_TYPE_INT4, 4);
 
240
#endif
 
241
 
 
242
void
 
243
getColInfo(COL_INFO *col_info, FIELD_INFO *fi, int k)
 
244
{
 
245
        char       *str;
 
246
        Int2    reserved_cols;
 
247
 
 
248
#if (ODBCVER >= 0x0300)
 
249
        reserved_cols = 18;
 
250
#else
 
251
        reserved_cols = 12;
 
252
#endif /* ODBCVER */
 
253
        if (fi->name[0] == '\0')
 
254
                strcpy(fi->name, QR_get_value_manual(col_info->result, k, 3));
 
255
 
 
256
        fi->type = atoi(QR_get_value_manual(col_info->result, k, (Int2)(reserved_cols + 1)));
 
257
        fi->column_size = atoi(QR_get_value_manual(col_info->result, k, 6));
 
258
        fi->length = atoi(QR_get_value_manual(col_info->result, k, 7));
 
259
        if (str = QR_get_value_manual(col_info->result, k, 8), str)
 
260
                fi->decimal_digits = atoi(str);
 
261
        else
 
262
                fi->decimal_digits = -1;
 
263
        fi->nullable = atoi(QR_get_value_manual(col_info->result, k, 10));
 
264
        fi->display_size = atoi(QR_get_value_manual(col_info->result, k, reserved_cols));
 
265
}
 
266
 
 
267
 
 
268
char
 
269
searchColInfo(COL_INFO *col_info, FIELD_INFO *fi)
 
270
{
 
271
        int                     k,
 
272
                                cmp;
 
273
        char       *col;
 
274
 
 
275
        for (k = 0; k < QR_get_num_backend_tuples(col_info->result); k++)
 
276
        {
 
277
                col = QR_get_value_manual(col_info->result, k, 3);
 
278
                if (fi->dquote)
 
279
                        cmp = strcmp(col, fi->name);
 
280
                else
 
281
                        cmp = stricmp(col, fi->name);
 
282
                if (!cmp)
 
283
                {
 
284
                        if (!fi->dquote)
 
285
                                strcpy(fi->name, col);
 
286
                        getColInfo(col_info, fi, k);
 
287
 
 
288
                        mylog("PARSE: searchColInfo: \n");
 
289
                        return TRUE;
 
290
                }
 
291
        }
 
292
 
 
293
        return FALSE;
 
294
}
 
295
 
 
296
/*
 
297
 *      lower the unquoted name
 
298
 */
 
299
static
 
300
void lower_the_name(char *name, ConnectionClass *conn, BOOL dquote)
 
301
{
 
302
        if (!dquote)
 
303
        {
 
304
                char            *ptr;
 
305
                encoded_str     encstr;
 
306
                make_encoded_str(&encstr, conn, name);
 
307
 
 
308
                /* lower case table name */
 
309
                for (ptr = name; *ptr; ptr++)
 
310
                {
 
311
                        encoded_nextchar(&encstr);
 
312
                        if (ENCODE_STATUS(encstr) == 0)
 
313
                                *ptr = tolower((unsigned char) *ptr);
 
314
                }
 
315
        }
 
316
}
 
317
 
 
318
char
 
319
parse_statement(StatementClass *stmt)
 
320
{
 
321
        CSTR            func = "parse_statement";
 
322
        char            token[256], stoken[256];
 
323
        char            delim,
 
324
                                quote,
 
325
                                dquote,
 
326
                                numeric,
 
327
                                unquoted;
 
328
        char       *ptr,
 
329
                           *pptr = NULL;
 
330
        char            in_select = FALSE,
 
331
                                in_distinct = FALSE,
 
332
                                in_on = FALSE,
 
333
                                in_from = FALSE,
 
334
                                in_where = FALSE,
 
335
                                in_table = FALSE,
 
336
                                out_table = TRUE;
 
337
        char            in_field = FALSE,
 
338
                                in_expr = FALSE,
 
339
                                in_func = FALSE,
 
340
                                in_dot = FALSE,
 
341
                                in_as = FALSE;
 
342
        int                     j,
 
343
                                i,
 
344
                                k = 0,
 
345
                                n,
 
346
                                blevel = 0, old_blevel, subqlevel = 0;
 
347
        FIELD_INFO **fi;
 
348
        TABLE_INFO **ti;
 
349
        char            parse;
 
350
        ConnectionClass *conn = stmt->hdbc;
 
351
        HSTMT           hcol_stmt;
 
352
        StatementClass *col_stmt;
 
353
        IRDFields       *irdflds = SC_get_IRD(stmt);
 
354
        RETCODE         result;
 
355
        BOOL            updatable = TRUE;
 
356
 
 
357
        mylog("%s: entering...\n", func);
 
358
 
 
359
        ptr = stmt->statement;
 
360
        fi = irdflds->fi;
 
361
        ti = stmt->ti;
 
362
 
 
363
        irdflds->nfields = 0;
 
364
        stmt->ntab = 0;
 
365
        stmt->from_pos = -1;
 
366
        stmt->where_pos = -1;
 
367
 
 
368
        while (pptr = ptr, (ptr = getNextToken(conn->ccsc, pptr, token, sizeof(token), &delim, &quote, &dquote, &numeric)) != NULL)
 
369
        {
 
370
                unquoted = !(quote || dquote);
 
371
 
 
372
                mylog("unquoted=%d, quote=%d, dquote=%d, numeric=%d, delim='%c', token='%s', ptr='%s'\n", unquoted, quote, dquote, numeric, delim, token, ptr);
 
373
 
 
374
                old_blevel = blevel;
 
375
                if (unquoted && blevel == 0)
 
376
                {
 
377
                        if (in_select)
 
378
                        {
 
379
                                if (!stricmp(token, "distinct"))
 
380
                                {
 
381
                                        in_distinct = TRUE;
 
382
                                        updatable = FALSE;
 
383
 
 
384
                                        mylog("DISTINCT\n");
 
385
                                        continue;
 
386
                                }
 
387
                                else if (!stricmp(token, "into"))
 
388
                                {
 
389
                                        in_select = FALSE;
 
390
                                        mylog("INTO\n");
 
391
                                        stmt->statement_type = STMT_TYPE_CREATE;
 
392
                                        stmt->parse_status = STMT_PARSE_FATAL;
 
393
                                        return FALSE;
 
394
                                }
 
395
                                else if (!stricmp(token, "from"))
 
396
                                {
 
397
                                        in_select = FALSE;
 
398
                                        in_from = TRUE;
 
399
                                        if (stmt->from_pos < 0 &&
 
400
                                                (!strnicmp(pptr, "from", 4)))
 
401
                                        {
 
402
                                                mylog("First ");
 
403
                                                stmt->from_pos = pptr - stmt->statement;
 
404
                                        }
 
405
 
 
406
                                        mylog("FROM\n");
 
407
                                        continue;
 
408
                                }
 
409
                        } /* in_select && unquoted && blevel == 0 */
 
410
                        else if ((!stricmp(token, "where") ||
 
411
                                 !stricmp(token, "union") ||
 
412
                                 !stricmp(token, "intersect") ||
 
413
                                 !stricmp(token, "except") ||
 
414
                                 !stricmp(token, "order") ||
 
415
                                 !stricmp(token, "group") ||
 
416
                                 !stricmp(token, "having")))
 
417
                        {
 
418
                                in_from = FALSE;
 
419
                                in_where = TRUE;
 
420
 
 
421
                                if (stmt->where_pos < 0)
 
422
                                        stmt->where_pos = pptr - stmt->statement;
 
423
                                mylog("%s...\n", token);
 
424
                                if (stricmp(token, "where") &&
 
425
                                    stricmp(token, "order"))
 
426
                                {
 
427
                                        updatable = FALSE;
 
428
                                        break;
 
429
                                }
 
430
                                continue;
 
431
                        }
 
432
                } /* unquoted && blevel == 0 */
 
433
                /* check the change of blevel etc */
 
434
                if (unquoted)
 
435
                {
 
436
                        if (!stricmp(token, "select"))
 
437
                        {
 
438
                                stoken[0] = '\0';
 
439
                                if (0 == blevel)
 
440
                                {
 
441
                                        in_select = TRUE; 
 
442
                                        mylog("SELECT\n");
 
443
                                        continue;
 
444
                                }
 
445
                                else
 
446
                                {
 
447
                                        mylog("SUBSELECT\n");
 
448
                                        if (0 == subqlevel)
 
449
                                                subqlevel = blevel;
 
450
                                }
 
451
                        }
 
452
                        else if (token[0] == '(')
 
453
                        {
 
454
                                blevel++;
 
455
                                mylog("blevel++ = %d\n", blevel);
 
456
                                /* aggregate function ? */
 
457
                                if (stoken[0] && updatable && 0 == subqlevel)
 
458
                                {
 
459
                                        if (stricmp(stoken, "count") == 0 ||
 
460
                                            stricmp(stoken, "sum") == 0 ||
 
461
                                            stricmp(stoken, "avg") == 0 ||
 
462
                                            stricmp(stoken, "max") == 0 ||
 
463
                                            stricmp(stoken, "min") == 0 ||
 
464
                                            stricmp(stoken, "variance") == 0 ||
 
465
                                            stricmp(stoken, "stddev") == 0)
 
466
                                                updatable = FALSE;
 
467
                                }
 
468
                        }
 
469
                        else if (token[0] == ')')
 
470
                        {
 
471
                                blevel--;
 
472
                                mylog("blevel-- = %d\n", blevel);
 
473
                                if (blevel < subqlevel)
 
474
                                        subqlevel = 0;
 
475
                        }
 
476
                        if (blevel >= old_blevel && ',' != delim)
 
477
                                strcpy(stoken, token);
 
478
                        else
 
479
                                stoken[0] = '\0';
 
480
                }
 
481
                if (in_select)
 
482
                {
 
483
                        if (in_expr || in_func)
 
484
                        {
 
485
                                /* just eat the expression */
 
486
                                mylog("in_expr=%d or func=%d\n", in_expr, in_func);
 
487
 
 
488
                                if (blevel == 0)
 
489
                                {
 
490
                                        if (delim == ',')
 
491
                                        {
 
492
                                                mylog("**** Got comma in_expr/func\n");
 
493
                                                in_func = FALSE;
 
494
                                                in_expr = FALSE;
 
495
                                                in_field = FALSE;
 
496
                                        }
 
497
                                        else if (unquoted && !stricmp(token, "as"))
 
498
                                        {
 
499
                                                mylog("got AS in_expr\n");
 
500
                                                in_func = FALSE;
 
501
                                                in_expr = FALSE;
 
502
                                                in_as = TRUE;
 
503
                                                in_field = TRUE;
 
504
                                        }
 
505
                                }
 
506
                                continue;
 
507
                        } /* (in_expr || in_func) && in_select */
 
508
 
 
509
                        if (in_distinct)
 
510
                        {
 
511
                                mylog("in distinct\n");
 
512
 
 
513
                                if (unquoted && !stricmp(token, "on"))
 
514
                                {
 
515
                                        in_on = TRUE;
 
516
                                        mylog("got on\n");
 
517
                                        continue;
 
518
                                }
 
519
                                if (in_on)
 
520
                                {
 
521
                                        in_distinct = FALSE;
 
522
                                        in_on = FALSE;
 
523
                                        continue;       /* just skip the unique on field */
 
524
                                }
 
525
                                mylog("done distinct\n");
 
526
                                in_distinct = FALSE;
 
527
                        } /* in_distinct */
 
528
 
 
529
                        if (!in_field)
 
530
                        {
 
531
                                if (!token[0])
 
532
                                        continue;
 
533
 
 
534
                                if (!(irdflds->nfields % FLD_INCR))
 
535
                                {
 
536
                                        mylog("reallocing at nfld=%d\n", irdflds->nfields);
 
537
                                        fi = (FIELD_INFO **) realloc(fi, (irdflds->nfields + FLD_INCR) * sizeof(FIELD_INFO *));
 
538
                                        if (!fi)
 
539
                                        {
 
540
                                                stmt->parse_status = STMT_PARSE_FATAL;
 
541
                                                return FALSE;
 
542
                                        }
 
543
                                        irdflds->fi = fi;
 
544
                                }
 
545
 
 
546
                                fi[irdflds->nfields] = (FIELD_INFO *) malloc(sizeof(FIELD_INFO));
 
547
                                if (fi[irdflds->nfields] == NULL)
 
548
                                {
 
549
                                        stmt->parse_status = STMT_PARSE_FATAL;
 
550
                                        return FALSE;
 
551
                                }
 
552
 
 
553
                                /* Initialize the field info */
 
554
                                memset(fi[irdflds->nfields], 0, sizeof(FIELD_INFO));
 
555
 
 
556
                                /* double quotes are for qualifiers */
 
557
                                if (dquote)
 
558
                                        fi[irdflds->nfields]->dquote = TRUE;
 
559
 
 
560
                                if (quote)
 
561
                                {
 
562
                                        fi[irdflds->nfields]->quote = TRUE;
 
563
                                        fi[irdflds->nfields]->column_size = strlen(token);
 
564
                                }
 
565
                                else if (numeric)
 
566
                                {
 
567
                                        mylog("**** got numeric: nfld = %d\n", irdflds->nfields);
 
568
                                        fi[irdflds->nfields]->numeric = TRUE;
 
569
                                }
 
570
                                else if (0 == old_blevel && blevel > 0)
 
571
                                {                               /* expression */
 
572
                                        mylog("got EXPRESSION\n");
 
573
                                        fi[irdflds->nfields++]->expr = TRUE;
 
574
                                        in_expr = TRUE;
 
575
                                        continue;
 
576
                                }
 
577
                                else
 
578
                                {
 
579
                                        strcpy(fi[irdflds->nfields]->name, token);
 
580
                                        fi[irdflds->nfields]->dot[0] = '\0';
 
581
                                }
 
582
                                mylog("got field='%s', dot='%s'\n", fi[irdflds->nfields]->name, fi[irdflds->nfields]->dot);
 
583
 
 
584
                                if (delim == ',')
 
585
                                        mylog("comma (1)\n");
 
586
                                else
 
587
                                        in_field = TRUE;
 
588
                                irdflds->nfields++;
 
589
                                continue;
 
590
                        } /* !in_field */
 
591
 
 
592
                        /*
 
593
                         * We are in a field now
 
594
                         */
 
595
                        if (in_dot)
 
596
                        {
 
597
                                int     ifld = irdflds->nfields - 1;
 
598
 
 
599
                                if (fi[ifld]->dot[0])
 
600
                                {
 
601
                                        fi[ifld]->schema = strdup(fi[ifld]->dot);
 
602
                                }
 
603
                                strcpy(fi[ifld]->dot, fi[ifld]->name);
 
604
                                strcpy(fi[ifld]->name, token);
 
605
 
 
606
                                if (delim == ',')
 
607
                                {
 
608
                                        mylog("in_dot: got comma\n");
 
609
                                        in_field = FALSE;
 
610
                                }
 
611
                                in_dot = FALSE;
 
612
                                continue;
 
613
                        }
 
614
 
 
615
                        if (in_as)
 
616
                        {
 
617
                                irdflds->nfields--;
 
618
                                strcpy(fi[irdflds->nfields]->alias, token);
 
619
                                mylog("alias for field '%s' is '%s'\n", fi[irdflds->nfields]->name, fi[irdflds->nfields]->alias);
 
620
                                in_as = FALSE;
 
621
                                in_field = FALSE;
 
622
 
 
623
                                irdflds->nfields++;
 
624
 
 
625
                                if (delim == ',')
 
626
                                        mylog("comma(2)\n");
 
627
                                continue;
 
628
                        }
 
629
 
 
630
                        /* Function */
 
631
                        if (0 == old_blevel && blevel > 0)
 
632
                        {
 
633
                                in_dot = FALSE;
 
634
                                in_func = TRUE;
 
635
                                fi[irdflds->nfields - 1]->func = TRUE;
 
636
 
 
637
                                /*
 
638
                                 * name will have the function name -- maybe useful some
 
639
                                 * day
 
640
                                 */
 
641
                                mylog("**** got function = '%s'\n", fi[irdflds->nfields - 1]->name);
 
642
                                continue;
 
643
                        }
 
644
 
 
645
                        if (token[0] == '.')
 
646
                        {
 
647
                                in_dot = TRUE;
 
648
                                mylog("got dot\n");
 
649
                                continue;
 
650
                        }
 
651
 
 
652
                        in_dot = FALSE;
 
653
                        if (!stricmp(token, "as"))
 
654
                        {
 
655
                                in_as = TRUE;
 
656
                                mylog("got AS\n");
 
657
                                continue;
 
658
                        }
 
659
 
 
660
                        /* otherwise, it's probably an expression */
 
661
                        in_expr = TRUE;
 
662
                        fi[irdflds->nfields - 1]->expr = TRUE;
 
663
                        fi[irdflds->nfields - 1]->name[0] = '\0';
 
664
                        fi[irdflds->nfields - 1]->column_size = 0;
 
665
                        mylog("*** setting expression\n");
 
666
                } /* in_select end */
 
667
 
 
668
                if (in_from)
 
669
                {
 
670
                        if (token[0] == ';')
 
671
                        {
 
672
                                in_from = FALSE;
 
673
                                break;
 
674
                        }
 
675
                        switch (token[0])
 
676
                        {
 
677
                                case '\0':
 
678
                                        continue;
 
679
                                case ',':
 
680
                                        out_table = TRUE; 
 
681
                                        continue;
 
682
                        }
 
683
                        if (out_table && !in_table) /* new table */
 
684
                        {
 
685
                                if (!dquote)
 
686
                                {
 
687
                                        if (token[0] == '(' ||
 
688
                                            token[0] == ')')
 
689
                                                continue;
 
690
                                }
 
691
                                if (!(stmt->ntab % TAB_INCR))
 
692
                                {
 
693
                                        ti = (TABLE_INFO **) realloc(ti, (stmt->ntab + TAB_INCR) * sizeof(TABLE_INFO *));
 
694
                                        if (!ti)
 
695
                                        {
 
696
                                                stmt->parse_status = STMT_PARSE_FATAL;
 
697
                                                return FALSE;
 
698
                                        }
 
699
                                        stmt->ti = ti;
 
700
                                }
 
701
                                ti[stmt->ntab] = (TABLE_INFO *) malloc(sizeof(TABLE_INFO));
 
702
                                if (ti[stmt->ntab] == NULL)
 
703
                                {
 
704
                                        stmt->parse_status = STMT_PARSE_FATAL;
 
705
                                        return FALSE;
 
706
                                }
 
707
 
 
708
                                ti[stmt->ntab]->schema[0] = '\0';
 
709
                                ti[stmt->ntab]->alias[0] = '\0';
 
710
                                ti[stmt->ntab]->updatable = 1;
 
711
 
 
712
                                strcpy(ti[stmt->ntab]->name, token);
 
713
                                lower_the_name(ti[stmt->ntab]->name, conn, dquote);
 
714
                                mylog("got table = '%s'\n", ti[stmt->ntab]->name);
 
715
 
 
716
                                if (delim == ',')
 
717
                                {
 
718
                                        out_table = TRUE;
 
719
                                        mylog("more than 1 tables\n");
 
720
                                }
 
721
                                else
 
722
                                {
 
723
                                        out_table = FALSE;
 
724
                                        in_table = TRUE;
 
725
                                }
 
726
                                stmt->ntab++;
 
727
                                in_dot = FALSE;
 
728
                                continue;
 
729
                        }
 
730
 
 
731
                        if (!dquote && stricmp(token, "JOIN") == 0)
 
732
                        {
 
733
                                in_table = FALSE;
 
734
                                out_table = TRUE;
 
735
                                continue;
 
736
                        }
 
737
                        if (in_table)
 
738
                        {
 
739
                                if (in_dot)
 
740
                                {
 
741
                                        strcpy(ti[stmt->ntab - 1]->schema, ti[stmt->ntab - 1]->name);
 
742
                                        strcpy(ti[stmt->ntab - 1]->name, token);
 
743
                                        lower_the_name(ti[stmt->ntab - 1]->name, conn, dquote);
 
744
                                        in_dot = FALSE;
 
745
                                        continue;
 
746
                                }
 
747
                                if (strcmp(token, ".") == 0)
 
748
                                {
 
749
                                        in_dot = TRUE;
 
750
                                        continue;
 
751
                                }
 
752
                                if (dquote || stricmp(token, "as"))
 
753
                                {
 
754
                                        if (stricmp(token, "LEFT") == 0 ||
 
755
                                            stricmp(token, "RIGHT") == 0 ||
 
756
                                            stricmp(token, "OUTER") == 0 ||
 
757
                                            stricmp(token, "FULL") == 0 ||
 
758
                                            stricmp(token, "ON") == 0)
 
759
                                        {
 
760
                                                if (!dquote)
 
761
                                                {
 
762
                                                        in_table = FALSE;
 
763
                                                        continue;
 
764
                                                }
 
765
                                        }
 
766
                                        strcpy(ti[stmt->ntab - 1]->alias, token);
 
767
                                        mylog("alias for table '%s' is '%s'\n", ti[stmt->ntab - 1]->name, ti[stmt->ntab - 1]->alias);
 
768
                                        in_table = FALSE;
 
769
                                        if (delim == ',')
 
770
                                        {
 
771
                                                out_table = TRUE;
 
772
                                                mylog("more than 1 tables\n");
 
773
                                        }
 
774
                                }
 
775
                        }
 
776
                } /* in_from */
 
777
        }
 
778
 
 
779
        /*
 
780
         * Resolve any possible field names with tables
 
781
         */
 
782
 
 
783
        parse = TRUE;
 
784
 
 
785
        /* Resolve field names with tables */
 
786
        for (i = 0; i < (int) irdflds->nfields; i++)
 
787
        {
 
788
                if (fi[i]->func || fi[i]->expr || fi[i]->numeric)
 
789
                {
 
790
                        fi[i]->ti = NULL;
 
791
                        fi[i]->type = -1;
 
792
                        parse = FALSE;
 
793
                        continue;
 
794
                }
 
795
                else if (fi[i]->quote)
 
796
                {                                               /* handle as text */
 
797
                        fi[i]->ti = NULL;
 
798
 
 
799
                        /*
 
800
                         * fi[i]->type = PG_TYPE_TEXT; fi[i]->column_size = 0; the
 
801
                         * following may be better
 
802
                         */
 
803
                        fi[i]->type = PG_TYPE_UNKNOWN;
 
804
                        if (fi[i]->column_size == 0)
 
805
                        {
 
806
                                fi[i]->type = PG_TYPE_VARCHAR;
 
807
                                fi[i]->column_size = 254;
 
808
                        }
 
809
                        fi[i]->length = fi[i]->column_size;
 
810
                        continue;
 
811
                }
 
812
                /* field name contains the schema name */
 
813
                else if (fi[i]->schema)
 
814
                {
 
815
                        int     matchidx = -1;
 
816
 
 
817
                        for (k = 0; k < stmt->ntab; k++)
 
818
                        {
 
819
                                if (!stricmp(ti[k]->name, fi[i]->dot))
 
820
                                {
 
821
                                        if (!stricmp(ti[k]->schema, fi[i]->schema))
 
822
                                        {
 
823
                                                fi[i]->ti = ti[k];
 
824
                                                break;
 
825
                                        }
 
826
                                        else if (!ti[k]->schema[0])
 
827
                                        {
 
828
                                                if (matchidx < 0)
 
829
                                                        matchidx = k;
 
830
                                                else
 
831
                                                {
 
832
                                                        stmt->parse_status = STMT_PARSE_FATAL;
 
833
                                                        SC_set_error(stmt, STMT_EXEC_ERROR, "duplicated Table name");
 
834
                                                        stmt->updatable = FALSE;
 
835
                                                        return FALSE;
 
836
                                                }
 
837
                                        }
 
838
                                }
 
839
                        }
 
840
                        if (matchidx >= 0)
 
841
                                fi[i]->ti = ti[matchidx];
 
842
                }
 
843
                /* it's a dot, resolve to table or alias */
 
844
                else if (fi[i]->dot[0])
 
845
                {
 
846
                        for (k = 0; k < stmt->ntab; k++)
 
847
                        {
 
848
                                if (!stricmp(ti[k]->alias, fi[i]->dot))
 
849
                                {
 
850
                                        fi[i]->ti = ti[k];
 
851
                                        break;
 
852
                                }
 
853
                                else if (!stricmp(ti[k]->name, fi[i]->dot))
 
854
                                {
 
855
                                        fi[i]->ti = ti[k];
 
856
                                        break;
 
857
                                }
 
858
                        }
 
859
                }
 
860
                else if (stmt->ntab == 1)
 
861
                        fi[i]->ti = ti[0];
 
862
        }
 
863
 
 
864
        mylog("--------------------------------------------\n");
 
865
        mylog("nfld=%d, ntab=%d\n", irdflds->nfields, stmt->ntab);
 
866
        if (0 == stmt->ntab)
 
867
        {
 
868
                stmt->parse_status = STMT_PARSE_FATAL;
 
869
                return  FALSE;
 
870
        }
 
871
 
 
872
        for (i = 0; i < (int) irdflds->nfields; i++)
 
873
        {
 
874
                mylog("Field %d:  expr=%d, func=%d, quote=%d, dquote=%d, numeric=%d, name='%s', alias='%s', dot='%s'\n", i, fi[i]->expr, fi[i]->func, fi[i]->quote, fi[i]->dquote, fi[i]->numeric, fi[i]->name, fi[i]->alias, fi[i]->dot);
 
875
                if (fi[i]->ti)
 
876
                        mylog("     ----> table_name='%s', table_alias='%s'\n", fi[i]->ti->name, fi[i]->ti->alias);
 
877
        }
 
878
 
 
879
        for (i = 0; i < stmt->ntab; i++)
 
880
                mylog("Table %d: name='%s', alias='%s'\n", i, ti[i]->name, ti[i]->alias);
 
881
 
 
882
 
 
883
        /*
 
884
         * Now save the SQLColumns Info for the parse tables
 
885
         */
 
886
 
 
887
        /* Call SQLColumns for each table and store the result */
 
888
        if (stmt->ntab > 1)
 
889
                updatable = FALSE;
 
890
        else if (stmt->from_pos < 0)
 
891
                updatable = FALSE;
 
892
        for (i = 0; i < stmt->ntab; i++)
 
893
        {
 
894
                /* See if already got it */
 
895
                char            found = FALSE;
 
896
 
 
897
                if (conn->schema_support)
 
898
                {
 
899
                        if (!ti[i]->schema[0])
 
900
                        {
 
901
                                const char *curschema = CC_get_current_schema(conn);
 
902
                                /*
 
903
                                 * Though current_schema() doesn't have
 
904
                                 * much sense in PostgreSQL, we first
 
905
                                 * check the current_schema() when no
 
906
                                 * explicit schema name was specified.
 
907
                                 */
 
908
                                for (k = 0; k < conn->ntables; k++)
 
909
                                {
 
910
                                        if (!stricmp(conn->col_info[k]->name, ti[i]->name) &&
 
911
                                            !stricmp(conn->col_info[k]->schema, curschema))
 
912
                                        {
 
913
                                                mylog("FOUND col_info table='%s' current schema='%s'\n", ti[i]->name, curschema);
 
914
                                                found = TRUE;
 
915
                                                strcpy(ti[i]->schema, curschema);
 
916
                                                break;
 
917
                                        }
 
918
                                }
 
919
                                if (!found)
 
920
                                {
 
921
                                        QResultClass    *res;
 
922
                                        BOOL            tblFound = FALSE;
 
923
 
 
924
                                        /*
 
925
                                         * We also have to check as follows.
 
926
                                         */
 
927
                                        sprintf(token, "select nspname from pg_namespace n, pg_class c"
 
928
                                                " where c.relnamespace=n.oid and c.oid='\"%s\"'::regclass", ti[i]->name);
 
929
                                        res = CC_send_query(conn, token, NULL, CLEAR_RESULT_ON_ABORT);
 
930
                                        if (res)
 
931
                                        {
 
932
                                                if (QR_get_num_total_tuples(res) == 1)
 
933
                                                {
 
934
                                                        tblFound = TRUE;
 
935
                                                        strcpy(ti[i]->schema, QR_get_value_backend_row(res, 0, 0));
 
936
                                                }
 
937
                                                QR_Destructor(res);
 
938
                                        }
 
939
                                        else
 
940
                                                CC_abort(conn);
 
941
                                        if (!tblFound)
 
942
                                        {
 
943
                                                stmt->parse_status = STMT_PARSE_FATAL;
 
944
                                                SC_set_error(stmt, STMT_EXEC_ERROR, "Table not found");
 
945
                                                stmt->updatable = FALSE;
 
946
                                                return FALSE;
 
947
                                        }
 
948
                                }
 
949
                        }
 
950
                        if (!found && ti[i]->schema[0])
 
951
                        {
 
952
                                for (k = 0; k < conn->ntables; k++)
 
953
                                {
 
954
                                        if (!stricmp(conn->col_info[k]->name, ti[i]->name) &&
 
955
                                            !stricmp(conn->col_info[k]->schema, ti[i]->schema))
 
956
                                        {
 
957
                                                mylog("FOUND col_info table='%s' schema='%s'\n", ti[i]->name, ti[i]->schema);
 
958
                                                found = TRUE;
 
959
                                                break;
 
960
                                        }
 
961
                                }
 
962
                        }
 
963
                }
 
964
                else
 
965
                {
 
966
                        for (k = 0; k < conn->ntables; k++)
 
967
                        {
 
968
                                if (!stricmp(conn->col_info[k]->name, ti[i]->name))
 
969
                                {
 
970
                                        mylog("FOUND col_info table='%s'\n", ti[i]->name);
 
971
                                        found = TRUE;
 
972
                                        break;
 
973
                                }
 
974
                        }
 
975
                }
 
976
 
 
977
                if (!found)
 
978
                {
 
979
                        mylog("PARSE: Getting PG_Columns for table[%d]='%s'\n", i, ti[i]->name);
 
980
 
 
981
                        result = PGAPI_AllocStmt(stmt->hdbc, &hcol_stmt);
 
982
                        if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
 
983
                        {
 
984
                                SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for columns.");
 
985
                                stmt->parse_status = STMT_PARSE_FATAL;
 
986
                                return FALSE;
 
987
                        }
 
988
 
 
989
                        col_stmt = (StatementClass *) hcol_stmt;
 
990
                        col_stmt->internal = TRUE;
 
991
 
 
992
                        result = PGAPI_Columns(hcol_stmt, "", 0, ti[i]->schema,
 
993
                                         SQL_NTS, ti[i]->name, SQL_NTS, "", 0, PODBC_NOT_SEARCH_PATTERN);
 
994
 
 
995
                        mylog("        Past PG_Columns\n");
 
996
                        if (result == SQL_SUCCESS)
 
997
                        {
 
998
                                mylog("      Success\n");
 
999
                                if (!(conn->ntables % COL_INCR))
 
1000
                                {
 
1001
                                        mylog("PARSE: Allocing col_info at ntables=%d\n", conn->ntables);
 
1002
 
 
1003
                                        conn->col_info = (COL_INFO **) realloc(conn->col_info, (conn->ntables + COL_INCR) * sizeof(COL_INFO *));
 
1004
                                        if (!conn->col_info)
 
1005
                                        {
 
1006
                                                stmt->parse_status = STMT_PARSE_FATAL;
 
1007
                                                return FALSE;
 
1008
                                        }
 
1009
                                }
 
1010
 
 
1011
                                mylog("PARSE: malloc at conn->col_info[%d]\n", conn->ntables);
 
1012
                                conn->col_info[conn->ntables] = (COL_INFO *) malloc(sizeof(COL_INFO));
 
1013
                                if (!conn->col_info[conn->ntables])
 
1014
                                {
 
1015
                                        stmt->parse_status = STMT_PARSE_FATAL;
 
1016
                                        return FALSE;
 
1017
                                }
 
1018
 
 
1019
                                /*
 
1020
                                 * Store the table name and the SQLColumns result
 
1021
                                 * structure
 
1022
                                 */
 
1023
                                if (ti[i]->schema[0])
 
1024
                                        conn->col_info[conn->ntables]->schema = strdup(ti[i]->schema);
 
1025
                                else
 
1026
                                        conn->col_info[conn->ntables]->schema = NULL;
 
1027
                                strcpy(conn->col_info[conn->ntables]->name, ti[i]->name);
 
1028
                                conn->col_info[conn->ntables]->result = SC_get_Curres(col_stmt);
 
1029
 
 
1030
                                /*
 
1031
                                 * The connection will now free the result structures, so
 
1032
                                 * make sure that the statement doesn't free it
 
1033
                                 */
 
1034
                                SC_set_Result(col_stmt, NULL);
 
1035
 
 
1036
                                conn->ntables++;
 
1037
 
 
1038
                                PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
1039
                                mylog("Created col_info table='%s', ntables=%d\n", ti[i]->name, conn->ntables);
 
1040
                        }
 
1041
                        else
 
1042
                        {
 
1043
                                PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
 
1044
                                break;
 
1045
                        }
 
1046
                }
 
1047
 
 
1048
                /* Associate a table from the statement with a SQLColumn info */
 
1049
                ti[i]->col_info = conn->col_info[k];
 
1050
                mylog("associate col_info: i=%d, k=%d\n", i, k);
 
1051
        }
 
1052
 
 
1053
        mylog("Done PG_Columns\n");
 
1054
 
 
1055
        /*
 
1056
         * Now resolve the fields to point to column info
 
1057
         */
 
1058
        if (updatable && 1 == stmt->ntab)
 
1059
                updatable = stmt->ti[0]->updatable;
 
1060
        for (i = 0; i < (int) irdflds->nfields;)
 
1061
        {
 
1062
                fi[i]->updatable = updatable;
 
1063
                /* Dont worry about functions or quotes */
 
1064
                if (fi[i]->func || fi[i]->quote || fi[i]->numeric)
 
1065
                {
 
1066
                        fi[i]->updatable = FALSE;
 
1067
                        i++;
 
1068
                        continue;
 
1069
                }
 
1070
 
 
1071
                /* Stars get expanded to all fields in the table */
 
1072
                else if (fi[i]->name[0] == '*')
 
1073
                {
 
1074
                        char            do_all_tables;
 
1075
                        int                     total_cols,
 
1076
                                                old_alloc,
 
1077
                                                new_size,
 
1078
                                                cols;
 
1079
                        int                     increased_cols;
 
1080
 
 
1081
                        mylog("expanding field %d\n", i);
 
1082
 
 
1083
                        total_cols = 0;
 
1084
 
 
1085
                        if (fi[i]->ti)          /* The star represents only the qualified
 
1086
                                                                 * table */
 
1087
                                total_cols = QR_get_num_backend_tuples(fi[i]->ti->col_info->result);
 
1088
 
 
1089
                        else
 
1090
                        {                                       /* The star represents all tables */
 
1091
 
 
1092
                                /* Calculate the total number of columns after expansion */
 
1093
                                for (k = 0; k < stmt->ntab; k++)
 
1094
                                        total_cols += QR_get_num_backend_tuples(ti[k]->col_info->result);
 
1095
                        }
 
1096
                        increased_cols = total_cols - 1;
 
1097
 
 
1098
                        /* Allocate some more field pointers if necessary */
 
1099
                        old_alloc = ((irdflds->nfields - 1) / FLD_INCR + 1) * FLD_INCR;
 
1100
                        new_size = irdflds->nfields + increased_cols;
 
1101
 
 
1102
                        mylog("k=%d, increased_cols=%d, old_alloc=%d, new_size=%d\n", k, increased_cols, old_alloc, new_size);
 
1103
 
 
1104
                        if (new_size > old_alloc)
 
1105
                        {
 
1106
                                int                     new_alloc = ((new_size / FLD_INCR) + 1) * FLD_INCR;
 
1107
 
 
1108
                                mylog("need more cols: new_alloc = %d\n", new_alloc);
 
1109
                                fi = (FIELD_INFO **) realloc(fi, new_alloc * sizeof(FIELD_INFO *));
 
1110
                                if (!fi)
 
1111
                                {
 
1112
                                        stmt->parse_status = STMT_PARSE_FATAL;
 
1113
                                        return FALSE;
 
1114
                                }
 
1115
                                irdflds->fi = fi;
 
1116
                        }
 
1117
 
 
1118
                        /*
 
1119
                         * copy any other fields (if there are any) up past the
 
1120
                         * expansion
 
1121
                         */
 
1122
                        for (j = irdflds->nfields - 1; j > i; j--)
 
1123
                        {
 
1124
                                mylog("copying field %d to %d\n", j, increased_cols + j);
 
1125
                                fi[increased_cols + j] = fi[j];
 
1126
                        }
 
1127
                        mylog("done copying fields\n");
 
1128
 
 
1129
                        /* Set the new number of fields */
 
1130
                        irdflds->nfields += increased_cols;
 
1131
                        mylog("irdflds->nfields now at %d\n", irdflds->nfields);
 
1132
 
 
1133
 
 
1134
                        /* copy the new field info */
 
1135
                        do_all_tables = (fi[i]->ti ? FALSE : TRUE);
 
1136
 
 
1137
                        for (k = 0; k < (do_all_tables ? stmt->ntab : 1); k++)
 
1138
                        {
 
1139
                                TABLE_INFO *the_ti = do_all_tables ? ti[k] : fi[i]->ti;
 
1140
 
 
1141
                                cols = QR_get_num_backend_tuples(the_ti->col_info->result);
 
1142
 
 
1143
                                for (n = 0; n < cols; n++)
 
1144
                                {
 
1145
                                        mylog("creating field info: n=%d\n", n);
 
1146
                                        /* skip malloc (already did it for the Star) */
 
1147
                                        if (k > 0 || n > 0)
 
1148
                                        {
 
1149
                                                mylog("allocating field info at %d\n", n + i);
 
1150
                                                fi[n + i] = (FIELD_INFO *) malloc(sizeof(FIELD_INFO));
 
1151
                                                if (fi[n + i] == NULL)
 
1152
                                                {
 
1153
                                                        stmt->parse_status = STMT_PARSE_FATAL;
 
1154
                                                        return FALSE;
 
1155
                                                }
 
1156
                                        }
 
1157
                                        /* Initialize the new space (or the * field) */
 
1158
                                        memset(fi[n + i], 0, sizeof(FIELD_INFO));
 
1159
                                        fi[n + i]->ti = the_ti;
 
1160
 
 
1161
                                        mylog("about to copy at %d\n", n + i);
 
1162
 
 
1163
                                        getColInfo(the_ti->col_info, fi[n + i], n);
 
1164
                                        fi[n + i]->updatable = updatable;
 
1165
 
 
1166
                                        mylog("done copying\n");
 
1167
                                }
 
1168
 
 
1169
                                i += cols;
 
1170
                                mylog("i now at %d\n", i);
 
1171
                        }
 
1172
                }
 
1173
 
 
1174
                /*
 
1175
                 * We either know which table the field was in because it was
 
1176
                 * qualified with a table name or alias -OR- there was only 1
 
1177
                 * table.
 
1178
                 */
 
1179
                else if (fi[i]->ti)
 
1180
                {
 
1181
                        if (!searchColInfo(fi[i]->ti->col_info, fi[i]))
 
1182
                        {
 
1183
                                parse = FALSE;
 
1184
                                fi[i]->updatable = FALSE;
 
1185
                        }
 
1186
                        i++;
 
1187
                }
 
1188
 
 
1189
                /* Don't know the table -- search all tables in "from" list */
 
1190
                else
 
1191
                {
 
1192
                        for (k = 0; k < stmt->ntab; k++)
 
1193
                        {
 
1194
                                if (searchColInfo(ti[k]->col_info, fi[i]))
 
1195
                                {
 
1196
                                        fi[i]->ti = ti[k];      /* now know the table */
 
1197
                                        break;
 
1198
                                }
 
1199
                        }
 
1200
                        if (k >= stmt->ntab)
 
1201
                        {
 
1202
                                parse = FALSE;
 
1203
                                fi[i]->updatable = FALSE;
 
1204
                        }
 
1205
                        i++;
 
1206
                }
 
1207
        }
 
1208
 
 
1209
        if (!parse)
 
1210
                stmt->parse_status = STMT_PARSE_INCOMPLETE;
 
1211
        else
 
1212
                stmt->parse_status = STMT_PARSE_COMPLETE;
 
1213
 
 
1214
        stmt->updatable = updatable;
 
1215
        mylog("done parse_statement: parse=%d, parse_status=%d\n", parse, stmt->parse_status);
 
1216
        return parse;
 
1217
}