2 * Description: This module contains routines related to parsing SQL
3 * statements. This can be useful for two reasons:
5 * 1. So the query does not actually have to be executed
6 * to return data about it
8 * 2. To be able to return information about precision,
9 * nullability, aliases, etc. in the functions
10 * SQLDescribeCol and SQLColAttributes. Currently,
11 * Postgres doesn't return any information about
12 * these things in a query.
14 /* Multibyte support Eiji Tokuya 2001-03-15 */
22 #include "statement.h"
23 #include "connection.h"
26 #include "pgapifunc.h"
29 #include "multibyte.h"
35 static char *getNextToken(int ccsc
, char escape_in_literal
, char *s
,
36 char *token
, int smax
, char *delim
,
37 char *quote
, char *dquote
, char *numeric
);
38 static void getColInfo(COL_INFO
* col_info
, FIELD_INFO
* fi
, int k
);
39 static char searchColInfo(COL_INFO
* col_info
, FIELD_INFO
* fi
);
41 Int4
FI_precision(const FIELD_INFO
* fi
)
51 return fi
->column_size
;
56 Int4
FI_scale(const FIELD_INFO
* fi
)
66 return fi
->decimal_digits
;
71 static char *getNextToken(int ccsc
, /* client encoding */
73 char *s
, char *token
, int smax
, char *delim
,
74 char *quote
, char *dquote
, char *numeric
)
78 char qc
, in_quote
, in_dollar_quote
, in_escape
;
79 const char *tag
, *tagend
;
81 char literal_quote
= LITERAL_QUOTE
, identifier_quote
=
82 IDENTIFIER_QUOTE
, dollar_quote
=
83 DOLLAR_QUOTE
, escape_in_literal
;
90 /* skip leading delimiters */
91 while (isspace((UCHAR
) s
[i
]) || s
[i
] == ',')
93 /* mylog("skipping '%c'\n", s[i]); */
110 encoded_str_constr(&encstr
, ccsc
, &s
[i
]);
111 /* get the next token */
112 while (s
[i
] != '\0' && out
< smax
)
114 encoded_nextchar(&encstr
);
115 if (ENCODE_STATUS(encstr
) != 0)
117 token
[out
++] = s
[i
++];
120 if (isspace((UCHAR
) s
[i
]) || s
[i
] == ',')
122 /* Handle quoted stuff */
123 in_quote
= in_dollar_quote
= FALSE
;
126 escape_in_literal
= '\0';
130 if (qc
== dollar_quote
)
132 in_quote
= in_dollar_quote
= TRUE
;
136 strchr(s
+ i
+ 1, dollar_quote
), NULL
!= tagend
)
137 taglen
= tagend
- s
- i
+ 1;
139 encoded_position_shift(&encstr
, taglen
- 1);
142 } else if (qc
== literal_quote
)
147 escape_in_literal
= escape_ch
;
148 if (!escape_in_literal
)
150 if (LITERAL_EXT
== s
[i
- 1])
151 escape_in_literal
= ESCAPE_IN_LITERAL
;
153 } else if (qc
== identifier_quote
)
162 i
++; /* dont return the quote */
164 while (s
[i
] != '\0' && out
!= smax
)
166 encoded_nextchar(&encstr
);
167 if (ENCODE_STATUS(encstr
) != 0)
169 token
[out
++] = s
[i
++];
176 if (!in_dollar_quote
)
178 if (strncmp(s
+ i
, tag
, taglen
) == 0)
181 encoded_position_shift(&encstr
, taglen
- 1);
185 } else if (literal_quote
== qc
186 && s
[i
] == escape_in_literal
)
200 /* Check for numeric literals */
201 if (out
== 0 && isdigit((UCHAR
) s
[i
]))
205 token
[out
++] = s
[i
++];
206 while (isalnum((UCHAR
) s
[i
]) || s
[i
] == '.')
207 token
[out
++] = s
[i
++];
212 if (ispunct((UCHAR
) s
[i
]) && s
[i
] != '_')
214 mylog("got ispunct: s[%d] = '%c'\n", i
, s
[i
]);
218 token
[out
++] = s
[i
++];
230 /* mylog("done -- s[%d] = '%c'\n", i, s[i]); */
234 /* find the delimiter */
235 while (isspace((UCHAR
) s
[i
]))
238 /* return the most priority delimiter */
243 } else if (s
[i
] == '\0')
253 /* skip trailing blanks */
254 while (isspace((UCHAR
) s
[i
]))
260 static void getColInfo(COL_INFO
* col_info
, FIELD_INFO
* fi
, int k
)
264 inolog("getColInfo non-manual result\n");
266 STR_TO_NAME(fi
->column_name
,
267 QR_get_value_backend_text(col_info
->result
, k
,
268 COLUMNS_COLUMN_NAME
));
271 (OID
) QR_get_value_backend_int(col_info
->result
, k
,
272 COLUMNS_FIELD_TYPE
, NULL
);
274 QR_get_value_backend_int(col_info
->result
, k
, COLUMNS_PRECISION
,
277 QR_get_value_backend_int(col_info
->result
, k
, COLUMNS_LENGTH
,
280 QR_get_value_backend_text(col_info
->result
, k
, COLUMNS_SCALE
),
282 fi
->decimal_digits
= atoi(str
);
284 fi
->decimal_digits
= -1;
286 QR_get_value_backend_int(col_info
->result
, k
, COLUMNS_NULLABLE
,
289 QR_get_value_backend_int(col_info
->result
, k
,
290 COLUMNS_DISPLAY_SIZE
, NULL
);
292 QR_get_value_backend_int(col_info
->result
, k
,
293 COLUMNS_AUTO_INCREMENT
, NULL
);
297 static char searchColInfo(COL_INFO
* col_info
, FIELD_INFO
* fi
)
302 inolog("searchColInfo num_cols=%d col=%s\n",
303 QR_get_num_cached_tuples(col_info
->result
),
304 PRINT_NAME(fi
->column_name
));
307 for (k
= 0; k
< QR_get_num_cached_tuples(col_info
->result
); k
++)
312 QR_get_value_backend_int(col_info
->result
, k
,
313 COLUMNS_PHYSICAL_NUMBER
, NULL
);
314 inolog("searchColInfo %d attnum=%d\n", k
, attnum
);
315 if (attnum
== fi
->attnum
)
317 getColInfo(col_info
, fi
, k
);
318 mylog("PARSE: searchColInfo by attnum=%d\n", attnum
);
321 } else if (NAME_IS_VALID(fi
->column_name
))
324 QR_get_value_backend_text(col_info
->result
, k
,
325 COLUMNS_COLUMN_NAME
);
326 inolog("searchColInfo %d col=%s\n", k
, col
);
328 cmp
= strcmp(col
, GET_NAME(fi
->column_name
));
330 cmp
= stricmp(col
, GET_NAME(fi
->column_name
));
334 STR_TO_NAME(fi
->column_name
, col
);
335 getColInfo(col_info
, fi
, k
);
337 mylog("PARSE: searchColInfo: \n");
347 * lower the unquoted name
350 void lower_the_name(char *name
, ConnectionClass
* conn
, BOOL dquote
)
356 make_encoded_str(&encstr
, conn
, name
);
358 /* lower case table name */
359 for (ptr
= name
; *ptr
; ptr
++)
361 encoded_nextchar(&encstr
);
362 if (ENCODE_STATUS(encstr
) == 0)
363 *ptr
= tolower((UCHAR
) * ptr
);
368 static BOOL
CheckHasOids(StatementClass
* stmt
)
371 BOOL hasoids
= TRUE
, foundKey
= FALSE
;
373 ConnectionClass
*conn
= SC_get_conn(stmt
);
376 if (0 != SC_checked_hasoids(stmt
))
378 if (!stmt
->ti
|| !stmt
->ti
[0])
382 "select relhasoids, c.oid from pg_class c, pg_namespace n where relname = '%s' and nspname = '%s' and c.relnamespace = n.oid",
383 SAFE_NAME(ti
->table_name
), SAFE_NAME(ti
->schema_name
));
385 CC_send_query(conn
, query
, NULL
,
386 ROLLBACK_ON_ERROR
| IGNORE_ABORT_ON_CONN
, NULL
);
387 if (QR_command_maybe_successful(res
))
389 stmt
->num_key_fields
= PG_NUM_NORMAL_KEYS
;
390 if (1 == QR_get_num_total_tuples(res
))
392 const char *value
= QR_get_value_backend_text(res
, 0, 0);
393 if (value
&& ('f' == *value
|| '0' == *value
))
396 TI_set_has_no_oids(ti
);
401 STR_TO_NAME(ti
->bestitem
, OID_NAME
);
402 strcpy(query
, "\"oid\" = %u");
403 /*strcpy(query, "\"oid\" = %%u"); */
404 STR_TO_NAME(ti
->bestqual
, query
);
406 TI_set_hasoids_checked(ti
);
408 (OID
) strtoul(QR_get_value_backend_text(res
, 0, 1),
416 "select a.attname, a.atttypid from pg_index i, pg_attribute a where indrelid=%u and indnatts=1 and indisunique and indexprs is null and indpred is null and i.indrelid = a.attrelid and a.attnum=i.indkey[0] and attnotnull and atttypid in (%d, %d)",
417 ti
->table_oid
, PG_TYPE_INT4
, PG_TYPE_OID
);
419 CC_send_query(conn
, query
, NULL
,
420 ROLLBACK_ON_ERROR
| IGNORE_ABORT_ON_CONN
,
422 if (QR_command_maybe_successful(res
)
423 && QR_get_num_total_tuples(res
) > 0)
426 STR_TO_NAME(ti
->bestitem
,
427 QR_get_value_backend_text(res
, 0, 0));
428 sprintf(query
, "\"%s\" = %%", SAFE_NAME(ti
->bestitem
));
430 (OID
) QR_get_value_backend_int(res
, 0, 1, NULL
))
434 STR_TO_NAME(ti
->bestqual
, query
);
437 /* stmt->updatable = FALSE; */
439 stmt
->num_key_fields
--;
444 SC_set_checked_hasoids(stmt
, foundKey
);
448 static BOOL
increaseNtab(StatementClass
* stmt
, const char *func
)
450 TABLE_INFO
**ti
= stmt
->ti
, *wti
;
452 if (!(stmt
->ntab
% TAB_INCR
))
454 ti
= (TABLE_INFO
**) realloc(ti
,
456 TAB_INCR
) * sizeof(TABLE_INFO
*));
459 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
460 "PGAPI_AllocStmt failed in parse_statement for TABLE_INFO.",
466 wti
= ti
[stmt
->ntab
] = (TABLE_INFO
*) malloc(sizeof(TABLE_INFO
));
469 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
470 "PGAPI_AllocStmt failed in parse_statement for TABLE_INFO(2).",
475 TI_Constructor(wti
, SC_get_conn(stmt
));
480 static void setNumFields(IRDFields
* irdflds
, size_t numFields
)
482 FIELD_INFO
**fi
= irdflds
->fi
;
483 size_t nfields
= irdflds
->nfields
;
485 if (numFields
< nfields
)
489 for (i
= (int) numFields
; i
< (int) nfields
; i
++)
495 irdflds
->nfields
= (UInt4
) numFields
;
498 void SC_initialize_cols_info(StatementClass
* stmt
, BOOL DCdestroy
,
501 IRDFields
*irdflds
= SC_get_IRDF(stmt
);
503 /* Free the parsed table information */
506 TI_Destructor(stmt
->ti
, stmt
->ntab
);
511 if (DCdestroy
) /* Free the parsed field information */
512 DC_Destructor((DescriptorClass
*) SC_get_IRD(stmt
));
514 setNumFields(irdflds
, 0);
517 stmt
->parse_status
= STMT_PARSE_NONE
;
518 stmt
->updatable
= FALSE
;
522 static BOOL
allocateFields(IRDFields
* irdflds
, size_t sizeRequested
)
524 FIELD_INFO
**fi
= irdflds
->fi
;
525 size_t alloc_size
, incr_size
;
527 if (sizeRequested
<= irdflds
->allocated
)
530 (0 != irdflds
->allocated
? irdflds
->allocated
: FLD_INCR
);
531 for (; alloc_size
< sizeRequested
; alloc_size
*= 2)
534 sizeof(FIELD_INFO
*) * (alloc_size
- irdflds
->allocated
);
536 fi
= (FIELD_INFO
**) realloc(fi
, alloc_size
* sizeof(FIELD_INFO
*));
540 irdflds
->allocated
= irdflds
->nfields
= 0;
543 memset(&fi
[irdflds
->allocated
], 0, incr_size
);
545 irdflds
->allocated
= (SQLSMALLINT
) alloc_size
;
550 static void xxxxx(FIELD_INFO
* fi
, QResultClass
* res
, int i
)
552 STR_TO_NAME(fi
->column_alias
, QR_get_fieldname(res
, i
));
553 fi
->basetype
= QR_get_field_type(res
, i
);
554 if (0 == fi
->columntype
)
555 fi
->columntype
= fi
->basetype
;
558 fi
->nullable
= FALSE
;
559 fi
->updatable
= FALSE
;
560 } else if (fi
->attnum
> 0)
561 fi
->nullable
= TRUE
; /* probably ? */
563 if (NAME_IS_NULL(fi
->column_name
))
568 STR_TO_NAME(fi
->column_name
, "ctid");
571 STR_TO_NAME(fi
->column_name
, OID_NAME
);
574 STR_TO_NAME(fi
->column_name
, "xmin");
581 * SQLColAttribute tries to set the FIELD_INFO (using protocol 3).
583 static BOOL
ColAttSet(StatementClass
* stmt
, TABLE_INFO
* rti
)
585 QResultClass
*res
= SC_get_Curres(stmt
);
586 IRDFields
*irdflds
= SC_get_IRDF(stmt
);
587 COL_INFO
*col_info
= NULL
;
588 FIELD_INFO
**fi
, *wfi
;
592 BOOL fi_reuse
, updatable
;
594 mylog("ColAttSet in\n");
597 if (reloid
= rti
->table_oid
, 0 == reloid
)
599 if (0 != (rti
->flags
& TI_COLATTRIBUTE
))
601 col_info
= rti
->col_info
;
603 if (!QR_command_maybe_successful(res
))
605 if (num_fields
= QR_NumPublicResultCols(res
), num_fields
<= 0)
608 if (num_fields
> (int) irdflds
->allocated
)
610 if (!allocateFields(irdflds
, num_fields
))
614 setNumFields(irdflds
, num_fields
);
615 updatable
= rti
? TI_is_updatable(rti
) : FALSE
;
616 mylog("updatable=%d tab=%d fields=%d", updatable
, stmt
->ntab
,
622 else if (SC_has_join(stmt
))
628 for (i
= 0; i
< num_fields
; i
++)
630 greloid
= QR_get_relid(res
, i
);
631 if (0 != greloid
&& reloid
!= greloid
)
639 mylog("->%d\n", updatable
);
640 for (i
= 0; i
< num_fields
; i
++)
642 if (reloid
== (OID
) QR_get_relid(res
, i
))
644 if (wfi
= fi
[i
], NULL
== wfi
)
646 wfi
= (FIELD_INFO
*) malloc(sizeof(FIELD_INFO
));
649 } else if (FI_is_applicable(wfi
))
653 FI_Constructor(wfi
, fi_reuse
);
654 attid
= (Int2
) QR_get_attid(res
, i
);
656 if (searchColInfo(col_info
, wfi
))
658 STR_TO_NAME(wfi
->column_alias
,
659 QR_get_fieldname(res
, i
));
660 wfi
->basetype
= QR_get_field_type(res
, i
);
661 wfi
->updatable
= updatable
;
667 wfi
->flag
|= FIELD_COL_ATTRIBUTE
;
671 rti
->flags
|= TI_COLATTRIBUTE
;
676 getCOLIfromTable(ConnectionClass
* conn
, pgNAME
* schema_name
,
677 pgNAME table_name
, COL_INFO
** coli
)
683 if (NAME_IS_NULL(table_name
))
685 if (conn
->schema_support
)
687 if (NAME_IS_NULL(*schema_name
))
689 const char *curschema
= CC_get_current_schema(conn
);
691 * Though current_schema() doesn't have
692 * much sense in PostgreSQL, we first
693 * check the current_schema() when no
694 * explicit schema name was specified.
696 for (colidx
= 0; colidx
< conn
->ntables
; colidx
++)
699 (conn
->col_info
[colidx
]->table_name
, table_name
)
702 (conn
->col_info
[colidx
]->schema_name
),
706 ("FOUND col_info table='%s' current schema='%s'\n",
707 PRINT_NAME(table_name
), curschema
);
709 STR_TO_NAME(*schema_name
, curschema
);
717 BOOL tblFound
= FALSE
;
720 * We also have to check as follows.
723 "select nspname from pg_namespace n, pg_class c"
724 " where c.relnamespace=n.oid and c.oid='\"%s\"'::regclass",
725 SAFE_NAME(table_name
));
727 CC_send_query(conn
, token
, NULL
,
729 IGNORE_ABORT_ON_CONN
, NULL
);
730 if (QR_command_maybe_successful(res
))
732 if (QR_get_num_total_tuples(res
) == 1)
735 STR_TO_NAME(*schema_name
,
736 QR_get_value_backend_text(res
, 0,
745 if (!found
&& NAME_IS_VALID(*schema_name
))
747 for (colidx
= 0; colidx
< conn
->ntables
; colidx
++)
750 (conn
->col_info
[colidx
]->table_name
, table_name
)
751 && !NAMEICMP(conn
->col_info
[colidx
]->schema_name
,
754 mylog("FOUND col_info table='%s' schema='%s'\n",
755 PRINT_NAME(table_name
),
756 PRINT_NAME(*schema_name
));
764 for (colidx
= 0; colidx
< conn
->ntables
; colidx
++)
767 (conn
->col_info
[colidx
]->table_name
, table_name
))
769 mylog("FOUND col_info table='%s'\n", table_name
);
775 *coli
= found
? conn
->col_info
[colidx
] : NULL
;
776 return TRUE
; /* success */
779 BOOL
getCOLIfromTI(const char *func
, ConnectionClass
* conn
,
780 StatementClass
* stmt
, const OID reloid
,
783 BOOL colatt
= FALSE
, found
= FALSE
;
784 OID greloid
= reloid
;
785 TABLE_INFO
*wti
= *pti
;
787 HSTMT hcol_stmt
= NULL
;
790 inolog("getCOLIfromTI reloid=%u ti=%p\n", reloid
, wti
);
792 conn
= SC_get_conn(stmt
);
793 if (!wti
) /* SQLColAttribute case */
799 for (i
= 0; i
< stmt
->ntab
; i
++)
801 if (stmt
->ti
[i
]->table_oid
== greloid
)
809 inolog("before increaseNtab\n");
810 if (!increaseNtab(stmt
, func
))
812 wti
= stmt
->ti
[stmt
->ntab
- 1];
813 wti
->table_oid
= greloid
;
817 inolog("fi=%p greloid=%d col_info=%p\n", wti
, greloid
,
820 greloid
= wti
->table_oid
;
821 if (NULL
!= wti
->col_info
)
830 for (colidx
= 0; colidx
< conn
->ntables
; colidx
++)
832 if (conn
->col_info
[colidx
]->table_oid
== greloid
)
834 mylog("FOUND col_info table=%ul\n", greloid
);
836 wti
->col_info
= conn
->col_info
[colidx
];
842 if (!getCOLIfromTable
843 (conn
, &wti
->schema_name
, wti
->table_name
, &coli
))
847 SC_set_parse_status(stmt
, STMT_PARSE_FATAL
);
848 SC_set_error(stmt
, STMT_EXEC_ERROR
, "Table not found",
850 stmt
->updatable
= FALSE
;
853 } else if (NULL
!= coli
)
856 wti
->col_info
= coli
;
861 else if (0 != greloid
|| NAME_IS_VALID(wti
->table_name
))
864 StatementClass
*col_stmt
;
866 mylog("PARSE: Getting PG_Columns for table='%s'\n",
869 result
= PGAPI_AllocStmt(conn
, &hcol_stmt
);
870 if ((result
!= SQL_SUCCESS
)
871 && (result
!= SQL_SUCCESS_WITH_INFO
))
874 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
875 "PGAPI_AllocStmt failed in parse_statement for columns.",
880 col_stmt
= (StatementClass
*) hcol_stmt
;
881 col_stmt
->internal
= TRUE
;
884 result
= PGAPI_Columns(hcol_stmt
, NULL
, 0,
885 NULL
, 0, NULL
, 0, NULL
, 0,
886 PODBC_SEARCH_BY_IDS
, greloid
, 0);
889 PGAPI_Columns(hcol_stmt
, NULL
, 0,
890 (const UCHAR
*)SAFE_NAME(wti
->schema_name
),
892 (const UCHAR
*)SAFE_NAME(wti
->table_name
),
894 PODBC_NOT_SEARCH_PATTERN
, 0, 0);
896 mylog(" Past PG_Columns\n");
897 res
= SC_get_Curres(col_stmt
);
898 if ((SQL_SUCCESS
== result
|| SQL_SUCCESS_WITH_INFO
== result
)
899 && res
&& QR_get_num_cached_tuples(res
) > 0)
904 if (conn
->ntables
>= conn
->coli_allocated
)
908 new_alloc
= conn
->coli_allocated
* 2;
909 if (new_alloc
<= conn
->ntables
)
910 new_alloc
= COLI_INCR
;
911 mylog("PARSE: Allocating col_info at ntables=%d\n",
915 (COL_INFO
**) realloc(conn
->col_info
,
921 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
922 "PGAPI_AllocStmt failed in parse_statement for col_info.",
926 conn
->coli_allocated
= new_alloc
;
929 mylog("PARSE: malloc at conn->col_info[%d]\n",
931 coli
= conn
->col_info
[conn
->ntables
] =
932 (COL_INFO
*) malloc(sizeof(COL_INFO
));
936 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
937 "PGAPI_AllocStmt failed in parse_statement for col_info(2).",
941 col_info_initialize(coli
);
944 if (res
&& QR_get_num_cached_tuples(res
) > 0)
949 strtoul(QR_get_value_backend_text
950 (res
, 0, COLUMNS_TABLE_OID
), NULL
, 10);
952 wti
->table_oid
= greloid
;
953 if (NAME_IS_NULL(wti
->schema_name
))
954 STR_TO_NAME(wti
->schema_name
,
955 QR_get_value_backend_text(res
, 0,
956 COLUMNS_SCHEMA_NAME
));
957 if (NAME_IS_NULL(wti
->table_name
))
958 STR_TO_NAME(wti
->table_name
,
959 QR_get_value_backend_text(res
, 0,
960 COLUMNS_TABLE_NAME
));
962 inolog("#2 %p->table_name=%s(%u)\n", wti
,
963 PRINT_NAME(wti
->table_name
), wti
->table_oid
);
965 * Store the table name and the SQLColumns result
968 if (NAME_IS_VALID(wti
->schema_name
))
970 NAME_TO_NAME(coli
->schema_name
, wti
->schema_name
);
972 NULL_THE_NAME(coli
->schema_name
);
973 NAME_TO_NAME(coli
->table_name
, wti
->table_name
);
974 coli
->table_oid
= wti
->table_oid
;
977 * The connection will now free the result structures, so
978 * make sure that the statement doesn't free it
980 SC_init_Result(col_stmt
);
984 if (res
&& QR_get_num_cached_tuples(res
) > 0)
985 inolog("oid item == %s\n",
986 QR_get_value_backend_text(res
, 0, 3));
988 mylog("Created col_info table='%s', ntables=%d\n",
989 PRINT_NAME(wti
->table_name
), conn
->ntables
);
990 /* Associate a table from the statement with a SQLColumn info */
992 wti
->col_info
= coli
;
997 PGAPI_FreeStmt(hcol_stmt
, SQL_DROP
);
1000 QResultClass
*res
= wti
->col_info
->result
;
1002 if (res
&& QR_get_num_cached_tuples(res
) > 0)
1007 strtoul(QR_get_value_backend_text
1008 (res
, 0, COLUMNS_TABLE_OID
), NULL
, 10);
1009 if (!wti
->table_oid
)
1010 wti
->table_oid
= greloid
;
1011 if (NAME_IS_NULL(wti
->schema_name
))
1012 STR_TO_NAME(wti
->schema_name
,
1013 QR_get_value_backend_text(res
, 0,
1014 COLUMNS_SCHEMA_NAME
));
1015 if (NAME_IS_NULL(wti
->table_name
))
1016 STR_TO_NAME(wti
->table_name
,
1017 QR_get_value_backend_text(res
, 0,
1018 COLUMNS_TABLE_NAME
));
1020 inolog("#1 %p->table_name=%s(%u)\n", wti
,
1021 PRINT_NAME(wti
->table_name
), wti
->table_oid
);
1022 if (colatt
/* SQLColAttribute case */
1023 && 0 == (wti
->flags
& TI_COLATTRIBUTE
))
1026 ColAttSet(stmt
, wti
);
1028 } else if (!colatt
&& stmt
)
1029 SC_set_parse_status(stmt
, STMT_PARSE_FATAL
);
1030 inolog("getCOLIfromTI returns %d\n", found
);
1034 char parse_statement(StatementClass
* stmt
, BOOL check_hasoids
)
1036 CSTR func
= "parse_statement";
1037 char token
[256], stoken
[256];
1038 char delim
, quote
, dquote
, numeric
, unquoted
;
1039 char *ptr
, *pptr
= NULL
;
1040 char in_select
= FALSE
,
1041 in_distinct
= FALSE
,
1044 in_where
= FALSE
, in_table
= FALSE
, out_table
= TRUE
;
1045 char in_field
= FALSE
,
1046 in_expr
= FALSE
, in_func
= FALSE
, in_dot
= FALSE
, in_as
= FALSE
;
1051 blevel
= 0, old_blevel
, subqlevel
= 0, allocated_size
, new_size
;
1052 FIELD_INFO
**fi
, *wfi
;
1053 TABLE_INFO
**ti
, *wti
;
1054 char parse
, maybe_join
= 0;
1055 ConnectionClass
*conn
= SC_get_conn(stmt
);
1056 IRDFields
*irdflds
= SC_get_IRDF(stmt
);
1057 BOOL updatable
= TRUE
;
1059 mylog("%s: entering...\n", func
);
1061 if (SC_parsed_status(stmt
) != STMT_PARSE_NONE
)
1067 stmt
->updatable
= FALSE
;
1068 ptr
= stmt
->statement
;
1072 allocated_size
= irdflds
->allocated
;
1073 SC_initialize_cols_info(stmt
, FALSE
, TRUE
);
1074 stmt
->from_pos
= -1;
1075 stmt
->where_pos
= -1;
1076 #define return DONT_CALL_RETURN_FROM_HERE???
1080 getNextToken(conn
->ccsc
, CC_get_escape(conn
), pptr
,
1081 token
, sizeof(token
), &delim
, "e
,
1082 &dquote
, &numeric
)) != NULL
)
1084 unquoted
= !(quote
|| dquote
);
1087 ("unquoted=%d, quote=%d, dquote=%d, numeric=%d, delim='%c', token='%s', ptr='%s'\n",
1088 unquoted
, quote
, dquote
, numeric
, delim
, token
, ptr
);
1090 old_blevel
= blevel
;
1091 if (unquoted
&& blevel
== 0)
1095 if (!stricmp(token
, "distinct"))
1100 mylog("DISTINCT\n");
1102 } else if (!stricmp(token
, "into"))
1106 stmt
->statement_type
= STMT_TYPE_CREATE
;
1107 SC_set_parse_status(stmt
, STMT_PARSE_FATAL
);
1109 } else if (!stricmp(token
, "from"))
1113 if (stmt
->from_pos
< 0 &&
1114 (!strnicmp(pptr
, "from", 4)))
1117 stmt
->from_pos
= pptr
- stmt
->statement
;
1123 } /* in_select && unquoted && blevel == 0 */
1124 else if ((!stricmp(token
, "where") ||
1125 !stricmp(token
, "union") ||
1126 !stricmp(token
, "intersect") ||
1127 !stricmp(token
, "except") ||
1128 !stricmp(token
, "order") ||
1129 !stricmp(token
, "group") ||
1130 !stricmp(token
, "having")))
1135 if (stmt
->where_pos
< 0)
1136 stmt
->where_pos
= pptr
- stmt
->statement
;
1137 mylog("%s...\n", token
);
1138 if (stricmp(token
, "where") && stricmp(token
, "order"))
1146 /* unquoted && blevel == 0 */
1147 /* check the change of blevel etc */
1150 if (!stricmp(token
, "select"))
1160 mylog("SUBSELECT\n");
1164 } else if (token
[0] == '(')
1167 mylog("blevel++ = %d\n", blevel
);
1168 /* aggregate function ? */
1169 if (stoken
[0] && updatable
&& 0 == subqlevel
)
1171 if (stricmp(stoken
, "count") == 0 ||
1172 stricmp(stoken
, "sum") == 0 ||
1173 stricmp(stoken
, "avg") == 0 ||
1174 stricmp(stoken
, "max") == 0 ||
1175 stricmp(stoken
, "min") == 0 ||
1176 stricmp(stoken
, "variance") == 0 ||
1177 stricmp(stoken
, "stddev") == 0)
1180 } else if (token
[0] == ')')
1183 mylog("blevel-- = %d\n", blevel
);
1184 if (blevel
< subqlevel
)
1187 if (blevel
>= old_blevel
&& ',' != delim
)
1188 strcpy(stoken
, token
);
1194 if (in_expr
|| in_func
)
1196 /* just eat the expression */
1197 mylog("in_expr=%d or func=%d\n", in_expr
, in_func
);
1203 mylog("**** Got comma in_expr/func\n");
1207 } else if (unquoted
&& !stricmp(token
, "as"))
1209 mylog("got AS in_expr\n");
1218 /* (in_expr || in_func) && in_select */
1221 mylog("in distinct\n");
1223 if (unquoted
&& !stricmp(token
, "on"))
1231 in_distinct
= FALSE
;
1233 continue; /* just skip the unique on field */
1235 mylog("done distinct\n");
1236 in_distinct
= FALSE
;
1241 BOOL fi_reuse
= FALSE
;
1246 /* if (!(irdflds->nfields % FLD_INCR)) */
1247 if (irdflds
->nfields
>= allocated_size
)
1249 mylog("reallocing at nfld=%d\n", irdflds
->nfields
);
1250 new_size
= irdflds
->nfields
+ 1;
1251 if (!allocateFields(irdflds
, new_size
))
1253 SC_set_parse_status(stmt
, STMT_PARSE_FATAL
);
1254 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
1255 "PGAPI_AllocStmt failed in parse_statement for FIELD_INFO.",
1260 allocated_size
= irdflds
->allocated
;
1263 wfi
= fi
[irdflds
->nfields
];
1267 wfi
= fi
[irdflds
->nfields
] =
1268 (FIELD_INFO
*) malloc(sizeof(FIELD_INFO
));
1271 SC_set_parse_status(stmt
, STMT_PARSE_FATAL
);
1272 SC_set_error(stmt
, STMT_NO_MEMORY_ERROR
,
1273 "PGAPI_AllocStmt failed in parse_statement for FIELD_INFO(2).",
1278 /* Initialize the field info */
1279 FI_Constructor(wfi
, fi_reuse
);
1280 wfi
->flag
= FIELD_PARSING
;
1282 /* double quotes are for qualifiers */
1289 wfi
->column_size
= (int) strlen(token
);
1292 mylog("**** got numeric: nfld = %d\n",
1294 wfi
->numeric
= TRUE
;
1295 } else if (0 == old_blevel
&& blevel
> 0)
1297 mylog("got EXPRESSION\n");
1303 STR_TO_NAME(wfi
->column_name
, token
);
1304 NULL_THE_NAME(wfi
->before_dot
);
1306 mylog("got field='%s', dot='%s'\n",
1307 PRINT_NAME(wfi
->column_name
),
1308 PRINT_NAME(wfi
->before_dot
));
1311 mylog("comma (1)\n");
1320 * We are in a field now
1322 wfi
= fi
[irdflds
->nfields
- 1];
1325 if (NAME_IS_VALID(wfi
->before_dot
))
1327 MOVE_NAME(wfi
->schema_name
, wfi
->before_dot
);
1329 MOVE_NAME(wfi
->before_dot
, wfi
->column_name
);
1330 STR_TO_NAME(wfi
->column_name
, token
);
1334 mylog("in_dot: got comma\n");
1343 STR_TO_NAME(wfi
->column_alias
, token
);
1344 mylog("alias for field '%s' is '%s'\n",
1345 PRINT_NAME(wfi
->column_name
),
1346 PRINT_NAME(wfi
->column_alias
));
1351 mylog("comma(2)\n");
1356 if (0 == old_blevel
&& blevel
> 0)
1363 * name will have the function name -- maybe useful some
1366 mylog("**** got function = '%s'\n",
1367 PRINT_NAME(wfi
->column_name
));
1371 if (token
[0] == '.')
1379 if (!stricmp(token
, "as"))
1386 /* otherwise, it's probably an expression */
1389 NULL_THE_NAME(wfi
->column_name
);
1390 wfi
->column_size
= 0;
1391 mylog("*** setting expression\n");
1394 if (in_from
|| in_where
)
1396 if (token
[0] == ';') /* end of the first command */
1398 in_select
= in_from
= in_where
= in_table
= FALSE
;
1412 if (out_table
&& !in_table
) /* new table */
1418 if (token
[0] == '(' || token
[0] == ')')
1422 if (!increaseNtab(stmt
, func
))
1424 SC_set_parse_status(stmt
, STMT_PARSE_FATAL
);
1429 wti
= ti
[stmt
->ntab
- 1];
1430 if (dquote
|| stricmp(token
, "select"))
1432 STR_TO_NAME(wti
->table_name
, token
);
1433 lower_the_name(GET_NAME(wti
->table_name
), conn
,
1437 NULL_THE_NAME(wti
->table_name
);
1438 TI_no_updatable(wti
);
1440 mylog("got table = '%s'\n",
1441 PRINT_NAME(wti
->table_name
));
1443 if (0 == blevel
&& delim
== ',')
1446 mylog("more than 1 tables\n");
1456 /* out_table is FALSE here */
1457 if (!dquote
&& !in_dot
)
1459 if (')' == token
[0])
1461 if (stricmp(token
, "LEFT") == 0 ||
1462 stricmp(token
, "RIGHT") == 0 ||
1463 stricmp(token
, "OUTER") == 0 ||
1464 stricmp(token
, "FULL") == 0)
1469 } else if (stricmp(token
, "INNER") == 0 ||
1470 stricmp(token
, "CROSS") == 0)
1475 } else if (stricmp(token
, "JOIN") == 0)
1482 SC_set_outer_join(stmt
);
1485 SC_set_inner_join(stmt
);
1495 wti
= ti
[stmt
->ntab
- 1];
1498 MOVE_NAME(wti
->schema_name
, wti
->table_name
);
1499 STR_TO_NAME(wti
->table_name
, token
);
1500 lower_the_name(GET_NAME(wti
->table_name
), conn
,
1505 if (strcmp(token
, ".") == 0)
1510 if (dquote
|| stricmp(token
, "as"))
1514 if (stricmp(token
, "ON") == 0)
1520 STR_TO_NAME(wti
->table_alias
, token
);
1521 mylog("alias for table '%s' is '%s'\n",
1522 PRINT_NAME(wti
->table_name
),
1523 PRINT_NAME(wti
->table_alias
));
1528 mylog("more than 1 tables\n");
1536 * Resolve any possible field names with tables
1541 /* Resolve field names with tables */
1542 for (i
= 0; i
< (int) irdflds
->nfields
; i
++)
1545 if (wfi
->func
|| wfi
->expr
|| wfi
->numeric
)
1548 wfi
->columntype
= wfi
->basetype
= (OID
) 0;
1551 } else if (wfi
->quote
)
1552 { /* handle as text */
1556 * wfi->type = PG_TYPE_TEXT; wfi->column_size = 0; the
1557 * following may be better
1559 wfi
->basetype
= PG_TYPE_UNKNOWN
;
1560 if (wfi
->column_size
== 0)
1562 wfi
->basetype
= PG_TYPE_VARCHAR
;
1563 wfi
->column_size
= 254;
1565 wfi
->length
= wfi
->column_size
;
1568 /* field name contains the schema name */
1569 else if (NAME_IS_VALID(wfi
->schema_name
))
1573 for (k
= 0; k
< stmt
->ntab
; k
++)
1576 if (!NAMEICMP(wti
->table_name
, wfi
->before_dot
))
1578 if (!NAMEICMP(wti
->schema_name
, wfi
->schema_name
))
1582 } else if (NAME_IS_NULL(wti
->schema_name
))
1588 SC_set_parse_status(stmt
, STMT_PARSE_FATAL
);
1589 SC_set_error(stmt
, STMT_EXEC_ERROR
,
1590 "duplicated Table name", func
);
1591 stmt
->updatable
= FALSE
;
1598 wfi
->ti
= ti
[matchidx
];
1600 /* it's a dot, resolve to table or alias */
1601 else if (NAME_IS_VALID(wfi
->before_dot
))
1603 for (k
= 0; k
< stmt
->ntab
; k
++)
1606 if (!NAMEICMP(wti
->table_alias
, wfi
->before_dot
))
1610 } else if (!NAMEICMP(wti
->table_name
, wfi
->before_dot
))
1616 } else if (stmt
->ntab
== 1)
1620 mylog("--------------------------------------------\n");
1621 mylog("nfld=%d, ntab=%d\n", irdflds
->nfields
, stmt
->ntab
);
1622 if (0 == stmt
->ntab
)
1624 SC_set_parse_status(stmt
, STMT_PARSE_FATAL
);
1628 for (i
= 0; i
< (int) irdflds
->nfields
; i
++)
1632 ("Field %d: expr=%d, func=%d, quote=%d, dquote=%d, numeric=%d, name='%s', alias='%s', dot='%s'\n",
1633 i
, wfi
->expr
, wfi
->func
, wfi
->quote
, wfi
->dquote
,
1634 wfi
->numeric
, PRINT_NAME(wfi
->column_name
),
1635 PRINT_NAME(wfi
->column_alias
),
1636 PRINT_NAME(wfi
->before_dot
));
1638 mylog(" ----> table_name='%s', table_alias='%s'\n",
1639 PRINT_NAME(wfi
->ti
->table_name
),
1640 PRINT_NAME(wfi
->ti
->table_alias
));
1643 for (i
= 0; i
< stmt
->ntab
; i
++)
1646 mylog("Table %d: name='%s', alias='%s'\n", i
,
1647 PRINT_NAME(wti
->table_name
),
1648 PRINT_NAME(wti
->table_alias
));
1652 * Now save the SQLColumns Info for the parse tables
1655 /* Call SQLColumns for each table and store the result */
1658 else if (stmt
->from_pos
< 0)
1660 for (i
= 0; i
< stmt
->ntab
; i
++)
1662 /* See if already got it */
1665 if (!getCOLIfromTI(func
, NULL
, stmt
, 0, &wti
))
1668 if (STMT_PARSE_FATAL
== SC_parsed_status(stmt
))
1673 mylog("Done PG_Columns\n");
1676 * Now resolve the fields to point to column info
1678 if (updatable
&& 1 == stmt
->ntab
)
1679 updatable
= TI_is_updatable(stmt
->ti
[0]);
1680 for (i
= 0; i
< (int) irdflds
->nfields
;)
1683 wfi
->updatable
= updatable
;
1684 /* Dont worry about functions or quotes */
1685 if (wfi
->func
|| wfi
->quote
|| wfi
->numeric
)
1687 wfi
->updatable
= FALSE
;
1692 /* Stars get expanded to all fields in the table */
1693 else if (SAFE_NAME(wfi
->column_name
)[0] == '*')
1696 Int2 total_cols
, cols
, increased_cols
;
1698 mylog("expanding field %d\n", i
);
1702 if (wfi
->ti
) /* The star represents only the qualified
1705 (Int2
) QR_get_num_cached_tuples(wfi
->ti
->col_info
->
1709 { /* The star represents all tables */
1710 /* Calculate the total number of columns after expansion */
1711 for (k
= 0; k
< stmt
->ntab
; k
++)
1713 (Int2
) QR_get_num_cached_tuples(ti
[k
]->
1717 increased_cols
= total_cols
- 1;
1719 /* Allocate some more field pointers if necessary */
1720 new_size
= irdflds
->nfields
+ increased_cols
;
1723 ("k=%d, increased_cols=%d, allocated_size=%d, new_size=%d\n",
1724 k
, increased_cols
, allocated_size
, new_size
);
1726 if (new_size
> allocated_size
)
1728 int new_alloc
= new_size
;
1730 mylog("need more cols: new_alloc = %d\n", new_alloc
);
1731 if (!allocateFields(irdflds
, new_alloc
))
1733 SC_set_parse_status(stmt
, STMT_PARSE_FATAL
);
1737 allocated_size
= irdflds
->allocated
;
1741 * copy any other fields (if there are any) up past the
1744 for (j
= irdflds
->nfields
- 1; j
> i
; j
--)
1746 mylog("copying field %d to %d\n", j
,
1747 increased_cols
+ j
);
1748 fi
[increased_cols
+ j
] = fi
[j
];
1750 mylog("done copying fields\n");
1752 /* Set the new number of fields */
1753 irdflds
->nfields
+= increased_cols
;
1754 mylog("irdflds->nfields now at %d\n", irdflds
->nfields
);
1757 /* copy the new field info */
1758 do_all_tables
= (wfi
->ti
? FALSE
: TRUE
);
1761 for (k
= 0; k
< (do_all_tables
? stmt
->ntab
: 1); k
++)
1763 TABLE_INFO
*the_ti
= do_all_tables
? ti
[k
] : fi
[i
]->ti
;
1766 (Int2
) QR_get_num_cached_tuples(the_ti
->col_info
->
1769 for (n
= 0; n
< cols
; n
++)
1774 mylog("creating field info: n=%d\n", n
);
1775 /* skip malloc (already did it for the Star) */
1778 mylog("allocating field info at %d\n", n
+ i
);
1780 (FIELD_INFO
*) malloc(sizeof(FIELD_INFO
));
1781 if (fi
[n
+ i
] == NULL
)
1783 SC_set_parse_status(stmt
, STMT_PARSE_FATAL
);
1789 /* Initialize the new space (or the * field) */
1790 FI_Constructor(afi
, reuse
);
1793 mylog("about to copy at %d\n", n
+ i
);
1795 getColInfo(the_ti
->col_info
, afi
, n
);
1796 afi
->updatable
= updatable
;
1798 mylog("done copying\n");
1802 mylog("i now at %d\n", i
);
1807 * We either know which table the field was in because it was
1808 * qualified with a table name or alias -OR- there was only 1
1813 if (!searchColInfo(fi
[i
]->ti
->col_info
, wfi
))
1816 wfi
->updatable
= FALSE
;
1821 /* Don't know the table -- search all tables in "from" list */
1824 for (k
= 0; k
< stmt
->ntab
; k
++)
1826 if (searchColInfo(ti
[k
]->col_info
, wfi
))
1828 wfi
->ti
= ti
[k
]; /* now know the table */
1832 if (k
>= stmt
->ntab
)
1835 wfi
->updatable
= FALSE
;
1841 if (check_hasoids
&& updatable
)
1843 SC_set_parse_status(stmt
,
1844 parse
? STMT_PARSE_COMPLETE
:
1845 STMT_PARSE_INCOMPLETE
);
1846 for (i
= 0; i
< (int) irdflds
->nfields
; i
++)
1849 wfi
->flag
&= ~FIELD_PARSING
;
1850 if (0 != wfi
->columntype
|| 0 != wfi
->basetype
)
1851 wfi
->flag
|= FIELD_PARSED_OK
;
1854 stmt
->updatable
= updatable
;
1857 if (STMT_PARSE_FATAL
== SC_parsed_status(stmt
))
1859 SC_initialize_cols_info(stmt
, FALSE
, FALSE
);
1863 mylog("done parse_statement: parse=%d, parse_status=%d\n", parse
,
1864 SC_parsed_status(stmt
));