Re-enabled variables in fetch/move command.
authorMichael Meskes <meskes@postgresql.org>
Tue, 15 Jan 2008 10:31:47 +0000 (10:31 +0000)
committerMichael Meskes <meskes@postgresql.org>
Tue, 15 Jan 2008 10:31:47 +0000 (10:31 +0000)
src/interfaces/ecpg/ChangeLog
src/interfaces/ecpg/ecpglib/descriptor.c
src/interfaces/ecpg/ecpglib/execute.c
src/interfaces/ecpg/ecpglib/extern.h
src/interfaces/ecpg/preproc/pgc.l
src/interfaces/ecpg/preproc/preproc.y
src/interfaces/ecpg/test/expected/sql-fetch.c
src/interfaces/ecpg/test/sql/fetch.pgc

index 59e22774d755566c4ca0c35e9dd829fb34867004..871630923c1e8cd288b4e6a013655c707a0d80de 100644 (file)
@@ -2293,6 +2293,10 @@ Mon, 14 Jan 2008 10:42:23 +0100
 
        - Set valid return values even in case of an error to prevent
          segfaults.
+
+Tue, 15 Jan 2008 11:26:14 +0100
+
+       - Re-enabled variables in fetch/move command.
        - Set pgtypes library version to 3.0.
        - Set compat library version to 3.0.
        - Set ecpg library version to 6.0.
index 0e76e244b16e22c5465ea12d2990525e36ae4117..df9ea2953447ddc874521c3d5817f3f3cf70aa4e 100644 (file)
@@ -1,6 +1,6 @@
 /* dynamic SQL support routines
  *
- * $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/descriptor.c,v 1.28 2007/11/15 21:14:45 momjian Exp $
+ * $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/descriptor.c,v 1.29 2008/01/15 10:31:47 meskes Exp $
  */
 
 #define POSTGRES_ECPG_INTERNAL
@@ -529,7 +529,7 @@ ECPGset_desc(int lineno, const char *desc_name, int index,...)
        for (;;)
        {
                enum ECPGdtype itemtype;
-               const char *tobeinserted = NULL;
+               char *tobeinserted = NULL;
 
                itemtype = va_arg(args, enum ECPGdtype);
 
index 1b1f47217b2c8a65e457ec697ef98f2ef5c322da..2ccdcbb68fb8cc2aee3ce91282f880d2d8300d70 100644 (file)
@@ -1,4 +1,4 @@
-/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/execute.c,v 1.74 2008/01/13 11:53:16 meskes Exp $ */
+/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/execute.c,v 1.75 2008/01/15 10:31:47 meskes Exp $ */
 
 /*
  * The aim is to get a simpler inteface to the database routines.
@@ -128,8 +128,8 @@ next_insert(char *text, int pos, bool questionmarks)
                                int                     i;
 
                                for (i = p + 1; isdigit(text[i]); i++);
-                               if (!isalpha(text[i]) &&isascii(text[i]) &&text[i] != '_')
-                                       /* not dollar delimeted quote */
+                               if (!isalpha(text[i]) && isascii(text[i]) && text[i] != '_')
+                                       /* not dollar delimited quote */
                                        return p;
                        }
                        else if (questionmarks && text[p] == '?')
@@ -451,7 +451,7 @@ ecpg_store_result(const PGresult *results, int act_field,
 
 bool
 ecpg_store_input(const int lineno, const bool force_indicator, const struct variable * var,
-                                const char **tobeinserted_p, bool quote)
+                                char **tobeinserted_p, bool quote)
 {
        char       *mallocedval = NULL;
        char       *newcopy = NULL;
@@ -1046,6 +1046,39 @@ free_params(const char **paramValues, int nParams, bool print, int lineno)
        ecpg_free(paramValues);
 }
 
