aboutsummaryrefslogtreecommitdiff
path: root/src/interfaces/odbc/parse.c
diff options
context:
space:
mode:
authorMarc G. Fournier <scrappy@hub.org>2002-08-22 22:43:14 +0000
committerMarc G. Fournier <scrappy@hub.org>2002-08-22 22:43:14 +0000
commit5a303f878ecd597c1524f7cb0b844d17cb9da266 (patch)
treeba28968f533df8a53f8759ee73b40efb9b44140a /src/interfaces/odbc/parse.c
parent03a7625a3a1d7adb9a49295d7447a0e3d224845d (diff)
downloadpostgresql-5a303f878ecd597c1524f7cb0b844d17cb9da266.tar.gz
postgresql-5a303f878ecd597c1524f7cb0b844d17cb9da266.zip
Remove all traces of the ODBC driver, which is now on GBorg as the psqlodbc
project ...
Diffstat (limited to 'src/interfaces/odbc/parse.c')
-rw-r--r--src/interfaces/odbc/parse.c1229
1 files changed, 0 insertions, 1229 deletions
diff --git a/src/interfaces/odbc/parse.c b/src/interfaces/odbc/parse.c
deleted file mode 100644
index a61b75e90cf..00000000000
--- a/src/interfaces/odbc/parse.c
+++ /dev/null
@@ -1,1229 +0,0 @@
-/*--------
- * Module: parse.c
- *
- * Description: This module contains routines related to parsing SQL
- * statements. This can be useful for two reasons:
- *
- * 1. So the query does not actually have to be executed
- * to return data about it
- *
- * 2. To be able to return information about precision,
- * nullability, aliases, etc. in the functions
- * SQLDescribeCol and SQLColAttributes. Currently,
- * Postgres doesn't return any information about
- * these things in a query.
- *
- * Classes: none
- *
- * API functions: none
- *
- * Comments: See "notice.txt" for copyright and license information.
- *--------
- */
-/* Multibyte support Eiji Tokuya 2001-03-15 */
-
-#include "psqlodbc.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-
-#include "statement.h"
-#include "connection.h"
-#include "qresult.h"
-#include "pgtypes.h"
-#include "pgapifunc.h"
-
-#ifdef MULTIBYTE
-#include "multibyte.h"
-#endif
-
-#define FLD_INCR 32
-#define TAB_INCR 8
-#define COL_INCR 16
-
-#ifdef MULTIBYTE
-char *getNextToken(int ccsc, char *s, char *token, int smax, char *delim, char *quote, char *dquote, char *numeric);
-#else
-char *getNextToken(char *s, char *token, int smax, char *delim, char *quote, char *dquote, char *numeric);
-#endif /* MULTIBYTE */
-void getColInfo(COL_INFO *col_info, FIELD_INFO *fi, int k);
-char searchColInfo(COL_INFO *col_info, FIELD_INFO *fi);
-
-Int4 FI_precision(const FIELD_INFO *fi)
-{
- if (!fi) return -1;
- switch (fi->type)
- {
- case PG_TYPE_NUMERIC:
- return fi->column_size;
- case PG_TYPE_DATETIME:
- case PG_TYPE_TIMESTAMP_NO_TMZONE:
- return fi->decimal_digits;
- }
- return 0;
-}
-Int4 FI_scale(const FIELD_INFO *fi)
-{
- if (!fi) return -1;
- switch (fi->type)
- {
- case PG_TYPE_NUMERIC:
- return fi->decimal_digits;
- }
- return 0;
-}
-
-char *
-getNextToken(
-#ifdef MULTIBYTE
- int ccsc, /* client encoding */
-#endif /* MULTIBYTE */
- char *s, char *token, int smax, char *delim, char *quote, char *dquote, char *numeric)
-{
- int i = 0;
- int out = 0;
- char qc,
- in_escape = FALSE;
-#ifdef MULTIBYTE
- encoded_str encstr;
-#endif
-
- if (smax <= 1)
- return NULL;
-
- smax--;
-
- /* skip leading delimiters */
- while (isspace((unsigned char) s[i]) || s[i] == ',')
- {
- /* mylog("skipping '%c'\n", s[i]); */
- i++;
- }
-
- if (s[i] == '\0')
- {
- token[0] = '\0';
- return NULL;
- }
-
- if (quote)
- *quote = FALSE;
- if (dquote)
- *dquote = FALSE;
- if (numeric)
- *numeric = FALSE;
-
-#ifdef MULTIBYTE
- encoded_str_constr(&encstr, ccsc, &s[i]);
-#endif
- /* get the next token */
- while (s[i] != '\0' && out < smax)
- {
-#ifdef MULTIBYTE
- encoded_nextchar(&encstr);
- if (ENCODE_STATUS(encstr) != 0)
- {
- token[out++] = s[i++];
- continue;
- }
-#endif
- if (isspace((unsigned char) s[i]) || s[i] == ',')
- break;
- /* Handle quoted stuff */
- if (out == 0 && (s[i] == '\"' || s[i] == '\''))
- {
- qc = s[i];
- if (qc == '\"')
- {
- if (dquote)
- *dquote = TRUE;
- }
- if (qc == '\'')
- {
- if (quote)
- *quote = TRUE;
- }
-
- i++; /* dont return the quote */
- while (s[i] != '\0' && out != smax)
- {
-#ifdef MULTIBYTE
- encoded_nextchar(&encstr);
- if (ENCODE_STATUS(encstr) != 0)
- {
- token[out++] = s[i++];
- continue;
- }
-#endif
- if (s[i] == qc && !in_escape)
- break;
- if (s[i] == '\\' && !in_escape)
- in_escape = TRUE;
- else
- {
- in_escape = FALSE;
- token[out++] = s[i];
- }
- i++;
- }
- if (s[i] == qc)
- i++;
- break;
- }
-
- /* Check for numeric literals */
- if (out == 0 && isdigit((unsigned char) s[i]))
- {
- if (numeric)
- *numeric = TRUE;
- token[out++] = s[i++];
- while (isalnum((unsigned char) s[i]) || s[i] == '.')
- token[out++] = s[i++];
-
- break;
- }
-
- if (ispunct((unsigned char) s[i]) && s[i] != '_')
- {
- mylog("got ispunct: s[%d] = '%c'\n", i, s[i]);
-
- if (out == 0)
- {
- token[out++] = s[i++];
- break;
- }
- else
- break;
- }
-
- if (out != smax)
- token[out++] = s[i];
-
- i++;
- }
-
- /* mylog("done -- s[%d] = '%c'\n", i, s[i]); */
-
- token[out] = '\0';
-
- /* find the delimiter */
- while (isspace((unsigned char) s[i]))
- i++;
-
- /* return the most priority delimiter */
- if (s[i] == ',')
- {
- if (delim)
- *delim = s[i];
- }
- else if (s[i] == '\0')
- {
- if (delim)
- *delim = '\0';
- }
- else
- {
- if (delim)
- *delim = ' ';
- }
-
- /* skip trailing blanks */
- while (isspace((unsigned char) s[i]))
- i++;
-
- return &s[i];
-}
-
-
-#if 0
-QR_set_num_fields(SC_get_Curres(stmt), 14);
-QR_set_field_info(SC_get_Curres(stmt), 0, "TABLE_QUALIFIER", PG_TYPE_TEXT, MAX_INFO_STRING);
-QR_set_field_info(SC_get_Curres(stmt), 1, "TABLE_OWNER", PG_TYPE_TEXT, MAX_INFO_STRING);
-QR_set_field_info(SC_get_Curres(stmt), 2, "TABLE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
-QR_set_field_info(SC_get_Curres(stmt), 3, "COLUMN_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
-QR_set_field_info(SC_get_Curres(stmt), 4, "DATA_TYPE", PG_TYPE_INT2, 2);
-QR_set_field_info(SC_get_Curres(stmt), 5, "TYPE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING);
-QR_set_field_info(SC_get_Curres(stmt), 6, "PRECISION", PG_TYPE_INT4, 4);
-QR_set_field_info(SC_get_Curres(stmt), 7, "LENGTH", PG_TYPE_INT4, 4);
-QR_set_field_info(SC_get_Curres(stmt), 8, "SCALE", PG_TYPE_INT2, 2);
-QR_set_field_info(SC_get_Curres(stmt), 9, "RADIX", PG_TYPE_INT2, 2);
-QR_set_field_info(SC_get_Curres(stmt), 10, "NULLABLE", PG_TYPE_INT2, 2);
-QR_set_field_info(SC_get_Curres(stmt), 11, "REMARKS", PG_TYPE_TEXT, 254);
-/* User defined fields */
-QR_set_field_info(SC_get_Curres(stmt), 12, "DISPLAY_SIZE", PG_TYPE_INT4, 4);
-QR_set_field_info(SC_get_Curres(stmt), 13, "FIELD_TYPE", PG_TYPE_INT4, 4);
-#endif
-
-void
-getColInfo(COL_INFO *col_info, FIELD_INFO *fi, int k)
-{
- char *str;
- Int2 reserved_cols;
-
-#if (ODBCVER >= 0x0300)
- reserved_cols = 18;
-#else
- reserved_cols = 12;
-#endif /* ODBCVER */
- if (fi->name[0] == '\0')
- strcpy(fi->name, QR_get_value_manual(col_info->result, k, 3));
-
- fi->type = atoi(QR_get_value_manual(col_info->result, k, (Int2)(reserved_cols + 1)));
- fi->column_size = atoi(QR_get_value_manual(col_info->result, k, 6));
- fi->length = atoi(QR_get_value_manual(col_info->result, k, 7));
- if (str = QR_get_value_manual(col_info->result, k, 8), str)
- fi->decimal_digits = atoi(str);
- else
- fi->decimal_digits = -1;
- fi->nullable = atoi(QR_get_value_manual(col_info->result, k, 10));
- fi->display_size = atoi(QR_get_value_manual(col_info->result, k, reserved_cols));
-}
-
-
-char
-searchColInfo(COL_INFO *col_info, FIELD_INFO *fi)
-{
- int k,
- cmp;
- char *col;
-
- for (k = 0; k < QR_get_num_backend_tuples(col_info->result); k++)
- {
- col = QR_get_value_manual(col_info->result, k, 3);
- if (fi->dquote)
- cmp = strcmp(col, fi->name);
- else
- cmp = stricmp(col, fi->name);
- if (!cmp)
- {
- if (!fi->dquote)
- strcpy(fi->name, col);
- getColInfo(col_info, fi, k);
-
- mylog("PARSE: searchColInfo: \n");
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-
-char
-parse_statement(StatementClass *stmt)
-{
- static char *func = "parse_statement";
- char token[256], stoken[256];
- char delim,
- quote,
- dquote,
- numeric,
- unquoted;
- char *ptr,
- *pptr = NULL;
- char in_select = FALSE,
- in_distinct = FALSE,
- in_on = FALSE,
- in_from = FALSE,
- in_where = FALSE,
- in_table = FALSE,
- out_table = TRUE;
- char in_field = FALSE,
- in_expr = FALSE,
- in_func = FALSE,
- in_dot = FALSE,
- in_as = FALSE;
- int j,
- i,
- k = 0,
- n,
- blevel = 0, old_blevel, subqlevel = 0;
- FIELD_INFO **fi;
- TABLE_INFO **ti;
- char parse;
- ConnectionClass *conn = stmt->hdbc;
- HSTMT hcol_stmt;
- StatementClass *col_stmt;
- IRDFields *irdflds = SC_get_IRD(stmt);
- RETCODE result;
- BOOL updatable = TRUE;
-
- mylog("%s: entering...\n", func);
-
- ptr = stmt->statement;
- fi = irdflds->fi;
- ti = stmt->ti;
-
- irdflds->nfields = 0;
- stmt->ntab = 0;
- stmt->from_pos = -1;
- stmt->where_pos = -1;
-
-#ifdef MULTIBYTE
- while (pptr = ptr, (ptr = getNextToken(conn->ccsc, pptr, token, sizeof(token), &delim, &quote, &dquote, &numeric)) != NULL)
-#else
- while (pptr = ptr, (ptr = getNextToken(pptr, token, sizeof(token), &delim, &quote, &dquote, &numeric)) != NULL)
-#endif
- {
- unquoted = !(quote || dquote);
-
- mylog("unquoted=%d, quote=%d, dquote=%d, numeric=%d, delim='%c', token='%s', ptr='%s'\n", unquoted, quote, dquote, numeric, delim, token, ptr);
-
- old_blevel = blevel;
- if (unquoted && blevel == 0)
- {
- if (in_select)
- {
- if (!stricmp(token, "distinct"))
- {
- in_distinct = TRUE;
- updatable = FALSE;
-
- mylog("DISTINCT\n");
- continue;
- }
- else if (!stricmp(token, "into"))
- {
- in_select = FALSE;
- mylog("INTO\n");
- stmt->statement_type = STMT_TYPE_CREATE;
- stmt->parse_status = STMT_PARSE_FATAL;
- return FALSE;
- }
- else if (!stricmp(token, "from"))
- {
- in_select = FALSE;
- in_from = TRUE;
- if (stmt->from_pos < 0 &&
- (!strnicmp(pptr, "from", 4)))
- {
- mylog("First ");
- stmt->from_pos = pptr - stmt->statement;
- }
-
- mylog("FROM\n");
- continue;
- }
- } /* in_select && unquoted && blevel == 0 */
- else if ((!stricmp(token, "where") ||
- !stricmp(token, "union") ||
- !stricmp(token, "intersect") ||
- !stricmp(token, "except") ||
- !stricmp(token, "order") ||
- !stricmp(token, "group") ||
- !stricmp(token, "having")))
- {
- in_from = FALSE;
- in_where = TRUE;
-
- if (stmt->where_pos < 0)
- stmt->where_pos = pptr - stmt->statement;
- mylog("%s...\n", token);
- if (stricmp(token, "where") &&
- stricmp(token, "order"))
- {
- updatable = FALSE;
- break;
- }
- continue;
- }
- } /* unquoted && blevel == 0 */
- /* check the change of blevel etc */
- if (unquoted)
- {
- if (!stricmp(token, "select"))
- {
- stoken[0] = '\0';
- if (0 == blevel)
- {
- in_select = TRUE;
- mylog("SELECT\n");
- continue;
- }
- else
- {
- mylog("SUBSELECT\n");
- if (0 == subqlevel)
- subqlevel = blevel;
- }
- }
- else if (token[0] == '(')
- {
- blevel++;
- mylog("blevel++ = %d\n", blevel);
- /* aggregate function ? */
- if (stoken[0] && updatable && 0 == subqlevel)
- {
- if (stricmp(stoken, "count") == 0 ||
- stricmp(stoken, "sum") == 0 ||
- stricmp(stoken, "avg") == 0 ||
- stricmp(stoken, "max") == 0 ||
- stricmp(stoken, "min") == 0 ||
- stricmp(stoken, "variance") == 0 ||
- stricmp(stoken, "stddev") == 0)
- updatable = FALSE;
- }
- }
- else if (token[0] == ')')
- {
- blevel--;
- mylog("blevel-- = %d\n", blevel);
- if (blevel < subqlevel)
- subqlevel = 0;
- }
- if (blevel >= old_blevel && ',' != delim)
- strcpy(stoken, token);
- else
- stoken[0] = '\0';
- }
- if (in_select)
- {
- if (in_expr || in_func)
- {
- /* just eat the expression */
- mylog("in_expr=%d or func=%d\n", in_expr, in_func);
-
- if (blevel == 0)
- {
- if (delim == ',')
- {
- mylog("**** Got comma in_expr/func\n");
- in_func = FALSE;
- in_expr = FALSE;
- in_field = FALSE;
- }
- else if (unquoted && !stricmp(token, "as"))
- {
- mylog("got AS in_expr\n");
- in_func = FALSE;
- in_expr = FALSE;
- in_as = TRUE;
- in_field = TRUE;
- }
- }
- continue;
- } /* (in_expr || in_func) && in_select */
-
- if (in_distinct)
- {
- mylog("in distinct\n");
-
- if (unquoted && !stricmp(token, "on"))
- {
- in_on = TRUE;
- mylog("got on\n");
- continue;
- }
- if (in_on)
- {
- in_distinct = FALSE;
- in_on = FALSE;
- continue; /* just skip the unique on field */
- }
- mylog("done distinct\n");
- in_distinct = FALSE;
- } /* in_distinct */
-
- if (!in_field)
- {
- if (!token[0])
- continue;
-
- if (!(irdflds->nfields % FLD_INCR))
- {
- mylog("reallocing at nfld=%d\n", irdflds->nfields);
- fi = (FIELD_INFO **) realloc(fi, (irdflds->nfields + FLD_INCR) * sizeof(FIELD_INFO *));
- if (!fi)
- {
- stmt->parse_status = STMT_PARSE_FATAL;
- return FALSE;
- }
- irdflds->fi = fi;
- }
-
- fi[irdflds->nfields] = (FIELD_INFO *) malloc(sizeof(FIELD_INFO));
- if (fi[irdflds->nfields] == NULL)
- {
- stmt->parse_status = STMT_PARSE_FATAL;
- return FALSE;
- }
-
- /* Initialize the field info */
- memset(fi[irdflds->nfields], 0, sizeof(FIELD_INFO));
-
- /* double quotes are for qualifiers */
- if (dquote)
- fi[irdflds->nfields]->dquote = TRUE;
-
- if (quote)
- {
- fi[irdflds->nfields]->quote = TRUE;
- fi[irdflds->nfields]->column_size = strlen(token);
- }
- else if (numeric)
- {
- mylog("**** got numeric: nfld = %d\n", irdflds->nfields);
- fi[irdflds->nfields]->numeric = TRUE;
- }
- else if (0 == old_blevel && blevel > 0)
- { /* expression */
- mylog("got EXPRESSION\n");
- fi[irdflds->nfields++]->expr = TRUE;
- in_expr = TRUE;
- continue;
- }
- else
- {
- strcpy(fi[irdflds->nfields]->name, token);
- fi[irdflds->nfields]->dot[0] = '\0';
- }
- mylog("got field='%s', dot='%s'\n", fi[irdflds->nfields]->name, fi[irdflds->nfields]->dot);
-
- if (delim == ',')
- mylog("comma (1)\n");
- else
- in_field = TRUE;
- irdflds->nfields++;
- continue;
- } /* !in_field */
-
- /*
- * We are in a field now
- */
- if (in_dot)
- {
- int ifld = irdflds->nfields - 1;
-
- if (fi[ifld]->dot[0])
- {
- fi[ifld]->schema = strdup(fi[ifld]->dot);
- }
- strcpy(fi[ifld]->dot, fi[ifld]->name);
- strcpy(fi[ifld]->name, token);
-
- if (delim == ',')
- {
- mylog("in_dot: got comma\n");
- in_field = FALSE;
- }
- in_dot = FALSE;
- continue;
- }
-
- if (in_as)
- {
- irdflds->nfields--;
- strcpy(fi[irdflds->nfields]->alias, token);
- mylog("alias for field '%s' is '%s'\n", fi[irdflds->nfields]->name, fi[irdflds->nfields]->alias);
- in_as = FALSE;
- in_field = FALSE;
-
- irdflds->nfields++;
-
- if (delim == ',')
- mylog("comma(2)\n");
- continue;
- }
-
- /* Function */
- if (0 == old_blevel && blevel > 0)
- {
- in_dot = FALSE;
- in_func = TRUE;
- fi[irdflds->nfields - 1]->func = TRUE;
-
- /*
- * name will have the function name -- maybe useful some
- * day
- */
- mylog("**** got function = '%s'\n", fi[irdflds->nfields - 1]->name);
- continue;
- }
-
- if (token[0] == '.')
- {
- in_dot = TRUE;
- mylog("got dot\n");
- continue;
- }
-
- in_dot = FALSE;
- if (!stricmp(token, "as"))
- {
- in_as = TRUE;
- mylog("got AS\n");
- continue;
- }
-
- /* otherwise, it's probably an expression */
- in_expr = TRUE;
- fi[irdflds->nfields - 1]->expr = TRUE;
- fi[irdflds->nfields - 1]->name[0] = '\0';
- fi[irdflds->nfields - 1]->column_size = 0;
- mylog("*** setting expression\n");
- } /* in_select end */
-
- if (in_from)
- {
- if (token[0] == ';')
- {
- in_from = FALSE;
- break;
- }
- switch (token[0])
- {
- case '\0':
- continue;
- case ',':
- out_table = TRUE;
- continue;
- }
- if (out_table && !in_table) /* new table */
- {
-
- if (!(stmt->ntab % TAB_INCR))
- {
- ti = (TABLE_INFO **) realloc(ti, (stmt->ntab + TAB_INCR) * sizeof(TABLE_INFO *));
- if (!ti)
- {
- stmt->parse_status = STMT_PARSE_FATAL;
- return FALSE;
- }
- stmt->ti = ti;
- }
- ti[stmt->ntab] = (TABLE_INFO *) malloc(sizeof(TABLE_INFO));
- if (ti[stmt->ntab] == NULL)
- {
- stmt->parse_status = STMT_PARSE_FATAL;
- return FALSE;
- }
-
- ti[stmt->ntab]->schema[0] = '\0';
- ti[stmt->ntab]->alias[0] = '\0';
- ti[stmt->ntab]->updatable = 1;
-
- strcpy(ti[stmt->ntab]->name, token);
- if (!dquote)
- {
- char *ptr;
-#ifdef MULTIBYTE
- encoded_str encstr;
- make_encoded_str(&encstr, conn, ti[stmt->ntab]->name);
-#endif /* MULTIBYTE */
-
- /* lower case table name */
- for (ptr = ti[stmt->ntab]->name; *ptr; ptr++)
- {
-#ifdef MULTIBYTE
- encoded_nextchar(&encstr);
- if (ENCODE_STATUS(encstr) != 0)
- ptr++;
- else
-#endif /* MULTIBYTE */
- *ptr = tolower((unsigned char) *ptr);
- }
- }
- mylog("got table = '%s'\n", ti[stmt->ntab]->name);
-
- if (delim == ',')
- {
- out_table = TRUE;
- mylog("more than 1 tables\n");
- }
- else
- {
- out_table = FALSE;
- in_table = TRUE;
- }
- stmt->ntab++;
- in_dot = FALSE;
- continue;
- }
-
- if (!dquote && stricmp(token, "JOIN") == 0)
- {
- in_table = FALSE;
- out_table = TRUE;
- continue;
- }
- if (in_table)
- {
- if (in_dot)
- {
- strcpy(ti[stmt->ntab - 1]->schema, ti[stmt->ntab - 1]->name);
- strcpy(ti[stmt->ntab - 1]->name, token);
- in_dot = FALSE;
- continue;
- }
- if (strcmp(token, ".") == 0)
- {
- in_dot = TRUE;
- continue;
- }
- if (!dquote && stricmp(token, "as"))
- {
- if (stricmp(token, "LEFT") == 0 ||
- stricmp(token, "RIGHT") == 0 ||
- stricmp(token, "OUTER") == 0 ||
- stricmp(token, "FULL") == 0 ||
- stricmp(token, "ON") == 0)
- {
- in_table = FALSE;
- continue;
- }
- strcpy(ti[stmt->ntab - 1]->alias, token);
- mylog("alias for table '%s' is '%s'\n", ti[stmt->ntab - 1]->name, ti[stmt->ntab - 1]->alias);
- in_table = FALSE;
- if (delim == ',')
- {
- out_table = TRUE;
- mylog("more than 1 tables\n");
- }
- }
- }
- } /* in_from */
- }
-
- /*
- * Resolve any possible field names with tables
- */
-
- parse = TRUE;
-
- /* Resolve field names with tables */
- for (i = 0; i < (int) irdflds->nfields; i++)
- {
- if (fi[i]->func || fi[i]->expr || fi[i]->numeric)
- {
- fi[i]->ti = NULL;
- fi[i]->type = -1;
- parse = FALSE;
- continue;
- }
- else if (fi[i]->quote)
- { /* handle as text */
- fi[i]->ti = NULL;
-
- /*
- * fi[i]->type = PG_TYPE_TEXT; fi[i]->column_size = 0; the
- * following may be better
- */
- fi[i]->type = PG_TYPE_UNKNOWN;
- if (fi[i]->column_size == 0)
- {
- fi[i]->type = PG_TYPE_VARCHAR;
- fi[i]->column_size = 254;
- }
- fi[i]->length = fi[i]->column_size;
- continue;
- }
- /* field name contains the schema name */
- else if (fi[i]->schema)
- {
- int matchidx = -1;
-
- for (k = 0; k < stmt->ntab; k++)
- {
- if (!stricmp(ti[k]->name, fi[i]->dot))
- {
- if (!stricmp(ti[k]->schema, fi[i]->schema))
- {
- fi[i]->ti = ti[k];
- break;
- }
- else if (!ti[k]->schema[0])
- {
- if (matchidx < 0)
- matchidx = k;
- else
- {
- stmt->parse_status = STMT_PARSE_FATAL;
- stmt->errornumber = STMT_EXEC_ERROR;
- stmt->errormsg = "duplicated Table name";
- stmt->updatable = FALSE;
- return FALSE;
- }
- }
- }
- }
- if (matchidx >= 0)
- fi[i]->ti = ti[matchidx];
- }
- /* it's a dot, resolve to table or alias */
- else if (fi[i]->dot[0])
- {
- for (k = 0; k < stmt->ntab; k++)
- {
- if (!stricmp(ti[k]->alias, fi[i]->dot))
- {
- fi[i]->ti = ti[k];
- break;
- }
- else if (!stricmp(ti[k]->name, fi[i]->dot))
- {
- fi[i]->ti = ti[k];
- break;
- }
- }
- }
- else if (stmt->ntab == 1)
- fi[i]->ti = ti[0];
- }
-
- mylog("--------------------------------------------\n");
- mylog("nfld=%d, ntab=%d\n", irdflds->nfields, stmt->ntab);
- if (0 == stmt->ntab)
- {
- stmt->parse_status = STMT_PARSE_FATAL;
- return FALSE;
- }
-
- for (i = 0; i < (int) irdflds->nfields; i++)
- {
- 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);
- if (fi[i]->ti)
- mylog(" ----> table_name='%s', table_alias='%s'\n", fi[i]->ti->name, fi[i]->ti->alias);
- }
-
- for (i = 0; i < stmt->ntab; i++)
- mylog("Table %d: name='%s', alias='%s'\n", i, ti[i]->name, ti[i]->alias);
-
-
- /*
- * Now save the SQLColumns Info for the parse tables
- */
-
- /* Call SQLColumns for each table and store the result */
- if (stmt->ntab > 1)
- updatable = FALSE;
- else if (stmt->from_pos < 0)
- updatable = FALSE;
- for (i = 0; i < stmt->ntab; i++)
- {
- /* See if already got it */
- char found = FALSE;
-
- if (conn->schema_support)
- {
- if (!ti[i]->schema[0])
- {
- const char *curschema = CC_get_current_schema(conn);
- /*
- * Though current_schema() doesn't have
- * much sense in PostgreSQL, we first
- * check the current_schema() when no
- * explicit schema name was specified.
- */
- for (k = 0; k < conn->ntables; k++)
- {
- if (!stricmp(conn->col_info[k]->name, ti[i]->name) &&
- !stricmp(conn->col_info[k]->schema, curschema))
- {
- mylog("FOUND col_info table='%s' current schema='%s'\n", ti[i]->name, curschema);
- found = TRUE;
- strcpy(ti[i]->schema, curschema);
- break;
- }
- }
- if (!found)
- {
- QResultClass *res;
- BOOL tblFound = FALSE;
-
- /*
- * We also have to check as follows.
- */
- sprintf(token, "select nspname from pg_namespace n, pg_class c"
- " where c.relnamespace=n.oid and c.oid='%s'::regclass", ti[i]->name);
- res = CC_send_query(conn, token, NULL, CLEAR_RESULT_ON_ABORT);
- if (res)
- {
- if (QR_get_num_total_tuples(res) == 1)
- {
- tblFound = TRUE;
- strcpy(ti[i]->schema, QR_get_value_backend_row(res, 0, 0));
- }
- QR_Destructor(res);
- }
- else
- CC_abort(conn);
- if (!tblFound)
- {
- stmt->parse_status = STMT_PARSE_FATAL;
- stmt->errornumber = STMT_EXEC_ERROR;
- stmt->errormsg = "Table not found";
- stmt->updatable = FALSE;
- return FALSE;
- }
- }
- }
- if (!found && ti[i]->schema[0])
- {
- for (k = 0; k < conn->ntables; k++)
- {
- if (!stricmp(conn->col_info[k]->name, ti[i]->name) &&
- !stricmp(conn->col_info[k]->schema, ti[i]->schema))
- {
- mylog("FOUND col_info table='%s' schema='%s'\n", ti[i]->name, ti[i]->schema);
- found = TRUE;
- break;
- }
- }
- }
- }
- else
- {
- for (k = 0; k < conn->ntables; k++)
- {
- if (!stricmp(conn->col_info[k]->name, ti[i]->name))
- {
- mylog("FOUND col_info table='%s'\n", ti[i]->name);
- found = TRUE;
- break;
- }
- }
- }
-
- if (!found)
- {
- mylog("PARSE: Getting PG_Columns for table[%d]='%s'\n", i, ti[i]->name);
-
- result = PGAPI_AllocStmt(stmt->hdbc, &hcol_stmt);
- if ((result != SQL_SUCCESS) && (result != SQL_SUCCESS_WITH_INFO))
- {
- stmt->errormsg = "PGAPI_AllocStmt failed in parse_statement for columns.";
- stmt->errornumber = STMT_NO_MEMORY_ERROR;
- stmt->parse_status = STMT_PARSE_FATAL;
- return FALSE;
- }
-
- col_stmt = (StatementClass *) hcol_stmt;
- col_stmt->internal = TRUE;
-
- result = PGAPI_Columns(hcol_stmt, "", 0, ti[i]->schema,
- SQL_NTS, ti[i]->name, SQL_NTS, "", 0, PODBC_NOT_SEARCH_PATTERN);
-
- mylog(" Past PG_Columns\n");
- if (result == SQL_SUCCESS)
- {
- mylog(" Success\n");
- if (!(conn->ntables % COL_INCR))
- {
- mylog("PARSE: Allocing col_info at ntables=%d\n", conn->ntables);
-
- conn->col_info = (COL_INFO **) realloc(conn->col_info, (conn->ntables + COL_INCR) * sizeof(COL_INFO *));
- if (!conn->col_info)
- {
- stmt->parse_status = STMT_PARSE_FATAL;
- return FALSE;
- }
- }
-
- mylog("PARSE: malloc at conn->col_info[%d]\n", conn->ntables);
- conn->col_info[conn->ntables] = (COL_INFO *) malloc(sizeof(COL_INFO));
- if (!conn->col_info[conn->ntables])
- {
- stmt->parse_status = STMT_PARSE_FATAL;
- return FALSE;
- }
-
- /*
- * Store the table name and the SQLColumns result
- * structure
- */
- if (ti[i]->schema[0])
- conn->col_info[conn->ntables]->schema = strdup(ti[i]->schema);
- else
- conn->col_info[conn->ntables]->schema = NULL;
- strcpy(conn->col_info[conn->ntables]->name, ti[i]->name);
- conn->col_info[conn->ntables]->result = SC_get_Curres(col_stmt);
-
- /*
- * The connection will now free the result structures, so
- * make sure that the statement doesn't free it
- */
- SC_set_Result(col_stmt, NULL);
-
- conn->ntables++;
-
- PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
- mylog("Created col_info table='%s', ntables=%d\n", ti[i]->name, conn->ntables);
- }
- else
- {
- PGAPI_FreeStmt(hcol_stmt, SQL_DROP);
- break;
- }
- }
-
- /* Associate a table from the statement with a SQLColumn info */
- ti[i]->col_info = conn->col_info[k];
- mylog("associate col_info: i=%d, k=%d\n", i, k);
- }
-
- mylog("Done PG_Columns\n");
-
- /*
- * Now resolve the fields to point to column info
- */
- if (updatable && 1 == stmt->ntab)
- updatable = stmt->ti[0]->updatable;
- for (i = 0; i < (int) irdflds->nfields;)
- {
- fi[i]->updatable = updatable;
- /* Dont worry about functions or quotes */
- if (fi[i]->func || fi[i]->quote || fi[i]->numeric)
- {
- fi[i]->updatable = FALSE;
- i++;
- continue;
- }
-
- /* Stars get expanded to all fields in the table */
- else if (fi[i]->name[0] == '*')
- {
- char do_all_tables;
- int total_cols,
- old_alloc,
- new_size,
- cols;
- int increased_cols;
-
- mylog("expanding field %d\n", i);
-
- total_cols = 0;
-
- if (fi[i]->ti) /* The star represents only the qualified
- * table */
- total_cols = QR_get_num_backend_tuples(fi[i]->ti->col_info->result);
-
- else
- { /* The star represents all tables */
-
- /* Calculate the total number of columns after expansion */
- for (k = 0; k < stmt->ntab; k++)
- total_cols += QR_get_num_backend_tuples(ti[k]->col_info->result);
- }
- increased_cols = total_cols - 1;
-
- /* Allocate some more field pointers if necessary */
- old_alloc = ((irdflds->nfields - 1) / FLD_INCR + 1) * FLD_INCR;
- new_size = irdflds->nfields + increased_cols;
-
- mylog("k=%d, increased_cols=%d, old_alloc=%d, new_size=%d\n", k, increased_cols, old_alloc, new_size);
-
- if (new_size > old_alloc)
- {
- int new_alloc = ((new_size / FLD_INCR) + 1) * FLD_INCR;
-
- mylog("need more cols: new_alloc = %d\n", new_alloc);
- fi = (FIELD_INFO **) realloc(fi, new_alloc * sizeof(FIELD_INFO *));
- if (!fi)
- {
- stmt->parse_status = STMT_PARSE_FATAL;
- return FALSE;
- }
- irdflds->fi = fi;
- }
-
- /*
- * copy any other fields (if there are any) up past the
- * expansion
- */
- for (j = irdflds->nfields - 1; j > i; j--)
- {
- mylog("copying field %d to %d\n", j, increased_cols + j);
- fi[increased_cols + j] = fi[j];
- }
- mylog("done copying fields\n");
-
- /* Set the new number of fields */
- irdflds->nfields += increased_cols;
- mylog("irdflds->nfields now at %d\n", irdflds->nfields);
-
-
- /* copy the new field info */
- do_all_tables = (fi[i]->ti ? FALSE : TRUE);
-
- for (k = 0; k < (do_all_tables ? stmt->ntab : 1); k++)
- {
- TABLE_INFO *the_ti = do_all_tables ? ti[k] : fi[i]->ti;
-
- cols = QR_get_num_backend_tuples(the_ti->col_info->result);
-
- for (n = 0; n < cols; n++)
- {
- mylog("creating field info: n=%d\n", n);
- /* skip malloc (already did it for the Star) */
- if (k > 0 || n > 0)
- {
- mylog("allocating field info at %d\n", n + i);
- fi[n + i] = (FIELD_INFO *) malloc(sizeof(FIELD_INFO));
- if (fi[n + i] == NULL)
- {
- stmt->parse_status = STMT_PARSE_FATAL;
- return FALSE;
- }
- }
- /* Initialize the new space (or the * field) */
- memset(fi[n + i], 0, sizeof(FIELD_INFO));
- fi[n + i]->ti = the_ti;
-
- mylog("about to copy at %d\n", n + i);
-
- getColInfo(the_ti->col_info, fi[n + i], n);
- fi[n + i]->updatable = updatable;
-
- mylog("done copying\n");
- }
-
- i += cols;
- mylog("i now at %d\n", i);
- }
- }
-
- /*
- * We either know which table the field was in because it was
- * qualified with a table name or alias -OR- there was only 1
- * table.
- */
- else if (fi[i]->ti)
- {
- if (!searchColInfo(fi[i]->ti->col_info, fi[i]))
- {
- parse = FALSE;
- fi[i]->updatable = FALSE;
- }
- i++;
- }
-
- /* Don't know the table -- search all tables in "from" list */
- else
- {
- for (k = 0; k < stmt->ntab; k++)
- {
- if (searchColInfo(ti[k]->col_info, fi[i]))
- {
- fi[i]->ti = ti[k]; /* now know the table */
- break;
- }
- }
- if (k >= stmt->ntab)
- {
- parse = FALSE;
- fi[i]->updatable = FALSE;
- }
- i++;
- }
- }
-
- if (!parse)
- stmt->parse_status = STMT_PARSE_INCOMPLETE;
- else
- stmt->parse_status = STMT_PARSE_COMPLETE;
-
- stmt->updatable = updatable;
- mylog("done parse_statement: parse=%d, parse_status=%d\n", parse, stmt->parse_status);
- return parse;
-}