Added files containing changes between gram.y and preproc.y.
authorMichael Meskes
Fri, 14 Nov 2008 10:03:33 +0000 (10:03 +0000)
committerMichael Meskes
Fri, 14 Nov 2008 10:03:33 +0000 (10:03 +0000)
src/interfaces/ecpg/preproc/ecpg.addons [new file with mode: 0644]
src/interfaces/ecpg/preproc/ecpg.header [new file with mode: 0644]
src/interfaces/ecpg/preproc/ecpg.tokens [new file with mode: 0644]
src/interfaces/ecpg/preproc/ecpg.trailer [new file with mode: 0644]
src/interfaces/ecpg/preproc/ecpg.type [new file with mode: 0644]

diff --git a/src/interfaces/ecpg/preproc/ecpg.addons b/src/interfaces/ecpg/preproc/ecpg.addons
new file mode 100644 (file)
index 0000000..e060ceb
--- /dev/null
@@ -0,0 +1,382 @@
+/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg.addons,v 1.1 2008/11/14 10:03:33 meskes Exp $ */
+
+ECPG: stmtClosePortalStmt block
+   {
+       if (INFORMIX_MODE)
+       {
+           if (pg_strcasecmp($1+strlen("close "), "database") == 0)
+           {
+               if (connection)
+                   mmerror(PARSE_ERROR, ET_ERROR, "no at option for close database statement\n");
+
+               fprintf(yyout, "{ ECPGdisconnect(__LINE__, \"CURRENT\");");
+               whenever_action(2);
+               free($1);
+               break;
+           }
+       }
+
+       output_statement($1, 0, ECPGst_normal);
+   }
+ECPG: stmtDeallocateStmt block
+   {
+       if (connection)
+           mmerror(PARSE_ERROR, ET_ERROR, "no at option for deallocate statement\n");
+
+       output_deallocate_prepare_statement($1);
+   }
+ECPG: stmtDeclareCursorStmt block
+   { output_simple_statement($1); }
+ECPG: stmtDeleteStmt block
+ECPG: stmtDiscardStmt block
+ECPG: stmtFetchStmt block
+ECPG: stmtInsertStmt block
+ECPG: stmtSelectStmt block
+ECPG: stmtUpdateStmt block
+   { output_statement($1, 1, ECPGst_normal); }
+ECPG: stmtExecuteStmt block
+   { output_statement($1, 1, ECPGst_execute); }
+ECPG: stmtPrepareStmt block
+   {
+       if ($1.type == NULL || strlen($1.type) == 0)
+           output_prepare_statement($1.name, $1.stmt);
+       else    
+           output_statement(cat_str(5, make_str("prepare"), $1.name, $1.type, make_str("as"), $1.stmt), 0, ECPGst_normal);
+   }
+ECPG: stmtTransactionStmt block
+   {
+       fprintf(yyout, "{ ECPGtrans(__LINE__, %s, \"%s\");", connection ? connection : "NULL", $1);
+       whenever_action(2);
+       free($1);
+   }
+ECPG: stmtViewStmt rule
+   | ECPGAllocateDescr
+   {
+       fprintf(yyout,"ECPGallocate_desc(__LINE__, %s);",$1);
+       whenever_action(0);
+       free($1);
+   }
+   | ECPGConnect
+   {
+       if (connection)
+           mmerror(PARSE_ERROR, ET_ERROR, "no at option for connect statement\n");
+
+       fprintf(yyout, "{ ECPGconnect(__LINE__, %d, %s, %d); ", compat, $1, autocommit);
+       reset_variables();
+       whenever_action(2);
+       free($1);
+   }
+   | ECPGCursorStmt
+   {
+       output_simple_statement($1);
+   }
+   | ECPGDeallocateDescr
+   {
+       if (connection)
+           mmerror(PARSE_ERROR, ET_ERROR, "no at option for deallocate statement\n");
+       fprintf(yyout,"ECPGdeallocate_desc(__LINE__, %s);",$1);
+       whenever_action(0);
+       free($1);
+   }
+   | ECPGDeclare
+   {
+       output_simple_statement($1);
+   }
+   | ECPGDescribe
+   {
+       fprintf(yyout, "{ ECPGdescribe(__LINE__, %s,", $1);
+       dump_variables(argsresult, 1);
+       fputs("ECPGt_EORT);", yyout);
+       fprintf(yyout, "}");
+       output_line_number();
+
+       free($1);
+   }
+   | ECPGDisconnect
+   {
+       if (connection)
+           mmerror(PARSE_ERROR, ET_ERROR, "no at option for disconnect statement\n");
+
+       fprintf(yyout, "{ ECPGdisconnect(__LINE__, %s);",
+               $1 ? $1 : "\"CURRENT\"");
+       whenever_action(2);
+       free($1);
+   }
+   | ECPGExecuteImmediateStmt  { output_statement($1, 0, ECPGst_exec_immediate); }
+   | ECPGFree
+   {
+       const char *con = connection ? connection : "NULL";
+       if (strcmp($1, "all"))
+           fprintf(yyout, "{ ECPGdeallocate(__LINE__, %d, %s, \"%s\");", compat, con, $1);
+       else
+           fprintf(yyout, "{ ECPGdeallocate_all(__LINE__, %d, %s);", compat, con);
+
+       whenever_action(2);
+       free($1);
+   }
+   | ECPGGetDescriptor
+   {
+       lookup_descriptor($1.name, connection);
+       output_get_descr($1.name, $1.str);
+       free($1.name);
+       free($1.str);
+   }
+   | ECPGGetDescriptorHeader
+   {
+       lookup_descriptor($1, connection);
+       output_get_descr_header($1);
+       free($1);
+   }
+   | ECPGOpen
+   {
+       struct cursor *ptr;
+
+       if ((ptr = add_additional_variables($1, true)) != NULL)
+       {
+           connection = ptr->connection ? mm_strdup(ptr->connection) : NULL;
+           output_statement(mm_strdup(ptr->command), 0, 0);
+           ptr->opened = true;
+       }
+   }
+   | ECPGSetAutocommit
+   {
+       fprintf(yyout, "{ ECPGsetcommit(__LINE__, \"%s\", %s);", $1, connection ? connection : "NULL");
+       whenever_action(2);
+       free($1);
+   }
+   | ECPGSetConnection
+   {
+       if (connection)
+           mmerror(PARSE_ERROR, ET_ERROR, "no at option for set connection statement\n");
+
+       fprintf(yyout, "{ ECPGsetconn(__LINE__, %s);", $1);
+       whenever_action(2);
+       free($1);
+   }
+   | ECPGSetDescriptor
+   {
+       lookup_descriptor($1.name, connection);
+       output_set_descr($1.name, $1.str);
+       free($1.name);
+       free($1.str);
+   }
+   | ECPGSetDescriptorHeader
+   {
+       lookup_descriptor($1, connection);
+       output_set_descr_header($1);
+       free($1);
+   }
+   | ECPGTypedef
+   {
+       if (connection)
+           mmerror(PARSE_ERROR, ET_ERROR, "no at option for typedef statement\n");
+
+       fprintf(yyout, "%s", $1);
+       free($1);
+       output_line_number();
+   }
+   | ECPGVar
+   {
+       if (connection)
+           mmerror(PARSE_ERROR, ET_ERROR, "no at option for var statement\n");
+
+       output_simple_statement($1);
+   }
+   | ECPGWhenever
+   {
+       if (connection)
+           mmerror(PARSE_ERROR, ET_ERROR, "no at option for whenever statement\n");
+
+       output_simple_statement($1);
+   }
+ECPG: CopyStmtCOPYopt_binaryqualified_nameopt_column_listopt_oidscopy_fromcopy_file_namecopy_delimiteropt_withcopy_opt_list addon
+           if (strcmp($6, "to") == 0 && strcmp($7, "stdin") == 0)
+               mmerror(PARSE_ERROR, ET_ERROR, "copy to stdin not possible\n");
+           else if (strcmp($6, "from") == 0 && strcmp($7, "stdout") == 0)
+               mmerror(PARSE_ERROR, ET_ERROR, "copy from stdout not possible\n");
+           else if (strcmp($6, "from") == 0 && strcmp($7, "stdin") == 0)
+               mmerror(PARSE_ERROR, ET_WARNING, "copy from stdin not implemented\n");
+ECPG: CopyStmtCOPYselect_with_parensTOcopy_file_nameopt_withcopy_opt_list addon
+           if (strcmp($4, "stdin") == 0)
+               mmerror(PARSE_ERROR, ET_ERROR, "copy to stdin not possible\n");
+ECPG: ConstraintAttributeSpecConstraintDeferrabilitySpecConstraintTimeSpec addon
+           if (strcmp($1, "deferrable") != 0 && strcmp($2, "initially deferrable") == 0 )
+               mmerror(PARSE_ERROR, ET_ERROR, "INITIALLY DEFERRED constraint must be DEFERRABLE\n");
+ECPG: ConstraintAttributeSpecConstraintTimeSpecConstraintDeferrabilitySpec addon
+           if (strcmp($2, "deferrable") != 0 && strcmp($1, "initially deferrable") == 0 )
+               mmerror(PARSE_ERROR, ET_ERROR, "INITIALLY DEFERRED constraint must be DEFERRABLE\n");
+ECPG: var_valueNumericOnly addon
+ECPG: fetch_directionSignedIconst addon
+       if ($1[1] == '$')
+       {
+           free($1);
+           $1 = make_str("$0");
+       }
+ECPG: fetch_directionABSOLUTE_PSignedIconst addon
+ECPG: fetch_directionRELATIVE_PSignedIconst addon
+ECPG: fetch_directionFORWARDSignedIconst addon
+ECPG: fetch_directionBACKWARDSignedIconst addon
+       if ($2[1] == '$')
+       {
+           free($2);
+           $2 = make_str("$0");
+       }
+ECPG: PrepareStmtPREPAREprepared_nameprep_type_clauseASPreparableStmt block
+   {
+       $$.name = $2;
+       $$.type = $3;
+       $$.stmt = cat_str(3, make_str("\""), $5, make_str("\""));
+   }
+   | PREPARE prepared_name FROM execstring
+   {
+       $$.name = $2;
+       $$.type = NULL;
+       $$.stmt = $4;
+   }
+ECPG: ExecuteStmtEXECUTEprepared_nameexecute_param_clauseexecute_rest block
+   { $$ = $2; }
+ECPG: DeclareCursorStmtDECLAREnamecursor_optionsCURSORopt_holdFORSelectStmt block
+   {
+       struct cursor *ptr, *this;
+
+       for (ptr = cur; ptr != NULL; ptr = ptr->next)
+       {
+           if (strcmp($2, ptr->name) == 0)
+               mmerror(PARSE_ERROR, ET_ERROR, "cursor \"%s\" already defined\n", $2);
+       }
+
+       this = (struct cursor *) mm_alloc(sizeof(struct cursor));
+
+       this->next = cur;
+       this->name = $2;
+       this->connection = connection;
+       this->opened = false;
+       this->command =  cat_str(7, make_str("declare"), mm_strdup($2), $3, make_str("cursor"), $5, make_str("for"), $7);
+       this->argsinsert = argsinsert;
+       this->argsresult = argsresult;
+       argsinsert = argsresult = NULL;
+       cur = this;
+
+       if (INFORMIX_MODE)
+           $$ = cat_str(5, adjust_informix(this->argsinsert), adjust_informix(this->argsresult), make_str("/*"), mm_strdup(this->command), make_str("*/"));
+       else
+           $$ = cat_str(3, make_str("/*"), mm_strdup(this->command), make_str("*/"));
+   }
+ECPG: opt_hold block
+   {
+       if (compat == ECPG_COMPAT_INFORMIX_SE && autocommit == true)
+           $$ = make_str("with hold");
+       else
+           $$ = EMPTY;
+   }
+ECPG: into_clauseINTOOptTempTableName block
+                   {
+                       FoundInto = 1;
+                       $$= cat2_str(make_str("into"), $2);
+                   }
+   | ecpg_into                     { $$ = EMPTY; }
+ECPG: table_refselect_with_parens addon
+       mmerror(PARSE_ERROR, ET_ERROR, "sub-SELECT in FROM must have an alias\n");
+ECPG: TypenameSimpleTypenameopt_array_bounds block
+   {   $$ = cat2_str($1, $2.str); }
+ECPG: TypenameSETOFSimpleTypenameopt_array_bounds block
+   {   $$ = $$ = cat_str(3, make_str("setof"), $2, $3.str); }
+ECPG: opt_array_boundsopt_array_bounds'['']' block
+   {
+       $$.index1 = $1.index1;
+       $$.index2 = $1.index2;
+       if (strcmp($$.index1, "-1") == 0)
+           $$.index1 = make_str("0");
+       else if (strcmp($1.index2, "-1") == 0)
+           $$.index2 = make_str("0");
+       $$.str = cat_str(2, $1.str, make_str("[]"));
+   }
+   | opt_array_bounds '[' Iresult ']'
+   {
+       $$.index1 = $1.index1;
+       $$.index2 = $1.index2;
+       if (strcmp($1.index1, "-1") == 0)
+           $$.index1 = strdup($3);
+       else if (strcmp($1.index2, "-1") == 0)
+           $$.index2 = strdup($3);
+       $$.str = cat_str(4, $1.str, make_str("["), $3, make_str("]"));
+   }
+ECPG: opt_array_bounds
+   {
+       $$.index1 = make_str("-1");
+       $$.index2 = make_str("-1");
+       $$.str= EMPTY;
+   }
+ECPG: IconstICONST block
+   { $$ = make_name(); }
+ECPG: AexprConstNULL_P rule
+   | civar         { $$ = $1; }
+   | civarind      { $$ = $1; }
+ECPG: ColIdcol_name_keyword rule
+   | ECPGKeywords                  { $$ = $1; }
+   | ECPGCKeywords                 { $$ = $1; }
+   | CHAR_P                        { $$ = make_str("char"); }
+   | VALUES                        { $$ = make_str("values"); }
+ECPG: type_function_nametype_func_name_keyword rule
+   | ECPGKeywords                          { $$ = $1; }
+   | ECPGTypeName                          { $$ = $1; }
+   | ECPGCKeywords                         { $$ = $1; }
+ECPG: VariableShowStmtSHOWALL block
+   {
+       mmerror(PARSE_ERROR, ET_ERROR, "SHOW ALL not implemented\n");
+       $$ = EMPTY;
+   }
+ECPG: FetchStmtFETCHfetch_directionfrom_inname block 
+   {
+       add_additional_variables($4, false);
+       $$ = cat_str(4, make_str("fetch"), $2, $3, $4);
+   }
+ECPG: FetchStmtFETCHname block
+   {
+       add_additional_variables($2, false);
+       $$ = cat_str(2, make_str("fetch"), $2);
+   }
+ECPG: FetchStmtMOVEname rule
+   | FETCH fetch_direction from_in name ecpg_into
+       {
+           add_additional_variables($4, false);
+           $$ = cat_str(4, make_str("fetch"), $2, $3, $4);
+       }
+   | FETCH fetch_direction name ecpg_into
+       {
+           add_additional_variables($3, false);
+           $$ = cat_str(4, make_str("fetch"), $2, make_str("from"), $3);
+       }
+   | FETCH from_in name ecpg_into
+       {
+           add_additional_variables($3, false);
+           $$ = cat_str(3, make_str("fetch"), $2, $3);
+       }
+   | FETCH name ecpg_into
+       {
+           add_additional_variables($2, false);
+           $$ = cat2_str(make_str("fetch"), $2);
+       }
+   | FETCH fetch_direction name
+       {
+           add_additional_variables($3, false);
+           $$ = cat_str(4, make_str("fetch"), $2, make_str("from"), $3);
+       }
+   | FETCH from_in name
+       {
+           add_additional_variables($3, false);
+           $$ = cat_str(3, make_str("fetch"), $2, $3);
+       }
+ECPG: SpecialRuleRelationOLD addon
+       if (!QueryIsRule)
+           mmerror(PARSE_ERROR, ET_ERROR, "OLD used in non-rule query\n");
+ECPG: SpecialRuleRelationNEW addon
+       if (!QueryIsRule)
+           mmerror(PARSE_ERROR, ET_ERROR, "NEW used in non-rule query\n");
+ECPG: select_limitLIMITselect_limit_value','select_offset_value block
+        {
+                mmerror(PARSE_ERROR, ET_WARNING, "no longer supported LIMIT #,# syntax passed to backend");
+                $$ = cat_str(4, make_str("limit"), $2, make_str(","), $4);
+        }
+ECPG: SignedIconstIconst rule
+   | civar { $$ = $1; }
diff --git a/src/interfaces/ecpg/preproc/ecpg.header b/src/interfaces/ecpg/preproc/ecpg.header
new file mode 100644 (file)
index 0000000..6e47fa0
--- /dev/null
@@ -0,0 +1,390 @@
+/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg.header,v 1.1 2008/11/14 10:03:33 meskes Exp $ */
+
+/* Copyright comment */
+%{
+#include "postgres_fe.h"
+
+#include "extern.h"
+#include 
+
+/* Location tracking support --- simpler than bison's default */
+#define YYLLOC_DEFAULT(Current, Rhs, N) \
+   do { \
+                if (N) \
+           (Current) = (Rhs)[1]; \
+       else \
+               (Current) = (Rhs)[0]; \
+   } while (0)
+
+/*
+ * The %name-prefix option below will make bison call base_yylex, but we
+ * really want it to call filtered_base_yylex (see parser.c).
+ */
+#define base_yylex filtered_base_yylex
+
+/*
+ * Variables containing simple states.
+ */
+int struct_level = 0;
+int braces_open; /* brace level counter */
+int ecpg_informix_var = 0;
+char   *connection = NULL;
+char   *input_filename = NULL;
+
+static int QueryIsRule = 0, FoundInto = 0;
+static int initializer = 0;
+static int pacounter = 1;
+static char     pacounter_buffer[sizeof(int) * CHAR_BIT * 10 / 3]; /* a rough guess at the size we need */
+static struct this_type actual_type[STRUCT_DEPTH];
+static char *actual_startline[STRUCT_DEPTH];
+
+/* temporarily store struct members while creating the data structure */
+struct ECPGstruct_member *struct_member_list[STRUCT_DEPTH] = { NULL };
+
+/* also store struct type so we can do a sizeof() later */
+static char *ECPGstruct_sizeof = NULL;
+
+/* for forward declarations we have to store some data as well */
+static char *forward_name = NULL;
+
+struct ECPGtype ecpg_no_indicator = {ECPGt_NO_INDICATOR, NULL, NULL, {NULL}, 0};
+struct variable no_indicator = {"no_indicator", &ecpg_no_indicator, 0, NULL};
+
+struct ECPGtype ecpg_query = {ECPGt_char_variable, NULL, NULL, {NULL}, 0};
+
+/*
+ * Handle parsing errors and warnings
+ */
+void
+mmerror(int error_code, enum errortype type, char * error, ...)
+{
+   va_list ap;
+
+   /* internationalize the error message string */
+   error = _(error);
+
+   fprintf(stderr, "%s:%d: ", input_filename, yylineno);
+
+   switch(type)
+   {
+       case ET_WARNING:
+           fprintf(stderr, _("WARNING: "));
+           break;
+       case ET_ERROR:
+       case ET_FATAL:
+           fprintf(stderr, _("ERROR: "));
+           break;
+   }
+
+   va_start(ap, error);
+   vfprintf(stderr, error, ap);
+   va_end(ap);
+
+   fprintf(stderr, "\n");
+
+   switch(type)
+   {
+       case ET_WARNING:
+           break;
+       case ET_ERROR:
+           ret_value = error_code;
+           break;
+       case ET_FATAL:
+           if (yyin)
+               fclose(yyin);
+           if (yyout)
+               fclose(yyout);
+           if (unlink(output_filename) != 0 && *output_filename != '-')
+                   fprintf(stderr, _("could not remove output file \"%s\"\n"), output_filename);
+           exit(error_code);
+   }
+}
+
+/*
+ * string concatenation
+ */
+
+static char *
+cat2_str(char *str1, char *str2)
+{
+   char * res_str  = (char *)mm_alloc(strlen(str1) + strlen(str2) + 2);
+
+   strcpy(res_str, str1);
+   strcat(res_str, " ");
+   strcat(res_str, str2);
+   free(str1);
+   free(str2);
+   return(res_str);
+}
+
+static char *
+cat_str(int count, ...)
+{
+   va_list     args;
+   int         i;
+   char        *res_str;
+
+   va_start(args, count);
+
+   res_str = va_arg(args, char *);
+
+   /* now add all other strings */
+   for (i = 1; i < count; i++)
+       res_str = cat2_str(res_str, va_arg(args, char *));
+
+   va_end(args);
+
+   return(res_str);
+}
+
+char *
+make_str(const char *str)
+{
+   char * res_str = (char *)mm_alloc(strlen(str) + 1);
+
+   strcpy(res_str, str);
+   return res_str;
+}
+
+static char *
+make2_str(char *str1, char *str2)
+{
+   char * res_str  = (char *)mm_alloc(strlen(str1) + strlen(str2) + 1);
+
+   strcpy(res_str, str1);
+   strcat(res_str, str2);
+   free(str1);
+   free(str2);
+   return(res_str);
+}
+
+static char *
+make3_str(char *str1, char *str2, char *str3)
+{
+   char * res_str  = (char *)mm_alloc(strlen(str1) + strlen(str2) +strlen(str3) + 1);
+
+   strcpy(res_str, str1);
+   strcat(res_str, str2);
+   strcat(res_str, str3);
+   free(str1);
+   free(str2);
+   free(str3);
+   return(res_str);
+}
+
+/* and the rest */
+static char *
+make_name(void)
+{
+   char * name = (char *)mm_alloc(yyleng + 1);
+
+   strncpy(name, yytext, yyleng);
+   name[yyleng] = '\0';
+   return(name);
+}
+
+static char *
+create_questionmarks(char *name, bool array)
+{
+   struct variable *p = find_variable(name);
+   int count;
+   char *result = EMPTY;
+
+   /* In case we have a struct, we have to print as many "?" as there are attributes in the struct
+    * An array is only allowed together with an element argument
+    * This is essantially only used for inserts, but using a struct as input parameter is an error anywhere else
+    * so we don't have to worry here. */
+
+   if (p->type->type == ECPGt_struct || (array && p->type->type == ECPGt_array && p->type->u.element->type == ECPGt_struct))
+   {
+       struct ECPGstruct_member *m;
+
+       if (p->type->type == ECPGt_struct)
+           m = p->type->u.members;
+       else
+           m = p->type->u.element->u.members;
+
+       for (count = 0; m != NULL; m=m->next, count++);
+   }
+   else
+       count = 1;
+
+   for (; count > 0; count --)
+   {
+       sprintf(pacounter_buffer, "$%d", pacounter++);
+       result = cat_str(3, result, strdup(pacounter_buffer), make_str(" , "));
+   }
+
+   /* removed the trailing " ," */
+
+   result[strlen(result)-3] = '\0';
+   return(result);
+}
+
+static char *
+adjust_informix(struct arguments *list)
+{
+   /* Informix accepts DECLARE with variables that are out of scope when OPEN is called.
+    * for instance you can declare variables in a function, and then subsequently use them
+    * {
+    *      declare_vars();
+    *      exec sql ... which uses vars declared in the above function
+    *
+    * This breaks standard and leads to some very dangerous programming.
+    * Since they do, we have to work around and accept their syntax as well.
+    * But we will do so ONLY in Informix mode.
+    * We have to change the variables to our own struct and just store the pointer instead of the variable
+    */
+
+    struct arguments *ptr;
+    char *result = make_str("");
+
+    for (ptr = list; ptr != NULL; ptr = ptr->next)
+    {
+       char temp[20]; /* this should be sufficient unless you have 8 byte integers */
+       char *original_var;
+
+       /* change variable name to "ECPG_informix_get_var()" */
+       original_var = ptr->variable->name;
+       sprintf(temp, "%d))", ecpg_informix_var);
+
+       if ((ptr->variable->type->type != ECPGt_varchar && ptr->variable->type->type != ECPGt_char && ptr->variable->type->type != ECPGt_unsigned_char) && atoi(ptr->variable->type->size) > 1)
+       {
+           ptr->variable = new_variable(cat_str(4, make_str("("), mm_strdup(ecpg_type_name(ptr->variable->type->u.element->type)), make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_array_type(ECPGmake_simple_type(ptr->variable->type->u.element->type, make_str("1"), ptr->variable->type->u.element->lineno), ptr->variable->type->size), 0);
+           sprintf(temp, "%d, (", ecpg_informix_var++);
+       }
+       else if ((ptr->variable->type->type == ECPGt_varchar || ptr->variable->type->type == ECPGt_char || ptr->variable->type->type == ECPGt_unsigned_char) && atoi(ptr->variable->type->size) > 1)
+       {
+           ptr->variable = new_variable(cat_str(4, make_str("("), mm_strdup(ecpg_type_name(ptr->variable->type->type)), make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_simple_type(ptr->variable->type->type, ptr->variable->type->size, ptr->variable->type->lineno), 0);
+           sprintf(temp, "%d, (", ecpg_informix_var++);
+       }
+       else
+       {
+           ptr->variable = new_variable(cat_str(4, make_str("*("), mm_strdup(ecpg_type_name(ptr->variable->type->type)), make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_simple_type(ptr->variable->type->type, ptr->variable->type->size, ptr->variable->type->lineno), 0);
+           sprintf(temp, "%d, &(", ecpg_informix_var++);
+       }
+
+       /* create call to "ECPG_informix_set_var()" */
+       result = cat_str(5, result, make_str("ECPG_informix_set_var("), mm_strdup(temp), mm_strdup(original_var), make_str("), __LINE__);\n"));
+
+       /* now the indicator if there is one */
+       if (ptr->indicator->type->type != ECPGt_NO_INDICATOR)
+       {
+           /* change variable name to "ECPG_informix_get_var()" */
+           original_var = ptr->indicator->name;
+           sprintf(temp, "%d))", ecpg_informix_var);
+
+           /* create call to "ECPG_informix_set_var()" */
+           if (atoi(ptr->indicator->type->size) > 1)
+           {
+               ptr->indicator = new_variable(cat_str(4, make_str("("), mm_strdup(ecpg_type_name(ptr->indicator->type->type)), make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_simple_type(ptr->indicator->type->type, ptr->indicator->type->size, ptr->variable->type->lineno), 0);
+               sprintf(temp, "%d, (", ecpg_informix_var++);
+           }
+           else
+           {
+               ptr->indicator = new_variable(cat_str(4, make_str("*("), mm_strdup(ecpg_type_name(ptr->indicator->type->type)), make_str(" *)(ECPG_informix_get_var("), mm_strdup(temp)), ECPGmake_simple_type(ptr->indicator->type->type, ptr->indicator->type->size, ptr->variable->type->lineno), 0);
+               sprintf(temp, "%d, &(", ecpg_informix_var++);
+           }
+           result = cat_str(5, result, make_str("ECPG_informix_set_var("), mm_strdup(temp), mm_strdup(original_var), make_str("), __LINE__);\n"));
+       }
+    }
+
+    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)
+   {
+       mmerror(PARSE_ERROR, ET_ERROR, "trying to access an undeclared cursor \"%s\"\n", name);
+       return NULL;
+   }
+
+   if (insert)
+   {
+       /* add all those input variables that were given earlier
+        * note that we have to append here but have to keep the existing order */
+       for (p = ptr->argsinsert; p; p = p->next)
+           add_variable_to_tail(&argsinsert, p->variable, p->indicator);
+   }
+
+   /* add all those output variables that were given earlier */
+   for (p = ptr->argsresult; p; p = p->next)
+       add_variable_to_tail(&argsresult, p->variable, p->indicator);
+
+   return ptr;
+}
+
+static void
+add_typedef(char *name, char * dimension, char * length, enum ECPGttype type_enum, char *type_dimension, char *type_index, int initializer, int array)
+{
+   /* add entry to list */
+   struct typedefs *ptr, *this;
+
+   if ((type_enum == ECPGt_struct ||
+        type_enum == ECPGt_union) &&
+       initializer == 1)
+       mmerror(PARSE_ERROR, ET_ERROR, "initializer not allowed in typedef command");
+   else
+   {
+       for (ptr = types; ptr != NULL; ptr = ptr->next)
+       {
+           if (strcmp(name, ptr->name) == 0)
+               /* re-definition is a bug */
+               mmerror(PARSE_ERROR, ET_ERROR, "type %s already defined", name);
+       }
+       adjust_array(type_enum, &dimension, &length, type_dimension, type_index, array, true);
+
+       this = (struct typedefs *) mm_alloc(sizeof(struct typedefs));
+
+       /* initial definition */
+       this->next = types;
+       this->name = name;
+       this->brace_level = braces_open;
+       this->type = (struct this_type *) mm_alloc(sizeof(struct this_type));
+       this->type->type_enum = type_enum;
+       this->type->type_str = mm_strdup(name);
+       this->type->type_dimension = dimension; /* dimension of array */
+       this->type->type_index = length;    /* length of string */
+       this->type->type_sizeof = ECPGstruct_sizeof;
+       this->struct_member_list = (type_enum == ECPGt_struct || type_enum == ECPGt_union) ?
+       ECPGstruct_member_dup(struct_member_list[struct_level]) : NULL;
+
+       if (type_enum != ECPGt_varchar &&
+           type_enum != ECPGt_char &&
+           type_enum != ECPGt_unsigned_char &&
+           atoi(this->type->type_index) >= 0)
+           mmerror(PARSE_ERROR, ET_ERROR, "no multidimensional array support for simple data types");
+
+       types = this;
+   }
+}
+%}
+
+%name-prefix="base_yy"
+%locations
+
+%union {
+   double  dval;
+   char    *str;
+   int     ival;
+   struct  when        action;
+   struct  index       index;
+   int     tagname;
+   struct  this_type   type;
+   enum    ECPGttype   type_enum;
+   enum    ECPGdtype   dtype_enum;
+   struct  fetch_desc  descriptor;
+   struct  su_symbol   struct_union;
+   struct  prep        prep;
+}
diff --git a/src/interfaces/ecpg/preproc/ecpg.tokens b/src/interfaces/ecpg/preproc/ecpg.tokens
new file mode 100644 (file)
index 0000000..9b51975
--- /dev/null
@@ -0,0 +1,28 @@
+/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg.tokens,v 1.1 2008/11/14 10:03:33 meskes Exp $ */
+/* special embedded SQL token */
+%token  SQL_ALLOCATE SQL_AUTOCOMMIT SQL_BOOL SQL_BREAK
+                SQL_CALL SQL_CARDINALITY SQL_CONNECT
+                SQL_COUNT 
+                SQL_DATETIME_INTERVAL_CODE
+                SQL_DATETIME_INTERVAL_PRECISION SQL_DESCRIBE
+                SQL_DESCRIPTOR SQL_DISCONNECT SQL_FOUND
+                SQL_FREE SQL_GET SQL_GO SQL_GOTO SQL_IDENTIFIED
+                SQL_INDICATOR SQL_KEY_MEMBER SQL_LENGTH
+                SQL_LONG SQL_NULLABLE SQL_OCTET_LENGTH
+                SQL_OPEN SQL_OUTPUT SQL_REFERENCE
+                SQL_RETURNED_LENGTH SQL_RETURNED_OCTET_LENGTH SQL_SCALE
+                SQL_SECTION SQL_SHORT SQL_SIGNED SQL_SQL SQL_SQLERROR
+                SQL_SQLPRINT SQL_SQLWARNING SQL_START SQL_STOP
+                SQL_STRUCT SQL_UNSIGNED SQL_VAR SQL_WHENEVER
+
+/* C token */
+%token  S_ADD S_AND S_ANYTHING S_AUTO S_CONST S_DEC S_DIV
+                S_DOTPOINT S_EQUAL S_EXTERN S_INC S_LSHIFT S_MEMPOINT
+                S_MEMBER S_MOD S_MUL S_NEQUAL S_OR S_REGISTER S_RSHIFT
+                S_STATIC S_SUB S_VOLATILE
+                S_TYPEDEF
+
+%token TYPECAST
+%token CSTRING CVARIABLE CPP_LINE IP 
+%token DOLCONST ECONST NCONST UCONST UIDENT
+
diff --git a/src/interfaces/ecpg/preproc/ecpg.trailer b/src/interfaces/ecpg/preproc/ecpg.trailer
new file mode 100644 (file)
index 0000000..819c764
--- /dev/null
@@ -0,0 +1,2003 @@
+/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg.trailer,v 1.1 2008/11/14 10:03:33 meskes Exp $ */
+
+statements: /*EMPTY*/
+                | statements statement
+                ;
+
+statement: ecpgstart at stmt ';'        { connection = NULL; }
+                | ecpgstart stmt ';'
+                | ecpgstart ECPGVarDeclaration
+                {
+                        fprintf(yyout, "%s", $2);
+                        free($2);
+                        output_line_number();
+                }
+                | ECPGDeclaration
+                | c_thing               { fprintf(yyout, "%s", $1); free($1); }
+                | CPP_LINE              { fprintf(yyout, "%s", $1); free($1); }
+                | '{'                   { braces_open++; fputs("{", yyout); }
+                | '}'                   { remove_typedefs(braces_open); remove_variables(braces_open--); fputs("}", yyout); }
+                ;
+
+CreateAsStmt: CREATE OptTemp TABLE create_as_target AS {FoundInto = 0;} SelectStmt opt_with_data
+       {
+           if (FoundInto == 1)
+               mmerror(PARSE_ERROR, ET_ERROR, "CREATE TABLE / AS SELECT cannot specify INTO\n");
+
+           $$ = cat_str(6, make_str("create"), $2, make_str("table"), $4, make_str("as"), $7);
+       }
+   ;
+
+RuleStmt: CREATE opt_or_replace RULE name AS
+       {QueryIsRule = 1;}
+       ON event TO qualified_name where_clause
+       DO opt_instead RuleActionList
+       {
+           QueryIsRule=0;
+           $$ = cat_str(12, make_str("create"), $2, make_str("rule"), $4, make_str("as on"), $8, make_str("to"), $10, $11, make_str("do"), $13, $14);
+       }
+   ;
+
+at: AT connection_object
+                {
+                        connection = $2;
+                        /*
+                         *      Do we have a variable as connection target?
+                         *      Remove the variable from the variable
+                         *      list or else it will be used twice
+                         */
+                        if (argsinsert != NULL)
+                                argsinsert = NULL;
+                }
+        ;
+
+/*
+ * the exec sql connect statement: connect to the given database
+ */
+ECPGConnect: SQL_CONNECT TO connection_target opt_connection_name opt_user
+           { $$ = cat_str(5, $3, make_str(","), $5, make_str(","), $4); }
+       | SQL_CONNECT TO DEFAULT
+           { $$ = make_str("NULL, NULL, NULL, \"DEFAULT\""); }
+         /* also allow ORACLE syntax */
+       | SQL_CONNECT ora_user
+           { $$ = cat_str(3, make_str("NULL,"), $2, make_str(", NULL")); }
+       | DATABASE connection_target
+           { $$ = cat2_str($2, make_str(", NULL, NULL, NULL")); }
+       ;
+
+connection_target: opt_database_name opt_server opt_port
+       {
+           /* old style: dbname[@server][:port] */
+           if (strlen($2) > 0 && *($2) != '@')
+               mmerror(PARSE_ERROR, ET_ERROR, "expected \"@\", found \"%s\"", $2);
+           
+           /* C strings need to be handled differently */
+           if ($1[0] == '\"')
+               $$ = $1;
+           else
+               $$ = make3_str(make_str("\""), make3_str($1, $2, $3), make_str("\""));
+       }
+       |  db_prefix ':' server opt_port '/' opt_database_name opt_options
+       {
+           /* new style: :postgresql://server[:port][/dbname] */
+           if (strncmp($1, "unix:postgresql", strlen("unix:postgresql")) != 0 && strncmp($1, "tcp:postgresql", strlen("tcp:postgresql")) != 0)
+               mmerror(PARSE_ERROR, ET_ERROR, "only protocols \"tcp\" and \"unix\" and database type \"postgresql\" are supported");
+
+           if (strncmp($3, "//", strlen("//")) != 0)
+               mmerror(PARSE_ERROR, ET_ERROR, "expected \"://\", found \"%s\"", $3);
+
+           if (strncmp($1, "unix", strlen("unix")) == 0 &&
+               strncmp($3 + strlen("//"), "localhost", strlen("localhost")) != 0 &&
+               strncmp($3 + strlen("//"), "127.0.0.1", strlen("127.0.0.1")) != 0)
+               mmerror(PARSE_ERROR, ET_ERROR, "unix domain sockets only work on \"localhost\" but not on \"%s\"", $3 + strlen("//"));
+
+           $$ = make3_str(make3_str(make_str("\""), $1, make_str(":")), $3, make3_str(make3_str($4, make_str("/"), $6),    $7, make_str("\"")));
+       }
+       | char_variable
+       {
+           $$ = $1;
+       }
+       | ecpg_sconst
+       {
+           /* We can only process double quoted strings not single quotes ones,
+            * so we change the quotes.
+            * Note, that the rule for ecpg_sconst adds these single quotes. */
+           $1[0] = '\"';
+           $1[strlen($1)-1] = '\"';
+           $$ = $1;
+       }
+       ;
+
+opt_database_name: database_name       { $$ = $1; }
+       | /*EMPTY*/         { $$ = EMPTY; }
+       ;
+
+db_prefix: ecpg_ident cvariable
+       {
+           if (strcmp($2, "postgresql") != 0 && strcmp($2, "postgres") != 0)
+               mmerror(PARSE_ERROR, ET_ERROR, "expected \"postgresql\", found \"%s\"", $2);
+
+           if (strcmp($1, "tcp") != 0 && strcmp($1, "unix") != 0)
+               mmerror(PARSE_ERROR, ET_ERROR, "illegal connection type %s", $1);
+
+           $$ = make3_str($1, make_str(":"), $2);
+       }
+       ;
+
+server: Op server_name
+       {
+           if (strcmp($1, "@") != 0 && strcmp($1, "//") != 0)
+               mmerror(PARSE_ERROR, ET_ERROR, "expected \"@\" or \"://\", found \"%s\"", $1);
+
+           $$ = make2_str($1, $2);
+       }
+       ;
+
+opt_server: server         { $$ = $1; }
+       | /*EMPTY*/         { $$ = EMPTY; }
+       ;
+
+server_name: ColId                 { $$ = $1; }
+       | ColId '.' server_name     { $$ = make3_str($1, make_str("."), $3); }
+       | IP                        { $$ = make_name(); }
+       ;
+
+opt_port: ':' Iconst       { $$ = make2_str(make_str(":"), $2); }
+       | /*EMPTY*/ { $$ = EMPTY; }
+       ;
+
+opt_connection_name: AS connection_object  { $$ = $2; }
+       | /*EMPTY*/         { $$ = make_str("NULL"); }
+       ;
+
+opt_user: USER ora_user        { $$ = $2; }
+       | /*EMPTY*/         { $$ = make_str("NULL, NULL"); }
+       ;
+
+ora_user: user_name
+           { $$ = cat2_str($1, make_str(", NULL")); }
+       | user_name '/' user_name
+           { $$ = cat_str(3, $1, make_str(","), $3); }
+       | user_name SQL_IDENTIFIED BY user_name
+           { $$ = cat_str(3, $1, make_str(","), $4); }
+       | user_name USING user_name
+           { $$ = cat_str(3, $1, make_str(","), $3); }
+       ;
+
+user_name: RoleId
+       {
+           if ($1[0] == '\"')
+               $$ = $1;
+           else
+               $$ = make3_str(make_str("\""), $1, make_str("\""));
+       }
+       | ecpg_sconst
+       {
+           if ($1[0] == '\"')
+               $$ = $1;
+           else
+               $$ = make3_str(make_str("\""), $1, make_str("\""));
+       }
+       | civar
+       {
+           enum ECPGttype type = argsinsert->variable->type->type;
+
+           /* if array see what's inside */
+           if (type == ECPGt_array)
+               type = argsinsert->variable->type->u.element->type;
+
+           /* handle varchars */
+           if (type == ECPGt_varchar)
+               $$ = make2_str(mm_strdup(argsinsert->variable->name), make_str(".arr"));
+           else
+               $$ = mm_strdup(argsinsert->variable->name);
+       }
+       ;
+
+char_variable: cvariable
+       {
+           /* check if we have a string variable */
+           struct variable *p = find_variable($1);
+           enum ECPGttype type = p->type->type;
+
+           /* If we have just one character this is not a string */
+           if (atol(p->type->size) == 1)
+                   mmerror(PARSE_ERROR, ET_ERROR, "invalid datatype");
+           else
+           {
+               /* if array see what's inside */
+               if (type == ECPGt_array)
+                   type = p->type->u.element->type;
+
+               switch (type)
+               {
+                   case ECPGt_char:
+                   case ECPGt_unsigned_char:
+                       $$ = $1;
+                       break;
+                   case ECPGt_varchar:
+                       $$ = make2_str($1, make_str(".arr"));
+                       break;
+                   default:
+                       mmerror(PARSE_ERROR, ET_ERROR, "invalid datatype");
+                       $$ = $1;
+                       break;
+               }
+           }
+       }
+       ;
+
+opt_options: Op connect_options
+       {
+           if (strlen($1) == 0)
+               mmerror(PARSE_ERROR, ET_ERROR, "incomplete statement");
+
+           if (strcmp($1, "?") != 0)
+               mmerror(PARSE_ERROR, ET_ERROR, "unrecognized token \"%s\"", $1);
+
+           $$ = make2_str(make_str("?"), $2);
+       }
+       | /*EMPTY*/     { $$ = EMPTY; }
+       ;
+
+connect_options:  ColId opt_opt_value 
+           { $$ = make2_str($1, $2); }
+   | ColId opt_opt_value Op connect_options
+           {
+               if (strlen($3) == 0)
+                   mmerror(PARSE_ERROR, ET_ERROR, "incomplete statement");
+
+               if (strcmp($3, "&") != 0)
+                   mmerror(PARSE_ERROR, ET_ERROR, "unrecognized token \"%s\"", $3);
+
+               $$ = cat_str(3, make2_str($1, $2), $3, $4);
+           }
+   ;
+
+opt_opt_value: /*EMPTY*/
+           { $$ = EMPTY; }
+       | '=' Iconst
+           { $$ = make2_str(make_str("="), $2); }
+       | '=' ecpg_ident
+           { $$ = make2_str(make_str("="), $2); }
+       | '=' civar
+           { $$ = make2_str(make_str("="), $2); }
+       ;
+
+prepared_name: name             {
+                                        if ($1[0] == '\"' && $1[strlen($1)-1] == '\"') /* already quoted? */
+                                                $$ = $1;
+                                        else /* not quoted => convert to lowercase */
+                                        {
+                                                int i;
+
+                                                for (i = 0; i< strlen($1); i++)
+                                                        $1[i] = tolower((unsigned char) $1[i]);
+
+                                                $$ = make3_str(make_str("\""), $1, make_str("\""));
+                                        }
+                                }
+                | char_variable { $$ = $1; }
+                ;
+
+/*
+ * 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 prepared_name
+       {
+           struct cursor *ptr, *this;
+           struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable));
+           const char *con = connection ? connection : "NULL";
+
+           for (ptr = cur; ptr != NULL; ptr = ptr->next)
+           {
+               if (strcmp($2, ptr->name) == 0)
+                   /* re-definition is a bug */
+                   mmerror(PARSE_ERROR, ET_ERROR, "cursor \"%s\" already defined", $2);
+           }
+
+           this = (struct cursor *) mm_alloc(sizeof(struct cursor));
+
+           /* initial definition */
+           this->next = cur;
+           this->name = $2;
+           this->connection = connection;
+           this->command =  cat_str(6, make_str("declare"), mm_strdup($2), $3, make_str("cursor"), $5, make_str("for $1"));
+           this->argsresult = NULL;
+
+           thisquery->type = &ecpg_query;
+           thisquery->brace_level = 0;
+           thisquery->next = NULL;
+           thisquery->name = (char *) mm_alloc(sizeof("ECPGprepared_statement(, , __LINE__)") + strlen(con) + strlen($7));
+           sprintf(thisquery->name, "ECPGprepared_statement(%s, %s, __LINE__)", con, $7);
+
+           this->argsinsert = NULL;
+           add_variable_to_head(&(this->argsinsert), thisquery, &no_indicator);
+
+           cur = this;
+
+           $$ = cat_str(3, make_str("/*"), mm_strdup(this->command), make_str("*/"));
+       }
+       ;
+
+ECPGExecuteImmediateStmt: EXECUTE IMMEDIATE execstring
+           { 
+             /* execute immediate means prepare the statement and
+              * immediately execute it */
+             $$ = $3;
+           };
+/*
+ * variable decalartion outside exec sql declare block
+ */
+ECPGVarDeclaration: single_vt_declaration;
+
+single_vt_declaration: type_declaration        { $$ = $1; }
+       | var_declaration       { $$ = $1; }
+       ;
+
+precision: NumericOnly { $$ = $1; };
+
+opt_scale: ',' NumericOnly { $$ = $2; }
+       | /* EMPTY */   { $$ = EMPTY; }
+       ;
+
+ecpg_interval: opt_interval    { $$ = $1; }
+       | YEAR_P TO MINUTE_P    { $$ = make_str("year to minute"); }
+       | YEAR_P TO SECOND_P    { $$ = make_str("year to second"); }
+       | DAY_P TO DAY_P        { $$ = make_str("day to day"); }
+       | MONTH_P TO MONTH_P    { $$ = make_str("month to month"); }
+       ;
+
+/*
+ * variable declaration inside exec sql declare block
+ */
+ECPGDeclaration: sql_startdeclare
+       { fputs("/* exec sql begin declare section */", yyout); }
+       var_type_declarations sql_enddeclare
+       {
+           fprintf(yyout, "%s/* exec sql end declare section */", $3);
+           free($3);
+           output_line_number();
+       }
+       ;
+
+sql_startdeclare: ecpgstart BEGIN_P DECLARE SQL_SECTION ';' {};
+
+sql_enddeclare: ecpgstart END_P DECLARE SQL_SECTION ';' {};
+
+var_type_declarations: /*EMPTY*/           { $$ = EMPTY; }
+       | vt_declarations           { $$ = $1; }
+       | CPP_LINE              { $$ = $1; }
+       ;
+
+vt_declarations:  var_declaration          { $$ = $1; }
+       | type_declaration          { $$ = $1; }
+       | vt_declarations var_declaration   { $$ = cat2_str($1, $2); }
+       | vt_declarations type_declaration  { $$ = cat2_str($1, $2); }
+       | vt_declarations CPP_LINE      { $$ = cat2_str($1, $2); }
+       ;
+
+variable_declarations: var_declaration     { $$ = $1; }
+       | variable_declarations var_declaration     { $$ = cat2_str($1, $2); }
+       ;
+
+type_declaration: S_TYPEDEF
+   {
+       /* reset this variable so we see if there was */
+       /* an initializer specified */
+       initializer = 0;
+   }
+   var_type opt_pointer ECPGColLabelCommon opt_array_bounds ';'
+   {
+       add_typedef($5, $6.index1, $6.index2, $3.type_enum, $3.type_dimension, $3.type_index, initializer, *$4 ? 1 : 0);
+
+       fprintf(yyout, "typedef %s %s %s %s;\n", $3.type_str, *$4 ? "*" : "", $5, $6.str);
+       output_line_number();
+       $$ = make_str("");
+   };
+
+var_declaration: storage_declaration
+       var_type
+       {
+           actual_type[struct_level].type_enum = $2.type_enum;
+           actual_type[struct_level].type_dimension = $2.type_dimension;
+           actual_type[struct_level].type_index = $2.type_index;
+           actual_type[struct_level].type_sizeof = $2.type_sizeof;
+
+           actual_startline[struct_level] = hashline_number();
+       }
+       variable_list ';'
+       {
+           $$ = cat_str(5, actual_startline[struct_level], $1, $2.type_str, $4, make_str(";\n"));
+       }
+       | var_type
+       {
+           actual_type[struct_level].type_enum = $1.type_enum;
+           actual_type[struct_level].type_dimension = $1.type_dimension;
+           actual_type[struct_level].type_index = $1.type_index;
+           actual_type[struct_level].type_sizeof = $1.type_sizeof;
+
+           actual_startline[struct_level] = hashline_number();
+       }
+       variable_list ';'
+       {
+           $$ = cat_str(4, actual_startline[struct_level], $1.type_str, $3, make_str(";\n"));
+       }
+       | struct_union_type_with_symbol ';'
+       {
+           $$ = cat2_str($1, make_str(";"));
+       }
+       ;
+
+opt_bit_field: ':' Iconst  { $$ =cat2_str(make_str(":"), $2); }
+       | /* EMPTY */   { $$ = EMPTY; }
+       ;
+
+storage_declaration: storage_clause storage_modifier
+           {$$ = cat2_str ($1, $2); }
+       | storage_clause        {$$ = $1; }
+       | storage_modifier      {$$ = $1; }
+       ;
+
+storage_clause : S_EXTERN  { $$ = make_str("extern"); }
+       | S_STATIC          { $$ = make_str("static"); }
+       | S_REGISTER        { $$ = make_str("register"); }
+       | S_AUTO            { $$ = make_str("auto"); }
+       ;
+
+storage_modifier : S_CONST { $$ = make_str("const"); }
+       | S_VOLATILE        { $$ = make_str("volatile"); }
+       ;
+
+var_type:  simple_type
+       {
+           $$.type_enum = $1;
+           $$.type_str = mm_strdup(ecpg_type_name($1));
+           $$.type_dimension = make_str("-1");
+           $$.type_index = make_str("-1");
+           $$.type_sizeof = NULL;
+       }
+       | struct_union_type
+       {
+           $$.type_str = $1;
+           $$.type_dimension = make_str("-1");
+           $$.type_index = make_str("-1");
+
+           if (strncmp($1, "struct", sizeof("struct")-1) == 0)
+           {
+               $$.type_enum = ECPGt_struct;
+               $$.type_sizeof = ECPGstruct_sizeof;
+           }
+           else
+           {
+               $$.type_enum = ECPGt_union;
+               $$.type_sizeof = NULL;
+           }
+       }
+       | enum_type
+       {
+           $$.type_str = $1;
+           $$.type_enum = ECPGt_int;
+           $$.type_dimension = make_str("-1");
+           $$.type_index = make_str("-1");
+           $$.type_sizeof = NULL;
+       }
+       | ECPGColLabelCommon '(' precision opt_scale ')'
+       {
+           if (strcmp($1, "numeric") == 0)
+           {
+               $$.type_enum = ECPGt_numeric;
+               $$.type_str = make_str("numeric");
+           }
+           else if (strcmp($1, "decimal") == 0)
+           {
+               $$.type_enum = ECPGt_decimal;
+               $$.type_str = make_str("decimal");
+           }
+           else
+           {
+               mmerror(PARSE_ERROR, ET_ERROR, "only numeric/decimal have precision/scale argument");
+               $$.type_enum = ECPGt_numeric;
+               $$.type_str = make_str("numeric");
+           }
+
+           $$.type_dimension = make_str("-1");
+           $$.type_index = make_str("-1");
+           $$.type_sizeof = NULL;
+       }
+       | ECPGColLabelCommon ecpg_interval
+       {
+           if (strlen($2) != 0 && strcmp ($1, "datetime") != 0 && strcmp ($1, "interval") != 0)
+               mmerror (PARSE_ERROR, ET_ERROR, "interval specification not allowed here");
+
+           /*
+            * Check for type names that the SQL grammar treats as
+            * unreserved keywords
+            */
+           if (strcmp($1, "varchar") == 0)
+           {
+               $$.type_enum = ECPGt_varchar;
+               $$.type_str = EMPTY; /*make_str("varchar");*/
+               $$.type_dimension = make_str("-1");
+               $$.type_index = make_str("-1");
+               $$.type_sizeof = NULL;
+           }
+           else if (strcmp($1, "float") == 0)
+           {
+               $$.type_enum = ECPGt_float;
+               $$.type_str = make_str("float");
+               $$.type_dimension = make_str("-1");
+               $$.type_index = make_str("-1");
+               $$.type_sizeof = NULL;
+           }
+           else if (strcmp($1, "double") == 0)
+           {
+               $$.type_enum = ECPGt_double;
+               $$.type_str = make_str("double");
+               $$.type_dimension = make_str("-1");
+               $$.type_index = make_str("-1");
+               $$.type_sizeof = NULL;
+           }
+           else if (strcmp($1, "numeric") == 0)
+           {
+               $$.type_enum = ECPGt_numeric;
+               $$.type_str = make_str("numeric");
+               $$.type_dimension = make_str("-1");
+               $$.type_index = make_str("-1");
+               $$.type_sizeof = NULL;
+           }
+           else if (strcmp($1, "decimal") == 0)
+           {
+               $$.type_enum = ECPGt_decimal;
+               $$.type_str = make_str("decimal");
+               $$.type_dimension = make_str("-1");
+               $$.type_index = make_str("-1");
+               $$.type_sizeof = NULL;
+           }
+           else if (strcmp($1, "date") == 0)
+           {
+               $$.type_enum = ECPGt_date;
+               $$.type_str = make_str("date");
+               $$.type_dimension = make_str("-1");
+               $$.type_index = make_str("-1");
+               $$.type_sizeof = NULL;
+           }
+           else if (strcmp($1, "timestamp") == 0)
+           {
+               $$.type_enum = ECPGt_timestamp;
+               $$.type_str = make_str("timestamp");
+               $$.type_dimension = make_str("-1");
+               $$.type_index = make_str("-1");
+               $$.type_sizeof = NULL;
+           }
+           else if (strcmp($1, "interval") == 0)
+           {
+               $$.type_enum = ECPGt_interval;
+               $$.type_str = make_str("interval");
+               $$.type_dimension = make_str("-1");
+               $$.type_index = make_str("-1");
+               $$.type_sizeof = NULL;
+           }
+           else if (strcmp($1, "datetime") == 0)
+           {
+               $$.type_enum = ECPGt_timestamp;
+               $$.type_str = make_str("timestamp");
+               $$.type_dimension = make_str("-1");
+               $$.type_index = make_str("-1");
+               $$.type_sizeof = NULL;
+           }
+           else
+           {
+               /* this is for typedef'ed types */
+               struct typedefs *this = get_typedef($1);
+
+               $$.type_str = (this->type->type_enum == ECPGt_varchar) ? EMPTY : mm_strdup(this->name);
+               $$.type_enum = this->type->type_enum;
+               $$.type_dimension = this->type->type_dimension;
+               $$.type_index = this->type->type_index;
+               if (this->type->type_sizeof && strlen(this->type->type_sizeof) != 0)
+                   $$.type_sizeof = this->type->type_sizeof;
+               else 
+                   $$.type_sizeof = cat_str(3, make_str("sizeof("), mm_strdup(this->name), make_str(")"));
+
+               struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list);
+           }
+       }
+       | s_struct_union_symbol
+       {
+           /* this is for named structs/unions */
+           char *name;
+           struct typedefs *this;
+           bool forward = (forward_name != NULL && strcmp($1.symbol, forward_name) == 0 && strcmp($1.su, "struct") == 0);
+
+           name = cat2_str($1.su, $1.symbol);
+           /* Do we have a forward definition? */
+           if (!forward)
+           {
+               /* No */
+
+               this = get_typedef(name);
+               $$.type_str = mm_strdup(this->name);
+               $$.type_enum = this->type->type_enum;
+               $$.type_dimension = this->type->type_dimension;
+               $$.type_index = this->type->type_index;
+               $$.type_sizeof = this->type->type_sizeof;
+               struct_member_list[struct_level] = ECPGstruct_member_dup(this->struct_member_list);
+               free(name);
+           }
+           else
+           {
+               $$.type_str = name;
+               $$.type_enum = ECPGt_long;
+               $$.type_dimension = make_str("-1");
+               $$.type_index = make_str("-1");
+               $$.type_sizeof = make_str("");
+               struct_member_list[struct_level] = NULL;
+           }
+       }
+       ;
+
+enum_type: ENUM_P symbol enum_definition
+           { $$ = cat_str(3, make_str("enum"), $2, $3); }
+       | ENUM_P enum_definition
+           { $$ = cat2_str(make_str("enum"), $2); }
+       | ENUM_P symbol
+           { $$ = cat2_str(make_str("enum"), $2); }
+       ;
+
+enum_definition: '{' c_list '}'
+           { $$ = cat_str(3, make_str("{"), $2, make_str("}")); };
+
+struct_union_type_with_symbol: s_struct_union_symbol
+       {
+           struct_member_list[struct_level++] = NULL;
+           if (struct_level >= STRUCT_DEPTH)
+                mmerror(PARSE_ERROR, ET_ERROR, "too many levels in nested structure/union definition");
+           forward_name = mm_strdup($1.symbol);
+       }
+       '{' variable_declarations '}'
+       {
+           struct typedefs *ptr, *this;
+           struct this_type su_type;
+
+           ECPGfree_struct_member(struct_member_list[struct_level]);
+           struct_member_list[struct_level] = NULL;
+           struct_level--;
+           if (strncmp($1.su, "struct", sizeof("struct")-1) == 0)
+               su_type.type_enum = ECPGt_struct;
+           else
+               su_type.type_enum = ECPGt_union;
+           su_type.type_str = cat2_str($1.su, $1.symbol);
+           free(forward_name);
+           forward_name = NULL;
+
+           /* This is essantially a typedef but needs the keyword struct/union as well.
+            * So we create the typedef for each struct definition with symbol */
+           for (ptr = types; ptr != NULL; ptr = ptr->next)
+           {
+                   if (strcmp(su_type.type_str, ptr->name) == 0)
+                           /* re-definition is a bug */
+                           mmerror(PARSE_ERROR, ET_ERROR, "type \"%s\" already defined", su_type.type_str);
+           }
+
+           this = (struct typedefs *) mm_alloc(sizeof(struct typedefs));
+
+           /* initial definition */
+           this->next = types;
+           this->name = mm_strdup(su_type.type_str);
+           this->brace_level = braces_open;
+           this->type = (struct this_type *) mm_alloc(sizeof(struct this_type));
+           this->type->type_enum = su_type.type_enum;
+           this->type->type_str = mm_strdup(su_type.type_str);
+           this->type->type_dimension = make_str("-1"); /* dimension of array */
+           this->type->type_index = make_str("-1");    /* length of string */
+           this->type->type_sizeof = ECPGstruct_sizeof;
+           this->struct_member_list = struct_member_list[struct_level];
+
+           types = this;
+           $$ = cat_str(4, su_type.type_str, make_str("{"), $4, make_str("}"));
+       }
+       ;
+
+struct_union_type: struct_union_type_with_symbol   { $$ = $1; }
+       | s_struct_union
+       {
+           struct_member_list[struct_level++] = NULL;
+           if (struct_level >= STRUCT_DEPTH)
+                mmerror(PARSE_ERROR, ET_ERROR, "too many levels in nested structure/union definition");
+       }
+       '{' variable_declarations '}'
+       {
+           ECPGfree_struct_member(struct_member_list[struct_level]);
+           struct_member_list[struct_level] = NULL;
+           struct_level--;
+           $$ = cat_str(4, $1, make_str("{"), $4, make_str("}"));
+       }
+       ;
+
+s_struct_union_symbol: SQL_STRUCT symbol
+       {
+           $$.su = make_str("struct");
+           $$.symbol = $2;
+           ECPGstruct_sizeof = cat_str(3, make_str("sizeof("), cat2_str(mm_strdup($$.su), mm_strdup($$.symbol)), make_str(")"));
+       }
+       | UNION symbol
+       {
+           $$.su = make_str("union");
+           $$.symbol = $2;
+       }
+       ;
+
+s_struct_union: SQL_STRUCT
+       {
+           ECPGstruct_sizeof = make_str(""); /* This must not be NULL to distinguish from simple types. */
+           $$ = make_str("struct");
+       }
+       | UNION     { $$ = make_str("union"); }
+       ;
+
+simple_type: unsigned_type                 { $$=$1; }
+       |   opt_signed signed_type          { $$=$2; }
+       ;
+
+unsigned_type: SQL_UNSIGNED SQL_SHORT      { $$ = ECPGt_unsigned_short; }
+       | SQL_UNSIGNED SQL_SHORT INT_P  { $$ = ECPGt_unsigned_short; }
+       | SQL_UNSIGNED                      { $$ = ECPGt_unsigned_int; }
+       | SQL_UNSIGNED INT_P                { $$ = ECPGt_unsigned_int; }
+       | SQL_UNSIGNED SQL_LONG             { $$ = ECPGt_unsigned_long; }
+       | SQL_UNSIGNED SQL_LONG INT_P       { $$ = ECPGt_unsigned_long; }
+       | SQL_UNSIGNED SQL_LONG SQL_LONG
+       {
+#ifdef HAVE_LONG_LONG_INT_64
+           $$ = ECPGt_unsigned_long_long;
+#else
+           $$ = ECPGt_unsigned_long;
+#endif
+       }
+       | SQL_UNSIGNED SQL_LONG SQL_LONG INT_P
+       {
+#ifdef HAVE_LONG_LONG_INT_64
+           $$ = ECPGt_unsigned_long_long;
+#else
+           $$ = ECPGt_unsigned_long;
+#endif
+       }
+       | SQL_UNSIGNED CHAR_P           { $$ = ECPGt_unsigned_char; }
+       ;
+
+signed_type: SQL_SHORT             { $$ = ECPGt_short; }
+       | SQL_SHORT INT_P           { $$ = ECPGt_short; }
+       | INT_P                     { $$ = ECPGt_int; }
+       | SQL_LONG                  { $$ = ECPGt_long; }
+       | SQL_LONG INT_P            { $$ = ECPGt_long; }
+       | SQL_LONG SQL_LONG
+       {
+#ifdef HAVE_LONG_LONG_INT_64
+           $$ = ECPGt_long_long;
+#else
+           $$ = ECPGt_long;
+#endif
+       }
+       | SQL_LONG SQL_LONG INT_P
+       {
+#ifdef HAVE_LONG_LONG_INT_64
+           $$ = ECPGt_long_long;
+#else
+           $$ = ECPGt_long;
+#endif
+       }
+       | SQL_BOOL                  { $$ = ECPGt_bool; }
+       | CHAR_P                    { $$ = ECPGt_char; }
+       | DOUBLE_P                  { $$ = ECPGt_double; }
+       ;
+
+opt_signed: SQL_SIGNED
+       |   /* EMPTY */
+       ;
+
+variable_list: variable
+           { $$ = $1; }
+       | variable_list ',' variable
+           { $$ = cat_str(3, $1, make_str(","), $3); }
+       ;
+
+variable: opt_pointer ECPGColLabel opt_array_bounds opt_bit_field opt_initializer
+       {
+           struct ECPGtype * type;
+           char *dimension = $3.index1; /* dimension of array */
+           char *length = $3.index2;    /* length of string */
+           char dim[14L];
+           char *vcn;
+
+           adjust_array(actual_type[struct_level].type_enum, &dimension, &length, actual_type[struct_level].type_dimension, actual_type[struct_level].type_index, strlen($1), false);
+
+           switch (actual_type[struct_level].type_enum)
+           {
+               case ECPGt_struct:
+               case ECPGt_union:
+                   if (atoi(dimension) < 0)
+                       type = ECPGmake_struct_type(struct_member_list[struct_level], actual_type[struct_level].type_enum, actual_type[struct_level].type_sizeof);
+                   else
+                       type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level], actual_type[struct_level].type_enum, actual_type[struct_level].type_sizeof), dimension);
+
+                   $$ = cat_str(5, $1, mm_strdup($2), $3.str, $4, $5);
+                   break;
+
+               case ECPGt_varchar:
+                   if (atoi(dimension) < 0)
+                       type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length, yylineno);
+                   else
+                       type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length, yylineno), dimension);
+                   
+                   if (strcmp(dimension, "0") == 0 || abs(atoi(dimension)) == 1)
+                           *dim = '\0';
+                   else
+                           sprintf(dim, "[%s]", dimension);
+                   /* cannot check for atoi <= 0 because a defined constant will yield 0 here as well */
+                   if (atoi(length) < 0 || strcmp(length, "0") == 0)
+                       mmerror(PARSE_ERROR, ET_ERROR, "pointer to varchar are not implemented");
+
+                   /* make sure varchar struct name is unique by adding linenumer of its definition */
+                   vcn = (char *) mm_alloc(strlen($2) + sizeof(int) * CHAR_BIT * 10 / 3);
+                   sprintf(vcn, "%s_%d", $2, yylineno);
+                   if (strcmp(dimension, "0") == 0)
+                       $$ = cat_str(7, make2_str(make_str(" struct varchar_"), vcn), make_str(" { int len; char arr["), mm_strdup(length), make_str("]; } *"), mm_strdup($2), $4, $5);
+                   else
+                       $$ = cat_str(8, make2_str(make_str(" struct varchar_"), vcn), make_str(" { int len; char arr["), mm_strdup(length), make_str("]; } "), mm_strdup($2), mm_strdup(dim), $4, $5);
+                   break;
+
+               case ECPGt_char:
+               case ECPGt_unsigned_char:
+                   if (atoi(dimension) == -1)
+                   {
+                       int i = strlen($5);
+
+                       if (atoi(length) == -1 && i > 0) /* char [] = "string" */
+                       {
+                           /* if we have an initializer but no string size set, let's use the initializer's length */
+                           free(length);
+                           length = mm_alloc(i+sizeof("sizeof()"));
+                           sprintf(length, "sizeof(%s)", $5+2);
+                       }
+                       type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length, 0);
+                   }
+                   else
+                       type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length, 0), dimension);
+
+                   $$ = cat_str(5, $1, mm_strdup($2), $3.str, $4, $5);
+                   break;
+
+               default:
+                   if (atoi(dimension) < 0)
+                       type = ECPGmake_simple_type(actual_type[struct_level].type_enum, make_str("1"), 0);
+                   else
+                       type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, make_str("1"), 0), dimension);
+
+                   $$ = cat_str(5, $1, mm_strdup($2), $3.str, $4, $5);
+                   break;
+           }
+
+           if (struct_level == 0)
+               new_variable($2, type, braces_open);
+           else
+               ECPGmake_struct_member($2, type, &(struct_member_list[struct_level - 1]));
+
+           free($2);
+       }
+       ;
+
+opt_initializer: /*EMPTY*/
+           { $$ = EMPTY; }
+       | '=' c_term
+       {
+           initializer = 1;
+           $$ = cat2_str(make_str("="), $2);
+       }
+       ;
+
+opt_pointer: /*EMPTY*/             { $$ = EMPTY; }
+       | '*'                       { $$ = make_str("*"); }
+       | '*' '*'                   { $$ = make_str("**"); }
+       ;
+
+/*
+ * We try to simulate the correct DECLARE syntax here so we get dynamic SQL
+ */
+ECPGDeclare: DECLARE STATEMENT ecpg_ident
+       {
+           /* this is only supported for compatibility */
+           $$ = cat_str(3, make_str("/* declare statement"), $3, make_str("*/"));
+       }
+       ;
+/*
+ * the exec sql disconnect statement: disconnect from the given database
+ */
+ECPGDisconnect: SQL_DISCONNECT dis_name { $$ = $2; }
+       ;
+
+dis_name: connection_object            { $$ = $1; }
+       | CURRENT_P         { $$ = make_str("\"CURRENT\""); }
+       | ALL               { $$ = make_str("\"ALL\""); }
+       | /* EMPTY */           { $$ = make_str("\"CURRENT\""); }
+       ;
+
+connection_object: database_name       { $$ = make3_str(make_str("\""), $1, make_str("\"")); }
+       | DEFAULT           { $$ = make_str("\"DEFAULT\""); }
+       | char_variable         { $$ = $1; }
+       ;
+
+execstring: char_variable
+           { $$ = $1; }
+       |   CSTRING
+           { $$ = make3_str(make_str("\""), $1, make_str("\"")); }
+       ;
+
+/*
+ * the exec sql free command to deallocate a previously
+ * prepared statement
+ */
+ECPGFree:  SQL_FREE name   { $$ = $2; }
+       | SQL_FREE ALL  { $$ = make_str("all"); }
+       ;
+
+/*
+ * open is an open cursor, at the moment this has to be removed
+ */
+ECPGOpen: SQL_OPEN name opt_ecpg_using { $$ = $2; };
+
+opt_ecpg_using: /*EMPTY*/  { $$ = EMPTY; }
+       | ecpg_using        { $$ = $1; }
+       ;
+
+ecpg_using:    USING using_list    { $$ = EMPTY; }
+       | using_descriptor      { $$ = $1; }
+       ;
+
+using_descriptor: USING opt_sql SQL_DESCRIPTOR quoted_ident_stringvar
+       {
+           add_variable_to_head(&argsinsert, descriptor_variable($4,0), &no_indicator);
+           $$ = EMPTY;
+       }
+       ;
+
+into_descriptor: INTO opt_sql SQL_DESCRIPTOR quoted_ident_stringvar
+       {
+           add_variable_to_head(&argsresult, descriptor_variable($4,1), &no_indicator);
+           $$ = EMPTY;
+       }
+       ;
+
+opt_sql: /*EMPTY*/ | SQL_SQL;
+
+using_list: UsingValue | UsingValue ',' using_list;
+
+UsingValue: UsingConst
+       {
+           char *length = mm_alloc(32);
+
+           sprintf(length, "%d", (int) strlen($1));
+           add_variable_to_head(&argsinsert, new_variable($1, ECPGmake_simple_type(ECPGt_const, length, 0), 0), &no_indicator);
+       }
+       | civar { $$ = EMPTY; }
+       | civarind { $$ = EMPTY; }
+       ; 
+
+UsingConst: Iconst         { $$ = $1; }
+       | ecpg_fconst       { $$ = $1; }
+       | ecpg_sconst       { $$ = $1; }
+       | ecpg_bconst       { $$ = $1; }
+       | ecpg_xconst       { $$ = $1; }
+       ;
+
+/*
+ * We accept descibe but do nothing with it so far.
+ */
+ECPGDescribe: SQL_DESCRIBE INPUT_P name using_descriptor
+   {
+       const char *con = connection ? connection : "NULL";
+       mmerror(PARSE_ERROR, ET_WARNING, "using unsupported describe statement\n");
+       $$ = (char *) mm_alloc(sizeof("1, ECPGprepared_statement(, \"\", __LINE__)") + strlen(con) + strlen($3));
+       sprintf($$, "1, ECPGprepared_statement(%s, \"%s\", __LINE__)", con, $3);
+   }
+   | SQL_DESCRIBE opt_output name using_descriptor
+   {
+       const char *con = connection ? connection : "NULL";
+       mmerror(PARSE_ERROR, ET_WARNING, "using unsupported describe statement\n");
+       $$ = (char *) mm_alloc(sizeof("0, ECPGprepared_statement(, \"\", __LINE__)") + strlen(con) + strlen($3));
+       sprintf($$, "0, ECPGprepared_statement(%s, \"%s\", __LINE__)", con, $3);
+   }
+   | SQL_DESCRIBE opt_output name into_descriptor
+   {
+       const char *con = connection ? connection : "NULL";
+       mmerror(PARSE_ERROR, ET_WARNING, "using unsupported describe statement\n");
+       $$ = (char *) mm_alloc(sizeof("0, ECPGprepared_statement(, \"\", __LINE__)") + strlen(con) + strlen($3));
+       sprintf($$, "0, ECPGprepared_statement(%s, \"%s\", __LINE__)", con, $3);
+   }
+   ;
+
+opt_output:    SQL_OUTPUT  { $$ = make_str("output"); }
+   |   /* EMPTY */ { $$ = EMPTY; }
+   ;
+
+/*
+ * dynamic SQL: descriptor based access
+ * originall written by Christof Petig 
+ *         and Peter Eisentraut 
+ */
+
+/*
+ * allocate a descriptor
+ */
+ECPGAllocateDescr:     SQL_ALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar
+       {
+           add_descriptor($3,connection);
+           $$ = $3;
+       }
+       ;
+
+
+/*
+ * deallocate a descriptor
+ */
+ECPGDeallocateDescr:   DEALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar
+       {
+           drop_descriptor($3,connection);
+           $$ = $3;
+       }
+       ;
+
+/*
+ * manipulate a descriptor header
+ */
+
+ECPGGetDescriptorHeader: SQL_GET SQL_DESCRIPTOR quoted_ident_stringvar ECPGGetDescHeaderItems
+           {  $$ = $3; }
+       ;
+
+ECPGGetDescHeaderItems: ECPGGetDescHeaderItem
+       | ECPGGetDescHeaderItems ',' ECPGGetDescHeaderItem
+       ;
+
+ECPGGetDescHeaderItem: cvariable '=' desc_header_item
+           { push_assignment($1, $3); }
+       ;
+
+
+ECPGSetDescriptorHeader: SET SQL_DESCRIPTOR quoted_ident_stringvar ECPGSetDescHeaderItems
+           { $$ = $3; }
+       ;
+
+ECPGSetDescHeaderItems: ECPGSetDescHeaderItem
+       | ECPGSetDescHeaderItems ',' ECPGSetDescHeaderItem
+       ;
+
+ECPGSetDescHeaderItem: desc_header_item '=' IntConstVar
+       {
+           push_assignment($3, $1);
+       }
+       ;
+
+IntConstVar:    Iconst
+                {
+                        char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3);
+
+                        sprintf(length, "%d", (int) strlen($1));
+                        new_variable($1, ECPGmake_simple_type(ECPGt_const, length, 0), 0);
+                        $$ = $1;
+                }
+                | cvariable     { $$ = $1; }
+                ;
+
+desc_header_item:  SQL_COUNT           { $$ = ECPGd_count; }
+       ;
+
+/*
+ * manipulate a descriptor
+ */
+
+ECPGGetDescriptor: SQL_GET SQL_DESCRIPTOR quoted_ident_stringvar VALUE_P IntConstVar ECPGGetDescItems
+           {  $$.str = $5; $$.name = $3; }
+       ;
+
+ECPGGetDescItems: ECPGGetDescItem
+       | ECPGGetDescItems ',' ECPGGetDescItem
+       ;
+
+ECPGGetDescItem: cvariable '=' descriptor_item { push_assignment($1, $3); };
+
+
+ECPGSetDescriptor: SET SQL_DESCRIPTOR quoted_ident_stringvar VALUE_P IntConstVar ECPGSetDescItems
+           {  $$.str = $5; $$.name = $3; }
+       ;
+
+ECPGSetDescItems: ECPGSetDescItem
+       | ECPGSetDescItems ',' ECPGSetDescItem
+       ;
+
+ECPGSetDescItem: descriptor_item '=' AllConstVar
+       {
+           push_assignment($3, $1);
+       }
+       ;
+
+AllConstVar:    ecpg_fconst
+                {
+                        char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3);
+
+                        sprintf(length, "%d", (int) strlen($1));
+                        new_variable($1, ECPGmake_simple_type(ECPGt_const, length, 0), 0);
+                        $$ = $1;
+                }
+                | IntConstVar           { $$ = $1; }
+                | '-' ecpg_fconst
+                {
+                        char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3);
+                        char *var = cat2_str(make_str("-"), $2);
+
+                        sprintf(length, "%d", (int) strlen(var));
+                        new_variable(var, ECPGmake_simple_type(ECPGt_const, length, 0), 0);
+                        $$ = var;
+                }
+                | '-' Iconst
+                {
+                        char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3);
+                        char *var = cat2_str(make_str("-"), $2);
+
+                        sprintf(length, "%d", (int) strlen(var));
+                        new_variable(var, ECPGmake_simple_type(ECPGt_const, length, 0), 0);
+                        $$ = var;
+                }
+                | ecpg_sconst
+                {
+                        char *length = mm_alloc(sizeof(int) * CHAR_BIT * 10 / 3);
+                        char *var = $1 + 1;
+
+                        var[strlen(var) - 1] = '\0';
+                        sprintf(length, "%d", (int) strlen(var));
+                        new_variable(var, ECPGmake_simple_type(ECPGt_const, length, 0), 0);
+                        $$ = var;
+                }
+       ;
+
+descriptor_item:   SQL_CARDINALITY         { $$ = ECPGd_cardinality; }
+       | DATA_P                { $$ = ECPGd_data; }
+       | SQL_DATETIME_INTERVAL_CODE        { $$ = ECPGd_di_code; }
+       | SQL_DATETIME_INTERVAL_PRECISION   { $$ = ECPGd_di_precision; }
+       | SQL_INDICATOR             { $$ = ECPGd_indicator; }
+       | SQL_KEY_MEMBER            { $$ = ECPGd_key_member; }
+       | SQL_LENGTH                { $$ = ECPGd_length; }
+       | NAME_P                { $$ = ECPGd_name; }
+       | SQL_NULLABLE              { $$ = ECPGd_nullable; }
+       | SQL_OCTET_LENGTH          { $$ = ECPGd_octet; }
+       | PRECISION             { $$ = ECPGd_precision; }
+       | SQL_RETURNED_LENGTH           { $$ = ECPGd_length; }
+       | SQL_RETURNED_OCTET_LENGTH     { $$ = ECPGd_ret_octet; }
+       | SQL_SCALE             { $$ = ECPGd_scale; }
+       | TYPE_P                { $$ = ECPGd_type; }
+       ;
+
+/*
+ * set/reset the automatic transaction mode, this needs a differnet handling
+ * as the other set commands
+ */
+ECPGSetAutocommit: SET SQL_AUTOCOMMIT '=' on_off   { $$ = $4; }
+       |  SET SQL_AUTOCOMMIT TO on_off   { $$ = $4; }
+       ;
+
+on_off: ON             { $$ = make_str("on"); }
+       | OFF           { $$ = make_str("off"); }
+       ;
+
+/*
+ * set the actual connection, this needs a differnet handling as the other
+ * set commands
+ */
+ECPGSetConnection: SET CONNECTION TO connection_object { $$ = $4; }
+       | SET CONNECTION '=' connection_object { $$ = $4; }
+       | SET CONNECTION  connection_object { $$ = $3; }
+       ;
+
+/*
+ * define a new type for embedded SQL
+ */
+ECPGTypedef: TYPE_P
+       {
+           /* reset this variable so we see if there was */
+           /* an initializer specified */
+           initializer = 0;
+       }
+       ECPGColLabelCommon IS var_type opt_array_bounds opt_reference
+       {
+           add_typedef($3, $6.index1, $6.index2, $5.type_enum, $5.type_dimension, $5.type_index, initializer, *$7 ? 1 : 0);
+
+           if (auto_create_c == false)
+               $$ = cat_str(7, make_str("/* exec sql type"), mm_strdup($3), make_str("is"), mm_strdup($5.type_str), mm_strdup($6.str), $7, make_str("*/"));
+           else
+               $$ = cat_str(6, make_str("typedef "), mm_strdup($5.type_str), *$7?make_str("*"):make_str(""), mm_strdup($6.str), mm_strdup($3), make_str(";"));
+       }
+       ;
+
+opt_reference: SQL_REFERENCE       { $$ = make_str("reference"); }
+       | /*EMPTY*/                 { $$ = EMPTY; }
+       ;
+
+/*
+ * define the type of one variable for embedded SQL
+ */
+ECPGVar: SQL_VAR
+       {
+           /* reset this variable so we see if there was */
+           /* an initializer specified */
+           initializer = 0;
+       }
+       ColLabel IS var_type opt_array_bounds opt_reference
+       {
+           struct variable *p = find_variable($3);
+           char *dimension = $6.index1;
+           char *length = $6.index2;
+           struct ECPGtype * type;
+
+           if (($5.type_enum == ECPGt_struct ||
+                $5.type_enum == ECPGt_union) &&
+               initializer == 1)
+               mmerror(PARSE_ERROR, ET_ERROR, "initializer not allowed in EXEC SQL VAR command");
+           else
+           {
+               adjust_array($5.type_enum, &dimension, &length, $5.type_dimension, $5.type_index, *$7?1:0, false);
+
+               switch ($5.type_enum)
+               {
+                   case ECPGt_struct:
+                   case ECPGt_union:
+                       if (atoi(dimension) < 0)
+                           type = ECPGmake_struct_type(struct_member_list[struct_level], $5.type_enum, $5.type_sizeof);
+                       else
+                           type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level], $5.type_enum,$5.type_sizeof), dimension);
+                       break;
+
+                   case ECPGt_varchar:
+                       if (atoi(dimension) == -1)
+                           type = ECPGmake_simple_type($5.type_enum, length, 0);
+                       else
+                           type = ECPGmake_array_type(ECPGmake_simple_type($5.type_enum, length, 0), dimension);
+                       break;
+
+                   case ECPGt_char:
+                   case ECPGt_unsigned_char:
+                       if (atoi(dimension) == -1)
+                           type = ECPGmake_simple_type($5.type_enum, length, 0);
+                       else
+                           type = ECPGmake_array_type(ECPGmake_simple_type($5.type_enum, length, 0), dimension);
+                       break;
+
+                   default:
+                       if (atoi(length) >= 0)
+                           mmerror(PARSE_ERROR, ET_ERROR, "no multidimensional array support for simple data types");
+
+                       if (atoi(dimension) < 0)
+                           type = ECPGmake_simple_type($5.type_enum, make_str("1"), 0);
+                       else
+                           type = ECPGmake_array_type(ECPGmake_simple_type($5.type_enum, make_str("1"), 0), dimension);
+                       break;
+               }
+
+               ECPGfree_type(p->type);
+               p->type = type;
+           }
+
+           $$ = cat_str(7, make_str("/* exec sql var"), mm_strdup($3), make_str("is"), mm_strdup($5.type_str), mm_strdup($6.str), $7, make_str("*/"));
+       }
+       ;
+
+/*
+ * whenever statement: decide what to do in case of error/no data found
+ * according to SQL standards we lack: SQLSTATE, CONSTRAINT and SQLEXCEPTION
+ */
+ECPGWhenever: SQL_WHENEVER SQL_SQLERROR action
+       {
+           when_error.code = $3.code;
+           when_error.command = $3.command;
+           $$ = cat_str(3, make_str("/* exec sql whenever sqlerror "), $3.str, make_str("; */"));
+       }
+       | SQL_WHENEVER NOT SQL_FOUND action
+       {
+           when_nf.code = $4.code;
+           when_nf.command = $4.command;
+           $$ = cat_str(3, make_str("/* exec sql whenever not found "), $4.str, make_str("; */"));
+       }
+       | SQL_WHENEVER SQL_SQLWARNING action
+       {
+           when_warn.code = $3.code;
+           when_warn.command = $3.command;
+           $$ = cat_str(3, make_str("/* exec sql whenever sql_warning "), $3.str, make_str("; */"));
+       }
+       ;
+
+action : CONTINUE_P
+       {
+           $$.code = W_NOTHING;
+           $$.command = NULL;
+           $$.str = make_str("continue");
+       }
+       | SQL_SQLPRINT
+       {
+           $$.code = W_SQLPRINT;
+           $$.command = NULL;
+           $$.str = make_str("sqlprint");
+       }
+       | SQL_STOP
+       {
+           $$.code = W_STOP;
+           $$.command = NULL;
+           $$.str = make_str("stop");
+       }
+       | SQL_GOTO name
+       {
+           $$.code = W_GOTO;
+           $$.command = strdup($2);
+           $$.str = cat2_str(make_str("goto "), $2);
+       }
+       | SQL_GO TO name
+       {
+           $$.code = W_GOTO;
+           $$.command = strdup($3);
+           $$.str = cat2_str(make_str("goto "), $3);
+       }
+       | DO name '(' c_args ')'
+       {
+           $$.code = W_DO;
+           $$.command = cat_str(4, $2, make_str("("), $4, make_str(")"));
+           $$.str = cat2_str(make_str("do"), mm_strdup($$.command));
+       }
+       | DO SQL_BREAK
+       {
+           $$.code = W_BREAK;
+           $$.command = NULL;
+           $$.str = make_str("break");
+       }
+       | SQL_CALL name '(' c_args ')'
+       {
+           $$.code = W_DO;
+           $$.command = cat_str(4, $2, make_str("("), $4, make_str(")"));
+           $$.str = cat2_str(make_str("call"), mm_strdup($$.command));
+       }
+       | SQL_CALL name
+       {
+           $$.code = W_DO;
+           $$.command = cat2_str($2, make_str("()"));
+           $$.str = cat2_str(make_str("call"), mm_strdup($$.command));
+       }
+       ;
+
+/* some other stuff for ecpg */
+
+/* additional unreserved keywords */
+ECPGKeywords: ECPGKeywords_vanames { $$ = $1; }
+       | ECPGKeywords_rest     { $$ = $1; }
+       ;
+
+ECPGKeywords_vanames:  SQL_BREAK       { $$ = make_str("break"); }
+       | SQL_CALL                      { $$ = make_str("call"); }
+       | SQL_CARDINALITY               { $$ = make_str("cardinality"); }
+       | SQL_COUNT                     { $$ = make_str("count"); }
+       | SQL_DATETIME_INTERVAL_CODE    { $$ = make_str("datetime_interval_code"); }
+       | SQL_DATETIME_INTERVAL_PRECISION   { $$ = make_str("datetime_interval_precision"); }
+       | SQL_FOUND                     { $$ = make_str("found"); }
+       | SQL_GO                        { $$ = make_str("go"); }
+       | SQL_GOTO                      { $$ = make_str("goto"); }
+       | SQL_IDENTIFIED                { $$ = make_str("identified"); }
+       | SQL_INDICATOR             { $$ = make_str("indicator"); }
+       | SQL_KEY_MEMBER            { $$ = make_str("key_member"); }
+       | SQL_LENGTH                { $$ = make_str("length"); }
+       | SQL_NULLABLE              { $$ = make_str("nullable"); }
+       | SQL_OCTET_LENGTH          { $$ = make_str("octet_length"); }
+       | SQL_RETURNED_LENGTH       { $$ = make_str("returned_length"); }
+       | SQL_RETURNED_OCTET_LENGTH { $$ = make_str("returned_octet_length"); }
+       | SQL_SCALE                 { $$ = make_str("scale"); }
+       | SQL_SECTION               { $$ = make_str("section"); }
+       | SQL_SQL               { $$ = make_str("sql"); }
+       | SQL_SQLERROR              { $$ = make_str("sqlerror"); }
+       | SQL_SQLPRINT              { $$ = make_str("sqlprint"); }
+       | SQL_SQLWARNING            { $$ = make_str("sqlwarning"); }
+       | SQL_STOP                  { $$ = make_str("stop"); }
+       ;
+
+ECPGKeywords_rest:  SQL_CONNECT        { $$ = make_str("connect"); }
+       | SQL_DESCRIBE              { $$ = make_str("describe"); }
+       | SQL_DISCONNECT            { $$ = make_str("disconnect"); }
+       | SQL_OPEN                  { $$ = make_str("open"); }
+       | SQL_VAR                   { $$ = make_str("var"); }
+       | SQL_WHENEVER              { $$ = make_str("whenever"); }
+       ;
+
+/* additional keywords that can be SQL type names (but not ECPGColLabels) */
+ECPGTypeName:  SQL_BOOL                { $$ = make_str("bool"); }
+       | SQL_LONG                  { $$ = make_str("long"); }
+       | SQL_OUTPUT                { $$ = make_str("output"); }
+       | SQL_SHORT                 { $$ = make_str("short"); }
+       | SQL_STRUCT                { $$ = make_str("struct"); }
+       | SQL_SIGNED                { $$ = make_str("signed"); }
+       | SQL_UNSIGNED              { $$ = make_str("unsigned"); }
+       ;
+
+symbol: ColLabel                   { $$ = $1; }
+       ;
+
+ECPGColId: ecpg_ident              { $$ = $1; }
+       | ECPGunreserved_interval   { $$ = $1; }
+       | ECPGunreserved_con        { $$ = $1; }
+       | col_name_keyword      { $$ = $1; }
+       | ECPGKeywords          { $$ = $1; }
+       | ECPGCKeywords         { $$ = $1; }
+       | CHAR_P            { $$ = make_str("char"); }
+       | VALUES            { $$ = make_str("values"); }
+       ;
+/* Column label --- allowed labels in "AS" clauses.
+ * This presently includes *all* Postgres keywords.
+ */
+ColLabel:  ECPGColLabel                { $$ = $1; }
+       | ECPGTypeName          { $$ = $1; }
+       | CHAR_P            { $$ = make_str("char"); }
+       | INPUT_P           { $$ = make_str("input"); }
+       | INT_P             { $$ = make_str("int"); }
+       | UNION             { $$ = make_str("union"); }
+       | TO                { $$ = make_str("to"); }
+       | ECPGCKeywords         { $$ = $1; }
+       | ECPGunreserved_interval   { $$ = $1; }
+       ;
+
+ECPGColLabelCommon:  ecpg_ident            { $$ = $1; }
+       | col_name_keyword      { $$ = $1; }
+       | type_func_name_keyword    { $$ = $1; }
+       | ECPGKeywords_vanames      { $$ = $1; }
+       ;
+
+ECPGColLabel:  ECPGColLabelCommon  { $$ = $1; }
+       | reserved_keyword      { $$ = $1; }
+       | ECPGunreserved        { $$ = $1; }
+       | ECPGKeywords_rest     { $$ = $1; }
+       ;
+
+ECPGCKeywords: S_AUTO          { $$ = make_str("auto"); }
+       | S_CONST               { $$ = make_str("const"); }
+       | S_EXTERN              { $$ = make_str("extern"); }
+       | S_REGISTER            { $$ = make_str("register"); }
+       | S_STATIC              { $$ = make_str("static"); }
+       | S_TYPEDEF             { $$ = make_str("typedef"); }
+       | S_VOLATILE            { $$ = make_str("volatile"); }
+       ;
+
+/*
+ * Keyword classification lists.  Generally, every keyword present in
+ * the Postgres grammar should appear in exactly one of these lists.
+ *
+ * Put a new keyword into the first list that it can go into without causing
+ * shift or reduce conflicts.  The earlier lists define "less reserved"
+ * categories of keywords.
+ */
+
+/* "Unreserved" keywords --- available for use as any kind of name.
+ */
+/* The following symbols must be excluded from ECPGColLabel and directly included into ColLabel
+   to enable C variables to get names from ECPGColLabel:
+   DAY_P, HOUR_P, MINUTE_P, MONTH_P, SECOND_P, YEAR_P
+ */
+unreserved_keyword: ECPGunreserved_interval | ECPGunreserved;
+
+ECPGunreserved_interval: DAY_P         { $$ = make_str("day"); }
+       | HOUR_P            { $$ = make_str("hour"); }
+       | MINUTE_P          { $$ = make_str("minute"); }
+       | MONTH_P           { $$ = make_str("month"); }
+       | SECOND_P          { $$ = make_str("second"); }
+       | YEAR_P            { $$ = make_str("year"); }
+       ;
+
+/* The following symbol must be excluded from var_name but still included in ColId
+   to enable ecpg special postgresql variables with this name:  CONNECTION
+ */
+ECPGunreserved:    ECPGunreserved_con      { $$ = $1; }
+       | CONNECTION            { $$ = make_str("connection"); }
+       ;
+
+ECPGunreserved_con:      ABORT_P           { $$ = make_str("abort"); }
+       | ABSOLUTE_P        { $$ = make_str("absolute"); }
+       | ACCESS            { $$ = make_str("access"); }
+       | ACTION            { $$ = make_str("action"); }
+       | ADD_P             { $$ = make_str("add"); }
+       | ADMIN             { $$ = make_str("admin"); }
+       | AFTER             { $$ = make_str("after"); }
+       | AGGREGATE         { $$ = make_str("aggregate"); }
+       | ALSO              { $$ = make_str("also"); }
+       | ALTER             { $$ = make_str("alter"); }
+       | ALWAYS            { $$ = make_str("always"); }
+       | ASSERTION         { $$ = make_str("assertion"); }
+       | ASSIGNMENT        { $$ = make_str("assignment"); }
+       | AT                { $$ = make_str("at"); }
+       | BACKWARD          { $$ = make_str("backward"); }
+       | BEFORE            { $$ = make_str("before"); }
+       | BEGIN_P           { $$ = make_str("begin"); }
+       | BY                { $$ = make_str("by"); }
+       | CACHE             { $$ = make_str("cache"); }
+       | CASCADE           { $$ = make_str("cascade"); }
+       | CASCADED          { $$ = make_str("cascaded"); }
+       | CHAIN             { $$ = make_str("chain"); }
+       | CHARACTERISTICS   { $$ = make_str("characteristics"); }
+       | CHECKPOINT        { $$ = make_str("checkpoint"); }
+       | CLASS             { $$ = make_str("class"); }
+       | CLOSE             { $$ = make_str("close"); }
+       | CLUSTER           { $$ = make_str("cluster"); }
+       | COMMENT           { $$ = make_str("comment"); }
+       | COMMIT            { $$ = make_str("commit"); }
+       | COMMITTED         { $$ = make_str("committed"); }
+       | CONCURRENTLY      { $$ = make_str("concurrently"); }
+       | CONFIGURATION     { $$ = make_str("configuration"); }
+/*     | CONNECTION        { $$ = make_str("connection"); }*/
+       | CONSTRAINTS       { $$ = make_str("constraints"); }
+       | CONTENT_P     { $$ = make_str("content"); }
+       | CONTINUE_P        { $$ = make_str("continue"); }
+       | CONVERSION_P      { $$ = make_str("conversion"); }
+       | COPY              { $$ = make_str("copy"); }
+       | COST              { $$ = make_str("cost"); }
+       | CREATEDB          { $$ = make_str("createdb"); }
+       | CREATEROLE        { $$ = make_str("createrole"); }
+       | CREATEUSER        { $$ = make_str("createuser"); }
+       | CSV               { $$ = make_str("csv"); }
+       | CTYPE         { $$ = make_str("ctype"); }
+       | CURSOR            { $$ = make_str("cursor"); }
+       | CYCLE             { $$ = make_str("cycle"); }
+       | DATA_P            { $$ = make_str("data"); }
+       | DATABASE          { $$ = make_str("database"); }
+/*     | DAY_P             { $$ = make_str("day"); }*/
+       | DEALLOCATE        { $$ = make_str("deallocate"); }
+       | DECLARE           { $$ = make_str("declare"); }
+       | DEFAULTS          { $$ = make_str("defaults"); }
+       | DEFERRED          { $$ = make_str("deferred"); }
+       | DELETE_P          { $$ = make_str("delete"); }
+       | DELIMITER         { $$ = make_str("delimiter"); }
+       | DELIMITERS        { $$ = make_str("delimiters"); }
+       | DICTIONARY        { $$ = make_str("dictionary"); }
+       | DISABLE_P         { $$ = make_str("disable"); }
+       | DISCARD           { $$ = make_str("discard"); }
+       | DOCUMENT_P            { $$ = make_str("document"); }
+       | DOMAIN_P          { $$ = make_str("domain"); }
+       | DOUBLE_P          { $$ = make_str("double"); }
+       | DROP              { $$ = make_str("drop"); }
+       | EACH              { $$ = make_str("each"); }
+       | ENABLE_P          { $$ = make_str("enable"); }
+       | ENCODING          { $$ = make_str("encoding"); }
+       | ENCRYPTED         { $$ = make_str("encrypted"); }
+/*     | ENUM_P            { $$ = make_str("enum"); }*/
+       | ESCAPE            { $$ = make_str("escape"); }
+       | EXCLUDING         { $$ = make_str("excluding"); }
+       | EXCLUSIVE         { $$ = make_str("exclusive"); }
+       | EXECUTE           { $$ = make_str("execute"); }
+       | EXPLAIN           { $$ = make_str("explain"); }
+       | EXTERNAL          { $$ = make_str("external"); }
+       | FAMILY            { $$ = make_str("family"); }
+/*     | FETCH             { $$ = make_str("fetch"); }*/
+       | FIRST_P           { $$ = make_str("first"); }
+       | FORCE             { $$ = make_str("force"); }
+       | FORWARD           { $$ = make_str("forward"); }
+       | FUNCTION          { $$ = make_str("function"); }
+       | GLOBAL            { $$ = make_str("global"); }
+       | GRANTED           { $$ = make_str("granted"); }
+       | HANDLER           { $$ = make_str("handler"); }
+       | HEADER_P          { $$ = make_str("header"); }
+       | HOLD              { $$ = make_str("hold"); }
+/*     | HOUR_P            { $$ = make_str("hour"); }*/
+       | IDENTITY_P            { $$ = make_str("identity"); }
+       | IF_P              { $$ = make_str("if"); }
+       | IMMEDIATE         { $$ = make_str("immediate"); }
+       | IMMUTABLE         { $$ = make_str("immutable"); }
+       | IMPLICIT_P        { $$ = make_str("implicit"); }
+       | INCLUDING         { $$ = make_str("including"); }
+       | INCREMENT         { $$ = make_str("increment"); }
+       | INDEX             { $$ = make_str("index"); }
+       | INDEXES           { $$ = make_str("indexes"); }
+       | INHERIT           { $$ = make_str("inherit"); }
+       | INHERITS          { $$ = make_str("inherits"); }
+       | INSENSITIVE       { $$ = make_str("insensitive"); }
+       | INSERT            { $$ = make_str("insert"); }
+       | INSTEAD           { $$ = make_str("instead"); }
+       | ISOLATION         { $$ = make_str("isolation"); }
+       | KEY               { $$ = make_str("key"); }
+       | LANCOMPILER       { $$ = make_str("lancompiler"); }
+       | LANGUAGE          { $$ = make_str("language"); }
+       | LARGE_P           { $$ = make_str("large"); }
+       | LAST_P            { $$ = make_str("last"); }
+       | LEVEL             { $$ = make_str("level"); }
+       | LISTEN            { $$ = make_str("listen"); }
+       | LOAD              { $$ = make_str("load"); }
+       | LOCAL             { $$ = make_str("local"); }
+       | LOCATION          { $$ = make_str("location"); }
+       | LOCK_P            { $$ = make_str("lock"); }
+       | LOGIN_P           { $$ = make_str("login"); }
+       | MAPPING           { $$ = make_str("mapping"); }
+       | MATCH             { $$ = make_str("match"); }
+       | MAXVALUE          { $$ = make_str("maxvalue"); }
+/*     | MINUTE_P          { $$ = make_str("minute"); }*/
+       | MINVALUE          { $$ = make_str("minvalue"); }
+       | MODE              { $$ = make_str("mode"); }
+/*     | MONTH_P           { $$ = make_str("month"); }*/
+       | MOVE              { $$ = make_str("move"); }
+       | NAME_P            { $$ = make_str("name"); }
+       | NAMES             { $$ = make_str("names"); }
+       | NEXT              { $$ = make_str("next"); }
+       | NO                { $$ = make_str("no"); }
+       | NOCREATEDB        { $$ = make_str("nocreatedb"); }
+       | NOCREATEROLE      { $$ = make_str("nocreaterole"); }
+       | NOCREATEUSER      { $$ = make_str("nocreateuser"); }
+       | NOINHERIT         { $$ = make_str("noinherit"); }
+       | NOLOGIN_P         { $$ = make_str("nologin"); }
+       | NOSUPERUSER       { $$ = make_str("nosuperuser"); }
+       | NOTHING           { $$ = make_str("nothing"); }
+       | NOTIFY            { $$ = make_str("notify"); }
+       | NOWAIT            { $$ = make_str("nowait"); }
+       | NULLS_P           { $$ = make_str("nulls"); }
+       | OBJECT_P          { $$ = make_str("object"); }
+       | OF                { $$ = make_str("of"); }
+       | OIDS              { $$ = make_str("oids"); }
+       | OPERATOR          { $$ = make_str("operator"); }
+       | OPTION            { $$ = make_str("option"); }
+       | OWNED             { $$ = make_str("owned"); }
+       | OWNER             { $$ = make_str("owner"); }
+       | PARSER            { $$ = make_str("parser"); }
+       | PARTIAL           { $$ = make_str("partial"); }
+       | PASSWORD          { $$ = make_str("password"); }
+       | PLANS             { $$ = make_str("plans"); }
+       | PREPARE           { $$ = make_str("prepare"); }
+       | PREPARED          { $$ = make_str("prepared"); }
+       | PRESERVE          { $$ = make_str("preserver"); }
+       | PRIOR             { $$ = make_str("prior"); }
+       | PRIVILEGES        { $$ = make_str("privileges"); }
+       | PROCEDURAL        { $$ = make_str("procedural"); }
+       | PROCEDURE         { $$ = make_str("procedure"); }
+       | QUOTE             { $$ = make_str("quote"); }
+       | READ              { $$ = make_str("read"); }
+       | REASSIGN          { $$ = make_str("reassign"); }
+       | RECHECK           { $$ = make_str("recheck"); }
+       | RECURSIVE         { $$ = make_str("recursive"); }
+       | REINDEX           { $$ = make_str("reindex"); }
+       | RELATIVE_P        { $$ = make_str("relative"); }
+       | RELEASE           { $$ = make_str("release"); }
+       | RENAME            { $$ = make_str("rename"); }
+       | REPEATABLE        { $$ = make_str("repeatable"); }
+       | REPLACE           { $$ = make_str("replace"); }
+       | REPLICA           { $$ = make_str("replica"); }
+       | RESET             { $$ = make_str("reset"); }
+       | RESTART           { $$ = make_str("restart"); }
+       | RESTRICT          { $$ = make_str("restrict"); }
+       | RETURNS           { $$ = make_str("returns"); }
+       | REVOKE            { $$ = make_str("revoke"); }
+       | ROLE              { $$ = make_str("role"); }
+       | ROLLBACK          { $$ = make_str("rollback"); }
+       | ROWS              { $$ = make_str("rows"); }
+       | RULE              { $$ = make_str("rule"); }
+       | SAVEPOINT         { $$ = make_str("savepoint"); }
+       | SCHEMA            { $$ = make_str("schema"); }
+       | SCROLL            { $$ = make_str("scroll"); }
+       | SEARCH            { $$ = make_str("search"); }
+/*     | SECOND_P          { $$ = make_str("second"); }*/
+       | SEQUENCE          { $$ = make_str("sequence"); }
+       | SERIALIZABLE      { $$ = make_str("serializable"); }
+       | SESSION           { $$ = make_str("session"); }
+       | SET               { $$ = make_str("set"); }
+       | SHARE             { $$ = make_str("share"); }
+       | SHOW              { $$ = make_str("show"); }
+       | SIMPLE            { $$ = make_str("simple"); }
+       | STABLE            { $$ = make_str("stable"); }
+       | STANDALONE_P          { $$ = make_str("standalone"); }
+       | START             { $$ = make_str("start"); }
+       | STATEMENT         { $$ = make_str("statement"); }
+       | STATISTICS        { $$ = make_str("statistics"); }
+       | STDIN             { $$ = make_str("stdin"); }
+       | STDOUT            { $$ = make_str("stdout"); }
+       | STORAGE           { $$ = make_str("storage"); }
+       | STRICT_P          { $$ = make_str("strict"); }
+       | STRIP_P           { $$ = make_str("strip"); }
+       | SUPERUSER_P       { $$ = make_str("superuser"); }
+       | SYSTEM_P          { $$ = make_str("system"); }
+       | SYSID             { $$ = make_str("sysid"); }
+       | TABLESPACE        { $$ = make_str("tablespace"); }
+       | TEMP              { $$ = make_str("temp"); }
+       | TEMPLATE          { $$ = make_str("template"); }
+       | TEMPORARY         { $$ = make_str("temporary"); }
+       | TEXT_P            { $$ = make_str("text"); }
+       | TRANSACTION       { $$ = make_str("transaction"); }
+       | TRIGGER           { $$ = make_str("trigger"); }
+       | TRUNCATE          { $$ = make_str("truncate"); }
+       | TRUSTED           { $$ = make_str("trusted"); }
+       | TYPE_P            { $$ = make_str("type"); }
+       | UNCOMMITTED       { $$ = make_str("uncommitted"); }
+       | UNENCRYPTED       { $$ = make_str("unencrypted"); }
+       | UNKNOWN           { $$ = make_str("unknown"); }
+       | UNLISTEN          { $$ = make_str("unlisten"); }
+       | UNTIL             { $$ = make_str("until"); }
+       | UPDATE            { $$ = make_str("update"); }
+       | VACUUM            { $$ = make_str("vacuum"); }
+       | VALID             { $$ = make_str("valid"); }
+       | VALIDATOR         { $$ = make_str("validator"); }
+       | VALUE_P           { $$ = make_str("value"); }
+       | VARYING           { $$ = make_str("varying"); }
+       | VERSION_P         { $$ = make_str("version"); }
+       | VIEW              { $$ = make_str("view"); }
+       | VOLATILE          { $$ = make_str("volatile"); }
+       | WHITESPACE_P          { $$ = make_str("whitespace"); }
+       | WITHOUT           { $$ = make_str("without"); }
+       | WORK              { $$ = make_str("work"); }
+       | WRITE             { $$ = make_str("write"); }
+       | XML_P             { $$ = make_str("xml"); }
+       | YES_P             { $$ = make_str("yes"); }
+/*     | YEAR_P            { $$ = make_str("year"); }*/
+       | ZONE              { $$ = make_str("zone"); }
+       ;
+
+into_list : coutputvariable | into_list ',' coutputvariable
+       ;
+
+ecpgstart: SQL_START   {
+               reset_variables();
+               pacounter = 1;
+           }
+       ;
+
+c_args: /*EMPTY*/      { $$ = EMPTY; }
+       | c_list        { $$ = $1; }
+       ;
+
+coutputvariable: cvariable indicator
+           { add_variable_to_head(&argsresult, find_variable($1), find_variable($2)); }
+       | cvariable
+           { add_variable_to_head(&argsresult, find_variable($1), &no_indicator); }
+       ;
+
+
+civarind: cvariable indicator
+       {
+           if (find_variable($2)->type->type == ECPGt_array)
+               mmerror(PARSE_ERROR, ET_ERROR, "arrays of indicators are not allowed on input");
+
+           add_variable_to_head(&argsinsert, find_variable($1), find_variable($2));
+           $$ = create_questionmarks($1, false);
+       }
+       ;
+
+civar: cvariable
+       {
+           add_variable_to_head(&argsinsert, find_variable($1), &no_indicator);
+           $$ = create_questionmarks($1, false);
+       }
+       ;
+
+indicator: cvariable               { check_indicator((find_variable($1))->type); $$ = $1; }
+       | SQL_INDICATOR cvariable   { check_indicator((find_variable($2))->type); $$ = $2; }
+       | SQL_INDICATOR name        { check_indicator((find_variable($2))->type); $$ = $2; }
+       ;
+
+cvariable: CVARIABLE
+       {
+           /* As long as multidimensional arrays are not implemented we have to check for those here */
+           char *ptr = $1;
+           int brace_open=0, brace = false;
+
+           for (; *ptr; ptr++)
+           {
+               switch (*ptr)
+               {
+                   case '[':
+                           if (brace)
+                               mmerror(PARSE_ERROR, ET_FATAL, "no multidimensional array support for simple data types");
+                           brace_open++;
+                           break;
+                   case ']':
+                           brace_open--;
+                           if (brace_open == 0)
+                               brace = true;
+                           break;
+                   case '\t':
+                   case ' ':
+                           break;
+                   default:
+                           if (brace_open == 0)
+                               brace = false;
+                           break;
+               }
+           }
+           $$ = $1;
+       }
+       ;
+
+ecpg_param:    PARAM       { $$ = make_name(); } ;
+
+ecpg_bconst:   BCONST      { $$ = make_name(); } ;
+
+ecpg_fconst:   FCONST      { $$ = make_name(); } ;
+
+ecpg_sconst:
+       SCONST
+       {
+           /* could have been input as '' or $$ */
+           $$ = (char *)mm_alloc(strlen($1) + 3);
+           $$[0]='\'';
+           strcpy($$+1, $1);
+           $$[strlen($1)+1]='\'';
+           $$[strlen($1)+2]='\0';
+           free($1);
+       }
+       | ECONST
+       {
+           $$ = (char *)mm_alloc(strlen($1) + 4);
+           $$[0]='E';
+           $$[1]='\'';
+           strcpy($$+2, $1);
+           $$[strlen($1)+2]='\'';
+           $$[strlen($1)+3]='\0';
+           free($1);
+       }
+       | NCONST
+       {
+           $$ = (char *)mm_alloc(strlen($1) + 4);
+           $$[0]='N';
+           $$[1]='\'';
+           strcpy($$+2, $1);
+           $$[strlen($1)+2]='\'';
+           $$[strlen($1)+3]='\0';
+           free($1);
+       }
+       | UCONST    { $$ = $1; }
+       | DOLCONST  { $$ = $1; }
+       ;
+
+ecpg_xconst:   XCONST      { $$ = make_name(); } ;
+
+ecpg_ident:    IDENT       { $$ = make_name(); }
+       | CSTRING   { $$ = make3_str(make_str("\""), $1, make_str("\"")) }
+       | UIDENT    { $$ = $1; }
+       ;
+
+quoted_ident_stringvar: name
+           { $$ = make3_str(make_str("\""), $1, make_str("\"")); }
+       | char_variable
+           { $$ = make3_str(make_str("("), $1, make_str(")")); }
+       ;
+
+/*
+ * C stuff
+ */
+
+c_stuff_item: c_anything           { $$ = $1; }
+       | '(' ')'           { $$ = make_str("()"); }
+       | '(' c_stuff ')'
+           { $$ = cat_str(3, make_str("("), $2, make_str(")")); }
+       ;
+
+c_stuff: c_stuff_item          { $$ = $1; }
+       | c_stuff c_stuff_item
+           { $$ = cat2_str($1, $2); }
+       ;
+
+c_list: c_term             { $$ = $1; }
+       | c_list ',' c_term { $$ = cat_str(3, $1, make_str(","), $3); }
+       ;
+
+c_term:  c_stuff           { $$ = $1; }
+       | '{' c_list '}'    { $$ = cat_str(3, make_str("{"), $2, make_str("}")); }
+       ;
+
+c_thing:   c_anything      { $$ = $1; }
+       |   '('     { $$ = make_str("("); }
+       |   ')'     { $$ = make_str(")"); }
+       |   ','     { $$ = make_str(","); }
+       |   ';'     { $$ = make_str(";"); }
+       ;
+
+c_anything:  ecpg_ident                { $$ = $1; }
+       | Iconst            { $$ = $1; }
+       | ecpg_fconst           { $$ = $1; }
+       | ecpg_sconst           { $$ = $1; }
+       | '*'               { $$ = make_str("*"); }
+       | '+'               { $$ = make_str("+"); }
+       | '-'               { $$ = make_str("-"); }
+       | '/'               { $$ = make_str("/"); }
+       | '%'               { $$ = make_str("%"); }
+       | NULL_P            { $$ = make_str("NULL"); }
+       | S_ADD             { $$ = make_str("+="); }
+       | S_AND             { $$ = make_str("&&"); }
+       | S_ANYTHING            { $$ = make_name(); }
+       | S_AUTO            { $$ = make_str("auto"); }
+       | S_CONST           { $$ = make_str("const"); }
+       | S_DEC             { $$ = make_str("--"); }
+       | S_DIV             { $$ = make_str("/="); }
+       | S_DOTPOINT            { $$ = make_str(".*"); }
+       | S_EQUAL           { $$ = make_str("=="); }
+       | S_EXTERN          { $$ = make_str("extern"); }
+       | S_INC             { $$ = make_str("++"); }
+       | S_LSHIFT          { $$ = make_str("<<"); }
+       | S_MEMBER          { $$ = make_str("->"); }
+       | S_MEMPOINT            { $$ = make_str("->*"); }
+       | S_MOD             { $$ = make_str("%="); }
+       | S_MUL             { $$ = make_str("*="); }
+       | S_NEQUAL          { $$ = make_str("!="); }
+       | S_OR              { $$ = make_str("||"); }
+       | S_REGISTER            { $$ = make_str("register"); }
+       | S_RSHIFT          { $$ = make_str(">>"); }
+       | S_STATIC          { $$ = make_str("static"); }
+       | S_SUB             { $$ = make_str("-="); }
+       | S_TYPEDEF         { $$ = make_str("typedef"); }
+       | S_VOLATILE            { $$ = make_str("volatile"); }
+       | SQL_BOOL          { $$ = make_str("bool"); }
+       | ENUM_P            { $$ = make_str("enum"); }
+       | HOUR_P            { $$ = make_str("hour"); }
+       | INT_P             { $$ = make_str("int"); }
+       | SQL_LONG          { $$ = make_str("long"); }
+       | MINUTE_P          { $$ = make_str("minute"); }
+       | MONTH_P           { $$ = make_str("month"); }
+       | SECOND_P          { $$ = make_str("second"); }
+       | SQL_SHORT         { $$ = make_str("short"); }
+       | SQL_SIGNED            { $$ = make_str("signed"); }
+       | SQL_STRUCT            { $$ = make_str("struct"); }
+       | SQL_UNSIGNED          { $$ = make_str("unsigned"); }
+       | YEAR_P            { $$ = make_str("year"); }
+       | CHAR_P            { $$ = make_str("char"); }
+       | FLOAT_P           { $$ = make_str("float"); }
+       | TO                { $$ = make_str("to"); }
+       | UNION             { $$ = make_str("union"); }
+       | VARCHAR           { $$ = make_str("varchar"); }
+       | '['               { $$ = make_str("["); }
+       | ']'               { $$ = make_str("]"); }
+       | '='               { $$ = make_str("="); }
+       | ':'               { $$ = make_str(":"); }
+       ;
+
+DeallocateStmt: DEALLOCATE prepared_name                { $$ = $2; }
+                | DEALLOCATE PREPARE prepared_name      { $$ = $3; }
+                | DEALLOCATE ALL                        { $$ = make_str("all"); }
+                | DEALLOCATE PREPARE ALL                { $$ = make_str("all"); }
+                ;
+
+Iresult:        Iconst         { $$ = $1; }
+                | '(' Iresult ')'       { $$ = cat_str(3, make_str("("), $2, make_str(")")); }
+                | Iresult '+' Iresult   { $$ = cat_str(3, $1, make_str("+"), $3); }
+                | Iresult '-' Iresult   { $$ = cat_str(3, $1, make_str("-"), $3); }
+                | Iresult '*' Iresult   { $$ = cat_str(3, $1, make_str("*"), $3); }
+                | Iresult '/' Iresult   { $$ = cat_str(3, $1, make_str("/"), $3); }
+                | Iresult '%' Iresult   { $$ = cat_str(3, $1, make_str("%"), $3); }
+                | ecpg_sconst      { $$ = $1; }
+                | ColId                 { $$ = $1; }
+                ;
+
+execute_rest: /* EMPTY */  { $$ = EMPTY; }
+   | ecpg_using ecpg_into  { $$ = EMPTY; }
+   | ecpg_into ecpg_using  { $$ = EMPTY; }
+   | ecpg_using            { $$ = EMPTY; }
+   | ecpg_into             { $$ = EMPTY; }
+   ; 
+
+ecpg_into: INTO into_list  { $$ = EMPTY; }
+        | into_descriptor  { $$ = $1; }
+   ;
+
+%%
+
+void base_yyerror(const char * error)
+{
+   char buf[1024];
+
+   snprintf(buf,sizeof buf, _("%s at or near \"%s\""), error, token_start ? token_start : yytext);
+   buf[sizeof(buf)-1]=0;
+   mmerror(PARSE_ERROR, ET_ERROR, buf);
+}
+
+void parser_init(void)
+{
+ /* This function is empty. It only exists for compatibility with the backend parser right now. */
+}
+
+/*
+ * Must undefine base_yylex before including pgc.c, since we want it
+ * to create the function base_yylex not filtered_base_yylex.
+ */
+#undef base_yylex
+
+#include "pgc.c"
diff --git a/src/interfaces/ecpg/preproc/ecpg.type b/src/interfaces/ecpg/preproc/ecpg.type
new file mode 100644 (file)
index 0000000..11f3d23
--- /dev/null
@@ -0,0 +1,143 @@
+/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg.type,v 1.1 2008/11/14 10:03:33 meskes Exp $ */
+%type  ECPGAllocateDescr
+%type  ECPGCKeywords
+%type  ECPGColId
+%type  ECPGColLabel
+%type  ECPGColLabelCommon
+%type  ECPGConnect
+%type  ECPGCursorStmt
+%type  ECPGDeallocateDescr
+%type  ECPGDeclaration
+%type  ECPGDeclare
+%type  ECPGDescribe
+%type  ECPGDisconnect
+%type  ECPGExecuteImmediateStmt
+%type  ECPGFree
+%type  ECPGGetDescHeaderItem
+%type  ECPGGetDescItem
+%type  ECPGGetDescriptorHeader
+%type  ECPGKeywords
+%type  ECPGKeywords_rest
+%type  ECPGKeywords_vanames
+%type  ECPGOpen
+%type  ECPGSetAutocommit
+%type  ECPGSetConnection
+%type  ECPGSetDescHeaderItem
+%type  ECPGSetDescItem
+%type  ECPGSetDescriptorHeader
+%type  ECPGTypeName
+%type  ECPGTypedef
+%type  ECPGVar
+%type  ECPGVarDeclaration
+%type  ECPGWhenever
+%type  ECPGunreserved
+%type  ECPGunreserved_con
+%type  ECPGunreserved_interval
+%type  UsingConst
+%type  UsingValue
+%type  c_anything
+%type  c_args
+%type  c_list
+%type  c_stuff
+%type  c_stuff_item
+%type  c_term
+%type  c_thing
+%type  char_variable
+%type  civar
+%type  civarind
+%type  ColLabel
+%type  connect_options
+%type  connection_object
+%type  connection_target
+%type  coutputvariable
+%type  cvariable
+%type  db_prefix
+%type  CreateAsStmt
+%type  DeallocateStmt
+%type  dis_name
+%type  ecpg_bconst
+%type  ecpg_fconst
+%type  ecpg_ident
+%type  ecpg_interval
+%type  ecpg_into
+%type  ecpg_param
+%type  ecpg_sconst
+%type  ecpg_using
+%type  ecpg_xconst
+%type  enum_definition
+%type  enum_type
+%type  execstring
+%type  execute_rest
+%type  indicator
+%type  into_descriptor
+%type  Iresult
+%type  on_off
+%type  opt_bit_field
+%type  opt_connection_name
+%type  opt_database_name
+%type  opt_ecpg_using
+%type  opt_initializer
+%type  opt_options
+%type  opt_output
+%type  opt_pointer
+%type  opt_port
+%type  opt_reference
+%type  opt_scale
+%type  opt_server
+%type  opt_user
+%type  opt_opt_value
+%type  ora_user
+%type  precision
+%type  prepared_name
+%type  quoted_ident_stringvar
+%type  RuleStmt
+%type  s_struct_union
+%type  server
+%type  server_name
+%type  single_vt_declaration
+%type  storage_clause
+%type  storage_declaration
+%type  storage_modifier
+%type  struct_union_type
+%type  struct_union_type_with_symbol
+%type  symbol
+%type  type_declaration
+%type  unreserved_keyword 
+%type  user_name
+%type  using_descriptor
+%type  var_declaration
+%type  var_type_declarations
+%type  variable
+%type  variable_declarations
+%type  variable_list
+%type  vt_declarations 
+
+%type  Op
+%type  IntConstVar
+%type  AllConstVar
+%type  CSTRING
+%type  CPP_LINE
+%type  CVARIABLE
+%type  DOLCONST
+%type  ECONST
+%type  NCONST
+%type  SCONST
+%type  UCONST
+%type  UIDENT
+
+%type   s_struct_union_symbol
+
+%type   ECPGGetDescriptor
+%type   ECPGSetDescriptor
+
+%type   simple_type
+%type   signed_type
+%type   unsigned_type
+
+%type   descriptor_item
+%type   desc_header_item
+
+%type     var_type
+
+%type   action
+