+
+static bool
+insert_tobeinserted(int position, int ph_len, struct statement * stmt, char *tobeinserted)
+{
+       char    *newcopy;
+
+       if (!(newcopy = (char *) ecpg_alloc(strlen(stmt->command)
+                                                                               + strlen(tobeinserted)
+                                                                               + 1, stmt->lineno)))
+       {
+               ecpg_free(tobeinserted);
+               return false;
+       }
+
+       strcpy(newcopy, stmt->command);
+       strcpy(newcopy + position - 1, tobeinserted);
+
+       /*
+        * The strange thing in the second argument is the rest of the
+        * string from the old string
+        */
+       strcat(newcopy,
+                  stmt->command
+                  + position
+                  + ph_len - 1);
+
+       ecpg_free(stmt->command);
+       stmt->command = newcopy;
+
+       ecpg_free((char *) tobeinserted);
+       return true;
+}
+
 static bool
 ecpg_execute(struct statement * stmt)
 {
@@ -1069,7 +1102,7 @@ ecpg_execute(struct statement * stmt)
        var = stmt->inlist;
        while (var)
        {
-               const char *tobeinserted;
+               char *tobeinserted;
                int                     counter = 1;
 
                tobeinserted = NULL;
@@ -1134,11 +1167,51 @@ ecpg_execute(struct statement * stmt)
 
                /*
                 * now tobeinserted points to an area that contains the next parameter
+                * now find the positin in the string where it belongs
+                */
+               if ((position = next_insert(stmt->command, position, stmt->questionmarks) + 1) == 0)
+               {
+                       /*
+                        * We have an argument but we dont have the matched up
+                        * placeholder in the string
+                        */
+                       ecpg_raise(stmt->lineno, ECPG_TOO_MANY_ARGUMENTS,
+                                       ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS,
+                                          NULL);
+                       free_params(paramValues, nParams, false, stmt->lineno);
+                       return false;
+               }
+
+               /* 
                 * if var->type=ECPGt_char_variable we have a dynamic cursor we have
                 * to simulate a dynamic cursor because there is no backend
                 * functionality for it
                 */
-               if (var->type != ECPGt_char_variable)
+               if (var->type == ECPGt_char_variable)
+               {
+                       int     ph_len = (stmt->command[position] == '?') ? strlen("?") : strlen("$1");
+
+                       if (!insert_tobeinserted(position, ph_len, stmt, tobeinserted))
+                       {
+                               free_params(paramValues, nParams, false, stmt->lineno);
+                               return false;
+                       }
+                       tobeinserted = NULL;
+               }
+               /*
+                * if the placeholder is '$0' we have to replace it on the client side
+                * this is for places we want to support variables at that are not supported in the backend
+                */
+               else if (stmt->command[position] == '0' ) 
+               {
+                       if (!insert_tobeinserted(position, 2, stmt, tobeinserted))
+                       {
+                               free_params(paramValues, nParams, false, stmt->lineno);
+                               return false;
+                       }
+                       tobeinserted = NULL;
+               }
+               else
                {
                        nParams++;
                        if (!(paramValues = (const char **) ecpg_realloc(paramValues, sizeof(const char *) * nParams, stmt->lineno)))
@@ -1149,107 +1222,28 @@ ecpg_execute(struct statement * stmt)
 
                        paramValues[nParams - 1] = tobeinserted;
 
-                       if ((position = next_insert(stmt->command, position, stmt->questionmarks) + 1) == 0)
-                       {
-                               /*
-                                * We have an argument but we dont have the matched up
-                                * placeholder in the string
-                                */
-                               ecpg_raise(stmt->lineno, ECPG_TOO_MANY_ARGUMENTS,
-                                               ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS,
-                                                  NULL);
-                               free_params(paramValues, nParams, false, stmt->lineno);
-                               return false;
-                       }
-
                        /* let's see if this was an old style placeholder */
-                       if (stmt->command[position - 1] == '?')
+                       if (stmt->command[position] == '?')
                        {
                                /* yes, replace with new style */
                                int                     buffersize = sizeof(int) * CHAR_BIT * 10 / 3;           /* a rough guess of the
                                                                                                                                                                 * size we need */
-                               char       *buffer,
-                                                  *newcopy;
 
-                               if (!(buffer = (char *) ecpg_alloc(buffersize, stmt->lineno)))
+                               if (!(tobeinserted = (char *) ecpg_alloc(buffersize, stmt->lineno)))
                                {
                                        free_params(paramValues, nParams, false, stmt->lineno);
                                        return false;
                                }
 
-                               snprintf(buffer, buffersize, "$%d", counter++);
+                               snprintf(tobeinserted, buffersize, "$%d", counter++);
 
-                               if (!(newcopy = (char *) ecpg_alloc(strlen(stmt->command) + strlen(buffer) + 1, stmt->lineno)))
+                               if (!insert_tobeinserted(position, 2, stmt, tobeinserted))
                                {
                                        free_params(paramValues, nParams, false, stmt->lineno);
-                                       ecpg_free(buffer);
                                        return false;
                                }
-
-                               strcpy(newcopy, stmt->command);
-
-                               /* set positional parameter */
-                               strcpy(newcopy + position - 1, buffer);
-
-                               /*
-                                * The strange thing in the second argument is the rest of the
-                                * string from the old string
-                                */
-                               strcat(newcopy,
-                                          stmt->command
-                                          + position + 1);
-                               ecpg_free(buffer);
-                               ecpg_free(stmt->command);
-                               stmt->command = newcopy;
-                       }
-               }
-               else
-               {
-                       char       *newcopy;
-
-                       if (!(newcopy = (char *) ecpg_alloc(strlen(stmt->command)
-                                                                                               + strlen(tobeinserted)
-                                                                                               + 1, stmt->lineno)))
-                       {
-                               free_params(paramValues, nParams, false, stmt->lineno);
-                               return false;
-                       }
-
-                       strcpy(newcopy, stmt->command);
-                       if ((position = next_insert(stmt->command, position, stmt->questionmarks) + 1) == 0)
-                       {
-                               /*
-                                * We have an argument but we dont have the matched up string
-                                * in the string
-                                */
-                               ecpg_raise(stmt->lineno, ECPG_TOO_MANY_ARGUMENTS,
-                                               ECPG_SQLSTATE_USING_CLAUSE_DOES_NOT_MATCH_PARAMETERS,
-                                                  NULL);
-                               free_params(paramValues, nParams, false, stmt->lineno);
-                               ecpg_free(newcopy);
-                               return false;
+                               tobeinserted = NULL;
                        }
-                       else
-                       {
-                               int                     ph_len = (stmt->command[position] == '?') ? strlen("?") : strlen("$1");
-
-                               strcpy(newcopy + position - 1, tobeinserted);
-
-                               /*
-                                * The strange thing in the second argument is the rest of the
-                                * string from the old string
-                                */
-                               strcat(newcopy,
-                                          stmt->command
-                                          + position
-                                          + ph_len - 1);
-                       }
-
-                       ecpg_free(stmt->command);
-                       stmt->command = newcopy;
-
-                       ecpg_free((char *) tobeinserted);
-                       tobeinserted = NULL;
                }
 
                if (desc_counter == 0)
index e366c9ce44835be4e634cb7297bc6bb4448b0345..975904eb7741e65d09c60a61bbf5de508a7b11ae 100644 (file)
@@ -1,4 +1,4 @@
-/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/extern.h,v 1.32 2007/11/15 21:14:45 momjian Exp $ */
+/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/extern.h,v 1.33 2008/01/15 10:31:47 meskes Exp $ */
 
 #ifndef _ECPG_LIB_EXTERN_H
 #define _ECPG_LIB_EXTERN_H
@@ -138,7 +138,7 @@ struct descriptor *ecpg_find_desc(int line, const char *name);
 
 bool ecpg_store_result(const PGresult *results, int act_field,
                                  const struct statement * stmt, struct variable * var);
-bool           ecpg_store_input(const int, const bool, const struct variable *, const char **, bool);
+bool           ecpg_store_input(const int, const bool, const struct variable *, char **, bool);
 
 bool           ecpg_check_PQresult(PGresult *, int, PGconn *, enum COMPAT_MODE);
 void           ecpg_raise(int line, int code, const char *sqlstate, const char *str);
index 1bdfc7e0fa9716c11526181356e8c0ab318a7e68..e5bd28be920a05f118cea85aa50529fc59569ae6 100644 (file)
@@ -12,7 +12,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/pgc.l,v 1.158 2008/01/11 15:19:16 meskes Exp $
+ *       $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/pgc.l,v 1.159 2008/01/15 10:31:47 meskes Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -28,7 +28,6 @@ extern YYSTYPE yylval;
 
 static int             xcdepth = 0;    /* depth of nesting in slash-star comments */
 static char       *dolqstart;      /* current $foo$ quote start string */
-static bool            escape_string_warning;
 static YY_BUFFER_STATE scanbufhandle;
 static char *scanbuf;
 
index 563a891bc66332ae30beff7edb9e01b4624bb363..9bcf99448031bdfc37c098a98403f05688fda462 100644 (file)
@@ -1,4 +1,4 @@
-/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/preproc.y,v 1.358 2008/01/14 09:43:42 meskes Exp $ */
+/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/preproc.y,v 1.359 2008/01/15 10:31:47 meskes Exp $ */
 
 /* Copyright comment */
 %{
@@ -566,7 +566,7 @@ add_typedef(char *name, char * dimension, char * length, enum ECPGttype type_enu
 %type  <str>   join_outer where_clause relation_expr sub_type arg_class
 %type  <str>   opt_column_list insert_rest InsertStmt param_name
 %type  <str>   columnList DeleteStmt UpdateStmt DeclareCursorStmt
-%type  <str>   NotifyStmt columnElem UnlistenStmt TableElement
+%type  <str>   NotifyStmt columnElem UnlistenStmt TableElement fetch_count
 %type  <str>   copy_delimiter ListenStmt CopyStmt copy_file_name opt_binary
 %type  <str>   FetchStmt from_in CreateOpClassStmt returning_clause
 %type  <str>   ClosePortalStmt DropStmt VacuumStmt AnalyzeStmt opt_verbose
@@ -2337,61 +2337,32 @@ FetchStmt: FETCH fetch_direction from_in name ecpg_into
                        { $$ = cat2_str(make_str("move"), $2); }
                ;
 
-fetch_direction:  NEXT                 { $$ = make_str("next"); }
-               | PRIOR                 { $$ = make_str("prior"); }
-               | FIRST_P               { $$ = make_str("first"); }
-               | LAST_P                { $$ = make_str("last"); }
-               | ABSOLUTE_P IntConst   { 
-                                         if ($2[1] == '$')
-                                         {
-                                                mmerror(PARSE_ERROR, ET_ERROR, "fetch/move count must not be a variable, ignoring it.\n");
-                                                $$ = make_str("absolute");
-                                         }
-                                         else
-                                               $$ = cat2_str(make_str("absolute"), $2);
-                                       }
-               | RELATIVE_P IntConst   { 
-                                         if ($2[1] == '$')
-                                         {
-                                               mmerror(PARSE_ERROR, ET_ERROR, "fetch/move count must not be a variable, ignoring it.\n");
-                                               $$ = make_str("relative");
-                                         }
-                                         else
-                                               $$ = cat2_str(make_str("relative"), $2);
+fetch_direction:  NEXT                         { $$ = make_str("next"); }
+               | PRIOR                         { $$ = make_str("prior"); }
+               | FIRST_P                       { $$ = make_str("first"); }
+               | LAST_P                        { $$ = make_str("last"); }
+               | ABSOLUTE_P fetch_count        { $$ = cat2_str(make_str("absolute"), $2); }
+               | RELATIVE_P fetch_count        { $$ = cat2_str(make_str("relative"), $2); }
+               | fetch_count                   { $$ = $1; }
+               | ALL                           { $$ = make_str("all"); }
+               | FORWARD                       { $$ = make_str("forward"); }
+               | FORWARD fetch_count           { $$ = cat2_str(make_str("forward"), $2); }
+               | FORWARD ALL                   { $$ = make_str("forward all"); }
+               | BACKWARD                      { $$ = make_str("backward"); }
+               | BACKWARD fetch_count          { $$ = cat2_str(make_str("backward"), $2); }
+               | BACKWARD ALL                  { $$ = make_str("backward all"); }
+               ;
+
+fetch_count:   IntConst        {
+                                       if ($1[1] == '$')
+                                       {
+                                               /* a variable here has to be replaced on the client side, thus we have to use '?' here */
+                                               $$ = make_str("$0");
+                                               free($1);
                                        }
-               | IntConst              {  
-                                         if ($1[1] == '$')
-                                         {
-                                               mmerror(PARSE_ERROR, ET_ERROR, "fetch/move count must not be a variablei, ignoring it.\n");
-                                               $$ = EMPTY;
-                                         }
-                                         else
+                                       else
                                                $$ = $1;
-                                       }
-               | ALL                   { $$ = make_str("all"); }
-               | FORWARD               { $$ = make_str("forward"); }
-               | FORWARD IntConst      {  
-                                         if ($2[1] == '$')
-                                         {
-                                               mmerror(PARSE_ERROR, ET_ERROR, "fetch/move count must not be a variable, ignoring it.\n");
-                                               $$ = make_str("forward");
-                                         }
-                                         else
-                                               $$ = cat2_str(make_str("forward"), $2);
-                                       }
-               | FORWARD ALL           { $$ = make_str("forward all"); }
-               | BACKWARD              { $$ = make_str("backward"); }
-               | BACKWARD IntConst     {  
-                                         if ($2[1] == '$')
-                                         {
-                                               mmerror(PARSE_ERROR, ET_ERROR, "fetch/move count must not be a variable, ignoring it.\n");
-                                               $$ = make_str("backward");
-                                         }
-                                         else
-                                               $$ = cat2_str(make_str("backward"), $2);
-                                       }
-               | BACKWARD ALL          { $$ = make_str("backward all"); }
-               ;
+                               }
 
 from_in: IN_P                          { $$ = make_str("in"); }
                | FROM                  { $$ = make_str("from"); }
index dd04d6f14fa6494195efe9a451d00d0a9cd4f673..54d69e47abceef9af3b7dd574a970c099f13abb4 100644 (file)
 int main(int argc, char* argv[]) {
   /* exec sql begin declare section */
      
-      
+       
   
 #line 9 "fetch.pgc"
  char  str [ 25 ]    ;
  
 #line 10 "fetch.pgc"
- int  i    ;
+ int  i    ,  count   = 1 ;
 /* exec sql end declare section */
 #line 11 "fetch.pgc"
 
@@ -146,7 +146,9 @@ if (sqlca.sqlcode < 0) sqlprint();}
 #line 37 "fetch.pgc"
 
 
-  { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "fetch 1 in C", ECPGt_EOIT, 
+  { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "fetch $0 in C", 
+       ECPGt_int,&(count),(long)1,(long)1,sizeof(int), 
+       ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EOIT, 
        ECPGt_int,&(i),(long)1,(long)1,sizeof(int), 
        ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
        ECPGt_char,(str),(long)25,(long)1,(25)*sizeof(char), 
index a65d393748e90d65f136732a4c3520d515befd16..340b888048edcea5ad6b0008366e454571d76d2a 100644 (file)
@@ -7,7 +7,7 @@ EXEC SQL INCLUDE ../regression;
 int main(int argc, char* argv[]) {
   EXEC SQL BEGIN DECLARE SECTION;
     char str[25];
-    int i; 
+    int i, count=1
   EXEC SQL END DECLARE SECTION;
 
   ECPGdebug(1, stderr);
@@ -36,7 +36,7 @@ int main(int argc, char* argv[]) {
   EXEC SQL WHENEVER NOT FOUND CONTINUE;
   EXEC SQL MOVE BACKWARD 2 IN C;
 
-  EXEC SQL FETCH 1 IN C INTO :i, :str;
+  EXEC SQL FETCH :count IN C INTO :i, :str;
   printf("%d: %s\n", i, str);
 
   EXEC SQL CLOSE C;