- Accept output variables for FETCH in DECLARE statement.
authorMichael Meskes <meskes@postgresql.org>
Thu, 18 Sep 2003 13:12:23 +0000 (13:12 +0000)
committerMichael Meskes <meskes@postgresql.org>
Thu, 18 Sep 2003 13:12:23 +0000 (13:12 +0000)
- Synced parser.
- Allowed C variables to carry the name of prepared statements.
- Added Informix handling of datatype converion errors.

src/interfaces/ecpg/ChangeLog
src/interfaces/ecpg/ecpglib/data.c
src/interfaces/ecpg/ecpglib/execute.c
src/interfaces/ecpg/preproc/preproc.y

index 902b73fd8ba7f5ca147dada1be929705b8adebf2..66aab16799368ab9ed8c30f64ac269e28f75e0b0 100644 (file)
@@ -1622,6 +1622,19 @@ Tue Sep  9 12:13:51 CEST 2003
 Wed Sep 10 20:01:49 CEST 2003
 
    - Some files still had uppercase typenames
+   
+Mon Sep 15 18:09:42 CEST 2003
+
+   - Accept output variables for FETCH in DECLARE statement.
+   
+Tue Sep 16 07:56:14 CEST 2003
+
+   - Synced parser.
+   - Allowed C variables to carry the name of prepared statements.
+   
+Thu Sep 18 14:54:47 CEST 2003
+
+   - Added Informix handling of datatype converion errors.
    - Set ecpg version to 3.0.0
    - Set ecpg library to 4.0.0
    - Set pgtypes library to 1.0.0
index 4bfcb128ba41989f0750e4aae947bde8a86e6d0c..dfe6e6e6e5e77ef176b304b2e65df650aad2be07 100644 (file)
@@ -1,4 +1,4 @@
-/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/data.c,v 1.17 2003/09/09 10:46:37 meskes Exp $ */
+/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/data.c,v 1.18 2003/09/18 13:12:23 meskes Exp $ */
 
 #define POSTGRES_ECPG_INTERNAL
 #include "postgres_fe.h"
@@ -390,6 +390,21 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno,
                    else
                        nres = PGTYPESnumeric_from_asc(pval, &scan_length);
 
