Don't barf when parsing queries with functions in the table list (eg. SELECT * FROM...
authorDave Page <dpage@pgadmin.org>
Wed, 23 Feb 2005 16:41:50 +0000 (16:41 +0000)
committerDave Page <dpage@pgadmin.org>
Wed, 23 Feb 2005 16:41:50 +0000 (16:41 +0000)
[Joost Kraaijeveld]

parse.c
statement.c

diff --git a/parse.c b/parse.c
index fa4d73f5199b72bd668575bb768cd414528d23e7..452e7d0b90d2e51d7e1c021989dbf634d4985f5e 100644 (file)
--- a/parse.c
+++ b/parse.c
@@ -334,6 +334,7 @@ parse_statement(StatementClass *stmt)
    char        in_field = FALSE,
                in_expr = FALSE,
                in_func = FALSE,
+                out_func = FALSE,
                in_dot = FALSE,
                in_as = FALSE;
    int         j,
@@ -351,6 +352,10 @@ parse_statement(StatementClass *stmt)
    RETCODE     result;
    BOOL        updatable = TRUE;
 
+   QResultClass*   resultClass;
+   HSTMT           privStmt;
+   
+
    mylog("%s: entering...\n", func);
 
    ptr = stmt->statement;
@@ -677,14 +682,33 @@ parse_statement(StatementClass *stmt)
                    out_table = TRUE; 
                    continue;
            }
-           if (out_table && !in_table) /* new table */
+           if (out_table && !in_table && !in_func) /* new table */
            {
                if (!dquote)
                {
                    if (token[0] == '(' ||
                        token[0] == ')')
                        continue;
+                    
+                   /* 
+                    * Detect a function call that looks like a table, eg.
+                    *   SELECT * FROM version()
+                    * 
+                    * This needs work to properly handle functions found in the from
+                    * clause, but this at least prevents nasty errors for now.
+                    *
+                    * DJP, 2005-01-08
+                    */
+                   if (ptr[0] == '(')
+                   {
+                        in_func = TRUE;
+                       mylog("**** got function = '%s'\n", token);
+                       mylog("FIXME: functions in the FROM clause are currently ignored!!\n");
+                       continue;
+                   }
                }
+                
+            
                if (!(stmt->ntab % TAB_INCR))
                {
                    ti = (TABLE_INFO **) realloc(ti, (stmt->ntab + TAB_INCR) * sizeof(TABLE_INFO *));
@@ -725,6 +749,64 @@ parse_statement(StatementClass *stmt)
                continue;
            }
 
+           if (out_table && !in_table && in_func) /* old function */
+           {
+                /* Just skipped a function alias */
+                if (out_func)
+                {
+                    in_func = FALSE;
+                    out_func = FALSE;
+                    mylog("leaving func (and ignoring alias)\n");
+                    continue;
+                }
+                
+                /* Normal function, no alias */
+                if (token[0] == ')' && (ptr[0] == ',' || strlen(ptr) == 0))
+                {
+                    in_func = FALSE;
+                    
+                    /* 
+                     * TODO: shouldn't we cache the metadata somewhere? 
+                     */
+                    SC_pre_execute(stmt);
+                   resultClass = SC_get_Curres(stmt);
+
+                   mylog("PGAPI_NumResultCols: result = %u, status = %d, numcols = %d\n", resultClass, stmt->status, resultClass!= NULL ? QR_NumResultCols(resultClass) : -1);
+                   if ((!resultClass) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE)))
+                   {
+                       /* no query has been executed on this statement */
+                       SC_set_error(stmt, STMT_EXEC_ERROR, "No query has been executed with that handle");
+                       SC_log_error(func, "", stmt);
+                       return SQL_ERROR;
+                   }
+                   else if (!QR_command_maybe_successful(resultClass))
+                   {
+                       SC_set_errornumber(stmt, STMT_EXEC_ERROR);
+                       SC_log_error(func, "", stmt);
+                       return SQL_ERROR;
+                   }
+                   /* 
+                    * If the parse_statement is called to get the number of 
+                    * result columns throught SQLColAttribute. 
+                    */
+                   irdflds->nfields = QR_NumPublicResultCols(resultClass);                    
+                    
+                    mylog("leaving func.\n");
+                    
+                    stmt->parse_status = STMT_PARSE_FATAL;
+                   return  FALSE;
+                }
+                
+                /* Function with following alias */
+                if (token[0] == ')')
+                {
+                    out_func = TRUE;
+                    continue;
+                }
+                    
+                
+            }
+            
            if (!dquote && stricmp(token, "JOIN") == 0)
            {
                in_table = FALSE;
index daebdf9de4dbe7c5e43f351b31ded3cc53e2fb4b..d90a1a9018b561d2ce84f201a169efeae5746b88 100644 (file)
@@ -500,6 +500,15 @@ BOOL   SC_opencheck(StatementClass *self, const char *func)
        SC_set_error(self, STMT_SEQUENCE_ERROR, "Statement is currently executing a transaction.");
        return TRUE;
    }
+   /*
+    * We get here if a statement is prepared and executed to get the metadata.
+    */
+   if (self->prepare && self->status == STMT_PREMATURE)
+   {
+       mylog("SC_opencheck: self->prepare && self->status == STMT_PREMATURE\n");
+       return FALSE;
+   }
+   
    if (res = SC_get_Curres(self), NULL != res)
    {
        if (res->backend_tuples)