4
* Description: This module contains routines related to parsing SQL
5
* statements. This can be useful for two reasons:
7
* 1. So the query does not actually have to be executed
8
* to return data about it
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.
20
* Comments: See "notice.txt" for copyright and license information.
23
/* Multibyte support Eiji Tokuya 2001-03-15 */
31
#include "statement.h"
32
#include "connection.h"
35
#include "pgapifunc.h"
37
#include "multibyte.h"
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);
47
Int4 FI_precision(const FIELD_INFO *fi)
53
return fi->column_size;
54
case PG_TYPE_DATETIME:
55
case PG_TYPE_TIMESTAMP_NO_TMZONE:
56
return fi->decimal_digits;
60
Int4 FI_scale(const FIELD_INFO *fi)
66
return fi->decimal_digits;
73
int ccsc, /* client encoding */
74
char *s, char *token, int smax, char *delim, char *quote, char *dquote, char *numeric)
87
/* skip leading delimiters */
88
while (isspace((unsigned char) s[i]) || s[i] == ',')
90
/* mylog("skipping '%c'\n", s[i]); */
107
encoded_str_constr(&encstr, ccsc, &s[i]);
108
/* get the next token */
109
while (s[i] != '\0' && out < smax)
111
encoded_nextchar(&encstr);
112
if (ENCODE_STATUS(encstr) != 0)
114
token[out++] = s[i++];
117
if (isspace((unsigned char) s[i]) || s[i] == ',')
119
/* Handle quoted stuff */
120
if (out == 0 && (s[i] == '\"' || s[i] == '\''))
134
i++; /* dont return the quote */
135
while (s[i] != '\0' && out != smax)
137
encoded_nextchar(&encstr);
138
if (ENCODE_STATUS(encstr) != 0)
140
token[out++] = s[i++];
143
if (s[i] == qc && !in_escape)
145
if (s[i] == '\\' && !in_escape)
159
/* Check for numeric literals */
160
if (out == 0 && isdigit((unsigned char) s[i]))
164
token[out++] = s[i++];
165
while (isalnum((unsigned char) s[i]) || s[i] == '.')
166
token[out++] = s[i++];
171
if (ispunct((unsigned char) s[i]) && s[i] != '_')
173
mylog("got ispunct: s[%d] = '%c'\n", i, s[i]);
177
token[out++] = s[i++];
190
/* mylog("done -- s[%d] = '%c'\n", i, s[i]); */
194
/* find the delimiter */
195
while (isspace((unsigned char) s[i]))
198
/* return the most priority delimiter */
204
else if (s[i] == '\0')
215
/* skip trailing blanks */
216
while (isspace((unsigned char) s[i]))
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);
243
getColInfo(COL_INFO *col_info, FIELD_INFO *fi, int k)
248
#if (ODBCVER >= 0x0300)
253
if (fi->name[0] == '\0')
254
strcpy(fi->name, QR_get_value_manual(col_info->result, k, 3));
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);
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));
269
searchColInfo(COL_INFO *col_info, FIELD_INFO *fi)
275
for (k = 0; k < QR_get_num_backend_tuples(col_info->result); k++)
277
col = QR_get_value_manual(col_info->result, k, 3);
279
cmp = strcmp(col, fi->name);
281
cmp = stricmp(col, fi->name);
285
strcpy(fi->name, col);
286
getColInfo(col_info, fi, k);
288
mylog("PARSE: searchColInfo: \n");
297
* lower the unquoted name
300
void lower_the_name(char *name, ConnectionClass *conn, BOOL dquote)
306
make_encoded_str(&encstr, conn, name);
308
/* lower case table name */
309
for (ptr = name; *ptr; ptr++)
311
encoded_nextchar(&encstr);
312
if (ENCODE_STATUS(encstr) == 0)
313
*ptr = tolower((unsigned char) *ptr);
319
parse_statement(StatementClass *stmt)
321
CSTR func = "parse_statement";
322
char token[256], stoken[256];
330
char in_select = FALSE,
337
char in_field = FALSE,
346
blevel = 0, old_blevel, subqlevel = 0;
350
ConnectionClass *conn = stmt->hdbc;
352
StatementClass *col_stmt;
353
IRDFields *irdflds = SC_get_IRD(stmt);
355
BOOL updatable = TRUE;
357
mylog("%s: entering...\n", func);
359
ptr = stmt->statement;
363
irdflds->nfields = 0;
366
stmt->where_pos = -1;
368
while (pptr = ptr, (ptr = getNextToken(conn->ccsc, pptr, token, sizeof(token), &delim, "e, &dquote, &numeric)) != NULL)
370
unquoted = !(quote || dquote);
372
mylog("unquoted=%d, quote=%d, dquote=%d, numeric=%d, delim='%c', token='%s', ptr='%s'\n", unquoted, quote, dquote, numeric, delim, token, ptr);
375
if (unquoted && blevel == 0)
379
if (!stricmp(token, "distinct"))
387
else if (!stricmp(token, "into"))
391
stmt->statement_type = STMT_TYPE_CREATE;
392
stmt->parse_status = STMT_PARSE_FATAL;
395
else if (!stricmp(token, "from"))
399
if (stmt->from_pos < 0 &&
400
(!strnicmp(pptr, "from", 4)))
403
stmt->from_pos = pptr - stmt->statement;
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")))
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"))
432
} /* unquoted && blevel == 0 */
433
/* check the change of blevel etc */
436
if (!stricmp(token, "select"))
447
mylog("SUBSELECT\n");
452
else if (token[0] == '(')
455
mylog("blevel++ = %d\n", blevel);
456
/* aggregate function ? */
457
if (stoken[0] && updatable && 0 == subqlevel)
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)
469
else if (token[0] == ')')
472
mylog("blevel-- = %d\n", blevel);
473
if (blevel < subqlevel)
476
if (blevel >= old_blevel && ',' != delim)
477
strcpy(stoken, token);
483
if (in_expr || in_func)
485
/* just eat the expression */
486
mylog("in_expr=%d or func=%d\n", in_expr, in_func);
492
mylog("**** Got comma in_expr/func\n");
497
else if (unquoted && !stricmp(token, "as"))
499
mylog("got AS in_expr\n");
507
} /* (in_expr || in_func) && in_select */
511
mylog("in distinct\n");
513
if (unquoted && !stricmp(token, "on"))
523
continue; /* just skip the unique on field */
525
mylog("done distinct\n");
534
if (!(irdflds->nfields % FLD_INCR))
536
mylog("reallocing at nfld=%d\n", irdflds->nfields);
537
fi = (FIELD_INFO **) realloc(fi, (irdflds->nfields + FLD_INCR) * sizeof(FIELD_INFO *));
540
stmt->parse_status = STMT_PARSE_FATAL;
546
fi[irdflds->nfields] = (FIELD_INFO *) malloc(sizeof(FIELD_INFO));
547
if (fi[irdflds->nfields] == NULL)
549
stmt->parse_status = STMT_PARSE_FATAL;
553
/* Initialize the field info */
554
memset(fi[irdflds->nfields], 0, sizeof(FIELD_INFO));
556
/* double quotes are for qualifiers */
558
fi[irdflds->nfields]->dquote = TRUE;
562
fi[irdflds->nfields]->quote = TRUE;
563
fi[irdflds->nfields]->column_size = strlen(token);
567
mylog("**** got numeric: nfld = %d\n", irdflds->nfields);
568
fi[irdflds->nfields]->numeric = TRUE;
570
else if (0 == old_blevel && blevel > 0)
572
mylog("got EXPRESSION\n");
573
fi[irdflds->nfields++]->expr = TRUE;
579
strcpy(fi[irdflds->nfields]->name, token);
580
fi[irdflds->nfields]->dot[0] = '\0';
582
mylog("got field='%s', dot='%s'\n", fi[irdflds->nfields]->name, fi[irdflds->nfields]->dot);
585
mylog("comma (1)\n");
593
* We are in a field now
597
int ifld = irdflds->nfields - 1;
599
if (fi[ifld]->dot[0])
601
fi[ifld]->schema = strdup(fi[ifld]->dot);
603
strcpy(fi[ifld]->dot, fi[ifld]->name);
604
strcpy(fi[ifld]->name, token);
608
mylog("in_dot: got comma\n");
618
strcpy(fi[irdflds->nfields]->alias, token);
619
mylog("alias for field '%s' is '%s'\n", fi[irdflds->nfields]->name, fi[irdflds->nfields]->alias);
631
if (0 == old_blevel && blevel > 0)
635
fi[irdflds->nfields - 1]->func = TRUE;
638
* name will have the function name -- maybe useful some
641
mylog("**** got function = '%s'\n", fi[irdflds->nfields - 1]->name);
653
if (!stricmp(token, "as"))
660
/* otherwise, it's probably an expression */
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 */
683
if (out_table && !in_table) /* new table */
687
if (token[0] == '(' ||
691
if (!(stmt->ntab % TAB_INCR))
693
ti = (TABLE_INFO **) realloc(ti, (stmt->ntab + TAB_INCR) * sizeof(TABLE_INFO *));
696
stmt->parse_status = STMT_PARSE_FATAL;
701
ti[stmt->ntab] = (TABLE_INFO *) malloc(sizeof(TABLE_INFO));
702
if (ti[stmt->ntab] == NULL)
704
stmt->parse_status = STMT_PARSE_FATAL;
708
ti[stmt->ntab]->schema[0] = '\0';
709
ti[stmt->ntab]->alias[0] = '\0';
710
ti[stmt->ntab]->updatable = 1;
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);
719
mylog("more than 1 tables\n");
731
if (!dquote && stricmp(token, "JOIN") == 0)
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);
747
if (strcmp(token, ".") == 0)
752
if (dquote || stricmp(token, "as"))
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)
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);
772
mylog("more than 1 tables\n");
780
* Resolve any possible field names with tables
785
/* Resolve field names with tables */
786
for (i = 0; i < (int) irdflds->nfields; i++)
788
if (fi[i]->func || fi[i]->expr || fi[i]->numeric)
795
else if (fi[i]->quote)
796
{ /* handle as text */
800
* fi[i]->type = PG_TYPE_TEXT; fi[i]->column_size = 0; the
801
* following may be better
803
fi[i]->type = PG_TYPE_UNKNOWN;
804
if (fi[i]->column_size == 0)
806
fi[i]->type = PG_TYPE_VARCHAR;
807
fi[i]->column_size = 254;
809
fi[i]->length = fi[i]->column_size;
812
/* field name contains the schema name */
813
else if (fi[i]->schema)
817
for (k = 0; k < stmt->ntab; k++)
819
if (!stricmp(ti[k]->name, fi[i]->dot))
821
if (!stricmp(ti[k]->schema, fi[i]->schema))
826
else if (!ti[k]->schema[0])
832
stmt->parse_status = STMT_PARSE_FATAL;
833
SC_set_error(stmt, STMT_EXEC_ERROR, "duplicated Table name");
834
stmt->updatable = FALSE;
841
fi[i]->ti = ti[matchidx];
843
/* it's a dot, resolve to table or alias */
844
else if (fi[i]->dot[0])
846
for (k = 0; k < stmt->ntab; k++)
848
if (!stricmp(ti[k]->alias, fi[i]->dot))
853
else if (!stricmp(ti[k]->name, fi[i]->dot))
860
else if (stmt->ntab == 1)
864
mylog("--------------------------------------------\n");
865
mylog("nfld=%d, ntab=%d\n", irdflds->nfields, stmt->ntab);
868
stmt->parse_status = STMT_PARSE_FATAL;
872
for (i = 0; i < (int) irdflds->nfields; i++)
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);
876
mylog(" ----> table_name='%s', table_alias='%s'\n", fi[i]->ti->name, fi[i]->ti->alias);
879
for (i = 0; i < stmt->ntab; i++)
880
mylog("Table %d: name='%s', alias='%s'\n", i, ti[i]->name, ti[i]->alias);
884
* Now save the SQLColumns Info for the parse tables
887
/* Call SQLColumns for each table and store the result */
890
else if (stmt->from_pos < 0)
892
for (i = 0; i < stmt->ntab; i++)
894
/* See if already got it */
897
if (conn->schema_support)
899
if (!ti[i]->schema[0])
901
const char *curschema = CC_get_current_schema(conn);
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.
908
for (k = 0; k < conn->ntables; k++)
910
if (!stricmp(conn->col_info[k]->name, ti[i]->name) &&
911
!stricmp(conn->col_info[k]->schema, curschema))
913
mylog("FOUND col_info table='%s' current schema='%s'\n", ti[i]->name, curschema);
915
strcpy(ti[i]->schema, curschema);
922
BOOL tblFound = FALSE;
925
* We also have to check as follows.
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);
932
if (QR_get_num_total_tuples(res) == 1)
935
strcpy(ti[i]->schema, QR_get_value_backend_row(res, 0, 0));
943
stmt->parse_status = STMT_PARSE_FATAL;
944
SC_set_error(stmt, STMT_EXEC_ERROR, "Table not found");
945
stmt->updatable = FALSE;
950
if (!found && ti[i]->schema[0])
952
for (k = 0; k < conn->ntables; k++)
954
if (!stricmp(conn->col_info[k]->name, ti[i]->name) &&
955
!stricmp(conn->col_info[k]->schema, ti[i]->schema))
957
mylog("FOUND col_info table='%s' schema='%s'\n", ti[i]->name, ti[i]->schema);
966
for (k = 0; k < conn->ntables; k++)
968
if (!stricmp(conn->col_info[k]->name, ti[i]->name))
970
mylog("FOUND col_info table='%s'\n", ti[i]->name);
979
mylog("PARSE: Getting PG_Columns for table[%d]='%s'\n", i, ti[i]->name);
981
result = PGAPI_AllocStmt(stmt->hdbc, &hcol_stmt);
982
if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
984
SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "PGAPI_AllocStmt failed in parse_statement for columns.");
985
stmt->parse_status = STMT_PARSE_FATAL;
989
col_stmt = (StatementClass *) hcol_stmt;
990
col_stmt->internal = TRUE;
992
result = PGAPI_Columns(hcol_stmt, "", 0, ti[i]->schema,
993
SQL_NTS, ti[i]->name, SQL_NTS, "", 0, PODBC_NOT_SEARCH_PATTERN);
995
mylog(" Past PG_Columns\n");
996
if (result == SQL_SUCCESS)
999
if (!(conn->ntables % COL_INCR))
1001
mylog("PARSE: Allocing col_info at ntables=%d\n", conn->ntables);
1003
conn->col_info = (COL_INFO **) realloc(conn->col_info, (conn->ntables + COL_INCR) * sizeof(COL_INFO *));
1004
if (!conn->col_info)
1006
stmt->parse_status = STMT_PARSE_FATAL;
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])
1015
stmt->parse_status = STMT_PARSE_FATAL;
1020
* Store the table name and the SQLColumns result
1023
if (ti[i]->schema[0])
1024
conn->col_info[conn->ntables]->schema = strdup(ti[i]->schema);
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);
1031
* The connection will now free the result structures, so
1032
* make sure that the statement doesn't free it
1034
SC_set_Result(col_stmt, NULL);
1038
PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
1039
mylog("Created col_info table='%s', ntables=%d\n", ti[i]->name, conn->ntables);
1043
PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
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);
1053
mylog("Done PG_Columns\n");
1056
* Now resolve the fields to point to column info
1058
if (updatable && 1 == stmt->ntab)
1059
updatable = stmt->ti[0]->updatable;
1060
for (i = 0; i < (int) irdflds->nfields;)
1062
fi[i]->updatable = updatable;
1063
/* Dont worry about functions or quotes */
1064
if (fi[i]->func || fi[i]->quote || fi[i]->numeric)
1066
fi[i]->updatable = FALSE;
1071
/* Stars get expanded to all fields in the table */
1072
else if (fi[i]->name[0] == '*')
1081
mylog("expanding field %d\n", i);
1085
if (fi[i]->ti) /* The star represents only the qualified
1087
total_cols = QR_get_num_backend_tuples(fi[i]->ti->col_info->result);
1090
{ /* The star represents all tables */
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);
1096
increased_cols = total_cols - 1;
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;
1102
mylog("k=%d, increased_cols=%d, old_alloc=%d, new_size=%d\n", k, increased_cols, old_alloc, new_size);
1104
if (new_size > old_alloc)
1106
int new_alloc = ((new_size / FLD_INCR) + 1) * FLD_INCR;
1108
mylog("need more cols: new_alloc = %d\n", new_alloc);
1109
fi = (FIELD_INFO **) realloc(fi, new_alloc * sizeof(FIELD_INFO *));
1112
stmt->parse_status = STMT_PARSE_FATAL;
1119
* copy any other fields (if there are any) up past the
1122
for (j = irdflds->nfields - 1; j > i; j--)
1124
mylog("copying field %d to %d\n", j, increased_cols + j);
1125
fi[increased_cols + j] = fi[j];
1127
mylog("done copying fields\n");
1129
/* Set the new number of fields */
1130
irdflds->nfields += increased_cols;
1131
mylog("irdflds->nfields now at %d\n", irdflds->nfields);
1134
/* copy the new field info */
1135
do_all_tables = (fi[i]->ti ? FALSE : TRUE);
1137
for (k = 0; k < (do_all_tables ? stmt->ntab : 1); k++)
1139
TABLE_INFO *the_ti = do_all_tables ? ti[k] : fi[i]->ti;
1141
cols = QR_get_num_backend_tuples(the_ti->col_info->result);
1143
for (n = 0; n < cols; n++)
1145
mylog("creating field info: n=%d\n", n);
1146
/* skip malloc (already did it for the Star) */
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)
1153
stmt->parse_status = STMT_PARSE_FATAL;
1157
/* Initialize the new space (or the * field) */
1158
memset(fi[n + i], 0, sizeof(FIELD_INFO));
1159
fi[n + i]->ti = the_ti;
1161
mylog("about to copy at %d\n", n + i);
1163
getColInfo(the_ti->col_info, fi[n + i], n);
1164
fi[n + i]->updatable = updatable;
1166
mylog("done copying\n");
1170
mylog("i now at %d\n", i);
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
1181
if (!searchColInfo(fi[i]->ti->col_info, fi[i]))
1184
fi[i]->updatable = FALSE;
1189
/* Don't know the table -- search all tables in "from" list */
1192
for (k = 0; k < stmt->ntab; k++)
1194
if (searchColInfo(ti[k]->col_info, fi[i]))
1196
fi[i]->ti = ti[k]; /* now know the table */
1200
if (k >= stmt->ntab)
1203
fi[i]->updatable = FALSE;
1210
stmt->parse_status = STMT_PARSE_INCOMPLETE;
1212
stmt->parse_status = STMT_PARSE_COMPLETE;
1214
stmt->updatable = updatable;
1215
mylog("done parse_statement: parse=%d, parse_status=%d\n", parse, stmt->parse_status);