+                   /* did we get an error? */
+                   if (errno != 0)
+                   {
+                       if (INFORMIX_MODE(compat))
+                       {
+                           /* Informix wants its own NULL value here instead of an error */
+                           ECPGset_informix_null(ECPGt_numeric, &nres);
+                           return (true);
+                       }
+                       else
+                       {
+                           ECPGraise(lineno, ECPG_NUMERIC_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
+                           return (false);
+                       }
+                   }
                    if (isarray && *scan_length == '"')
                        scan_length++;
 
@@ -417,6 +432,21 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno,
                    else
                        ires = PGTYPESinterval_from_asc(pval, &scan_length);
 
+                   /* did we get an error? */
+                   if (errno != 0)
+                   {
+                       if (INFORMIX_MODE(compat))
+                       {
+                           /* Informix wants its own NULL value here instead of an error */
+                           ECPGset_informix_null(ECPGt_interval, &ires);
+                           return (true);
+                       }
+                       else
+                       {
+                           ECPGraise(lineno, ECPG_INTERVAL_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
+                           return (false);
+                       }
+                   }
                    if (isarray && *scan_length == '"')
                        scan_length++;
 
@@ -440,6 +470,22 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno,
                    else
                        ddres = PGTYPESdate_from_asc(pval, &scan_length);
 
+                   /* did we get an error? */
+                   if (errno != 0)
+                   {
+                       if (INFORMIX_MODE(compat))
+                       {
+                           /* Informix wants its own NULL value here instead of an error */
+                           ECPGset_informix_null(ECPGt_date, &ddres);
+                           return (true);
+                       }
+                       else
+                       {
+                           ECPGraise(lineno, ECPG_DATE_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
+                           return (false);
+                       }
+                   }
+                   
                    if (isarray && *scan_length == '"')
                        scan_length++;
 
@@ -462,6 +508,21 @@ ECPGget_data(const PGresult *results, int act_tuple, int act_field, int lineno,
                    else
                        tres = PGTYPEStimestamp_from_asc(pval, &scan_length);
 
+                   /* did we get an error? */
+                   if (errno != 0)
+                   {
+                       if (INFORMIX_MODE(compat))
+                       {
+                           /* Informix wants its own NULL value here instead of an error */
+                           ECPGset_informix_null(ECPGt_timestamp, &tres);
+                           return (true);
+                       }
+                       else
+                       {
+                           ECPGraise(lineno, ECPG_TIMESTAMP_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval);
+                           return (false);
+                       }
+                   }
                    if (isarray && *scan_length == '"')
                        scan_length++;
 
index 6a6b4d8e465978feabc7f888c88e2585daa73f25..9f813f6be8bbf1453c6566a85f218ec52df04c2d 100644 (file)
@@ -1,4 +1,4 @@
-/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/execute.c,v 1.24 2003/09/09 10:46:37 meskes Exp $ */
+/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/execute.c,v 1.25 2003/09/18 13:12:23 meskes Exp $ */
 
 /*
  * The aim is to get a simpler inteface to the database routines.
@@ -857,7 +857,7 @@ ECPGstore_input(const struct statement * stmt, const struct variable * var,
                            else
                                PGTYPESnumeric_from_decimal((decimal *) ((var + var->offset * element)->value), nval);
 
-                           str = PGTYPESnumeric_to_asc(nval, 0);
+                           str = PGTYPESnumeric_to_asc(nval, nval->dscale);
                            PGTYPESnumeric_free(nval);
                            slen = strlen(str);
 
@@ -879,7 +879,7 @@ ECPGstore_input(const struct statement * stmt, const struct variable * var,
                        else
                            PGTYPESnumeric_from_decimal((decimal *) (var->value), nval);
 
-                       str = PGTYPESnumeric_to_asc(nval, 0);
+                       str = PGTYPESnumeric_to_asc(nval, nval->dscale);
 
                        PGTYPESnumeric_free(nval);
                        slen = strlen(str);
index 9976f6f533395e6fb45c74e7432ece37df28be92..9ceff4e2e411af96eea3e937be50a59b4ae349d0 100644 (file)
@@ -1,4 +1,4 @@
-/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/Attic/preproc.y,v 1.254 2003/09/09 10:46:38 meskes Exp $ */
+/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/Attic/preproc.y,v 1.255 2003/09/18 13:12:23 meskes Exp $ */
 
 /* Copyright comment */
 %{
@@ -247,6 +247,38 @@ adjust_informix(struct arguments *list)
     return result;
 }
 
+static struct cursor *
+add_additional_variables(char *name, bool insert)
+{
+   struct cursor *ptr;
+   struct arguments *p;
+
+   for (ptr = cur; ptr != NULL; ptr=ptr->next)
+   {
+       if (strcmp(ptr->name, name) == 0)
+           break;
+   }
+
+   if (ptr == NULL)
+   {
+       snprintf(errortext, sizeof(errortext), "trying to access an undeclared cursor %s\n", name);
+       mmerror(PARSE_ERROR, ET_ERROR, errortext);
+       return NULL;
+   }
+   if (insert)
+   {
+       /* add all those input variables that were given earlier */
+       for (p = ptr->argsinsert; p; p = p->next)
+           add_variable(&argsinsert, p->variable, p->indicator);
+   }
+   else
+   {
+       /* add all those output variables that were given earlier */
+       for (p = ptr->argsresult; p; p = p->next)
+           add_variable(&argsresult, p->variable, p->indicator);
+   }
+   return ptr;
+}
 %}
 
 %union {
@@ -416,7 +448,7 @@ adjust_informix(struct arguments *list)
 %type  <str>   trim_list in_expr substr_for attrs TableFuncElement
 %type  <str>   Typename SimpleTypename Numeric opt_float opt_numeric
 %type  <str>   opt_decimal Character character opt_varying opt_charset
-%type  <str>   opt_collate opt_timezone opt_interval table_ref fetch_direction
+%type  <str>   opt_timezone opt_interval table_ref fetch_direction
 %type  <str>   row_descriptor ConstDatetime AlterDomainStmt AlterSeqStmt
 %type  <str>   SelectStmt into_clause OptTemp ConstraintAttributeSpec
 %type  <str>   opt_table opt_all sort_clause sortby_list ConstraintAttr
@@ -507,7 +539,7 @@ adjust_informix(struct arguments *list)
 %type  <str>   col_name_keyword func_name_keyword precision opt_scale
 %type  <str>   ECPGTypeName using_list ECPGColLabelCommon UsingConst
 %type  <str>   inf_val_list inf_col_list using_descriptor into_descriptor 
-%type  <str>   ecpg_into_using
+%type  <str>   ecpg_into_using prepared_name
 
 %type  <struct_union> s_struct_union_symbol
 
@@ -743,30 +775,9 @@ stmt:  AlterDatabaseSetStmt        { output_statement($1, 0, connection); }
        | ECPGOpen
        {
            struct cursor *ptr;
-           struct arguments *p;
-
-           for (ptr = cur; ptr != NULL; ptr=ptr->next)
-           {
-               if (strcmp(ptr->name, $1) == 0)
-                   break;
-           }
-
-           if (ptr == NULL)
-           {
-               snprintf(errortext, sizeof(errortext), "trying to open undeclared cursor %s\n", $1);
-               mmerror(PARSE_ERROR, ET_ERROR, errortext);
-           }
-           else
-           {
-               /* merge variables given in prepare statement with those given here */
-               for (p = ptr->argsinsert; p; p = p->next)
-                   append_variable(&argsinsert, p->variable, p->indicator);
-
-               for (p = ptr->argsresult; p; p = p->next)
-                   add_variable(&argsresult, p->variable, p->indicator);
 
+           if ((ptr = add_additional_variables($1, true)) != NULL)
                output_statement(mm_strdup(ptr->command), 0, ptr->connection ? mm_strdup(ptr->connection) : NULL);
-           }
        }
        | ECPGPrepare
        {
@@ -1291,14 +1302,9 @@ TableElement:  columnDef     { $$ = $1; }
        | TableConstraint   { $$ = $1; }
        ;
 
-columnDef: ColId Typename ColQualList opt_collate
+columnDef: ColId Typename ColQualList 
        {
-           if (strlen($4) > 0)
-           {
-               snprintf(errortext, sizeof(errortext), "Currently unsupported CREATE TABLE / COLLATE %s will be passed to backend", $4);
-               mmerror(PARSE_ERROR, ET_WARNING, errortext);
-           }
-           $$ = cat_str(4, $1, $2, $3, $4);
+           $$ = cat_str(3, $1, $2, $3);
        }
        ;
 
@@ -1823,21 +1829,45 @@ TruncateStmt:  TRUNCATE opt_table qualified_name
  * translate it to the PGSQL syntax. */
  
 FetchStmt: FETCH fetch_direction from_in name ecpg_into_using
-           { $$ = cat_str(4, make_str("fetch"), $2, $3, $4); }
+           {
+               add_additional_variables($4, false);
+               $$ = cat_str(4, make_str("fetch"), $2, $3, $4);
+           }
        | FETCH fetch_direction name ecpg_into_using
-           { $$ = cat_str(4, make_str("fetch"), $2, make_str("from"), $3); }
+           {
+               add_additional_variables($3, false);
+               $$ = cat_str(4, make_str("fetch"), $2, make_str("from"), $3);
+           }
        | FETCH from_in name ecpg_into_using
-           { $$ = cat_str(3, make_str("fetch"), $2, $3); }
+           {
+                   add_additional_variables($3, false);
+               $$ = cat_str(3, make_str("fetch"), $2, $3);
+           }
        | FETCH name ecpg_into_using
-           { $$ = cat2_str(make_str("fetch"), $2); }
+           {
+                   add_additional_variables($2, false);
+               $$ = cat2_str(make_str("fetch"), $2);
+           }
        | FETCH fetch_direction from_in name
-           { $$ = cat_str(4, make_str("fetch"), $2, $3, $4); }
+           {
+                   add_additional_variables($4, false);
+               $$ = cat_str(4, make_str("fetch"), $2, $3, $4);
+           }
        | FETCH fetch_direction name
-           { $$ = cat_str(4, make_str("fetch"), $2, make_str("from"), $3); }
+           {
+                   add_additional_variables($3, false);
+               $$ = cat_str(4, make_str("fetch"), $2, make_str("from"), $3);
+           }
        | FETCH from_in name 
-           { $$ = cat_str(3, make_str("fetch"), $2, $3); }
+           {
+               add_additional_variables($3, false);
+               $$ = cat_str(3, make_str("fetch"), $2, $3);
+           }
        | FETCH name 
-           { $$ = cat2_str(make_str("fetch"), $2); }
+           {
+                   add_additional_variables($2, false);
+               $$ = cat2_str(make_str("fetch"), $2);
+           }
        | MOVE fetch_direction from_in name
            { $$ = cat_str(4, make_str("move"), $2, $3, $4); }
        | MOVE name
@@ -2487,9 +2517,9 @@ DropdbStmt: DROP DATABASE database_name
  *
  *****************************************************************************/
 
-CreateDomainStmt:  CREATE DOMAIN_P any_name opt_as Typename ColQualList opt_collate
+CreateDomainStmt:  CREATE DOMAIN_P any_name opt_as Typename ColQualList
            {
-               $$ = cat_str(6, make_str("create domain"), $3, $4, $5, $6, $7);
+               $$ = cat_str(55555, make_str("create domain"), $3, $4, $5, $6);
            }
        ;
 
@@ -3290,12 +3320,6 @@ opt_charset:  CHARACTER SET ColId
            { $$ = EMPTY; }
        ;
 
-opt_collate:  COLLATE ColId
-           { $$ = cat2_str(make_str("collate"), $2); }
-       | /*EMPTY*/
-           { $$ = EMPTY; }
-       ;
-
 ConstDatetime: TIMESTAMP '(' PosIntConst ')' opt_timezone
            { $$ = cat_str(4, make_str("timestamp("), $3, make_str(")"), $5); }
        | TIMESTAMP opt_timezone
@@ -4330,7 +4354,7 @@ opt_options: Op ColId
  * Declare a prepared cursor. The syntax is different from the standard
  * declare statement, so we create a new rule.
  */
-ECPGCursorStmt:  DECLARE name cursor_options CURSOR opt_hold FOR ident
+ECPGCursorStmt:  DECLARE name cursor_options CURSOR opt_hold FOR prepared_name
        {
            struct cursor *ptr, *this;
            struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable));
@@ -4357,8 +4381,8 @@ ECPGCursorStmt:  DECLARE name cursor_options CURSOR opt_hold FOR ident
            thisquery->type = &ecpg_query;
            thisquery->brace_level = 0;
            thisquery->next = NULL;
-           thisquery->name = (char *) mm_alloc(sizeof("ECPGprepared_statement(\"\")") + strlen($7));
-           sprintf(thisquery->name, "ECPGprepared_statement(\"%s\")", $7);
+           thisquery->name = (char *) mm_alloc(sizeof("ECPGprepared_statement()") + strlen($7));
+           sprintf(thisquery->name, "ECPGprepared_statement(%s)", $7);
 
            this->argsinsert = NULL;
            add_variable(&(this->argsinsert), thisquery, &no_indicator);
@@ -4373,9 +4397,9 @@ ECPGCursorStmt:  DECLARE name cursor_options CURSOR opt_hold FOR ident
  * the exec sql deallocate prepare command to deallocate a previously
  * prepared statement
  */
-ECPGDeallocate: DEALLOCATE PREPARE ident
+ECPGDeallocate: DEALLOCATE PREPARE prepared_name
            { $$ = $3; }
-       | DEALLOCATE ident
+       | DEALLOCATE prepared_name
            { $$ = $2; }
        ;
 
@@ -5170,8 +5194,7 @@ opt_pointer: /*EMPTY*/                { $$ = EMPTY; }
        ;
 
 /*
- * As long as the prepare statement is not supported by the backend, we will
- * try to simulate it here so we get dynamic SQL
+ * We try to simulate the correct DECLARE syntax here so we get dynamic SQL
  */
 ECPGDeclare: DECLARE STATEMENT ident
        {
@@ -5211,15 +5234,15 @@ ECPGExecute : EXECUTE IMMEDIATE execstring
 
            $$ = make_str("?");
        }
-       | EXECUTE name
+       | EXECUTE prepared_name
        {
            struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable));
 
            thisquery->type = &ecpg_query;
            thisquery->brace_level = 0;
            thisquery->next = NULL;
-           thisquery->name = (char *) mm_alloc(sizeof("ECPGprepared_statement(\"\")") + strlen($2));
-           sprintf(thisquery->name, "ECPGprepared_statement(\"%s\")", $2);
+           thisquery->name = (char *) mm_alloc(sizeof("ECPGprepared_statement()") + strlen($2));
+           sprintf(thisquery->name, "ECPGprepared_statement(%s)", $2);
 
            add_variable(&argsinsert, thisquery, &no_indicator);
        }
@@ -5242,6 +5265,9 @@ execstring: char_variable
            { $$ = make3_str(make_str("\""), $1, make_str("\"")); }
        ;
 
+prepared_name: name        { $$ = make3_str(make_str("\""), $1, make_str("\"")); }
+       | char_variable { $$ = $1; }
+
 /*
  * the exec sql free command to deallocate a previously
  * prepared statement
@@ -5304,8 +5330,8 @@ UsingConst: AllConst
  *
  * It is supported now but not usable yet by ecpg.
  */
-ECPGPrepare: PREPARE name FROM execstring
-           { $$ = cat2_str(make3_str(make_str("\""), $2, make_str("\",")), $4); }
+ECPGPrepare: PREPARE prepared_name FROM execstring
+           { $$ = cat_str(3, $2, make_str(","), $4); }
        ;
 /* 
  * We accept descibe but do nothing with it so far.
@@ -6167,8 +6193,8 @@ indicator: CVARIABLE              { check_indicator((find_variable($1))->type); $$ = $1; }
        | SQL_INDICATOR name        { check_indicator((find_variable($2))->type); $$ = $2; }
        ;
 
-ident: IDENT                       { $$ = $1; }
-       | CSTRING                   { $$ = make3_str(make_str("\""), $1, make_str("\"")); }
+ident: IDENT                   { $$ = $1; }
+       | CSTRING           { $$ = make3_str(make_str("\""), $1, make_str("\"")); }
        ;
 
 quoted_ident_stringvar: name