]> granicus.if.org Git - postgresql/blobdiff - src/interfaces/ecpg/preproc/preproc.y
Implement SQL-standard WITH clauses, including WITH RECURSIVE.
[postgresql] / src / interfaces / ecpg / preproc / preproc.y
index b5877f5ef9a906c3e7ef876a075d6c75fbf8e21b..b0d126e9bad26281ef7ac3a0ba7a2146aaebd24f 100644 (file)
@@ -1,23 +1,42 @@
+/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/preproc.y,v 1.373 2008/10/04 21:56:55 tgl Exp $ */
+
 /* Copyright comment */
 %{
 #include "postgres_fe.h"
 
 #include "extern.h"
+#include <unistd.h>
+
+/* 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 */
-char   errortext[128];
+int struct_level = 0;
+int braces_open; /* brace level counter */
+int ecpg_informix_var = 0;
 char   *connection = NULL;
-char   *input_filename = NULL;
+char   *input_filename = NULL;
 
-static int      QueryIsRule = 0, FoundInto = 0;
+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_storage[STRUCT_DEPTH];
-static char     *actual_startline[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 };
@@ -25,30 +44,60 @@ 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;
 
-struct ECPGtype ecpg_no_indicator = {ECPGt_NO_INDICATOR, 0L, NULL, {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, 0L, NULL, {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)
+mmerror(int error_code, enum errortype type, char * error, ...)
 {
-    switch(type)
-    {
-       case ET_WARNING: 
-               fprintf(stderr, "%s:%d: WARNING: %s\n", input_filename, yylineno, error); 
-               break;
-       case ET_ERROR:
-               fprintf(stderr, "%s:%d: ERROR: %s\n", input_filename, yylineno, error);
-               ret_value = error_code;
-               break;
-       case ET_FATAL:
-               fprintf(stderr, "%s:%d: ERROR: %s\n", input_filename, yylineno, error);
-               exit(error_code);
-    }
+       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);
+       }
 }
 
 /*
@@ -57,8 +106,8 @@ mmerror(int error_code, enum errortype type, char * error)
 
 static char *
 cat2_str(char *str1, char *str2)
-{ 
-       char * res_str  = (char *)mm_alloc(strlen(str1) + strlen(str2) + 2);
+{
+       char * res_str  = (char *)mm_alloc(strlen(str1) + strlen(str2) + 2);
 
        strcpy(res_str, str1);
        strcat(res_str, " ");
@@ -72,7 +121,7 @@ static char *
 cat_str(int count, ...)
 {
        va_list         args;
-       int             i; 
+       int                     i;
        char            *res_str;
 
        va_start(args, count);
@@ -99,8 +148,8 @@ make_str(const char *str)
 
 static char *
 make2_str(char *str1, char *str2)
-{ 
-       char * res_str  = (char *)mm_alloc(strlen(str1) + strlen(str2) + 1);
+{
+       char * res_str  = (char *)mm_alloc(strlen(str1) + strlen(str2) + 1);
 
        strcpy(res_str, str1);
        strcat(res_str, str2);
@@ -111,8 +160,8 @@ make2_str(char *str1, char *str2)
 
 static char *
 make3_str(char *str1, char *str2, char *str3)
-{ 
-       char * res_str  = (char *)mm_alloc(strlen(str1) + strlen(str2) +strlen(str3) + 1);
+{
+       char * res_str  = (char *)mm_alloc(strlen(str1) + strlen(str2) +strlen(str3) + 1);
 
        strcpy(res_str, str1);
        strcat(res_str, str2);
@@ -123,6 +172,7 @@ make3_str(char *str1, char *str2, char *str3)
        return(res_str);
 }
 
+/* and the rest */
 static char *
 make_name(void)
 {
@@ -133,136 +183,352 @@ make_name(void)
        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(<counter>)" */
+               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(<counter>, <pointer>. <linen number>)" */
+               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(<counter>)" */
+                       original_var = ptr->indicator->name;
+                       sprintf(temp, "%d))", ecpg_informix_var);
+
+                       /* create call to "ECPG_informix_set_var(<counter>, <pointer>. <linen number>)" */
+                       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;
-       int                     ival;
-       char *                  str;
-       struct when             action;
-       struct index            index;
-       int                     tagname;
-       struct this_type        type;
-       enum ECPGttype          type_enum;
-       enum ECPGdtype          dtype_enum;
-       struct fetch_desc       descriptor;
+       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;
 }
 
 /* special embedded SQL token */
-%token         SQL_ALLOCATE SQL_AUTOCOMMIT SQL_BOOL SQL_BREAK 
-%token         SQL_CALL SQL_CARDINALITY SQL_CONNECT SQL_CONNECTION 
-%token         SQL_CONTINUE SQL_COUNT
-%token         SQL_DATA SQL_DATETIME_INTERVAL_CODE SQL_DATETIME_INTERVAL_PRECISION
-%token         SQL_DEALLOCATE SQL_DESCRIPTOR SQL_DISCONNECT SQL_ENUM 
-%token         SQL_FOUND SQL_FREE SQL_GET SQL_GO SQL_GOTO
-%token         SQL_IDENTIFIED SQL_INDICATOR SQL_INT SQL_KEY_MEMBER 
-%token         SQL_LENGTH SQL_LONG
-%token         SQL_NAME SQL_NULLABLE
-%token         SQL_OCTET_LENGTH SQL_OPEN SQL_PREPARE
-%token         SQL_RELEASE SQL_REFERENCE SQL_RETURNED_LENGTH
-%token         SQL_RETURNED_OCTET_LENGTH
-%token         SQL_SCALE SQL_SECTION SQL_SHORT SQL_SIGNED SQL_SQL 
-%token         SQL_SQLERROR SQL_SQLPRINT
-%token         SQL_SQLWARNING SQL_START SQL_STOP SQL_STRUCT SQL_UNSIGNED
-%token         SQL_VALUE SQL_VAR SQL_WHENEVER
+%token SQL_ALLOCATE SQL_AUTOCOMMIT SQL_BOOL SQL_BREAK
+               SQL_CALL SQL_CARDINALITY SQL_CONNECT
+               SQL_COUNT SQL_DATA
+               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
-%token         S_EQUAL S_EXTERN S_INC S_LSHIFT
-%token         S_MEMPOINT S_MEMBER S_MOD S_MUL S_NEQUAL S_OR
-%token         S_REGISTER S_RSHIFT S_STATIC S_SUB S_VOLATILE
+%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
 
 /* I need this and don't know where it is defined inside the backend */
-%token         TYPECAST
-
-/* Keywords (in SQL92 reserved words) */
-%token  ABSOLUTE, ACTION, ADD, ALL, ALTER, AND, ANY, AS, ASC, AT, AUTHORIZATION, 
-                BEGIN_TRANS, BETWEEN, BOTH, BY,
-                CASCADE, CASE, CAST, CHAIN, CHAR, CHARACTER,
-               CHARACTERISTICS, CHECK, CLOSE,
-               COALESCE, COLLATE, COLUMN, COMMIT, 
-                CONSTRAINT, CONSTRAINTS, CREATE, CROSS, CURRENT, CURRENT_DATE,
-                CURRENT_TIME, CURRENT_TIMESTAMP, CURRENT_USER, CURSOR,
-                DAY_P, DEC, DECIMAL, DECLARE, DEFAULT, DELETE, DESC, DISTINCT, DOUBLE, DROP,
-                ELSE, ENCRYPTED, END_TRANS, EXCEPT, EXECUTE, EXISTS, EXTRACT,
-                FALSE_P, FETCH, FLOAT, FOR, FOREIGN, FROM, FULL,
-                GLOBAL, GRANT, GROUP, HAVING, HOUR_P,
-                IN, INNER_P, INOUT, INSENSITIVE, INSERT, INTERSECT, INTERVAL, INTO, IS,
-                ISOLATION, JOIN, KEY, LANGUAGE, LEADING, LEFT, LEVEL, LIKE, LOCAL,
-                MATCH, MINUTE_P, MONTH_P, NAMES,
-                NATIONAL, NATURAL, NCHAR, NEXT, NO, NOT, NULLIF, NULL_P, NUMERIC,
-                OF, OFF, OLD, ON, ONLY, OPTION, OR, ORDER, OUT, OUTER_P, OVERLAPS,
-                PARTIAL, PATH_P, POSITION, PRECISION, PRIMARY, PRIOR, PRIVILEGES, PROCEDURE, PUBLIC,
-                READ, REFERENCES, RELATIVE, REVOKE, RIGHT, ROLLBACK,
-                SCHEMA, SCROLL, SECOND_P, SELECT, SESSION, SESSION_USER, SET, SOME, SUBSTRING,
-                TABLE, TEMPORARY, THEN, TIME, TIMESTAMP
-               TO, TRAILING, TRANSACTION, TRIM, TRUE_P,
-                UNENCRYPTED, UNION, UNIQUE, UNKNOWN, UPDATE, USAGE, USER, USING,
-                VALUES, VARCHAR, VARYING, VIEW,
-                WHEN, WHERE, WITH, WITHOUT, WORK, YEAR_P, ZONE
-
-/* Keywords (in SQL3 reserved words) */
-%token DEFERRABLE, DEFERRED,
-               IMMEDIATE, INITIALLY,
-               PENDANT,
-               REPLACE, RESTRICT,
-               TRIGGER
-
-/* Keywords (in SQL92 non-reserved words) */
-%token  COMMITTED, SERIALIZABLE, TYPE_P
-
-/* Keywords for Postgres support (not in SQL92 reserved words)
- *
- * The CREATEDB and CREATEUSER tokens should go away
- * when some sort of pg_privileges relation is introduced.
- * - Todd A. Brandys 1998-01-01?
- */
-%token  ABORT_TRANS, ACCESS, AFTER, AGGREGATE, ANALYSE, ANALYZE,
-               BACKWARD, BEFORE, BINARY, BIT, CACHE, CHECKPOINT, CLUSTER,
-               COMMENT, COPY, CREATEDB, CREATEUSER, CYCLE, DATABASE,
-               DELIMITERS, DO, EACH, ENCODING, EXCLUSIVE, EXPLAIN,
-               FORCE, FORWARD, FREEZE, FUNCTION, HANDLER, INCREMENT,
-               INDEX, INHERITS, INSTEAD, ISNULL, LANCOMPILER, LIMIT,
-               LISTEN, UNLISTEN, LOAD, LOCATION, LOCK_P, MAXVALUE,
-               MINVALUE, MODE, MOVE, NEW, NOCREATEDB, NOCREATEUSER,
-               NONE, NOTHING, NOTIFY, NOTNULL, OFFSET, OIDS,
-               OPERATOR, OWNER, PASSWORD, PROCEDURAL, REINDEX, RENAME, RESET,
-               RETURNS, ROW, RULE, SEQUENCE, SETOF, SHARE,
-               SHOW, START, STATEMENT, STATISTICS, STDIN, STDOUT, STORAGE,
-               SYSID, TEMP,
-               TEMPLATE, TOAST, TRUNCATE, TRUSTED, UNLISTEN, UNTIL, VACUUM,
-               VALID, VERBOSE, VERSION
+%token TYPECAST
+
+/* ordinary key words in alphabetical order */
+%token <keyword> ABORT_P ABSOLUTE_P ACCESS ACTION ADD_P ADMIN AFTER
+       AGGREGATE ALL ALSO ALTER ALWAYS ANALYSE ANALYZE AND ANY ARRAY AS ASC
+       ASSERTION ASSIGNMENT ASYMMETRIC AT AUTHORIZATION
+
+       BACKWARD BEFORE BEGIN_P BETWEEN BIGINT BINARY BIT
+       BOOLEAN_P BOTH BY
+
+       CACHE CALLED CASCADE CASCADED CASE CAST CHAIN CHAR_P
+       CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE
+       CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT
+       COMMITTED CONCURRENTLY CONFIGURATION CONNECTION CONSTRAINT CONSTRAINTS 
+       CONTENT_P CONTINUE_P CONVERSION_P COPY COST CREATE CREATEDB
+       CREATEROLE CREATEUSER CROSS CSV CTYPE CURRENT_P CURRENT_DATE CURRENT_ROLE
+       CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE
+
+       DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS
+       DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS DESC
+       DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P DOUBLE_P DROP
+
+       EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ENUM_P ESCAPE EXCEPT EXCLUSIVE EXCLUDING
+       EXECUTE EXISTS EXPLAIN EXTERNAL EXTRACT
+
+       FALSE_P FAMILY FETCH FIRST_P FLOAT_P FOR FORCE FOREIGN FORWARD FREEZE FROM
+       FULL FUNCTION
+
+       GLOBAL GRANT GRANTED GREATEST GROUP_P
+
+       HANDLER HAVING HEADER_P HOLD HOUR_P
+
+       IDENTITY_P IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IN_P
+       INCLUDING INCREMENT INDEX INDEXES INHERIT INHERITS INITIALLY
+       INNER_P INOUT INPUT_P INSENSITIVE INSERT INSTEAD INT_P INTEGER
+       INTERSECT INTERVAL INTO INVOKER IS ISNULL ISOLATION
+
+       JOIN
+
+       KEY
+
+       LANCOMPILER LANGUAGE LARGE_P LAST_P LEADING LEAST LEFT LEVEL
+       LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCATION
+       LOCK_P LOGIN_P
+
+       MAPPING MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE
+
+       NAME_P NAMES NATIONAL NATURAL NCHAR NEW NEXT NO NOCREATEDB
+       NOCREATEROLE NOCREATEUSER NOINHERIT NOLOGIN_P NONE NOSUPERUSER
+       NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF NULLS_P NUMERIC
+
+       OBJECT_P OF OFF OFFSET OIDS OLD ON ONLY OPERATOR OPTION OR ORDER
+       OUT_P OUTER_P OVERLAPS OVERLAY OWNED OWNER
+
+       PARSER PARTIAL PASSWORD PLACING PLANS POSITION
+       PRECISION PRESERVE PREPARE PREPARED PRIMARY
+       PRIOR PRIVILEGES PROCEDURAL PROCEDURE
+
+       QUOTE
+
+       READ REAL REASSIGN RECHECK RECURSIVE REFERENCES REINDEX RELATIVE_P RELEASE RENAME
+       REPEATABLE REPLACE REPLICA RESET RESTART RESTRICT RETURNING RETURNS REVOKE
+       RIGHT ROLE ROLLBACK ROW ROWS RULE
+
+       SAVEPOINT SCHEMA SCROLL SEARCH SECOND_P SECURITY SELECT SEQUENCE
+       SERIALIZABLE SESSION SESSION_USER SET SETOF SHARE
+       SHOW SIMILAR SIMPLE SMALLINT SOME STABLE STANDALONE_P START STATEMENT
+       STATISTICS STDIN STDOUT STORAGE STRICT_P STRIP_P SUBSTRING SUPERUSER_P
+       SYMMETRIC SYSID SYSTEM_P
+
+       TABLE TABLESPACE TEMP TEMPLATE TEMPORARY TEXT_P THEN TIME TIMESTAMP TO 
+       TRAILING TRANSACTION TREAT TRIGGER TRIM TRUE_P TRUNCATE TRUSTED TYPE_P
+
+       UNCOMMITTED UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNTIL
+       UPDATE USER USING
+
+       VACUUM VALID VALIDATOR VALUE_P VALUES VARCHAR VARIADIC VARYING
+       VERBOSE VERSION_P VIEW VOLATILE
+       WHEN WHERE WHITESPACE_P WITH WITHOUT WORK WRITE
+
+       XML_P XMLATTRIBUTES XMLCONCAT XMLELEMENT XMLFOREST XMLPARSE
+       XMLPI XMLROOT XMLSERIALIZE
+
+       YEAR_P YES_P
+
+       ZONE
 
 /* The grammar thinks these are keywords, but they are not in the keywords.c
  * list and so can never be entered directly.  The filter in parser.c
  * creates these tokens when required.
  */
-%token                 UNIONJOIN
-                
-/* Special keywords, not in the query language - see the "lex" file */
-%token <str>    IDENT SCONST Op CSTRING CVARIABLE CPP_LINE IP BITCONST
-%token <ival>   ICONST PARAM
-%token <dval>   FCONST
+%token           NULLS_FIRST NULLS_LAST WITH_CASCADED WITH_LOCAL WITH_CHECK
 
-/* these are not real. they are here so that they get generated as #define's*/
-%token                  OP
+/* Special token types, not actually keywords - see the "lex" file */
+%token <str>   IDENT SCONST Op CSTRING CVARIABLE CPP_LINE IP BCONST
+%token <str>   XCONST DOLCONST ECONST NCONST
+%token <ival>  ICONST PARAM
+%token <dval>  FCONST
 
 /* precedence: lowest to highest */
+%nonassoc      SET                             /* see relation_expr_opt_alias */
 %left          UNION EXCEPT
 %left          INTERSECT
-%left          JOIN UNIONJOIN CROSS LEFT FULL RIGHT INNER_P NATURAL 
 %left          OR
 %left          AND
 %right         NOT
 %right         '='
 %nonassoc      '<' '>'
-%nonassoc      LIKE ILIKE
+%nonassoc      LIKE ILIKE SIMILAR
 %nonassoc      ESCAPE
 %nonassoc      OVERLAPS
 %nonassoc      BETWEEN
-%nonassoc      IN
-%left           POSTFIXOP                              /* dummy for postfix Op rules */    
-%left          Op                              /* multi-character ops and user-defined operators */
+%nonassoc      IN_P
+%left          POSTFIXOP               /* dummy for postfix Op rules */
+%nonassoc      IDENT                   /* to support target_el without AS */
+%left          Op OPERATOR             /* multi-character ops and user-defined operators */
 %nonassoc      NOTNULL
 %nonassoc      ISNULL
 %nonassoc      IS NULL_P TRUE_P FALSE_P UNKNOWN
@@ -270,336 +536,466 @@ make_name(void)
 %left          '*' '/' '%'
 %left          '^'
 /* Unary Operators */
-%left           AT ZONE
+%left          AT ZONE
 %right         UMINUS
-%left          '.'
 %left          '[' ']'
 %left          '(' ')'
 %left          TYPECAST
+%left          '.'
+%left          JOIN CROSS LEFT FULL RIGHT INNER_P NATURAL
+/* kluge to keep xml_whitespace_option from causing shift/reduce conflicts */
+%right         PRESERVE STRIP_P
 
-%type  <str>   Iconst Fconst Sconst TransactionStmt CreateStmt UserId
+%type  <str>   Iconst Fconst Sconst TransactionStmt CreateStmt RoleId
 %type  <str>   CreateAsElement OptCreateAs CreateAsList CreateAsStmt
-%type  <str>   key_reference comment_text ConstraintDeferrabilitySpec
-%type  <str>    key_match ColLabel SpecialRuleRelation ColId columnDef
-%type  <str>    ColConstraint ColConstraintElem drop_type Bitconst
-%type  <str>    OptTableElementList OptTableElement TableConstraint
-%type  <str>    ConstraintElem key_actions ColQualList type_name DropSchemaStmt
-%type  <str>    target_list target_el update_target_list alias_clause
-%type  <str>    update_target_el opt_id relation_name database_name
-%type  <str>    access_method attr_name class index_name name func_name
-%type  <str>    file_name AexprConst ParamNo c_expr ConstTypename
-%type  <str>   in_expr_nodes a_expr b_expr TruncateStmt CommentStmt
-%type  <str>   opt_indirection expr_list extract_list extract_arg
+%type  <str>   comment_text ConstraintDeferrabilitySpec TableElementList
+%type  <str>   key_match ColLabel SpecialRuleRelation ColId columnDef
+%type  <str>   ColConstraint ColConstraintElem drop_type Bconst Iresult
+%type  <str>   TableConstraint OptTableElementList Xconst opt_transaction
+%type  <str>   ConstraintElem key_actions ColQualList cluster_index_specification
+%type  <str>   target_list target_el alias_clause type_func_name_keyword
+%type  <str>   qualified_name database_name alter_using type_function_name
+%type  <str>   access_method attr_name index_name name func_name opt_restart_seqs
+%type  <str>   file_name AexprConst c_expr ConstTypename var_list 
+%type  <str>   a_expr b_expr TruncateStmt CommentStmt OnCommitOption opt_by
+%type  <str>   opt_indirection expr_list extract_list extract_arg OptSeqOptList
 %type  <str>   position_list substr_list substr_from alter_column_default
-%type  <str>   trim_list in_expr substr_for attr attrs drop_behavior
-%type  <str>   Typename SimpleTypename Generic Numeric opt_float opt_numeric
-%type  <str>   opt_decimal Character character opt_varying opt_charset
-%type  <str>   opt_collate opt_timezone opt_interval table_ref
-%type  <str>   row_expr row_descriptor row_list ConstDatetime opt_chain
+%type  <str>   trim_list in_expr substr_for attrs TableFuncElement
+%type  <str>   Typename SimpleTypename Numeric opt_float DiscardStmt
+%type  <str>   Character character opt_varying opt_charset enum_val_list
+%type  <str>   opt_timezone opt_interval table_ref fetch_direction
+%type  <str>   ConstDatetime AlterDomainStmt AlterSeqStmt table_func_column
 %type  <str>   SelectStmt into_clause OptTemp ConstraintAttributeSpec
-%type  <str>   opt_table opt_all sort_clause sortby_list ConstraintAttr 
-%type  <str>   sortby OptUseOp relation_name_list name_list ColId_or_Sconst
-%type  <str>   group_clause having_clause from_clause opt_distinct
-%type  <str>   join_outer where_clause relation_expr sub_type opt_arg
-%type  <str>   opt_column_list insert_rest InsertStmt OptimizableStmt
-%type  <str>    columnList DeleteStmt LockStmt UpdateStmt CursorStmt
-%type  <str>    NotifyStmt columnElem copy_dirn UnlistenStmt copy_null
-%type  <str>    copy_delimiter ListenStmt CopyStmt copy_file_name opt_binary
-%type  <str>    opt_with_copy FetchStmt direction fetch_how_many from_in
-%type  <str>    ClosePortalStmt DropStmt VacuumStmt AnalyzeStmt opt_verbose
-%type  <str>    opt_full func_arg OptWithOids opt_freeze opt_ecpg_into
-%type  <str>    analyze_keyword opt_name_list ExplainStmt index_params
-%type  <str>    index_list func_index index_elem opt_class access_method_clause
-%type  <str>    index_opt_unique IndexStmt func_return ConstInterval
-%type  <str>    func_args_list func_args opt_with ProcedureStmt def_arg
-%type  <str>    def_elem def_list definition DefineStmt select_with_parens
-%type  <str>    opt_instead event event_object RuleActionList opt_using
+%type  <str>   opt_table opt_all sort_clause sortby_list ConstraintAttr
+%type  <str>   sortby qualified_name_list name_list ColId_or_Sconst
+%type  <str>   group_clause having_clause from_clause opt_distinct opt_hold
+%type  <str>   join_outer where_clause relation_expr sub_type arg_class
+%type  <str>   opt_column_list insert_rest InsertStmt param_name
+%type  <str>   columnList DeleteStmt UpdateStmt DeclareCursorStmt
+%type  <str>   NotifyStmt columnElem UnlistenStmt TableElement fetch_count
+%type  <str>   copy_delimiter ListenStmt CopyStmt copy_file_name opt_binary
+%type  <str>   FetchStmt from_in CreateOpClassStmt returning_clause
+%type  <str>   ClosePortalStmt DropStmt VacuumStmt AnalyzeStmt opt_verbose
+%type  <str>   opt_full func_arg OptWith opt_freeze alter_table_cmd
+%type  <str>   analyze_keyword opt_name_list ExplainStmt index_params
+%type  <str>   index_elem opt_class access_method_clause alter_table_cmds
+%type  <str>   index_opt_unique IndexStmt func_return ConstInterval
+%type  <str>   func_args_list func_args opt_with def_arg overlay_placing
+%type  <str>   def_elem def_list definition DefineStmt select_with_parens
+%type  <str>   opt_instead event RuleActionList opt_using CreateAssertStmt
 %type  <str>   RuleActionStmtOrEmpty RuleActionMulti func_as reindex_type
-%type  <str>    RuleStmt opt_column opt_name oper_argtypes NumConst
-%type  <str>    MathOp RemoveFuncStmt aggr_argtype for_update_clause
-%type  <str>    RemoveAggrStmt opt_procedural select_no_parens
-%type  <str>    RemoveOperStmt RenameStmt all_Op opt_Trusted opt_lancompiler 
-%type  <str>    VariableSetStmt var_value zone_value VariableShowStmt
-%type  <str>    VariableResetStmt AlterTableStmt DropUserStmt from_list
-%type  <str>    opt_trans user_list OptUserList OptUserElem
-%type  <str>    CreateUserStmt AlterUserStmt CreateSeqStmt OptSeqList
-%type  <str>    OptSeqElem TriggerForSpec TriggerForOpt TriggerForType
+%type  <str>   RuleStmt opt_column oper_argtypes NumConst var_name
+%type  <str>   MathOp RemoveFuncStmt ECPGunreserved_con opt_database_name
+%type  <str>   RemoveAggrStmt opt_procedural select_no_parens CreateCastStmt
+%type  <str>   RemoveOperStmt RenameStmt all_Op opt_trusted opt_lancompiler
+%type  <str>   VariableSetStmt var_value zone_value VariableShowStmt
+%type  <str>   VariableResetStmt AlterTableStmt from_list overlay_list
+%type  <str>   relation_name OptTableSpace LockStmt opt_lock table_func_column_list
+%type  <str>   CreateUserStmt AlterUserStmt CreateSeqStmt SeqOptList
+%type  <str>   SeqOptElem TriggerForSpec TriggerForOpt TriggerForType
 %type  <str>   DropTrigStmt TriggerOneEvent TriggerEvents RuleActionStmt
-%type  <str>    TriggerActionTime CreateTrigStmt DropPLangStmt 
-%type  <str>    CreatePLangStmt TriggerFuncArgs TriggerFuncArg simple_select
-%type  <str>    ViewStmt LoadStmt CreatedbStmt createdb_opt_item
+%type  <str>   TriggerActionTime CreateTrigStmt DropPLangStmt DropCastStmt
+%type  <str>   CreatePLangStmt TriggerFuncArgs TriggerFuncArg simple_select
+%type  <str>   ViewStmt LoadStmt CreatedbStmt createdb_opt_item ExplainableStmt
 %type  <str>   createdb_opt_list opt_encoding OptInherit opt_equal
-%type  <str>   AlterUserSetStmt privilege_list privilege privilege_target
-%type  <str>    opt_grant_grant_option opt_revoke_grant_option
-%type  <str>   function_with_argtypes_list function_with_argtypes
-%type  <str>    DropdbStmt ClusterStmt grantee RevokeStmt Bit bit
-%type  <str>   GrantStmt privileges PosAllConst
-%type  <str>   opt_cursor ConstraintsSetStmt AllConst
+%type  <str>   privilege_list privilege privilege_target opt_if_exists
+%type  <str>   opt_grant_grant_option cursor_options DropOwnedStmt
+%type  <str>   transaction_mode_list_or_empty transaction_mode_list
+%type  <str>   function_with_argtypes_list function_with_argtypes IntConstVar
+%type  <str>   DropdbStmt ClusterStmt grantee RevokeStmt Bit DropOpClassStmt
+%type  <str>   GrantStmt privileges PosAllConst constraints_set_list
+%type  <str>   ConstraintsSetStmt AllConst CreateDomainStmt opt_nowait
 %type  <str>   case_expr when_clause_list case_default case_arg when_clause
-%type  <str>    select_clause opt_select_limit select_limit_value
-%type  <str>   ConstraintTimeSpec AlterDatabaseSetStmt
-%type  <str>    select_offset_value ReindexStmt join_type opt_boolean
-%type  <str>   join_qual update_list AlterSchemaStmt joined_table
-%type  <str>   opt_level opt_lock lock_type OptGroupList OptGroupElem
-%type  <str>    OptConstrFromTable OptTempTableName StringConst
-%type  <str>    constraints_set_list constraints_set_namelist
-%type  <str>   constraints_set_mode comment_type opt_empty_parentheses
+%type  <str>   select_clause opt_select_limit select_limit_value opt_recheck
+%type  <str>   ConstraintTimeSpec AlterDatabaseSetStmt DropAssertStmt
+%type  <str>   select_offset_value ReindexStmt join_type opt_boolean
+%type  <str>   join_qual joined_table opclass_item relation_expr_opt_alias
+%type  <str>   lock_type array_expr_list ReassignOwnedStmt for_locking_item
+%type  <str>   OptConstrFromTable OptTempTableName StringConst array_expr
+%type  <str>   constraints_set_mode comment_type opt_check_option
 %type  <str>   CreateGroupStmt AlterGroupStmt DropGroupStmt key_delete
 %type  <str>   opt_force key_update CreateSchemaStmt PosIntStringConst
-%type  <str>    IntConst PosIntConst grantee_list func_type opt_or_replace
-%type  <str>    select_limit opt_for_update_clause CheckPointStmt
-
+%type  <str>   IntConst PosIntConst grantee_list func_type opt_or_replace
+%type  <str>   select_limit CheckPointStmt ECPGColId old_aggr_list
+%type  <str>   OptSchemaName OptSchemaEltList schema_stmt opt_drop_behavior
+%type  <str>   handler_name any_name_list any_name opt_as insert_column_list
+%type  <str>   columnref values_clause AllConstVar prep_type_clause ExecuteStmt
+%type  <str>   insert_column_item DropRuleStmt ctext_expr execute_param_clause 
+%type  <str>   createfunc_opt_item set_rest 
+%type  <str>   CreateFunctionStmt createfunc_opt_list func_table
+%type  <str>   DropUserStmt copy_from copy_opt_list copy_opt_item
+%type  <str>   opt_oids TableLikeClause key_action opt_definition
+%type  <str>   cast_context row qual_Op qual_all_Op opt_default
+%type  <str>   CreateConversionStmt any_operator opclass_item_list
+%type  <str>   iso_level type_list CharacterWithLength ConstCharacter
+%type  <str>   CharacterWithoutLength BitWithLength BitWithoutLength
+%type  <str>   ConstBit GenericType TableFuncElementList opt_analyze
+%type  <str>   opt_sort_clause subquery_Op transaction_mode_item
 %type  <str>   ECPGWhenever ECPGConnect connection_target ECPGOpen
-%type  <str>   indicator ECPGExecute ECPGPrepare ecpg_using ecpg_into
-%type  <str>    storage_clause opt_initializer c_anything blockstart
-%type  <str>    blockend variable_list variable c_thing c_term
+%type  <str>   indicator ecpg_using ecpg_into DeallocateStmt
+%type  <str>   storage_declaration storage_clause opt_initializer c_anything
+%type  <str>   variable_list variable c_thing c_term ECPGKeywords_vanames
 %type  <str>   opt_pointer ECPGDisconnect dis_name storage_modifier
-%type  <str>   stmt ECPGRelease execstring server_name
+%type  <str>   execstring server_name ECPGVarDeclaration func_expr
 %type  <str>   connection_object opt_server opt_port c_stuff c_stuff_item
-%type  <str>    user_name opt_user char_variable ora_user ident opt_reference
-%type  <str>   quoted_ident_stringvar
-%type  <str>    db_prefix server opt_options opt_connection_name c_list
-%type  <str>   ECPGSetConnection cpp_line ECPGTypedef c_args ECPGKeywords
-%type  <str>   enum_type civar civarind ECPGCursorStmt ECPGDeallocate
-%type  <str>   ECPGFree ECPGDeclare ECPGVar opt_at enum_definition
-%type  <str>    struct_type s_struct declaration declarations variable_declarations
-%type  <str>    s_union union_type ECPGSetAutocommit on_off
-%type  <str>   ECPGAllocateDescr ECPGDeallocateDescr symbol opt_symbol
-%type  <str>   ECPGGetDescriptorHeader ECPGColLabel
-%type  <str>   reserved_keyword unreserved_keyword
-%type  <str>   col_name_keyword func_name_keyword
-%type  <str>   ECPGTypeName variablelist cvariable
-
-%type  <descriptor> ECPGGetDescriptor
+%type  <str>   user_name opt_user char_variable ora_user ident opt_reference
+%type  <str>   var_type_declarations quoted_ident_stringvar ECPGKeywords_rest
+%type  <str>   db_prefix server connect_options opt_options opt_connection_name c_list
+%type  <str>   ECPGSetConnection ECPGTypedef c_args ECPGKeywords ECPGCKeywords
+%type  <str>   enum_type civar civarind ECPGCursorStmt PreparableStmt
+%type  <str>   ECPGFree ECPGDeclare ECPGVar at enum_definition opt_opt_value
+%type  <str>   struct_union_type s_struct_union vt_declarations execute_rest
+%type  <str>   var_declaration type_declaration single_vt_declaration
+%type  <str>   ECPGSetAutocommit on_off variable_declarations ECPGDescribe
+%type  <str>   ECPGAllocateDescr ECPGDeallocateDescr symbol opt_output
+%type  <str>   ECPGGetDescriptorHeader ECPGColLabel SetResetClause AlterUserSetStmt
+%type  <str>   reserved_keyword unreserved_keyword ecpg_interval opt_ecpg_using
+%type  <str>   col_name_keyword precision opt_scale ECPGExecuteImmediateStmt
+%type  <str>   ECPGTypeName using_list ECPGColLabelCommon UsingConst 
+%type  <str>   using_descriptor into_descriptor opt_nulls_order opt_asc_desc
+%type  <str>   prepared_name struct_union_type_with_symbol OptConsTableSpace
+%type  <str>   ECPGunreserved ECPGunreserved_interval cvariable opt_bit_field
+%type  <str>   AlterOwnerStmt OptTableSpaceOwner CreateTableSpaceStmt
+%type  <str>   DropTableSpaceStmt indirection indirection_el ECPGSetDescriptorHeader
+%type  <str>   AlterDatabaseStmt CreateRoleStmt OptRoleList AlterRoleStmt AlterRoleSetStmt
+%type  <str>   DropRoleStmt add_drop opt_validator common_func_opt_item
+%type  <str>   opt_grant_admin_option AlterFunctionStmt alterfunc_opt_list opt_restrict
+%type  <str>   AlterObjectSchemaStmt alterdb_opt_list for_locking_clause opt_for_locking_clause
+%type  <str>   locked_rels_list opt_granted_by RevokeRoleStmt alterdb_opt_item using_clause
+%type  <str>   GrantRoleStmt opt_asymmetric aggr_args old_aggr_definition
+%type  <str>   old_aggr_elem for_locking_items TableLikeOptionList TableLikeOption
+%type  <str>   set_target_list set_clause_list set_clause multiple_set_clause
+%type  <str>   ctext_expr_list ctext_row single_set_clause set_target opt_type_modifiers
+%type  <str>   opclass_drop_list opclass_drop DropOpFamilyStmt opt_opfamily
+%type  <str>   CreateOpFamilyStmt AlterOpFamilyStmt create_as_target
+%type  <str>   xml_attributes xml_attribute_list document_or_content xml_whitespace_option
+%type  <str>   opt_xml_root_standalone xml_root_version xml_attribute_el 
+%type  <str>   where_or_current_clause AlterTSConfigurationStmt AlterTSDictionaryStmt
+
+%type  <struct_union> s_struct_union_symbol
+
+%type  <descriptor> ECPGGetDescriptor ECPGSetDescriptor
 
 %type  <type_enum> simple_type signed_type unsigned_type
 
 %type  <dtype_enum> descriptor_item desc_header_item
 
-%type  <type>  type
+%type  <type>  var_type
 
-%type  <action> action
+%type  <prep>  PrepareStmt
 
-%type  <index> opt_array_bounds opt_type_array_bounds
+%type  <action> action
 
-%type  <ival>  Iresult
+%type  <index> opt_array_bounds
 
-%token YYERROR_VERBOSE
 %%
 prog: statements;
 
-statements: /* empty */
-       | statements statement
-
-statement: ecpgstart opt_at stmt ';'   { connection = NULL; }
-       | ecpgstart stmt ';'
-       | ECPGDeclaration
-       | c_thing                       { fprintf(yyout, "%s", $1); free($1); }
-       | cpp_line                      { fprintf(yyout, "%s", $1); free($1); }
-       | blockstart                    { fputs($1, yyout); free($1); }
-       | blockend                      { fputs($1, yyout); free($1); }
-       ;
-
-opt_at:        AT connection_target            {
-                                               connection = $2;
-                                               /* 
-                                                  if we have a variable as connection
-                                                  target, remove it from the variable
-                                                  list or else it will be used twice
-                                               */
-                                               if (argsinsert != NULL)
-                                                       argsinsert = NULL;
-                                       };
-
-stmt:  AlterDatabaseSetStmt            { output_statement($1, 0, connection); }
-               | AlterGroupStmt        { output_statement($1, 0, connection); }
-               | AlterSchemaStmt       { output_statement($1, 0, connection); }
-               | AlterTableStmt        { output_statement($1, 0, connection); }
-               | AlterUserStmt         { output_statement($1, 0, connection); }
-               | AlterUserSetStmt      { output_statement($1, 0, connection); }
-               | ClosePortalStmt       { output_statement($1, 0, connection); }
-               | CommentStmt           { output_statement($1, 0, connection); }
-               | CopyStmt              { output_statement($1, 0, connection); }
-               | CreateStmt            { output_statement($1, 0, connection); }
-               | CreateAsStmt          { output_statement($1, 0, connection); }
-               | CreateSchemaStmt      { output_statement($1, 0, connection); }
-               | CreateGroupStmt       { output_statement($1, 0, connection); }
-               | CreateSeqStmt         { output_statement($1, 0, connection); }
-               | CreatePLangStmt       { output_statement($1, 0, connection); }
-               | CreateTrigStmt        { output_statement($1, 0, connection); }
-               | CreateUserStmt        { output_statement($1, 0, connection); }
-               | ClusterStmt           { output_statement($1, 0, connection); }
-               | DefineStmt            { output_statement($1, 0, connection); }
-               | DropStmt              { output_statement($1, 0, connection); }
-               | DropSchemaStmt        { output_statement($1, 0, connection); }
-               | TruncateStmt          { output_statement($1, 0, connection); }
-               | DropGroupStmt         { output_statement($1, 0, connection); }
-               | DropPLangStmt         { output_statement($1, 0, connection); }
-               | DropTrigStmt          { output_statement($1, 0, connection); }
-               | DropUserStmt          { output_statement($1, 0, connection); }
-               | ExplainStmt           { output_statement($1, 0, connection); }
-               | FetchStmt             { output_statement($1, 1, connection); }
-               | GrantStmt             { output_statement($1, 0, connection); }
-               | IndexStmt             { output_statement($1, 0, connection); }
-               | ListenStmt            { output_statement($1, 0, connection); }
-               | UnlistenStmt          { output_statement($1, 0, connection); }
-               | LockStmt              { output_statement($1, 0, connection); }
-               | NotifyStmt            { output_statement($1, 0, connection); }
-               | ProcedureStmt         { output_statement($1, 0, connection); }
-               | ReindexStmt           { output_statement($1, 0, connection); }
-               | RemoveAggrStmt        { output_statement($1, 0, connection); }
-               | RemoveOperStmt        { output_statement($1, 0, connection); }
-               | RemoveFuncStmt        { output_statement($1, 0, connection); }
-               | RenameStmt            { output_statement($1, 0, connection); }
-               | RevokeStmt            { output_statement($1, 0, connection); }
-                | OptimizableStmt      {
-                                               if (strncmp($1, "/* " , sizeof("/* ")-1) == 0)
-                                                       output_simple_statement($1);
-                                               else
-                                                       output_statement($1, 1, connection);
-                                       }
-               | RuleStmt              { output_statement($1, 0, connection); }
-               | TransactionStmt       {
-                                               fprintf(yyout, "{ ECPGtrans(__LINE__, %s, \"%s\");", connection ? connection : "NULL", $1);
-                                               whenever_action(2);
-                                               free($1);
-                                       }
-               | ViewStmt              { output_statement($1, 0, connection); }
-               | LoadStmt              { output_statement($1, 0, connection); }
-               | CreatedbStmt          { output_statement($1, 0, connection); }
-               | DropdbStmt            { output_statement($1, 0, connection); }
-               | VacuumStmt            { output_statement($1, 0, connection); }
-               | AnalyzeStmt           { output_statement($1, 0, connection); }
-               | VariableSetStmt       { output_statement($1, 0, connection); }
-               | VariableShowStmt      { output_statement($1, 0, connection); }
-               | VariableResetStmt     { output_statement($1, 0, connection); }
-               | ConstraintsSetStmt    { output_statement($1, 0, connection); }
-               | CheckPointStmt        { output_statement($1, 0, connection); }
-               | 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__, %s, %d); ", $1, autocommit);
-
-                                               reset_variables();
-
-                                               whenever_action(2);
-                                               free($1);
-                                       } 
-               | ECPGCursorStmt        {
-                                               output_simple_statement($1);
-                                       }
-               | ECPGDeallocate        {
-                                               if (connection)
-                                                       mmerror(PARSE_ERROR, ET_ERROR, "no at option for connect statement.\n");
+statements: /*EMPTY*/
+               | statements statement
+               ;
 
-                                               fputc('{', yyout);
-                                               fputs($1, yyout);
-                                               whenever_action(2);
-                                               free($1);
-                                       }
-               | ECPGDeallocateDescr   {       fprintf(yyout,"ECPGdeallocate_desc(__LINE__, %s);",$1);
-                                                                       whenever_action(0);
-                                                                       free($1);
-                                                               }
-               | ECPGDeclare           {
-                                               output_simple_statement($1);
-                                       }
-               | ECPGDisconnect        {
-                                               if (connection)
-                                                       mmerror(PARSE_ERROR, ET_ERROR, "no at option for disconnect statement.\n");
+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); }
+               ;
 
-                                               fprintf(yyout, "{ ECPGdisconnect(__LINE__, %s);", $1); 
-                                               whenever_action(2);
-                                               free($1);
-                                       } 
-               | ECPGExecute           {       output_statement($1, 0, connection); }
-               | ECPGFree              {
-                                               fprintf(yyout, "{ ECPGdeallocate(__LINE__, \"%s\");", $1);
+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;
+               }
+       ;
 
-                                               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;
-                                               struct arguments *p;
-                                               for (ptr = cur; ptr != NULL; ptr=ptr->next)
-                                               {
-                                                      if (strcmp(ptr->name, $1) == 0)
-                                                               break;
-                                               }
-                                               
-                                               if (ptr == NULL)
+stmt:  AlterDatabaseStmt               { output_statement($1, 0, ECPGst_normal); }
+               | AlterDatabaseSetStmt  { output_statement($1, 0, ECPGst_normal); }
+               | AlterDomainStmt       { output_statement($1, 0, ECPGst_normal); }
+               | AlterFunctionStmt     { output_statement($1, 0, ECPGst_normal); }
+               | AlterGroupStmt        { output_statement($1, 0, ECPGst_normal); }
+               | AlterObjectSchemaStmt { output_statement($1, 0, ECPGst_normal); }
+               | AlterOwnerStmt        { output_statement($1, 0, ECPGst_normal); }
+               | AlterSeqStmt          { output_statement($1, 0, ECPGst_normal); }
+               | AlterTableStmt        { output_statement($1, 0, ECPGst_normal); }
+               | AlterRoleSetStmt      { output_statement($1, 0, ECPGst_normal); }
+               | AlterRoleStmt         { output_statement($1, 0, ECPGst_normal); }
+               | AlterTSConfigurationStmt      { output_statement($1, 0, ECPGst_normal); }
+               | AlterTSDictionaryStmt { output_statement($1, 0, ECPGst_normal); }
+               | AlterUserStmt         { output_statement($1, 0, ECPGst_normal); }
+               | AlterUserSetStmt      { output_statement($1, 0, ECPGst_normal); }
+               | AnalyzeStmt           { output_statement($1, 0, ECPGst_normal); }
+               | CheckPointStmt        { output_statement($1, 0, ECPGst_normal); }
+               | ClosePortalStmt
+               {
+                       if (INFORMIX_MODE)
+                       {
+                               /*
+                                *      Informix also has a CLOSE DATABASE command that
+                                *      essantially works like a DISCONNECT CURRENT
+                                *      as far as I know.
+                                */
+                               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);
+                               }
+                               else
+                                       output_statement($1, 0, ECPGst_normal);
+                       }
+                       else
+                               output_statement($1, 0, ECPGst_normal);
+               }
+               | ClusterStmt           { output_statement($1, 0, ECPGst_normal); }
+               | CommentStmt           { output_statement($1, 0, ECPGst_normal); }
+               | ConstraintsSetStmt    { output_statement($1, 0, ECPGst_normal); }
+               | CopyStmt              { output_statement($1, 0, ECPGst_normal); }
+               | CreateAsStmt          { output_statement($1, 0, ECPGst_normal); }
+               | CreateAssertStmt      { output_statement($1, 0, ECPGst_normal); }
+               | CreateCastStmt        { output_statement($1, 0, ECPGst_normal); }
+               | CreateConversionStmt  { output_statement($1, 0, ECPGst_normal); }
+               | CreateDomainStmt      { output_statement($1, 0, ECPGst_normal); }
+               | CreateFunctionStmt    { output_statement($1, 0, ECPGst_normal); }
+               | CreateGroupStmt       { output_statement($1, 0, ECPGst_normal); }
+               | CreatePLangStmt       { output_statement($1, 0, ECPGst_normal); }
+               | CreateOpClassStmt     { output_statement($1, 0, ECPGst_normal); }
+               | CreateOpFamilyStmt    { output_statement($1, 0, ECPGst_normal); }
+               | AlterOpFamilyStmt     { output_statement($1, 0, ECPGst_normal); }
+               | CreateRoleStmt        { output_statement($1, 0, ECPGst_normal); }
+               | CreateSchemaStmt      { output_statement($1, 0, ECPGst_normal); }
+               | CreateSeqStmt         { output_statement($1, 0, ECPGst_normal); }
+               | CreateStmt            { output_statement($1, 0, ECPGst_normal); }
+               | CreateTableSpaceStmt  { output_statement($1, 0, ECPGst_normal); }
+               | CreateTrigStmt        { output_statement($1, 0, ECPGst_normal); }
+               | CreateUserStmt        { output_statement($1, 0, ECPGst_normal); }
+               | CreatedbStmt          { output_statement($1, 0, ECPGst_normal); }
+               | DeallocateStmt
+               {
+                       if (connection)
+                               mmerror(PARSE_ERROR, ET_ERROR, "no at option for deallocate statement\n");
+                               
+                       output_deallocate_prepare_statement($1);
+               }
+               | DeclareCursorStmt     { output_simple_statement($1); }
+               | DefineStmt            { output_statement($1, 0, ECPGst_normal); }
+               | DeleteStmt            { output_statement($1, 1, ECPGst_normal); }
+               | DiscardStmt           { output_statement($1, 1, ECPGst_normal); }
+               | DropAssertStmt        { output_statement($1, 0, ECPGst_normal); }
+               | DropCastStmt          { output_statement($1, 0, ECPGst_normal); }
+               | DropGroupStmt         { output_statement($1, 0, ECPGst_normal); }
+               | DropOpClassStmt       { output_statement($1, 0, ECPGst_normal); }
+               | DropOpFamilyStmt      { output_statement($1, 0, ECPGst_normal); }
+               | DropOwnedStmt         { output_statement($1, 0, ECPGst_normal); }
+               | DropPLangStmt         { output_statement($1, 0, ECPGst_normal); }
+               | DropRoleStmt          { output_statement($1, 0, ECPGst_normal); }
+               | DropRuleStmt          { output_statement($1, 0, ECPGst_normal); }
+               | DropStmt              { output_statement($1, 0, ECPGst_normal); }
+               | DropTableSpaceStmt    { output_statement($1, 0, ECPGst_normal); }
+               | DropTrigStmt          { output_statement($1, 0, ECPGst_normal); }
+               | DropUserStmt          { output_statement($1, 0, ECPGst_normal); }
+               | DropdbStmt            { output_statement($1, 0, ECPGst_normal); }
+               | ExplainStmt           { output_statement($1, 0, ECPGst_normal); }
+               | ExecuteStmt           { output_statement($1, 1, ECPGst_execute); }
+               | FetchStmt             { output_statement($1, 1, ECPGst_normal); }
+               | GrantStmt             { output_statement($1, 0, ECPGst_normal); }
+               | GrantRoleStmt         { output_statement($1, 0, ECPGst_normal); }
+               | IndexStmt             { output_statement($1, 0, ECPGst_normal); }
+               | InsertStmt            { output_statement($1, 1, ECPGst_normal); }
+               | ListenStmt            { output_statement($1, 0, ECPGst_normal); }
+               | LoadStmt              { output_statement($1, 0, ECPGst_normal); }
+               | LockStmt              { output_statement($1, 0, ECPGst_normal); }
+               | NotifyStmt            { output_statement($1, 0, ECPGst_normal); }
+               | PrepareStmt           { 
+                                               if ($1.type == NULL || strlen($1.type) == 0) /* use PQprepare without type parameters */
+                                                       output_prepare_statement($1.name, $1.stmt);  
+                                               else    /* use PQexec and let backend do its stuff */
                                                {
-                                                       sprintf(errortext, "trying to open undeclared cursor %s\n", $1);
-                                                       mmerror(PARSE_ERROR, ET_ERROR, errortext);
+                                                       char *txt = cat_str(5, make_str("prepare"), $1.name, $1.type, make_str("as"), $1.stmt);
+                                                       output_statement(txt, 0, ECPGst_normal);
                                                }
+                                       }               
+               | ReassignOwnedStmt     { output_statement($1, 0, ECPGst_normal); }
+               | ReindexStmt           { output_statement($1, 0, ECPGst_normal); }
+               | RemoveAggrStmt        { output_statement($1, 0, ECPGst_normal); }
+               | RemoveOperStmt        { output_statement($1, 0, ECPGst_normal); }
+               | RemoveFuncStmt        { output_statement($1, 0, ECPGst_normal); }
+               | RenameStmt            { output_statement($1, 0, ECPGst_normal); }
+               | RevokeStmt            { output_statement($1, 0, ECPGst_normal); }
+               | RevokeRoleStmt        { output_statement($1, 0, ECPGst_normal); }
+               | RuleStmt              { output_statement($1, 0, ECPGst_normal); }
+               | SelectStmt            { output_statement($1, 1, ECPGst_normal); }
+               | TransactionStmt
+               {
+                       fprintf(yyout, "{ ECPGtrans(__LINE__, %s, \"%s\");", connection ? connection : "NULL", $1);
+                       whenever_action(2);
+                       free($1);
+               }
+               | TruncateStmt          { output_statement($1, 0, ECPGst_normal); }
+               | UnlistenStmt          { output_statement($1, 0, ECPGst_normal); }
+               | UpdateStmt            { output_statement($1, 1, ECPGst_normal); }
+               | VacuumStmt            { output_statement($1, 0, ECPGst_normal); }
+               | VariableSetStmt       { output_statement($1, 0, ECPGst_normal); }
+               | VariableShowStmt      { output_statement($1, 0, ECPGst_normal); }
+               | VariableResetStmt     { output_statement($1, 0, ECPGst_normal); }
+               | ViewStmt              { output_statement($1, 0, ECPGst_normal); }
+               | 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");
 
-                                               /* merge variables given in prepare statement with those given here */
-                                               for (p = ptr->argsinsert; p; p = p->next)
-                                                       append_variable(&argsinsert, p->variable, p->indicator); 
+                       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();
+
+                       /* whenever_action(2); */
+                       free($1);
+               }
+               | ECPGDisconnect
+               {
+                       if (connection)
+                               mmerror(PARSE_ERROR, ET_ERROR, "no at option for disconnect statement\n");
 
-                                               for (p = ptr->argsresult; p; p = p->next)
-                                                       add_variable(&argsresult, p->variable, p->indicator); 
+                       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);
 
-                                               output_statement(mm_strdup(ptr->command), 0, ptr->connection ? mm_strdup(ptr->connection) : NULL);
-                                       }
-               | ECPGPrepare           {
-                                               if (connection)
-                                                       mmerror(PARSE_ERROR, ET_ERROR, "no at option for set connection statement.\n");
+                       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;
 
-                                               fprintf(yyout, "{ ECPGprepare(__LINE__, %s);", $1); 
-                                               whenever_action(2);
-                                               free($1);
-                                       }
-               | ECPGRelease           { /* output already done */ }
-               | 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");
+                       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);
-                                       }
-               | ECPGTypedef           {
-                                               if (connection)
-                                                       mmerror(PARSE_ERROR, ET_ERROR, "no at option for typedef 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");
 
-                                               output_simple_statement($1);
-                                       }
-               | ECPGVar               {
-                                               if (connection)
-                                                       mmerror(PARSE_ERROR, ET_ERROR, "no at option for var 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);
+               }
+               | ECPGWhenever
+               {
+                       if (connection)
+                               mmerror(PARSE_ERROR, ET_ERROR, "no at option for whenever statement\n");
 
-                                               output_simple_statement($1);
-                                       }
+                       output_simple_statement($1);
+               }
                ;
 
 
@@ -609,508 +1005,586 @@ stmt:  AlterDatabaseSetStmt            { output_statement($1, 0, connection); }
 
 /*****************************************************************************
  *
- * Create a new Postgres DBMS user
+ * Create a new Postgres DBMS role
  *
  *
  *****************************************************************************/
 
-CreateUserStmt: CREATE USER UserId OptUserList
-               {
-                       $$ = cat_str(3, make_str("create user"), $3, $4);
-               }
-              | CREATE USER UserId WITH OptUserList
-               {
-                       $$ = cat_str(4, make_str("create user"), $3, make_str("with"), $5);
-               }
+CreateRoleStmt: CREATE ROLE RoleId opt_with OptRoleList
+                       { $$ = cat_str(4, make_str("create role"), $3, make_str("with"), $5); }
+               ;
+
+opt_with:  WITH                { $$ = make_str("with"); }
+               | /*EMPTY*/     { $$ = EMPTY; }
                ;
 
+/*
+ * Options for CREATE ROLE and ALTER ROLE (also used by CREATE/ALTER USER
+ * for backwards compatibility).  Note: the only option required by SQL99
+ * is "WITH ADMIN name".
+ */
+OptRoleList:
+       PASSWORD Sconst                 { $$ = cat2_str(make_str("password"), $2); }
+       | PASSWORD NULL_P               { $$ = make_str("password null"); }
+       | ENCRYPTED PASSWORD Sconst     { $$ = cat2_str(make_str("encrypted password"), $3); }
+       | UNENCRYPTED PASSWORD Sconst   { $$ = cat2_str(make_str("unencrypted password"), $3); }
+       | SUPERUSER_P                   { $$ = make_str("superuser"); }
+       | NOSUPERUSER                   { $$ = make_str("nosuperuser"); }
+       | INHERIT                               { $$ = make_str("inherit"); }
+       | NOINHERIT                             { $$ = make_str("noinherit"); }
+       | CREATEDB                              { $$ = make_str("createdb"); }
+       | NOCREATEDB                    { $$ = make_str("nocreatedb"); }
+       | CREATEROLE                    { $$ = make_str("createrole"); }
+       | NOCREATEROLE                  { $$ = make_str("nocreaterole"); }
+       | LOGIN_P                               { $$ = make_str("login"); }
+       | NOLOGIN_P                             { $$ = make_str("nologin"); }
+       | CONNECTION LIMIT IntConst     { $$ = cat2_str(make_str("connection limit"), $3); }
+       | VALID UNTIL Sconst            { $$ = cat2_str(make_str("valid until"), $3); }
+       | USER name_list                { $$ = cat2_str(make_str("user"), $2); }
+       | SYSID PosIntConst             { $$ = cat2_str(make_str("sysid"), $2); }
+       | ADMIN name_list               { $$ = cat2_str(make_str("admin"), $2); }
+       | ROLE name_list                { $$ = cat2_str(make_str("role"), $2); }
+       | IN_P ROLE name_list   { $$ = cat2_str(make_str("in role"), $3); }
+       | IN_P GROUP_P name_list        { $$ = cat2_str(make_str("in group"), $3); }
+       ;
+
 /*****************************************************************************
  *
- * Alter a postgresql DBMS user
- *
+ * Create a new Postgres DBMS user (role with implied login ability)
  *
  *****************************************************************************/
 
-AlterUserStmt: ALTER USER UserId OptUserList
-               {
-                       $$ = cat_str(3, make_str("alter user"), $3, $4);
-               }
-              | ALTER USER UserId WITH OptUserList
-               {
-                       $$ = cat_str(4, make_str("alter user"), $3, make_str("with"), $5);
-               }
+CreateUserStmt:
+       CREATE USER RoleId opt_with OptRoleList
+               {$$ = cat_str(4, make_str("create user"), $3, $4, $5); }
+       ;
+
+       /*****************************************************************************
+        *
+        * Alter a postgresql DBMS role
+        *
+        *
+        *****************************************************************************/
+
+       AlterRoleStmt: ALTER ROLE RoleId opt_with OptRoleList
+                       { $$ = cat_str(4, make_str("alter role"), $3, $4, $5); }
                ;
 
-AlterUserSetStmt: ALTER USER UserId VariableSetStmt
-                       {
-                               $$ = cat_str(3, make_str("alter user"), $3, $4);
-                       }
-               | ALTER USER UserId VariableResetStmt
-                       {
-                               $$ = cat_str(3, make_str("alter user"), $3, $4);
-                       }
+       AlterRoleSetStmt: ALTER ROLE RoleId SetResetClause
+                       { $$ = cat_str(3, make_str("alter role"), $3, $4); }
                ;
 
-/*****************************************************************************
- *
- * Drop a postgresql DBMS user
- *
- *
- *****************************************************************************/
+       /*****************************************************************************
+        *
+        * Alter a postgresql DBMS user
+        *
+        *****************************************************************************/
 
-DropUserStmt:  DROP USER user_list
-                               {
-                                       $$ = cat2_str(make_str("drop user"), $3);
-                               }
+       AlterUserStmt: ALTER USER RoleId opt_with OptRoleList
+               { $$ = cat_str(4, make_str("alter user"), $3, $4, $5); };
+
+       AlterUserSetStmt: ALTER USER RoleId SetResetClause
+                       { $$ = cat_str(3, make_str("alter user"), $3, $4); }
                ;
 
-/*
- * Options for CREATE USER and ALTER USER
- */
-OptUserList: OptUserList OptUserElem           { $$ = cat2_str($1, $2); }
-                       | /* EMPTY */                                   { $$ = EMPTY; }
+       /*****************************************************************************
+        *
+        * Drop a postgresql DBMS role
+        *
+        *
+        *****************************************************************************/
+       DropRoleStmt:  DROP ROLE name_list
+                       { $$ = cat2_str(make_str("drop role"), $3);}
+                    | DROP ROLE IF_P EXISTS name_list
+                       { $$ = cat2_str(make_str("drop role if exists"), $5);}
                ;
 
-OptUserElem:  PASSWORD Sconst
-                { 
-                                       $$ = cat2_str(make_str("password"), $2);
-                               }
-              | SYSID Iconst
-                               {
-                                       $$ = cat2_str(make_str("sysid"), $2);
-                               }
-              | CREATEDB
-                { 
-                                       $$ = make_str("createdb");
-                               }
-              | NOCREATEDB
-                { 
-                                       $$ = make_str("nocreatedb");
-                               }
-              | CREATEUSER
-                { 
-                                       $$ = make_str("createuser");
-                               }
-              | NOCREATEUSER
-                { 
-                                       $$ = make_str("nocreateuser");
-                               }
-              | IN GROUP user_list
-                { 
-                                       $$ = cat2_str(make_str("in group"), $3); 
-                               }
-              | VALID UNTIL Sconst
-                { 
-                                       $$ = cat2_str(make_str("valid until"), $3); 
-                               }
-        ;
+       /*****************************************************************************
+        *
+        * Drop a postgresql DBMS user
+        *
+        *
+        *****************************************************************************/
+       DropUserStmt:  DROP USER name_list
+                       { $$ = cat2_str(make_str("drop user"), $3);}
+                    | DROP USER IF_P EXISTS name_list
+                       { $$ = cat2_str(make_str("drop user if exists"), $5);}
 
-user_list:  user_list ',' UserId
-                               {
-                                       $$ = cat_str(3, $1, make_str(","), $3);
-                               }
-                       | UserId
-                               {
-                                       $$ = $1;
-                               }
                ;
 
+       /*****************************************************************************
+        *
+        * Create a postgresql group
+        *
+        *
+        ****************************************************************************/
+       CreateGroupStmt:  CREATE GROUP_P RoleId opt_with OptRoleList
+                       { $$ = cat_str(4, make_str("create group"), $3, $4, $5); }
+               ;
 
-/*****************************************************************************
- *
- * Create a postgresql group
- *
- *
- ****************************************************************************/
-CreateGroupStmt:  CREATE GROUP UserId OptGroupList
-                               {
-                                       $$ = cat_str(3, make_str("create group"), $3, $4);
-                               }
-                       | CREATE GROUP UserId WITH OptGroupList
-                               {
-                                       $$ = cat_str(4, make_str("create group"), $3, make_str("with"), $5);
-                               }
+       /*****************************************************************************
+        *
+        * Alter a postgresql group
+        *
+        *
+        *****************************************************************************/
+       AlterGroupStmt: ALTER GROUP_P RoleId add_drop USER name_list
+                       { $$ = cat_str(5, make_str("alter group"), $3, $4, make_str("user"), $6); }
                ;
 
-/*
- * Options for CREATE GROUP
- */
-OptGroupList: OptGroupList OptGroupElem                { $$ = cat2_str($1, $2); }
-                       | /* EMPTY */                                   { $$ = EMPTY; }
+       add_drop: ADD_P         { $$ = make_str("add"); }
+               | DROP          { $$ = make_str("drop"); }
                ;
 
-OptGroupElem:  USER user_list
-                { 
-                                       $$ = cat2_str(make_str("user"), $2);
-                               }
-               | SYSID Iconst
-                               {
-                                       $$ = cat2_str(make_str("sysid"), $2);
-                               }
-        ;
-
-
-/*****************************************************************************
- *
- * Alter a postgresql group
- *
- *
- *****************************************************************************/
-AlterGroupStmt: ALTER GROUP UserId ADD USER user_list
-                {
-                       $$ = cat_str(4, make_str("alter group"), $3, make_str("add user"), $6);
-                }
-                | ALTER GROUP UserId DROP USER user_list
-                {
-                       $$ = cat_str(4, make_str("alter group"), $3, make_str("drop user"), $6);
-                }
-                ;
+       /*****************************************************************************
+        *
+        * Drop a postgresql group
+        *
+        *
+        *****************************************************************************/
+       DropGroupStmt: DROP GROUP_P name_list
+                       { $$ = cat2_str(make_str("drop group"), $3); }
+                    | DROP GROUP_P IF_P EXISTS name_list
+                       { $$ = cat2_str(make_str("drop group if exists"), $5); }
+               ;
 
-/*****************************************************************************
- *
- * Drop a postgresql group
- *
- *
- *****************************************************************************/
-DropGroupStmt: DROP GROUP UserId
-               {
-                       $$ = cat2_str(make_str("drop group"), $3);
-               }
-               ;
+       /*****************************************************************************
+        *
+        * Manipulate a schema
+        *
+        *
+        *****************************************************************************/
 
-/*****************************************************************************
- *
- * Manipulate a schema
- *
- *
- *****************************************************************************/
-CreateSchemaStmt:  CREATE SCHEMA UserId 
-               {
-                       $$ = cat2_str(make_str("create scheme"), $3);
-               }
+       CreateSchemaStmt:  CREATE SCHEMA OptSchemaName AUTHORIZATION RoleId OptSchemaEltList
+                       { $$ = cat_str(5, make_str("create schema"), $3, make_str("authorization"), $5, $6); }
+               | CREATE SCHEMA ColId OptSchemaEltList
+                       { $$ = cat_str(3, make_str("create schema"), $3, $4); }
                ;
 
-AlterSchemaStmt:  ALTER SCHEMA UserId 
-               {
-                       $$ = cat2_str(make_str("alter scheme"), $3);
-               }
+       OptSchemaName: ColId            { $$ = $1; }
+               | /* EMPTY */   { $$ = EMPTY; }
                ;
 
-DropSchemaStmt:  DROP SCHEMA UserId 
-               {
-                       $$ = cat2_str(make_str("drop scheme"), $3);
-               }
+OptSchemaEltList: OptSchemaEltList schema_stmt         { $$ = cat2_str($1, $2); }
+               | /* EMPTY */   { $$ = EMPTY; }
                ;
 
+/*
+ *     schema_stmt are the ones that can show up inside a CREATE SCHEMA
+ *     statement (in addition to by themselves).
+ */
+schema_stmt: CreateStmt                { $$ = $1; }
+                  | IndexStmt          { $$ = $1; }
+                  | CreateSeqStmt      { $$ = $1; }
+                  | CreateTrigStmt { $$ = $1; }
+                  | GrantStmt          { $$ = $1; }
+                  | ViewStmt           { $$ = $1; }
+                  ;
+
+
+
 /*****************************************************************************
  *
  * Set PG internal variable
  *       SET name TO 'var_value'
  * Include SQL92 syntax (thomas 1997-10-22):
- *    SET TIME ZONE 'var_value'
+ *       SET TIME ZONE 'var_value'
  *
  *****************************************************************************/
+VariableSetStmt:  SET set_rest
+                       { $$ = cat2_str(make_str("set"), $2 ); }
+               | SET LOCAL set_rest
+                       { $$ = cat2_str(make_str("set local"), $3 ); }
+               | SET SESSION set_rest
+                       { $$ = cat2_str(make_str("set session"), $3 ); }
+               ;
+
+set_rest:      /* Generic SET syntaxes: */
+               var_name TO var_list
+                       { $$ = cat_str(3, $1, make_str("to"), $3); }
+               | var_name "=" var_list
+                       { $$ = cat_str(3, $1, make_str("="), $3); }
+               | var_name TO DEFAULT
+                       { $$ = cat2_str($1, make_str("to default")); }
+               | var_name "=" DEFAULT
+                       { $$ = cat2_str($1, make_str("= default")); }
+               | var_name FROM CURRENT_P
+                       { $$ = cat2_str($1, make_str("from current")); }
+               /* Special syntaxes mandated by SQL standard: */
+               | TIME ZONE zone_value
+                       { $$ = cat2_str(make_str("time zone"), $3); }
+               | TRANSACTION transaction_mode_list
+                       { $$ = cat2_str(make_str("transaction"), $2); }
+               | SESSION CHARACTERISTICS AS TRANSACTION transaction_mode_list
+                       { $$ = cat2_str(make_str("session characteristics as transaction"), $5); }
+               | NAMES opt_encoding
+                       { $$ = cat2_str(make_str("names"), $2); }
+               | ROLE ColId_or_Sconst
+                       { $$ = cat2_str(make_str("role"), $2); }
+               | SESSION AUTHORIZATION ColId_or_Sconst
+                       { $$ = cat2_str(make_str("session authorization"), $3); }
+               | SESSION AUTHORIZATION DEFAULT
+                       { $$ = make_str("session authorization default"); }
+               | XML_P OPTION document_or_content
+                       { $$ = cat2_str(make_str("xml option"), $3); }
+               ;
+
+var_name:      ECPGColId               { $$ = $1; }
+               | var_name '.' ColId    { $$ = cat_str(3, $1, make_str("."), $3); }
+               ;
+
+
+var_list:  var_value
+                       { $$ = $1; }
+               | var_list ',' var_value
+                       { $$ = cat_str(3, $1, make_str(","), $3); }
+               ;
 
-VariableSetStmt:  SET ColId TO var_value
-                               {
-                                       $$ = cat_str(4, make_str("set"), $2, make_str("to"), $4);
-                               }
-               | SET ColId '=' var_value
-                               {
-                                       $$ = cat_str(4, make_str("set"), $2, make_str("="), $4);
-                               }
-               | SET TIME ZONE zone_value
-                               {
-                                       $$ = cat2_str(make_str("set time zone"), $4);
-                               }
-               | SET TRANSACTION ISOLATION LEVEL opt_level
-                               {
-                                       $$ = cat2_str(make_str("set transaction isolation level"), $5);
-                               }
-               | SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL opt_level
-                               {
-                                       $$ = cat2_str(make_str("set session characteristics as transaction isolation level"), $8);
-                               }
-               | SET NAMES opt_encoding
-                                {
-                                       $$ = cat2_str(make_str("set names"), $3);
-                                }
-               | SET SESSION AUTHORIZATION ColId_or_Sconst 
-                                {
-                                       $$ = cat2_str(make_str("set session authorization"), $4);
-                                }
-                ;
-
-opt_level:  READ COMMITTED      { $$ = make_str("read committed"); }
-               | SERIALIZABLE   { $$ = make_str("serializable"); }
-               ;
-
-
-var_value:  opt_boolean                { $$ = $1; }
-               | AllConst              { $$ = $1; }
-               | name_list             { 
-                                         if (strlen($1) == 0)
-                                               mmerror(PARSE_ERROR, ET_ERROR, "SET must have at least one argument.");
-
-                                         $$ = $1;
-                                       }
-               | DEFAULT               { $$ = make_str("default"); }
+iso_level:     READ UNCOMMITTED        { $$ = make_str("read uncommitted"); }
+               | READ COMMITTED                { $$ = make_str("read committed"); }
+               | REPEATABLE READ               { $$ = make_str("repeatable read"); }
+               | SERIALIZABLE                  { $$ = make_str("serializable"); }
                ;
 
-opt_boolean:  TRUE_P           { $$ = make_str("true"); }
-               | FALSE_P       { $$ = make_str("false"); }
-               | ON            { $$ = make_str("on"); }
-               | OFF           { $$ = make_str("off"); }
+var_value:     opt_boolean             { $$ = $1; }
+               | AllConst                      {       /* we have to check for a variable here because it has to be
+                                                       replaced with its value on the client side */
+                                                       if ($1[1] == '$')
+                                                       {
+                                                               $$ = make_str("$0");
+                                                               free($1);
+                                                       }
+                                                       else
+                                                               $$ = $1;
+                                               }
+               | ColId                         { $$ = $1; }
                ;
 
+opt_boolean:  TRUE_P           { $$ = make_str("true"); }
+               | FALSE_P                       { $$ = make_str("false"); }
+               | ON                            { $$ = make_str("on"); }
+               | OFF                           { $$ = make_str("off"); }
+               ;
 /* Timezone values can be:
-* - a string such as 'pst8pdt'
-* - an integer or floating point number
-* - a time interval per SQL99
-*/
+ * - a string such as 'pst8pdt'
+ * - a column identifier such as "pst8pdt"
+ * - an integer or floating point number
+ * - a time interval per SQL99
+ * ConstInterval and ColId give shift/reduce errors,
+ * so use IDENT and reject anything which is a reserved word.
+ */
 zone_value:  AllConst          { $$ = $1; }
+               | ident         { $$ = $1; }
                | ConstInterval StringConst opt_interval
-                                       {
-                                         $$ = cat_str(3, $1, $2, $3); 
-                                       }
+                       { $$ = cat_str(3, $1, $2, $3); }
                | ConstInterval '(' PosIntConst ')' StringConst opt_interval
-                                       {
-                                         $$ = cat_str(6, $1, make_str("("), $3, make_str(")"), $5, $6);
-                                       }
-               | DEFAULT               { $$ = make_str("default"); }
-               | LOCAL                 { $$ = make_str("local"); }
+                       { $$ = cat_str(6, $1, make_str("("), $3, make_str(")"), $5, $6); }
+               | DEFAULT
+                       { $$ = make_str("default"); }
+               | LOCAL
+                       { $$ = make_str("local"); }
                ;
 
-opt_encoding:  StringConst             { $$ = $1; }
-               | DEFAULT       { $$ = make_str("default"); }
-               | /*EMPTY*/     { $$ = EMPTY; }
+opt_encoding:  StringConst             { $$ = $1; }
+               | DEFAULT                               { $$ = make_str("default"); }
+               | /*EMPTY*/                             { $$ = EMPTY; }
                ;
 
-ColId_or_Sconst: ColId         { $$ = $1; }
-               | StringConst   { $$ = $1; }
+ColId_or_Sconst: ColId                 { $$ = $1; }
+               | StringConst                   { $$ = $1; }
                ;
 
-VariableShowStmt:  SHOW ColId
-                               {
-                                       $$ = cat2_str(make_str("show"), $2);
-                               }
-               | SHOW TIME ZONE
-                               {
-                                       $$ = make_str("show time zone");
-                               }
+VariableShowStmt:  SHOW var_name ecpg_into
+                       { $$ = cat2_str(make_str("show"), $2); }
+               | SHOW TIME ZONE ecpg_into
+                       { $$ = make_str("show time zone"); }
+               | SHOW TRANSACTION ISOLATION LEVEL ecpg_into
+                       { $$ = make_str("show transaction isolation level"); }
+               | SHOW SESSION AUTHORIZATION ecpg_into
+                       { $$ = make_str("show session authorization"); }
                | SHOW ALL
-                               {
-                                       $$ = make_str("show all");
-                               }
-               | SHOW TRANSACTION ISOLATION LEVEL
-                               {
-                                       $$ = make_str("show transaction isolation level");
-                               }
+                       {
+                               mmerror(PARSE_ERROR, ET_ERROR, "SHOW ALL not implemented");
+                               $$ = EMPTY;
+                       }
                ;
 
-VariableResetStmt:     RESET ColId
-                               {
-                                       $$ = cat2_str(make_str("reset"), $2);
-                               }
+VariableResetStmt:     RESET var_name
+                       { $$ = cat2_str(make_str("reset"), $2); }
                | RESET TIME ZONE
-                               {
-                                       $$ = make_str("reset time zone");
-                               }
+                       { $$ = make_str("reset time zone"); }
                | RESET TRANSACTION ISOLATION LEVEL
-                               {
-                                       $$ = make_str("reset transaction isolation level");
-                               }
+                       { $$ = make_str("reset transaction isolation level"); }
+               | RESET SESSION AUTHORIZATION
+                       { $$ = make_str("reset session authorization"); }
                | RESET ALL
-                                {
-                                        $$ = make_str("reset all");
-                                }
+                       { $$ = make_str("reset all"); }
+               ;
+
+/* SetResetClause allows SET or RESET without LOCAL */
+SetResetClause:
+               SET set_rest            { $$ = cat2_str(make_str("set"), $2); }
+               | VariableResetStmt     { $$ = $1; }
                ;
 
 ConstraintsSetStmt:    SET CONSTRAINTS constraints_set_list constraints_set_mode
-                               {
-                                       $$ = cat_str(3, make_str("set constraints"), $3, $4);
-                               }
-               ;
+                       { $$ = cat_str(3, make_str("set constraints"), $3, $4); }
+               ;
 
 constraints_set_list:  ALL
-                               {
-                                       $$ = make_str("all");
-                               }
-               | constraints_set_namelist
-                               {
-                                       $$ = $1;
-                               }
-               ;
-
-
-constraints_set_namelist:      ColId
-                               {
-                                       $$ = $1;
-                               }
-               | constraints_set_namelist ',' ColId
-                               {
-                                       $$ = cat_str(3, $1, make_str(","), $3);
-                               }
-               ;
+                       { $$ = make_str("all"); }
+               | qualified_name_list
+                       { $$ = $1; }
+               ;
 
-constraints_set_mode:  DEFERRED
-                               {
-                                       $$ = make_str("deferred");
-                               }
-               | IMMEDIATE
-                               {
-                                       $$ = make_str("immediate");
-                               }
-               ;
+constraints_set_mode:  DEFERRED                { $$ = make_str("deferred"); }
+               | IMMEDIATE             { $$ = make_str("immediate"); }
+               ;
 
 /*
  * Checkpoint statement
  */
-CheckPointStmt: CHECKPOINT     { $$= make_str("checkpoint"); }
-                        ;  
+CheckPointStmt: CHECKPOINT        { $$= make_str("checkpoint"); }
+               ;
 
+DiscardStmt:
+               DISCARD ALL             { $$ = make_str("discard all"); }
+               | DISCARD TEMP          { $$ = make_str("discard temp"); }
+               | DISCARD TEMPORARY     { $$ = make_str("discard temporary"); }
+               | DISCARD PLANS         { $$ = make_str("discard plans"); }
+               ;
 
 /*****************************************************************************
  *
- *     ALTER TABLE variations
+ *     ALTER [ TABLE | INDEX | SEQUENCE | VIEW ] variations
  *
  *****************************************************************************/
 
 AlterTableStmt:
-/* ALTER TABLE <relation> ADD [COLUMN] <coldef> */
-        ALTER TABLE relation_expr ADD opt_column columnDef
-               {
-                       $$ = cat_str(5, make_str("alter table"), $3, make_str("add"), $5, $6);
-               }
-/* ALTER TABLE <relation> ALTER [COLUMN] <colname> {SET DEFAULT <expr>|DROP DEFAULT} */
-       | ALTER TABLE relation_expr ALTER opt_column ColId alter_column_default
-               {
-                       $$ = cat_str(6, make_str("alter table"), $3, make_str("alter"), $5, $6, $7);
-               }
-/* ALTER TABLE <relation> ALTER [COLUMN] <colname> SET STATISTICS <Iconst> */
-       | ALTER TABLE relation_expr ALTER opt_column ColId SET STATISTICS Iconst
-               {
-                       $$ = cat_str(7, make_str("alter table"), $3, make_str("alter"), $5, $6, make_str("set statistics"), $9);
-               }
-/* ALTER TABLE <relation> ALTER [COLUMN] <colname> SET STORAGE <storagemode> */
-       | ALTER TABLE relation_expr ALTER opt_column ColId SET STORAGE ColId
-               {
-                       $$ = cat_str(7, make_str("alter table"), $3, make_str("alter"), $5, $6, make_str("set storage"), $9);
-               }
-/* ALTER TABLE <relation> DROP [COLUMN] <colname> {RESTRICT|CASCADE} */
-       | ALTER TABLE relation_expr DROP opt_column ColId drop_behavior
-               {
-                       $$ = cat_str(6, make_str("alter table"), $3, make_str("drop"), $5, $6, $7);
-               }
-/* ALTER TABLE <relation> ADD CONSTRAINT ... */
-       | ALTER TABLE relation_expr ADD TableConstraint
-               {
-                       $$ = cat_str(4, make_str("alter table"), $3, make_str("add"), $5);
-               }
-/* ALTER TABLE <relation> DROP CONSTRAINT ... */
-       | ALTER TABLE relation_expr DROP CONSTRAINT name drop_behavior
-               {
-                       $$ = cat_str(5, make_str("alter table"), $3, make_str("drop constraint"), $6, $7);
-               }
-/* ALTER TABLE <name> OWNER TO UserId */     
-       | ALTER TABLE relation_name OWNER TO UserId   
-               {
-                       $$ = cat_str(4, make_str("alter table"), $3, make_str("owner to"), $6);
-               }
+               ALTER TABLE relation_expr alter_table_cmds
+                       { $$ = cat_str(3, make_str("alter table"), $3, $4); }
+               |       ALTER INDEX relation_expr alter_table_cmds
+                       { $$ = cat_str(3, make_str("alter index"), $3, $4); }
+               |       ALTER SEQUENCE relation_expr alter_table_cmds
+                       { $$ = cat_str(3, make_str("alter sequence"), $3, $4); }
+               |       ALTER VIEW relation_expr alter_table_cmds
+                       { $$ = cat_str(3, make_str("alter view"), $3, $4); }
+               ;
+
+alter_table_cmds:
+               alter_table_cmd                         { $$ = $1; }
+               | alter_table_cmds ',' alter_table_cmd  { $$ = cat_str(3, $1, make_str(","), $3); }
+               ;
+
+alter_table_cmd:
+/* ALTER TABLE <name> ADD [COLUMN] <coldef> */
+               ADD_P opt_column columnDef
+                       { $$ = cat_str(3, make_str("add"), $2, $3); }
+/* ALTER TABLE <name> ALTER [COLUMN] <colname> {SET DEFAULT <expr>|DROP DEFAULT} */
+               | ALTER opt_column ColId alter_column_default
+                       { $$ = cat_str(4, make_str("alter"), $2, $3, $4); }
+/* ALTER TABLE <name> ALTER [COLUMN] <colname> DROP NOT NULL */
+               | ALTER opt_column ColId DROP NOT NULL_P
+                       { $$ = cat_str(4, make_str("alter"), $2, $3, make_str("drop not null")); }
+/* ALTER TABLE <name> ALTER [COLUMN] <colname> SET NOT NULL */
+               | ALTER opt_column ColId SET NOT NULL_P
+                       { $$ = cat_str(4, make_str("alter"), $2, $3, make_str("set not null")); }
+/* ALTER TABLE <name> ALTER [COLUMN] <colname> SET STATISTICS <IntegerOnly> */
+               | ALTER opt_column ColId SET STATISTICS PosIntConst
+                       { $$ = cat_str(5, make_str("alter"), $2, $3, make_str("set statistics"), $6); }
+/* ALTER TABLE <name> ALTER [COLUMN] <colname> SET STORAGE <storagemode> */
+               | ALTER opt_column ColId SET STORAGE ColId
+                       { $$ = cat_str(5, make_str("alter"), $2, $3, make_str("set storage"), $6); }
+/* ALTER TABLE <name> DROP [COLUMN] <colname> {RESTRICT|CASCADE} */
+               | DROP opt_column ColId opt_drop_behavior
+                       { $$ = cat_str(4, make_str("drop"), $2, $3, $4); }
+/* ALTER TABLE <name> ALTER [COLUMN] <colname> TYPE <typename> [ USING <expression> ] */
+               | ALTER opt_column ColId TYPE_P Typename alter_using
+                       { $$ = cat_str(6, make_str("alter"), $2, $3, make_str("type"), $5, $6); }
+/* ALTER TABLE <name> ADD CONSTRAINT ... */
+               | ADD_P TableConstraint
+                       { $$ = cat_str(2, make_str("add"), $2); }
+/* ALTER TABLE <name> DROP CONSTRAINT ... */
+               | DROP CONSTRAINT name opt_drop_behavior
+                       { $$ = cat_str(3, make_str("drop constraint"), $3, $4); }
+/* ALTER TABLE <name> SET WITHOUT OIDS  */
+               | SET WITHOUT OIDS
+                       { $$ = make_str("set without oids"); }
+/* ALTER TABLE <name> CLUSTER ON <indexname> */
+               | CLUSTER ON name
+                       { $$ = cat_str(2, make_str("cluster on"), $3); }
+/* ALTER TABLE <name> SET WITHOUT CLUSTER */
+               | SET WITHOUT CLUSTER
+                       { $$ = make_str("set without cluster"); }
+/* ALTER TABLE <name> ENABLE TRIGGER <trig> */
+               | ENABLE_P TRIGGER name
+                       { $$ = cat2_str(make_str("enable trigger"), $3); }
+/* ALTER TABLE <name> ENABLE ALWAYS TRIGGER <trig> */
+               | ENABLE_P ALWAYS TRIGGER name
+                       { $$ = cat2_str(make_str("enable always trigger"), $4); }
+/* ALTER TABLE <name> ENABLE REPLICA TRIGGER <trig> */
+               | ENABLE_P REPLICA TRIGGER name
+                       { $$ = cat2_str(make_str("enable replica trigger"), $4); }
+/* ALTER TABLE <name> ENABLE TRIGGER ALL */
+               | ENABLE_P TRIGGER ALL
+                       { $$ = make_str("enable trigger all"); }
+/* ALTER TABLE <name> ENABLE TRIGGER USER */
+               | ENABLE_P TRIGGER USER
+                       { $$ = make_str("enable trigger user"); }
+/* ALTER TABLE <name> DISABLE TRIGGER <trig> */
+               | DISABLE_P TRIGGER name
+                       { $$ = cat2_str(make_str("disable trigger"), $3); }
+/* ALTER TABLE <name> DISABLE TRIGGER ALL */
+               | DISABLE_P TRIGGER ALL
+                       { $$ = make_str("disable trigger all"); }
+/* ALTER TABLE <name> DISABLE TRIGGER USER */
+               | DISABLE_P TRIGGER USER
+                       { $$ = make_str("disable trigger user"); }
+/* ALTER TABLE <name> ENABLE RULE <rule> */
+               | ENABLE_P RULE name
+                       { $$ = cat2_str(make_str("enable rule"), $3); }
+/* ALTER TABLE <name> ENABLE ALWAYS RULE <rule> */
+               | ENABLE_P ALWAYS RULE name
+                       { $$ = cat2_str(make_str("enable always rule"), $4); }
+/* ALTER TABLE <name> ENABLE REPLICA RULE <rule> */
+               | ENABLE_P REPLICA RULE name
+                       { $$ = cat2_str(make_str("enable replica rule"), $4); }
+/* ALTER TABLE <name> DISABLE RULE <rule> */
+               | DISABLE_P RULE name
+                       { $$ = cat2_str(make_str("disable rule"), $3); }
+/* ALTER TABLE <name> ALTER INHERITS ADD <parent> */
+               | INHERIT qualified_name
+                       { $$ = cat2_str(make_str("inherit"), $2); }
+/* ALTER TABLE <name> NO INHERITS <parent> */
+               | NO INHERIT qualified_name
+                       { $$ = cat2_str(make_str("no inherit"), $3); }
+               /* ALTER <name> OWNER TO RoleId */
+               | OWNER TO RoleId
+                       { $$ = cat2_str(make_str("owner to"), $3); }
+               /* ALTER <name> SET TABLESPACE <tablespacename> */
+               | SET TABLESPACE name
+                       { $$ = cat2_str(make_str("set tablespace"), $3); }
+               | SET definition
+                       { $$ = cat2_str(make_str("set"), $2); }
+               | RESET definition
+                       { $$ = cat2_str(make_str("reset"), $2); }
                ;
 
 alter_column_default:
-        SET DEFAULT a_expr     { $$ = cat2_str(make_str("set default"), $3); }
-        | DROP DEFAULT          { $$ = make_str("drop default"); }
-        ;
-
-drop_behavior: CASCADE { $$ = make_str("cascade"); }
-               | RESTRICT { $$ = make_str("restrict"); }
-        ;
-
-/*****************************************************************************
- *
- *             QUERY :
- *                             close <optname>
- *
- *****************************************************************************/
+               SET DEFAULT a_expr              { $$ = cat2_str(make_str("set default"), $3); }
+               | DROP DEFAULT                  { $$ = make_str("drop default"); }
+               ;
 
-ClosePortalStmt:  CLOSE opt_id
-                               {
-                                       $$ = cat2_str(make_str("close"), $2);
-                               }
+opt_drop_behavior: CASCADE             { $$ = make_str("cascade"); }
+               | RESTRICT                              { $$ = make_str("restrict"); }
+               | /* EMPTY */                   { $$ = EMPTY; }
                ;
 
-opt_id:  ColId         { $$ = $1; }
-       | /*EMPTY*/     { $$ = NULL; }
-       ;
+alter_using:   USING a_expr    { $$ = cat2_str(make_str("using"), $2); }
+               | /* EMPTY */                   { $$ = EMPTY; }
+               ;
 
 /*****************************************************************************
  *
  *             QUERY :
- *                             COPY [BINARY] <relname> FROM/TO
- *                             [USING DELIMITERS <delimiter>]
+ *                             close <portalname>
  *
  *****************************************************************************/
 
-CopyStmt:  COPY opt_binary relation_name opt_with_copy copy_dirn copy_file_name copy_delimiter copy_null
-                               {
-                                       $$ = cat_str(8, make_str("copy"), $2, $3, $4, $5, $6, $7, $8);
-                               }
+ClosePortalStmt:  CLOSE name
+                       { $$ = cat2_str(make_str("close"), $2); }
+               | CLOSE ALL
+                       { $$ = make_str("close all"); }
+               ;
+
+CopyStmt:  COPY opt_binary qualified_name opt_oids copy_from
+               copy_file_name copy_delimiter opt_with copy_opt_list
+                       {
+                               if (strcmp($5, "to") == 0 && strcmp($6, "stdin") == 0)
+                                       mmerror(PARSE_ERROR, ET_ERROR, "copy to stdin not possible\n");
+                               else if (strcmp($5, "from") == 0 && strcmp($6, "stdout") == 0)
+                                       mmerror(PARSE_ERROR, ET_ERROR, "copy from stdout not possible\n");
+                               else if (strcmp($5, "from") == 0 && strcmp($6, "stdin") == 0)
+                                       mmerror(PARSE_ERROR, ET_WARNING, "copy from stdin not implemented\n");
+                               
+                               $$ = cat_str(9, make_str("copy"), $2, $3, $4, $5, $6, $7, $8, $9);
+                       }
+               | COPY select_with_parens TO copy_file_name opt_with copy_opt_list
+                       {
+                               if (strcmp($4, "stdin") == 0)
+                                       mmerror(PARSE_ERROR, ET_ERROR, "copy to stdin is not possible\n");
+                               
+                               $$ = cat_str(6, make_str("copy"), $2, make_str("to"), $4, $5, $6);
+                       }
                ;
 
-copy_dirn:     TO
-                               { $$ = make_str("to"); }
-               | FROM
-                               { $$ = make_str("from"); }
+copy_from:     TO                                      { $$ = make_str("to"); }
+               | FROM                                  { $$ = make_str("from"); }
                ;
 
-/*
- * copy_file_name NULL indicates stdio is used. Whether stdin or stdout is
- * used depends on the direction. (It really doesn't make sense to copy from
- * stdout. We silently correct the "typo".              - AY 9/94
- */
-copy_file_name:  StringConst                                   { $$ = $1; }
+copy_file_name:  StringConst                           { $$ = $1; }
                | STDIN                                 { $$ = make_str("stdin"); }
                | STDOUT                                { $$ = make_str("stdout"); }
                ;
 
-opt_binary:  BINARY                                    { $$ = make_str("binary"); }
-               | /*EMPTY*/                             { $$ = EMPTY; }
+copy_opt_list: copy_opt_list copy_opt_item     { $$ = cat2_str($1, $2); }
+               | /* EMPTY */                   { $$ = EMPTY; }
                ;
 
-opt_with_copy: WITH OIDS                               { $$ = make_str("with oids"); }
-               | /*EMPTY*/                             { $$ = EMPTY; }
+copy_opt_item: BINARY          { $$ = make_str("binary"); }
+               | OIDS          { $$ = make_str("oids"); }
+               | DELIMITER opt_as StringConst
+                       { $$ = cat_str(3, make_str("delimiter"), $2, $3); }
+               | NULL_P opt_as StringConst
+                       { $$ = cat_str(3, make_str("null"), $2, $3); }
+               | CSV           { $$ = make_str("csv"); }
+               | HEADER_P      { $$ = make_str("header"); }
+               | QUOTE opt_as Sconst
+                       { $$ = cat_str(3, make_str("quote"), $2, $3); }
+               | ESCAPE opt_as Sconst
+                       { $$ = cat_str(3, make_str("escape"), $2, $3); }
+               | FORCE QUOTE columnList
+                       { $$ = cat2_str(make_str("force quote"), $3); }
+               | FORCE NOT NULL_P columnList
+                       { $$ = cat2_str(make_str("force not null"), $4); }
+
+               ;
+
+opt_binary:    BINARY          { $$ = make_str("binary"); }
+               | /* EMPTY */   { $$ = EMPTY; }
+               ;
+
+opt_oids:      WITH OIDS       { $$ = make_str("with oids"); }
+               | /* EMPTY */   { $$ = EMPTY; }
                ;
 
+
 /*
  * the default copy delimiter is tab but the user can configure it
  */
-copy_delimiter:  opt_using DELIMITERS StringConst              { $$ = cat_str(3, $1, make_str("delimiters"), $3); }
-               | /*EMPTY*/                             { $$ = EMPTY; }
+copy_delimiter:  opt_using DELIMITERS StringConst
+                       { $$ = cat_str(3, $1, make_str("delimiters"), $3); }
+               | /*EMPTY*/
+                       { $$ = EMPTY; }
                ;
 
 opt_using:     USING           { $$ = make_str("using"); }
                | /* EMPTY */   { $$ = EMPTY; }
                ;
 
-copy_null:     WITH NULL_P AS StringConst      { $$ = cat2_str(make_str("with null as"), $4); }
-               | /* EMPTY */   { $$ = EMPTY; }
-               ;
-
 /*****************************************************************************
  *
  *             QUERY :
- *                             CREATE relname
+ *                             CREATE TABLE relname
  *
  *****************************************************************************/
 
-CreateStmt:  CREATE OptTemp TABLE relation_name '(' OptTableElementList ')'
-                               OptInherit OptWithOids
-                               {
-                                       $$ = cat_str(9, make_str("create"), $2, make_str("table"), $4, make_str("("), $6, make_str(")"), $8, $9);
-                               }
+CreateStmt:  CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
+                               OptInherit OptWith OnCommitOption OptTableSpace
+                       { $$ = cat_str(11, make_str("create"), $2, make_str("table"), $4, make_str("("), $6, make_str(")"), $8, $9, $10, $11); }
+               | CREATE OptTemp TABLE qualified_name OF qualified_name
+                       '(' OptTableElementList ')' OptWith OnCommitOption OptTableSpace
+                       { $$ = cat_str(12, make_str("create"), $2, make_str("table"), $4, make_str("of"), $6, make_str("("), $8, make_str(")"), $10, $11, $12); }
                ;
 
 /*
@@ -1118,59 +1592,44 @@ CreateStmt:  CREATE OptTemp TABLE relation_name '(' OptTableElementList ')'
  * since TEMP is not a reserved word.  See also OptTempTableName.
  */
 
-OptTemp:       TEMPORARY               { $$ = make_str("temporary"); }
-               | TEMP                  { $$ = make_str("temp"); }
+OptTemp: TEMPORARY                     { $$ = make_str("temporary"); }
+               | TEMP                          { $$ = make_str("temp"); }
                | LOCAL TEMPORARY       { $$ = make_str("local temporary"); }
                | LOCAL TEMP            { $$ = make_str("local temp"); }
-               | GLOBAL TEMPORARY      {
-                                         mmerror(PARSE_ERROR, ET_WARNING, "Currently unsupported CREATE TABLE / GLOBAL TEMPORARY will be passed to backend");
-                                         $$ = make_str("global temporary");
-                                       }
-               | GLOBAL TEMP           {
-                                         mmerror(PARSE_ERROR, ET_WARNING, "Currently unsupported CREATE TABLE / GLOBAL TEMP will be passed to backend");
-                                         $$ = make_str("global temp");
-                                       }
-               | /*EMPTY*/             { $$ = EMPTY; }
+               | GLOBAL TEMPORARY      { $$ = make_str("global temporary"); }
+               | GLOBAL TEMP           { $$ = make_str("global temp"); }
+               | /*EMPTY*/                     { $$ = EMPTY; }
                ;
 
-OptTableElementList:  OptTableElementList ',' OptTableElement
-                               {
-                                       $$ = cat_str(3, $1, make_str(","), $3);
-                               }
-                       | OptTableElement
-                               {
-                                       $$ = $1;
-                               }
-                       | /*EMPTY*/     { $$ = EMPTY; }
+
+OptTableElementList:  TableElementList
+                       { $$ = $1; }
+               | /*EMPTY*/
+                       { $$ = EMPTY; }
+               ;
+TableElementList: TableElement
+                       { $$ = $1; }
+               | TableElementList ',' TableElement
+                       { $$ = cat_str(3, $1, make_str(","), $3); }
                ;
 
-OptTableElement:  columnDef            { $$ = $1; }
-                       | TableConstraint       { $$ = $1; }
+TableElement:  columnDef               { $$ = $1; }
+               | TableLikeClause       { $$ = $1; }
+               | TableConstraint       { $$ = $1; }
                ;
 
-columnDef:  ColId Typename ColQualList opt_collate
-                               {
-                                       if (strlen($4) > 0)
-                                       {
-                                               sprintf(errortext, "Currently unsupported CREATE TABLE / COLLATE %s will be passed to backend", $4);
-                                               mmerror(PARSE_ERROR, ET_WARNING, errortext);
-                                       }
-                                       $$ = cat_str(4, $1, $2, $3, $4);
-                               }
+columnDef:     ColId Typename ColQualList
+                       {$$ = cat_str(3, $1, $2, $3); }
                ;
 
-ColQualList:  ColQualList ColConstraint        { $$ = cat2_str($1,$2); }
-                       | /*EMPTY*/     { $$ = EMPTY; }
+ColQualList:  ColQualList ColConstraint { $$ = cat2_str($1,$2); }
+               | /*EMPTY*/                                             { $$ = EMPTY; }
                ;
 
 ColConstraint: CONSTRAINT name ColConstraintElem
-                               {
-                                       $$ = cat_str(3, make_str("constraint"), $2, $3);
-                               }
-               | ColConstraintElem
-                               { $$ = $1; }
-               | ConstraintAttr
-                               { $$ = $1; }
+                       { $$ = cat_str(3, make_str("constraint"), $2, $3); }
+               | ColConstraintElem             { $$ = $1; }
+               | ConstraintAttr                { $$ = $1; }
                ;
 
 /* DEFAULT NULL is already the default for Postgres.
@@ -1184,35 +1643,21 @@ ColConstraint:  CONSTRAINT name ColConstraintElem
  * shift/reduce conflicts with WITH TIME ZONE anyway.
  * - thomas 1999-01-08
  */
-ColConstraintElem:     NOT NULL_P
-                               {
-                                       $$ = make_str("not null");
-                               }
-                       | NULL_P
-                               {
-                                       $$ = make_str("null");
-                               }
-                       | UNIQUE
-                               {
-                                       $$ = make_str("unique");
-                               }
-                       | PRIMARY KEY
-                               {
-                                       $$ = make_str("primary key");
-                               }
-                       | CHECK '(' a_expr ')'
-                               {
-                                       $$ = cat_str(3, make_str("check ("), $3, make_str(")"));
-                               }
-                       | DEFAULT b_expr
-                               {
-                                       $$ = cat2_str(make_str("default"), $2);
-                               }
-                       |  REFERENCES ColId opt_column_list key_match key_actions 
-                               {
-                                       $$ = cat_str(5, make_str("references"), $2, $3, $4, $5);  
-                               }
-                       ;
+ColConstraintElem:     NOT NULL_P
+                       { $$ = make_str("not null"); }
+               | NULL_P
+                       { $$ = make_str("null"); }
+               | UNIQUE opt_definition OptConsTableSpace
+                       { $$ = cat_str(3, make_str("unique"), $2, $3); }
+               | PRIMARY KEY opt_definition OptConsTableSpace
+                       { $$ = cat_str(3, make_str("primary key"), $3, $4); }
+               | CHECK '(' a_expr ')'
+                       { $$ = cat_str(3, make_str("check ("), $3, make_str(")")); }
+               | DEFAULT b_expr
+                       { $$ = cat2_str(make_str("default"), $2); }
+               |  REFERENCES qualified_name opt_column_list key_match key_actions
+                       { $$ = cat_str(5, make_str("references"), $2, $3, $4, $5); }
+               ;
 
 /*
  * ConstraintAttr represents constraint attributes, which we parse as if
@@ -1231,101 +1676,149 @@ ConstraintAttr: DEFERRABLE            { $$ = make_str("deferrable"); }
                | INITIALLY IMMEDIATE   { $$ = make_str("initially immediate"); }
                ;
 
+TableLikeClause:  LIKE qualified_name TableLikeOptionList
+                       {$$ = cat_str(3, make_str("like"), $2, $3); }
+               ;
+
+TableLikeOptionList: TableLikeOptionList TableLikeOption
+                               { $$ = cat2_str($1, $2); }
+               | /* EMPTY */   { $$ = EMPTY; }
+               ;
+
+TableLikeOption:
+               INCLUDING DEFAULTS      { $$ = make_str("including defaults"); }
+               | EXCLUDING DEFAULTS    { $$ = make_str("excluding defaults"); }
+               | INCLUDING CONSTRAINTS { $$ = make_str("including constraints"); }
+               | EXCLUDING CONSTRAINTS { $$ = make_str("excluding constraints"); }
+               | INCLUDING INDEXES     { $$ = make_str("including indexes"); }
+               | EXCLUDING INDEXES     { $$ = make_str("excluding indexes"); }
+               ;
+
 /* ConstraintElem specifies constraint syntax which is not embedded into
- *  a column definition. ColConstraintElem specifies the embedded form.
+ *     a column definition. ColConstraintElem specifies the embedded form.
  * - thomas 1997-12-03
  */
 TableConstraint:  CONSTRAINT name ConstraintElem
-                               {
-                                               $$ = cat_str(3, make_str("constraint"), $2, $3);
-                               }
+                       { $$ = cat_str(3, make_str("constraint"), $2, $3); }
                | ConstraintElem
-                               { $$ = $1; }
+                       { $$ = $1; }
                ;
 
 ConstraintElem:  CHECK '(' a_expr ')'
-                               {
-                                       $$ = cat_str(3, make_str("check("), $3, make_str(")"));
-                               }
-               | UNIQUE '(' columnList ')'
-                               {
-                                       $$ = cat_str(3, make_str("unique("), $3, make_str(")"));
-                               }
-               | PRIMARY KEY '(' columnList ')'
-                               {
-                                       $$ = cat_str(3, make_str("primary key("), $4, make_str(")"));
-                               }
-               | FOREIGN KEY '(' columnList ')' REFERENCES ColId opt_column_list
+                       { $$ = cat_str(3, make_str("check("), $3, make_str(")")); }
+               | UNIQUE '(' columnList ')' opt_definition OptConsTableSpace
+                       { $$ = cat_str(5, make_str("unique("), $3, make_str(")"), $5, $6); }
+               | PRIMARY KEY '(' columnList ')' opt_definition OptConsTableSpace
+                       { $$ = cat_str(5, make_str("primary key("), $4, make_str(")"), $6, $7); }
+               | FOREIGN KEY '(' columnList ')' REFERENCES qualified_name opt_column_list
                        key_match key_actions ConstraintAttributeSpec
-                               {
-                                       $$ = cat_str(8, make_str("foreign key("), $4, make_str(") references"), $7, $8, $9, $10, $11);
-                               }
+                       { $$ = cat_str(8, make_str("foreign key("), $4, make_str(") references"), $7, $8, $9, $10, $11); }
                ;
 
-key_match:  MATCH FULL
-               {
-                        $$ = make_str("match full");
-               }
-               | MATCH PARTIAL         
+opt_column_list:  '(' columnList ')'   { $$ = cat_str(3, make_str("("), $2, make_str(")")); }
+               | /*EMPTY*/             { $$ = EMPTY; }
+               ;
+
+columnList:  columnList ',' columnElem
+                       { $$ = cat_str(3, $1, make_str(","), $3); }
+               | columnElem
+                       { $$ = $1; }
+               ;
+
+columnElem:  ColId     { $$ = $1; }
+               ;
+
+key_match:     MATCH FULL
+                       { $$ = make_str("match full"); }
+               | MATCH PARTIAL
                {
-                       mmerror(PARSE_ERROR, ET_WARNING, "Currently unsupported FOREIGN KEY/MATCH PARTIAL will be passed to backend");
+                       mmerror(PARSE_ERROR, ET_WARNING, "currently unsupported FOREIGN KEY/MATCH PARTIAL will be passed to backend");
                        $$ = make_str("match partial");
                }
                | /*EMPTY*/
-               {
-                       $$ = EMPTY;
-               }
+                       { $$ = EMPTY; }
                ;
 
-key_actions:  key_delete               { $$ = $1; }
-               | key_update            { $$ = $1; }
-               | key_delete key_update { $$ = cat2_str($1, $2); }
-               | key_update key_delete { $$ = cat2_str($1, $2); }
-               | /*EMPTY*/             { $$ = EMPTY; }
+key_actions:  key_delete                       { $$ = $1; }
+               | key_update                            { $$ = $1; }
+               | key_delete key_update         { $$ = cat2_str($1, $2); }
+               | key_update key_delete         { $$ = cat2_str($1, $2); }
+               | /*EMPTY*/                                     { $$ = EMPTY; }
                ;
 
-key_delete: ON DELETE key_reference    { $$ = cat2_str(make_str("on delete"), $3); }
+key_delete: ON DELETE_P key_action
+                       { $$ = cat2_str(make_str("on delete"), $3); }
+               ;
+
+key_update: ON UPDATE key_action
+                       { $$ = cat2_str(make_str("on update"), $3); }
+               ;
+
+key_action:    NO ACTION                               { $$ = make_str("no action"); }
+               | RESTRICT                                      { $$ = make_str("restrict"); }
+               | CASCADE                                       { $$ = make_str("cascade"); }
+               | SET DEFAULT                           { $$ = make_str("set default"); }
+               | SET NULL_P                            { $$ = make_str("set null"); }
+               ;
 
-key_update: ON UPDATE key_reference    { $$ = cat2_str(make_str("on update"), $3); }
+OptInherit:  INHERITS '(' qualified_name_list ')'
+                       { $$ = cat_str(3, make_str("inherits ("), $3, make_str(")")); }
+               | /*EMPTY*/
+                       { $$ = EMPTY; }
+               ;
 
-key_reference:  NO ACTION      { $$ = make_str("no action"); }
-               | RESTRICT      { $$ = make_str("restrict"); }
-               | CASCADE       { $$ = make_str("cascade"); }
-               | SET DEFAULT   { $$ = make_str("set default"); }
-               | SET NULL_P    { $$ = make_str("set null"); }
+OptWith:       WITH definition                 { $$ = cat2_str(make_str("with"), $2); }
+               | WITH OIDS                     { $$ = make_str("with oids"); }
+               | WITHOUT OIDS                  { $$ = make_str("without oids"); }
+               | /*EMPTY*/                     { $$ = EMPTY; }
                ;
 
-OptInherit:  INHERITS '(' relation_name_list ')'                { $$ = cat_str(3, make_str("inherits ("), $3, make_str(")")); }
-                | /*EMPTY*/                                    { $$ = EMPTY; }
-                ;
+OnCommitOption:   ON COMMIT DROP       { $$ = make_str("on commit drop"); }
+               | ON COMMIT DELETE_P ROWS       { $$ = make_str("on commit delete rows"); }
+               | ON COMMIT PRESERVE ROWS       { $$ = make_str("on commit preserve rows"); }
+               | /*EMPTY*/                                     { $$ = EMPTY; }
+               ;
 
-OptWithOids:  WITH OIDS                                                { $$ = make_str("with oids"); }
-                       | WITHOUT OIDS                                  { $$ = make_str("without oids"); }
-                       | /*EMPTY*/                                             { $$ = EMPTY; }
+OptTableSpace:  TABLESPACE name        { $$ = cat2_str(make_str("tablespace"), $2); }
+               | /*EMPTY*/     { $$ = EMPTY; }
                ;
 
+OptConsTableSpace: USING INDEX TABLESPACE name { $$ = cat2_str(make_str("using index tablespace"), $4); }
+                       | /*EMPTY*/             { $$ = EMPTY; }
+                       ;
 
 /*
  * Note: CREATE TABLE ... AS SELECT ... is just another spelling for
  * SELECT ... INTO.
  */
 
-CreateAsStmt:  CREATE OptTemp TABLE relation_name OptCreateAs AS
-               { FoundInto = 0; } SelectStmt
+CreateAsStmt:  CREATE OptTemp TABLE create_as_target AS
+               { FoundInto = 0; }
+               SelectStmt
                {
                        if (FoundInto == 1)
-                               mmerror(PARSE_ERROR, ET_ERROR, "CREATE TABLE / AS SELECT may not specify INTO");
+                               mmerror(PARSE_ERROR, ET_ERROR, "CREATE TABLE / AS SELECT cannot specify INTO");
 
-                       $$ = cat_str(7, make_str("create"), $2, make_str("table"), $4, $5, make_str("as"), $8); 
+                       $$ = cat_str(6, make_str("create"), $2, make_str("table"), $4, make_str("as"), $7);
+               }
+               ;
+
+create_as_target:  qualified_name OptCreateAs OptWith OnCommitOption OptTableSpace
+               {
+                       $$ = cat_str(5, $1, $2, $3, $4, $5);
                }
                ;
 
-OptCreateAs:  '(' CreateAsList ')' { $$ = cat_str(3, make_str("("), $2, make_str(")")); }
-                       | /*EMPTY*/ { $$ = EMPTY; }     
+OptCreateAs:  '(' CreateAsList ')'
+                       { $$ = cat_str(3, make_str("("), $2, make_str(")")); }
+               | /*EMPTY*/
+                       { $$ = EMPTY; }
                ;
 
-CreateAsList:  CreateAsList ',' CreateAsElement        { $$ = cat_str(3, $1, make_str(","), $3); }
-                       | CreateAsElement       { $$ = $1; }
+CreateAsList:  CreateAsList ',' CreateAsElement
+                       { $$ = cat_str(3, $1, make_str(","), $3); }
+               | CreateAsElement
+                       { $$ = $1; }
                ;
 
 CreateAsElement:  ColId { $$ = $1; }
@@ -1335,44 +1828,54 @@ CreateAsElement:  ColId { $$ = $1; }
  *
  *             QUERY :
  *                             CREATE SEQUENCE seqname
+ *                              ALTER SEQUENCE seqname
  *
  *****************************************************************************/
 
-CreateSeqStmt:  CREATE OptTemp SEQUENCE relation_name OptSeqList
-                               {
-                                       $$ = cat_str(4, make_str("create sequence"), $2, $4, $5);
-                               }
+CreateSeqStmt: CREATE OptTemp SEQUENCE qualified_name OptSeqOptList
+                       { $$ = cat_str(5, make_str("create"), $2, make_str("sequence"), $4, $5); }
                ;
 
-OptSeqList:  OptSeqList OptSeqElem
-                               { $$ = cat2_str($1, $2); }
-                       |       { $$ = EMPTY; }
+AlterSeqStmt: ALTER SEQUENCE relation_expr SeqOptList
+                       { $$ = cat_str(3,make_str("alter sequence"), $3, $4); }
                ;
 
-OptSeqElem:  CACHE NumConst
-                               {
-                                       $$ = cat2_str(make_str("cache"), $2);
-                               }
-                       | CYCLE
-                               {
-                                       $$ = make_str("cycle");
-                               }
-                       | INCREMENT NumConst
-                               {
-                                       $$ = cat2_str(make_str("increment"), $2);
-                               }
-                       | MAXVALUE NumConst
-                               {
-                                       $$ = cat2_str(make_str("maxvalue"), $2);
-                               }
-                       | MINVALUE NumConst
-                               {
-                                       $$ = cat2_str(make_str("minvalue"), $2);
-                               }
-                       | START NumConst
-                               {
-                                       $$ = cat2_str(make_str("start"), $2);
-                               }
+OptSeqOptList:  SeqOptList     { $$ = $1; }
+               | /*EMPTY*/     { $$ = EMPTY; }
+               ;
+
+SeqOptList:    SeqOptElem              { $$ = $1; }
+               | SeqOptList SeqOptElem { $$ = cat2_str($1, $2); }
+               ;
+
+SeqOptElem:  CACHE NumConst
+                       { $$ = cat2_str(make_str("cache"), $2); }
+               | CYCLE
+                       { $$ = make_str("cycle"); }
+               | NO CYCLE
+                       { $$ = make_str("no cycle"); }
+               | INCREMENT opt_by NumConst
+                       { $$ = cat_str(3, make_str("increment"), $2, $3); }
+               | MAXVALUE NumConst
+                       { $$ = cat2_str(make_str("maxvalue"), $2); }
+               | MINVALUE NumConst
+                       { $$ = cat2_str(make_str("minvalue"), $2); }
+               | NO MAXVALUE
+                       { $$ = make_str("no maxvalue"); }
+               | NO MINVALUE
+                       { $$ = make_str("no minvalue"); }
+               | OWNED BY any_name
+                       { $$ = cat2_str(make_str("owned by"), $3); }
+               | START opt_with NumConst
+                       { $$ = cat_str(3, make_str("start"), $2, $3); }
+               | RESTART
+                       { $$ = make_str("restart"); }
+               | RESTART opt_with NumConst
+                       { $$ = cat_str(3, make_str("restart"), $2, $3); }
+               ;
+
+opt_by:                BY      { $$ = make_str("by"); }
+               | /*EMPTY*/     { $$ = EMPTY; }
                ;
 
 /*****************************************************************************
@@ -1383,30 +1886,78 @@ OptSeqElem:  CACHE NumConst
  *
  *****************************************************************************/
 
-CreatePLangStmt:  CREATE opt_Trusted opt_procedural LANGUAGE ColId_or_Sconst
-                       HANDLER func_name opt_lancompiler
-                       {
-                               $$ = cat_str(8, make_str("create"), $2, $3, make_str("language"), $5, make_str("handler"), $7, $8);
-                       }
+CreatePLangStmt:  CREATE opt_trusted opt_procedural LANGUAGE ColId_or_Sconst
+                       { $$ = cat_str(5, make_str("create"), $2, $3, make_str("language"), $5); }
+               | CREATE opt_trusted opt_procedural LANGUAGE ColId_or_Sconst
+                       HANDLER handler_name opt_validator opt_lancompiler
+                       { $$ = cat_str(9, make_str("create"), $2, $3, make_str("language"), $5, make_str("handler"), $7, $8, $9); }
                ;
 
-opt_Trusted:           TRUSTED { $$ = make_str("trusted"); }
-                       |       { $$ = EMPTY; }
-                       ;
+opt_trusted:   TRUSTED { $$ = make_str("trusted"); }
+               | /*EMPTY*/             { $$ = EMPTY; }
+               ;
 
-opt_lancompiler: LANCOMPILER StringConst       { $$ = cat2_str(make_str("lancompiler"), $2); }
-                        | /*EMPTY*/              { $$ = ""; }
-                       ;
+/* This ought to be just func_name, but that causes reduce/reduce conflicts
+ * (CREATE LANGUAGE is the only place where func_name isn't followed by '(').
+ * Work around by using simple names instead.
+ */
+handler_name: name     { $$ = $1; }
+               | name attrs    { $$ = cat2_str($1, $2); }
+               ;
 
-DropPLangStmt:  DROP opt_procedural LANGUAGE StringConst
-                       {
-                               $$ = cat_str(4, make_str("drop"), $2, make_str("language"), $4);
-                       }
+opt_validator: VALIDATOR handler_name
+                       { $$ = cat2_str(make_str("validator"), $2); }
+               | /*EMPTY*/
+                       { $$ = ""; }
+               ;
+opt_lancompiler: LANCOMPILER StringConst
+                       { $$ = cat2_str(make_str("lancompiler"), $2); }
+               | /*EMPTY*/
+                       { $$ = ""; }
+               ;
+
+DropPLangStmt: DROP opt_procedural LANGUAGE StringConst opt_drop_behavior
+                       { $$ = cat_str(5, make_str("drop"), $2, make_str("language"), $4, $5); }
+               | DROP opt_procedural LANGUAGE IF_P EXISTS StringConst opt_drop_behavior
+                       { $$ = cat_str(5, make_str("drop"), $2, make_str("language if exists"), $6, $7); }
+               ;
+
+opt_procedural: PROCEDURAL     { $$ = make_str("prcedural"); }
+               | /*EMPTY*/                     { $$ = EMPTY; }
+               ;
+
+/*****************************************************************************
+ *
+ *             QUERY:
+ *             CREATE TABLESPACE tablespace LOCATION '/path/to/tablespace/'
+ *
+ *****************************************************************************/
+
+CreateTableSpaceStmt: CREATE TABLESPACE name OptTableSpaceOwner LOCATION Sconst
+                       { $$ = cat_str(5,make_str("create tablespace"), $3, $4, make_str("location"), $6); }
+               ;
+
+OptTableSpaceOwner: OWNER name { $$ = cat2_str(make_str("owner"), $2); }
+               | /*EMPTY*/     { $$ = EMPTY; }
+               ;
+
+/*****************************************************************************
+ *
+ *             QUERY :
+ *                             DROP TABLESPACE <tablespace>
+ *
+ *             No need for drop behaviour as we cannot implement dependencies for
+ *             objects in other databases; we can only support RESTRICT.
+ *
+ ****************************************************************************/
+
+
+DropTableSpaceStmt: DROP TABLESPACE name
+                       { $$ = cat2_str(make_str("drop tablespace"), $3); }
+               | DROP TABLESPACE IF_P EXISTS name
+                       { $$ = cat2_str(make_str("drop tablespace if exists"), $5); }
                ;
 
-opt_procedural: PROCEDURAL             { $$ = make_str("prcedural"); }
-                       | /*EMPTY*/     { $$ = EMPTY; }
-               ;
 
 /*****************************************************************************
  *
@@ -1417,321 +1968,480 @@ opt_procedural: PROCEDURAL             { $$ = make_str("prcedural"); }
  *****************************************************************************/
 
 CreateTrigStmt:  CREATE TRIGGER name TriggerActionTime TriggerEvents ON
-                               relation_name TriggerForSpec EXECUTE PROCEDURE
-                               name '(' TriggerFuncArgs ')'
-                               {
-                                       $$ = cat_str(12, make_str("create trigger"), $3, $4, $5, make_str("on"), $7, $8, make_str("execute procedure"), $11, make_str("("), $13, make_str(")"));
-                               }
-       |       CREATE CONSTRAINT TRIGGER name AFTER TriggerEvents ON
-                                relation_name OptConstrFromTable
-                               ConstraintAttributeSpec
-                                FOR EACH ROW EXECUTE PROCEDURE
-                               name '(' TriggerFuncArgs ')'
-                               {
-                                       $$ = cat_str(13, make_str("create constraint trigger"), $4, make_str("after"), $6, make_str("on"), $8, $9, $10, make_str("for each row execute procedure"), $16, make_str("("), $18, make_str(")"));
-                               }
+                               qualified_name TriggerForSpec EXECUTE PROCEDURE name
+                               '(' TriggerFuncArgs ')'
+                       { $$ = cat_str(12, make_str("create trigger"), $3, $4, $5, make_str("on"), $7, $8, make_str("execute procedure"), $11, make_str("("), $13, make_str(")")); }
+               |       CREATE CONSTRAINT TRIGGER name AFTER TriggerEvents ON
+                               qualified_name OptConstrFromTable ConstraintAttributeSpec
+                               FOR EACH ROW EXECUTE PROCEDURE
+                               func_name '(' TriggerFuncArgs ')'
+                       { $$ = cat_str(13, make_str("create constraint trigger"), $4, make_str("after"), $6, make_str("on"), $8, $9, $10, make_str("for each row execute procedure"), $16, make_str("("), $18, make_str(")")); }
                ;
 
-TriggerActionTime:  BEFORE                             { $$ = make_str("before"); }
-                       | AFTER                         { $$ = make_str("after"); }
+TriggerActionTime:     BEFORE          { $$ = make_str("before"); }
+               | AFTER                                 { $$ = make_str("after"); }
                ;
 
 TriggerEvents: TriggerOneEvent
-                               {
-                                       $$ = $1;
-                               }
-                       | TriggerOneEvent OR TriggerOneEvent
-                               {
-                                       $$ = cat_str(3, $1, make_str("or"), $3);
-                               }
-                       | TriggerOneEvent OR TriggerOneEvent OR TriggerOneEvent
-                               {
-                                       $$ = cat_str(5, $1, make_str("or"), $3, make_str("or"), $5);
-                               }
+                       { $$ = $1; }
+               | TriggerOneEvent OR TriggerOneEvent
+                       { $$ = cat_str(3, $1, make_str("or"), $3); }
+               | TriggerOneEvent OR TriggerOneEvent OR TriggerOneEvent
+                       { $$ = cat_str(5, $1, make_str("or"), $3, make_str("or"), $5); }
                ;
 
-TriggerOneEvent:  INSERT                               { $$ = make_str("insert"); }
-                       | DELETE                        { $$ = make_str("delete"); }
-                       | UPDATE                        { $$ = make_str("update"); }
+TriggerOneEvent:  INSERT       { $$ = make_str("insert"); }
+               | DELETE_P                      { $$ = make_str("delete"); }
+               | UPDATE                        { $$ = make_str("update"); }
                ;
 
 TriggerForSpec:  FOR TriggerForOpt TriggerForType
-                               {
-                                       $$ = cat_str(3, make_str("for"), $2, $3);
-                               }
+                       { $$ = cat_str(3, make_str("for"), $2, $3); }
+               | /* EMPTY */
+                       { $$ = EMPTY; }
                ;
 
-TriggerForOpt:  EACH                                   { $$ = make_str("each"); }
-                       | /*EMPTY*/                     { $$ = EMPTY; }
+TriggerForOpt: EACH            { $$ = make_str("each"); }
+               | /*EMPTY*/                     { $$ = EMPTY; }
                ;
 
-TriggerForType:  ROW                                   { $$ = make_str("row"); }
-                       | STATEMENT                     { $$ = make_str("statement"); }
+TriggerForType:  ROW           { $$ = make_str("row"); }
+               | STATEMENT                     { $$ = make_str("statement"); }
                ;
 
 TriggerFuncArgs:  TriggerFuncArg
-                               { $$ = $1; }
-                       | TriggerFuncArgs ',' TriggerFuncArg
-                               { $$ = cat_str(3, $1, make_str(","), $3); }
-                       | /*EMPTY*/
-                               { $$ = EMPTY; }
+                       { $$ = $1; }
+               | TriggerFuncArgs ',' TriggerFuncArg
+                       { $$ = cat_str(3, $1, make_str(","), $3); }
+               | /*EMPTY*/
+                       { $$ = EMPTY; }
                ;
 
-TriggerFuncArg:  PosAllConst
-                               {
-                                       $$ = $1;
-                               }
-                       | ColId         {  $$ = $1; }
-               ;
-
-OptConstrFromTable:                     /* Empty */
-                                {
-                                        $$ = EMPTY;
-                                }
-                | FROM relation_name
-                                {
-                                        $$ = cat2_str(make_str("from"), $2);
-                                }
-                ;
-
-ConstraintAttributeSpec: ConstraintDeferrabilitySpec
-                {      $$ = $1; }
-       | ConstraintDeferrabilitySpec ConstraintTimeSpec
-               {       
+TriggerFuncArg:  PosAllConst   { $$ = $1; }
+               | ColId         { $$ = $1; }
+               ;
+
+OptConstrFromTable: /* Empty */                { $$ = EMPTY; }
+               | FROM qualified_name           { $$ = cat2_str(make_str("from"), $2); }
+               ;
+
+ConstraintAttributeSpec: ConstraintDeferrabilitySpec   { $$ = $1; }
+               | ConstraintDeferrabilitySpec ConstraintTimeSpec
+               {
                        if (strcmp($1, "deferrable") != 0 && strcmp($2, "initially deferrable") == 0 )
                                mmerror(PARSE_ERROR, ET_ERROR, "INITIALLY DEFERRED constraint must be DEFERRABLE");
 
                        $$ = cat2_str($1, $2);
                }
-       | ConstraintTimeSpec
-               {       $$ = $1; }
-       | ConstraintTimeSpec ConstraintDeferrabilitySpec
+               | ConstraintTimeSpec            { $$ = $1; }
+               | ConstraintTimeSpec ConstraintDeferrabilitySpec
                {
                        if (strcmp($2, "deferrable") != 0 && strcmp($1, "initially deferrable") == 0 )
                                mmerror(PARSE_ERROR, ET_ERROR, "INITIALLY DEFERRED constraint must be DEFERRABLE");
 
-                       $$ = cat2_str($1, $2);
+                       $$ = cat2_str($1, $2);
                }
-       ;
+               | /* EMPTY */
+               {
+                       $$ = EMPTY;
+               }
+               ;
 
-ConstraintDeferrabilitySpec: NOT DEFERRABLE    { $$ = make_str("not deferrable"); }
-                       | DEFERRABLE    { $$ = make_str("deferrable"); }
-                ;
+ConstraintDeferrabilitySpec: NOT DEFERRABLE
+                       { $$ = make_str("not deferrable"); }
+               | DEFERRABLE
+                       { $$ = make_str("deferrable"); }
+               ;
 
-ConstraintTimeSpec: INITIALLY IMMEDIATE                { $$ = make_str("initially immediate"); }
-                | INITIALLY DEFERRED   { $$ = make_str("initially deferred"); }
-                ;
+ConstraintTimeSpec: INITIALLY IMMEDIATE
+                       { $$ = make_str("initially immediate"); }
+               | INITIALLY DEFERRED
+                       { $$ = make_str("initially deferred"); }
+               ;
 
-DropTrigStmt:  DROP TRIGGER name ON relation_name
-                               {
-                                       $$ = cat_str(4, make_str("drop trigger"), $3, make_str("on"), $5);
-                               }
+DropTrigStmt:  DROP TRIGGER name ON qualified_name opt_drop_behavior
+                       { $$ = cat_str(5, make_str("drop trigger"), $3, make_str("on"), $5, $6); }
+               | DROP TRIGGER IF_P EXISTS name ON qualified_name opt_drop_behavior
+                       { $$ = cat_str(5, make_str("drop trigger if exists"), $5, make_str("on"), $7, $8); }
                ;
 
 /*****************************************************************************
  *
- *             QUERY :
- *                             define (type,operator,aggregate)
+ *             QUERIES :
+ *                             CREATE ASSERTION ...
+ *                             DROP ASSERTION ...
  *
  *****************************************************************************/
-
-DefineStmt:  CREATE AGGREGATE func_name definition
+CreateAssertStmt:  CREATE ASSERTION name
+               CHECK '(' a_expr ')' ConstraintAttributeSpec
                {
-                       $$ = cat_str(3, make_str("create aggregate"), $3, $4);
+                       mmerror(PARSE_ERROR, ET_ERROR, "CREATE ASSERTION is not yet supported");
+                       $$ = cat_str(6, make_str("create assertion"), $3, make_str("check ("), $6, make_str(")"), $8);
                }
-                | CREATE OPERATOR all_Op definition
-               {
-                       $$ = cat_str(3, make_str("create operator"), $3, $4);
-               }
-                | CREATE TYPE_P name definition  
+               ;
+
+DropAssertStmt:  DROP ASSERTION name
                {
-                       $$ = cat_str(3, make_str("create type"), $3, $4);
+                       mmerror(PARSE_ERROR, ET_ERROR, "DROP ASSERTION is not yet supported");
+                       $$ = cat2_str(make_str("drop assertion"), $3);
                }
                ;
 
-definition:  '(' def_list ')'                          { $$ = cat_str(3, make_str("("), $2, make_str(")")); }
+
+/*****************************************************************************
+ *
+ *             QUERY :
+ *                             define (type,operator,aggregate)
+ *
+ *****************************************************************************/
+
+DefineStmt:  CREATE AGGREGATE func_name aggr_args definition
+                       { $$ = cat_str(4, make_str("create aggregate"), $3, $4, $5); }
+               | CREATE AGGREGATE func_name old_aggr_definition
+                       { $$ = cat_str(3, make_str("create aggregate"), $3, $4); }
+               | CREATE OPERATOR all_Op definition
+                       { $$ = cat_str(3, make_str("create operator"), $3, $4); }
+               | CREATE TYPE_P any_name definition
+                       { $$ = cat_str(3, make_str("create type"), $3, $4); }
+               | CREATE TYPE_P any_name
+                       { $$ = cat2_str(make_str("create type"), $3); }
+               | CREATE TYPE_P any_name AS '(' TableFuncElementList ')'
+                       { $$ = cat_str(5, make_str("create type"), $3, make_str("as ("), $6, make_str(")")); }
+               | CREATE TYPE_P any_name AS ENUM_P '(' enum_val_list ')'
+                       { $$ = cat_str(5, make_str("create type"), $3, make_str("as enum ("), $7, make_str(")")); }
+               | CREATE TEXT_P SEARCH PARSER any_name definition
+                       { $$ = cat_str(3, make_str("create text search parser"), $5, $6); }
+               | CREATE TEXT_P SEARCH DICTIONARY any_name definition
+                       { $$ = cat_str(3, make_str("create text search dictionary"), $5, $6); }
+               | CREATE TEXT_P SEARCH TEMPLATE any_name definition
+                       { $$ = cat_str(3, make_str("create text search template"), $5, $6); }
+               | CREATE TEXT_P SEARCH CONFIGURATION any_name definition
+                       { $$ = cat_str(3, make_str("create text search configuration"), $5, $6); }
+               ;
+
+definition:  '(' def_list ')'
+                       { $$ = cat_str(3, make_str("("), $2, make_str(")")); }
                ;
 
 def_list:  def_elem                                    { $$ = $1; }
-               | def_list ',' def_elem                 { $$ = cat_str(3, $1, make_str(","), $3); }
+               | def_list ',' def_elem         { $$ = cat_str(3, $1, make_str(","), $3); }
                ;
 
-def_elem:  ColLabel '=' def_arg        {
-                                       $$ = cat_str(3, $1, make_str("="), $3);
-                               }
-               | ColLabel
-                               {
-                                       $$ = $1;
-                               }
+def_elem:  ColLabel '=' def_arg                { $$ = cat_str(3, $1, make_str("="), $3); }
+               | ColLabel                                      { $$ = $1; }
                ;
 
 /* Note: any simple identifier will be returned as a type name! */
-def_arg:  func_return          {  $$ = $1; }
-               | all_Op        {  $$ = $1; }
-               | AllConst      {  $$ = $1; }
+def_arg:  func_type                            { $$ = $1; }
+               | reserved_keyword              { $$ = $1; }
+               | qual_all_Op                   { $$ = $1; }
+               | AllConst                      { $$ = $1; }
                ;
 
-/*****************************************************************************
- *
- *             QUERY:
- *
- *             DROP itemtype itemname [, itemname ...]       
- *
- *****************************************************************************/
+aggr_args:      '(' type_list ')'              { $$ = cat_str(3, make_str("("), $2, make_str(")")); }
+               | '(' '*' ')'                   { $$ = make_str("(*)"); }
+               ;
 
-DropStmt:  DROP drop_type relation_name_list
-                               {
-                                       $$ = cat_str(3, make_str("drop"), $2, $3);
+old_aggr_definition: '(' old_aggr_list ')'     { $$ = cat_str(3, make_str("("), $2, make_str(")")); }
+               ;
+
+old_aggr_list: old_aggr_elem                           { $$ = $1; }
+                | old_aggr_list ',' old_aggr_elem      { $$ = cat_str(3, $1, make_str(","), $3); }
+                ;
+
+old_aggr_elem:  ident '=' def_arg      { $$ = cat_str(3, $1, make_str("="), $3); }
+               ;
+
+enum_val_list:  StringConst                    { $$ = $1; }
+               | enum_val_list ',' StringConst { $$ = cat_str(3, $1, make_str(","), $3);}
+               ;
+
+CreateOpClassStmt:      CREATE OPERATOR CLASS any_name opt_default FOR TYPE_P Typename
+                                               USING access_method opt_opfamily AS opclass_item_list
+               {
+                       $$ = cat_str(10, make_str("create operator class"), $4, $5, make_str("for type"), $8, make_str("using"), $10, $11, make_str("as"), $13);
+               }
+               ;
+
+opclass_item_list:     opclass_item            { $$ = $1; }
+               | opclass_item_list ',' opclass_item    { $$ = cat_str(3, $1, make_str(","), $3); }
+               ;
+
+opclass_item:  OPERATOR PosIntConst any_operator opt_recheck
+                       { $$ = cat_str(4, make_str("operator"), $2, $3, $4); }
+               | OPERATOR PosIntConst any_operator '(' oper_argtypes ')' opt_recheck
+                       { $$ =  cat_str(7, make_str("operator"), $2, $3, make_str("("), $5, make_str(")"), $7); }
+               | FUNCTION PosIntConst func_name func_args
+                       { $$ = cat_str(4, make_str("function"), $2, $3, $4); }
+               | FUNCTION PosIntConst '(' type_list ')' func_name func_args
+                       { $$ = cat_str(7, make_str("function"), $2, make_str("("), $4, make_str(")"), $6, $7); }
+               | STORAGE Typename
+                       { $$ = cat2_str(make_str("storage"), $2); }
+               ;
+
+opt_default:   DEFAULT { $$ = make_str("default"); }
+               |  /*EMPTY*/    { $$ = EMPTY; }
+               ;
+
+opt_opfamily:  FAMILY any_name         { $$ = cat2_str(make_str("family"), $2); }
+                       | /*EMPTY*/     { $$ = EMPTY; }
+               ;
+
+opt_recheck:   RECHECK         { 
+                                       mmerror(PARSE_ERROR, ET_WARNING, "no longer supported RECHECK OPTION will be passed to backend");
+                                       $$ = make_str("recheck");
                                }
+               |  /*EMPTY*/    { $$ = EMPTY; }
                ;
 
-drop_type:     TABLE           { $$ = make_str("table"); }
-       |       SEQUENCE        { $$ = make_str("sequence"); }
-       |       VIEW            { $$ = make_str("view"); }
-       |       INDEX           { $$ = make_str("index"); }
-       |       RULE            { $$ = make_str("rule"); }
-       |       TYPE_P          { $$ = make_str("type"); }
-       ;
+CreateOpFamilyStmt: CREATE OPERATOR FAMILY any_name USING access_method
+               { $$ = cat_str(4, make_str("create operator family"), $4, make_str("using"), $6); }
+               ;
+
+AlterOpFamilyStmt: ALTER OPERATOR FAMILY any_name USING access_method ADD_P opclass_item_list
+                       { $$ = cat_str(6, make_str("alter operator family"), $4, make_str("using"), $6, make_str("add"), $8); }
+                | ALTER OPERATOR FAMILY any_name USING access_method DROP opclass_drop_list
+                       { $$ = cat_str(6, make_str("alter operator family"), $4, make_str("using"), $6, make_str("drop"), $8); }
+                ;
+
+opclass_drop_list: opclass_drop                                { $$ = $1; }
+               | opclass_drop_list ',' opclass_drop    { $$ = cat_str(3, $1, make_str(","), $3); }
+               ;
+
+opclass_drop:
+               OPERATOR PosIntConst '(' type_list ')'
+                       { $$ = cat_str(5, make_str("operator"), $2, make_str("("), $4, make_str(")")); }
+               | FUNCTION PosIntConst '(' type_list ')'
+                       { $$ = cat_str(5, make_str("function"), $2, make_str("("), $4, make_str(")")); }
+               ;
+
+DropOpClassStmt: DROP OPERATOR CLASS any_name USING access_method opt_drop_behavior
+                       { $$ = cat_str(5,make_str("drop operator class"), $4, make_str("using"), $6, $7); }
+               | DROP OPERATOR CLASS IF_P EXISTS any_name USING access_method opt_drop_behavior
+                       { $$ = cat_str(5,make_str("drop operator class if exists"), $6, make_str("using"), $8, $9); }
+               ;
+
+DropOpFamilyStmt: DROP OPERATOR FAMILY any_name USING access_method opt_drop_behavior
+                       { $$ = cat_str(5,make_str("drop operator family"), $4, make_str("using"), $6, $7); }
+               | DROP OPERATOR FAMILY IF_P EXISTS any_name USING access_method opt_drop_behavior
+                       { $$ = cat_str(5,make_str("drop operator family if exists"), $6, make_str("using"), $8, $9); }
+               ;
 
 /*****************************************************************************
  *
- *             QUERY:
- *                             truncate table relname
+ *             QUERY:
+ *
+ *             DROP OWNED BY username [, username ...] [ RESTRICT | CASCADE ]
+ *             REASSIGN OWNED BY username [, username ...] TO username
  *
  *****************************************************************************/
-TruncateStmt:  TRUNCATE opt_table relation_name
-                               {
-                                       $$ = cat2_str(make_str("truncate table"), $3);
-                               }
-                       ;
+DropOwnedStmt:
+       DROP OWNED BY name_list opt_drop_behavior
+                       {$$ = cat_str(3, make_str("drop owned by"), $4, $5); }
+               ;
+
+ReassignOwnedStmt:
+       REASSIGN OWNED BY name_list TO name
+                       {$$ = cat_str(4, make_str("reassign owned by"), $4, make_str("to"), $6); }
+               ;
 
 /*****************************************************************************
  *
  *             QUERY:
- *                     fetch/move [forward | backward] [ # | all ] [ in <portalname> ]
- *                     fetch [ forward | backward | absolute | relative ]
- *                           [ # | all | next | prior ] [ [ in | from ] <portalname> ]
+ *
+ *                        DROP itemtype [ IF EXISTS ] itemname [, itemname ...] [ RESTRICT | CASCADE ]
  *
  *****************************************************************************/
 
-FetchStmt: FETCH direction fetch_how_many from_in name ecpg_into
-                               {
-                                       if (strcmp($2, "relative") == 0 && atol($3) == 0L)
-                                               mmerror(PARSE_ERROR, ET_ERROR, "FETCH/RELATIVE at current position is not supported");
+DropStmt:  DROP drop_type IF_P EXISTS any_name_list opt_drop_behavior
+                       { $$ = cat_str(5, make_str("drop"), $2, make_str("if exists"), $5, $6); }
+               | DROP drop_type any_name_list opt_drop_behavior
+                       { $$ = cat_str(4, make_str("drop"), $2, $3, $4); }
+               ;
 
-                                       $$ = cat_str(5, make_str("fetch"), $2, $3, $4, $5);
-                               }
-               | FETCH fetch_how_many from_in name ecpg_into
-                               {
-                                       $$ = cat_str(4, make_str("fetch"), $2, $3, $4);
-                               }
-               | FETCH direction from_in name ecpg_into
-                               {
-                                       $$ = cat_str(4, make_str("fetch"), $2, $3, $4);
-                               }
-               | FETCH from_in name ecpg_into
-                               {
-                                       $$ = cat_str(3, make_str("fetch"), $2, $3);
-                               }
-               | FETCH name ecpg_into
-                               {
-                                       $$ = cat2_str(make_str("fetch"), $2);
-                               }
-               | MOVE direction fetch_how_many from_in name
-                               {
-                                       $$ = cat_str(5, make_str("move"), $2, $3, $4, $5);
-                               }
-               | MOVE fetch_how_many from_in name
-                               {
-                                       $$ = cat_str(4, make_str("move"), $2, $3, $4);
-                               }
-               | MOVE direction from_in name
-                               {
-                                       $$ = cat_str(4, make_str("move"), $2, $3, $4);
-                               }
-               | MOVE from_in name
-                               {
-                                       $$ = cat_str(3, make_str("move"), $2, $3);
-                               }
-               | MOVE name
-                               {
-                                       $$ = cat2_str(make_str("move"), $2);
-                               }
+drop_type:     TABLE                           { $$ = make_str("table"); }
+               | SEQUENCE                      { $$ = make_str("sequence"); }
+               | VIEW                          { $$ = make_str("view"); }
+               | INDEX                         { $$ = make_str("index"); }
+               | TYPE_P                        { $$ = make_str("type"); }
+               | DOMAIN_P                      { $$ = make_str("domain"); }
+               | CONVERSION_P                  { $$ = make_str("conversion"); }
+               | SCHEMA                        { $$ = make_str("schema"); }
+               | TEXT_P SEARCH PARSER          { $$ = make_str("text search parser"); }
+               | TEXT_P SEARCH DICTIONARY      { $$ = make_str("text search dictionary"); }
+               | TEXT_P SEARCH TEMPLATE        { $$ = make_str("text search template"); }
+               | TEXT_P SEARCH CONFIGURATION   { $$ = make_str("text search configuration"); }
                ;
 
-direction:     FORWARD         { $$ = make_str("forward"); }
-               | BACKWARD      { $$ = make_str("backward"); }
-               | RELATIVE      { $$ = make_str("relative"); }
-                | ABSOLUTE     {
-                                       mmerror(PARSE_ERROR, ET_WARNING, "Currently unsupported FETCH/ABSOLUTE will be passed to backend, backend will use RELATIVE");
-                                       $$ = make_str("absolute");
-                               }
+any_name_list:  any_name
+                       { $$ = $1; }
+               | any_name_list ',' any_name
+                       { $$ = cat_str(3, $1, make_str(","), $3); }
                ;
 
-fetch_how_many:   IntConst        { $$ = $1; }
-               | ALL           { $$ = make_str("all"); }
-               | NEXT          { $$ = make_str("next"); }
-               | PRIOR         { $$ = make_str("prior"); }
+any_name: ColId        { $$ = $1; }
+               | ColId attrs  { $$ = cat2_str($1, $2); }
                ;
 
-from_in:   IN  { $$ = make_str("in"); }
-       | FROM  { $$ = make_str("from"); }
-       ;
+attrs: '.' attr_name           { $$ = cat2_str(make_str("."), $2); }
+               | attrs '.' attr_name   { $$ = cat_str(3, $1, make_str("."), $3); }
+               ;
 
 /*****************************************************************************
  *
- *  The COMMENT ON statement can take different forms based upon the type of
- *  the object associated with the comment. The form of the statement is:
+ *                        QUERY:
+ *                                truncate table relname1, relname2, ....
  *
- *  COMMENT ON [ [ DATABASE | INDEX | RULE | SEQUENCE | TABLE | TYPE | VIEW ]
- *               <objname> | AGGREGATE <aggname> (<aggtype>) | FUNCTION
- *              <funcname> (arg1, arg2, ...) | OPERATOR <op>
- *              (leftoperand_typ rightoperand_typ) | TRIGGER <triggername> ON
- *              <relname> ] IS 'text'
+ *****************************************************************************/
+TruncateStmt:  TRUNCATE opt_table qualified_name_list opt_restart_seqs opt_drop_behavior
+                       { $$ = cat_str(5, make_str("truncate table"), $2, $3, $4, $5); }
+               ;
+
+opt_restart_seqs:
+                       CONTINUE_P IDENTITY_P   { $$ = cat2_str(make_str("continue"), make_str("identity")); }
+                       | RESTART IDENTITY_P    { $$ = cat2_str(make_str("restart"), make_str("identity")); }
+                       | /* EMPTY */           { $$ = EMPTY; }
+                       ;
+
+/*****************************************************************************
+ *
+ *             QUERY:
+ *                     fetch/move
  *
  *****************************************************************************/
-CommentStmt:   COMMENT ON comment_type name IS comment_text
-                        {
-                                $$ = cat_str(5, make_str("comment on"), $3, $4, make_str("is"), $6);
-                        }
-                | COMMENT ON COLUMN relation_name '.' attr_name IS comment_text
-                        { 
-                                $$ = cat_str(6, make_str("comment on column"), $4, make_str("."), $6, make_str("is"), $8);
+
+/* This is different from the backend as we try to be compatible with many other
+ * embedded SQL implementations. So we accept their syntax as well and
+ * translate it to the PGSQL syntax. */
+
+FetchStmt: FETCH fetch_direction from_in name ecpg_into
+                       {
+                               add_additional_variables($4, false);
+                               $$ = cat_str(4, make_str("fetch"), $2, $3, $4);
                        }
-                | COMMENT ON AGGREGATE name '(' aggr_argtype ')' IS comment_text
-                        {
-                                $$ = cat_str(6, make_str("comment on aggregate"), $4, make_str("("), $6, make_str(") is"), $9);
+               | FETCH fetch_direction name ecpg_into
+                       {
+                               add_additional_variables($3, false);
+                               $$ = cat_str(4, make_str("fetch"), $2, make_str("from"), $3);
                        }
-                | COMMENT ON AGGREGATE name aggr_argtype IS comment_text
-                        {
-                                $$ = cat_str(5, make_str("comment on aggregate"), $4, $5, make_str("is"), $7);
+               | FETCH from_in name ecpg_into
+                       {
+                               add_additional_variables($3, false);
+                               $$ = cat_str(3, make_str("fetch"), $2, $3);
                        }
-               | COMMENT ON FUNCTION func_name func_args IS comment_text
+               | FETCH name ecpg_into
                        {
-                                $$ = cat_str(5, make_str("comment on function"), $4, $5, make_str("is"), $7);
+                               add_additional_variables($2, false);
+                               $$ = cat2_str(make_str("fetch"), $2);
                        }
-               | COMMENT ON OPERATOR all_Op '(' oper_argtypes ')' IS comment_text
+               | FETCH fetch_direction from_in name
                        {
-                               $$ = cat_str(6, make_str("comment on operator"), $4, make_str("("), $6, make_str(") is"), $9);
+                               add_additional_variables($4, false);
+                               $$ = cat_str(4, make_str("fetch"), $2, $3, $4);
                        }
-               | COMMENT ON TRIGGER name ON relation_name IS comment_text
-                        {
-                                $$ = cat_str(6, make_str("comment on trigger"), $4, make_str("on"), $6, make_str("is"), $8);
+               | 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);
+                       }
+               | FETCH name
+                       {
+                               add_additional_variables($2, false);
+                               $$ = cat2_str(make_str("fetch"), $2);
+                       }
+               | MOVE fetch_direction from_in name
+                       { $$ = cat_str(4, make_str("move"), $2, $3, $4); }
+               | MOVE name
+                       { $$ = cat2_str(make_str("move"), $2); }
+               ;
+
+fetch_direction:  NEXT                         { $$ = make_str("next"); }
+               | PRIOR                         { $$ = make_str("prior"); }
+               | FIRST_P                       { $$ = make_str("first"); }
+               | LAST_P                        { $$ = make_str("last"); }
+               | ABSOLUTE_P fetch_count        { $$ = cat2_str(make_str("absolute"), $2); }
+               | RELATIVE_P fetch_count        { $$ = cat2_str(make_str("relative"), $2); }
+               | fetch_count                   { $$ = $1; }
+               | ALL                           { $$ = make_str("all"); }
+               | FORWARD                       { $$ = make_str("forward"); }
+               | FORWARD fetch_count           { $$ = cat2_str(make_str("forward"), $2); }
+               | FORWARD ALL                   { $$ = make_str("forward all"); }
+               | BACKWARD                      { $$ = make_str("backward"); }
+               | BACKWARD fetch_count          { $$ = cat2_str(make_str("backward"), $2); }
+               | BACKWARD ALL                  { $$ = make_str("backward all"); }
+               ;
+
+fetch_count:   IntConst        {
+                                       if ($1[1] == '$')
+                                       {
+                                               /* a variable here has to be replaced on the client side, thus we have to use '$0' here */
+                                               $$ = make_str("$0");
+                                               free($1);
+                                       }
+                                       else
+                                               $$ = $1;
+                               }
 
-comment_type:  DATABASE        { $$ = make_str("database"); }
-                | INDEX                { $$ = make_str("idnex"); }
-                | RULE         { $$ = make_str("rule"); }
-                | SEQUENCE     { $$ = make_str("sequence"); }
-                | TABLE                { $$ = make_str("table"); }
-                | TYPE_P       { $$ = make_str("type"); }
-                | VIEW         { $$ = make_str("view"); }
+from_in: IN_P                          { $$ = make_str("in"); }
+               | FROM                  { $$ = make_str("from"); }
                ;
 
-comment_text:    StringConst           { $$ = $1; }
-               | NULL_P                { $$ = make_str("null"); }
-               ;
+CommentStmt:   COMMENT ON comment_type name IS comment_text
+                       { $$ = cat_str(5, make_str("comment on"), $3, $4, make_str("is"), $6); }
+               | COMMENT ON AGGREGATE func_name aggr_args IS comment_text
+                       { $$ = cat_str(5, make_str("comment on aggregate"), $4, $5, make_str("is"), $7); }
+               | COMMENT ON FUNCTION func_name func_args IS comment_text
+                       { $$ = cat_str(5, make_str("comment on function"), $4, $5, make_str("is"), $7); }
+               | COMMENT ON OPERATOR all_Op '(' oper_argtypes ')' IS comment_text
+                       { $$ = cat_str(6, make_str("comment on operator"), $4, make_str("("), $6, make_str(") is"), $9); }
+               | COMMENT ON TRIGGER name ON any_name IS comment_text
+                       { $$ = cat_str(6, make_str("comment on trigger"), $4, make_str("on"), $6, make_str("is"), $8); }
+               | COMMENT ON RULE name ON any_name IS comment_text
+                       { $$ = cat_str(6, make_str("comment on rule"), $4, make_str("on"), $6, make_str("is"), $8); }
+               | COMMENT ON RULE name IS comment_text
+                       { $$ = cat_str(4, make_str("comment on rule"), $4, make_str("is"), $6); }
+               | COMMENT ON OPERATOR CLASS any_name USING access_method IS comment_text
+                       { $$ = cat_str(6, make_str("comment on operator class"), $5, make_str("using"), $7, make_str("is"), $9); }
+               | COMMENT ON OPERATOR FAMILY any_name USING access_method IS comment_text
+                       { $$ = cat_str(6, make_str("comment on operator family"), $5, make_str("using"), $7, make_str("is"), $9); }
+               | COMMENT ON LARGE_P OBJECT_P NumConst IS comment_text
+                       { $$ = cat_str(4, make_str("comment on large object"), $5, make_str("is"), $7); }
+               | COMMENT ON CAST '(' Typename AS Typename ')' IS comment_text
+                       { $$ = cat_str(6, make_str("comment on cast ("), $5, make_str("as"), $7, make_str(") is"), $10); }
+               | COMMENT ON opt_procedural LANGUAGE any_name IS comment_text
+                       { $$ = cat_str(6, make_str("comment on"), $3, make_str("language"), $5, make_str("is"), $7); }
+               | COMMENT ON TEXT_P SEARCH PARSER any_name IS comment_text
+                       { $$ = cat_str(4, make_str("comment on test search parser"), $6, make_str("is"), $8); }
+               | COMMENT ON TEXT_P SEARCH DICTIONARY any_name IS comment_text
+                       { $$ = cat_str(4, make_str("comment on test search dictionary"), $6, make_str("is"), $8); }
+               | COMMENT ON TEXT_P SEARCH TEMPLATE any_name IS comment_text
+                       { $$ = cat_str(4, make_str("comment on test search template"), $6, make_str("is"), $8); }
+               | COMMENT ON TEXT_P SEARCH CONFIGURATION any_name IS comment_text
+                       { $$ = cat_str(4, make_str("comment on test search configuration"), $6, make_str("is"), $8); }
+               ;
+
+comment_type:  COLUMN          { $$ = make_str("column"); }
+               | DATABASE                      { $$ = make_str("database"); }
+               | SCHEMA                        { $$ = make_str("schema"); }
+               | INDEX                         { $$ = make_str("idnex"); }
+               | SEQUENCE                      { $$ = make_str("sequence"); }
+               | TABLE                         { $$ = make_str("table"); }
+               | DOMAIN_P                      { $$ = make_str("domain"); }
+               | TYPE_P                        { $$ = make_str("type"); }
+               | VIEW                          { $$ = make_str("view"); }
+               | CONVERSION_P                  { $$ = make_str("conversion"); }
+               | TABLESPACE                    { $$ = make_str("tablespace"); }
+               | ROLE                          { $$ = make_str("role"); }
+               ;
+
+comment_text:  StringConst { $$ = $1; }
+               | NULL_P                        { $$ = make_str("null"); }
+               ;
 
 /*****************************************************************************
  *
@@ -1740,374 +2450,386 @@ comment_text:    StringConst          { $$ = $1; }
  *
  *****************************************************************************/
 
-GrantStmt:  GRANT privileges ON privilege_target TO grantee_list opt_grant_grant_option
-                               {
-                                       $$ = cat_str(7, make_str("grant"), $2, make_str("on"), $4, make_str("to"), $6, $7);
-                               }
+GrantStmt:     GRANT privileges ON privilege_target TO grantee_list opt_grant_grant_option
+                       { $$ = cat_str(7, make_str("grant"), $2, make_str("on"), $4, make_str("to"), $6, $7); }
                ;
 
-RevokeStmt:  REVOKE opt_revoke_grant_option privileges ON privilege_target FROM grantee_list
-                               {
-                                       $$ = cat_str(8, make_str("revoke"), $2, $3, make_str("on"), $5, make_str("from"), $7);
-                               }
+RevokeStmt:  REVOKE privileges ON privilege_target FROM grantee_list opt_drop_behavior
+                       {$$ = cat_str(7, make_str("revoke"), $2, make_str("on"), $4, make_str("from"), $6, $7); }
+               | REVOKE GRANT OPTION FOR privileges ON privilege_target FROM grantee_list opt_drop_behavior
+                       {$$ = cat_str(7, make_str("revoke grant option for"), $5, make_str("on"), $7, make_str("from"), $9, $10); }
                ;
 
-privileges:  ALL PRIVILEGES
-                               {
-                                $$ = make_str("all privileges");
-                               }
-               | ALL
-                               {
-                                $$ = make_str("all");
-                               }
-               | privilege_list
-                               {
-                                $$ = $1;
-                               }
+privileges:  ALL PRIVILEGES            { $$ = make_str("all privileges"); }
+               | ALL                                   { $$ = make_str("all"); }
+               | privilege_list                { $$ = $1; }
                ;
 
 privilege_list:  privilege
-                               {
-                                               $$ = $1;
-                               }
+                       { $$ = $1; }
                | privilege_list ',' privilege
-                               {
-                                               $$ = cat_str(3, $1, make_str(","), $3);
-                               }
+                       { $$ = cat_str(3, $1, make_str(","), $3); }
                ;
 
-privilege:  SELECT
-                               {
-                                               $$ = make_str("select");
-                               }
-               | INSERT
-                               {
-                                               $$ = make_str("insert");
-                               }
-               | UPDATE
-                               {
-                                               $$ = make_str("update");
-                               }
-               | DELETE
-                               {
-                                               $$ = make_str("delete");
-                               }
-               | RULE
-                               {
-                                               $$ = make_str("rule");
-                               }
-               | REFERENCES
-                               {
-                                               $$ = make_str("references");
-                               }
-               | TRIGGER
-                               {
-                                               $$ = make_str("trigger");
-                               }
-               | EXECUTE
-                               {
-                                               $$ = make_str("execute");
-                               }
-               | USAGE
-                               {
-                                               $$ = make_str("usage");
-                               }
+privilege:     SELECT                  { $$ = make_str("select"); }
+               | REFERENCES            { $$ = make_str("references"); }
+               | CREATE                        { $$ = make_str("create"); }
+               | ColId                         { $$ = $1; }
                ;
 
-privilege_target: relation_name_list
-                        {
-                               $$ = $1;
-                       }
-               | TABLE relation_name_list
-                       {
-                               $$ = cat2_str(make_str("table"), $2);
-                       }
+privilege_target: qualified_name_list
+                       { $$ = $1; }
+               | TABLE qualified_name_list
+                       { $$ = cat2_str(make_str("table"), $2); }
+               | SEQUENCE qualified_name_list
+                       { $$ = cat2_str(make_str("sequence"), $2); }
                | FUNCTION function_with_argtypes_list
-                       {
-                               $$ = cat2_str(make_str("function"), $2);
-                       }
+                       { $$ = cat2_str(make_str("function"), $2); }
+               | DATABASE name_list
+                       { $$ = cat2_str(make_str("database"), $2); }
                | LANGUAGE name_list
-                       {
-                               $$ = cat2_str(make_str("language") , $2);
-                       }
+                       { $$ = cat2_str(make_str("language") , $2); }
+               | SCHEMA name_list
+                       { $$ = cat2_str(make_str("schema") , $2); }
+               | TABLESPACE name_list
+                       { $$ = cat2_str(make_str("tablespace") , $2); }
                ;
-       
-grantee_list: grantee                                  { $$ = $1; }
-               | grantee_list ',' grantee      { $$ = cat_str(3, $1, make_str(","), $3); }
+
+grantee_list: grantee
+                       { $$ = $1; }
+               | grantee_list ',' grantee
+                       { $$ = cat_str(3, $1, make_str(","), $3); }
                ;
-               
-grantee:  PUBLIC
-                               {
-                                               $$ = make_str("public");
-                               }
-               | GROUP ColId
-                               {
-                                               $$ = cat2_str(make_str("group"), $2);
-                               }
-               | ColId
-                               {
-                                               $$ = $1;
-                               }
+
+grantee:  RoleId                       { $$ = $1; }
+               | GROUP_P RoleId        { $$ = cat2_str(make_str("group"), $2); }
                ;
 
 opt_grant_grant_option:  WITH GRANT OPTION
-                {
-                       mmerror(PARSE_ERROR, ET_WARNING, "Currently unsupported GRANT/WITH GRANT OPTION will be passed to backend");
+               {
+                       mmerror(PARSE_ERROR, ET_WARNING, "currently unsupported GRANT/WITH GRANT OPTION will be passed to backend");
                        $$ = make_str("with grant option");
                }
-               | /*EMPTY*/ { $$ = EMPTY; }
+               | /*EMPTY*/             { $$ = EMPTY; }
                ;
 
-opt_revoke_grant_option: GRANT OPTION FOR
-                   {
-                           mmerror(PARSE_ERROR, ET_WARNING, "Currently unsupported REVOKE/GRANT OPTION FOR will be passed to backend");
-                            $$ = make_str("with grant option");
-                    }
-                    | /*EMPTY*/ { $$ = EMPTY; }
-                    ;
-
 function_with_argtypes_list: function_with_argtypes
-                       { $$ = $1; }
+                       { $$ = $1; }
                | function_with_argtypes_list ',' function_with_argtypes
                        { $$ = cat_str(3, $1, make_str(","), $3); }
                ;
 
-function_with_argtypes: func_name func_args
-               { $$ = cat2_str($1, $2); };
+function_with_argtypes: func_name func_args { $$ = cat2_str($1, $2); };
 
 /*****************************************************************************
  *
- *             QUERY:
- *                             create index <indexname> on <relname>
- *                               [ using <access> ] "(" (<col> with <op>)+ ")"
- *                               [ where <predicate> ]
+ * GRANT and REVOKE ROLE statements
  *
  *****************************************************************************/
 
-IndexStmt:     CREATE index_opt_unique INDEX index_name ON relation_name
-                       access_method_clause '(' index_params ')' where_clause
-                               {
-                                       $$ = cat_str(11, make_str("create"), $2, make_str("index"), $4, make_str("on"), $6, $7, make_str("("), $9, make_str(")"), $11);
-                               }
+GrantRoleStmt:
+               GRANT privilege_list TO name_list opt_grant_admin_option opt_granted_by
+                       { $$ = cat_str(6, make_str("grant"), $2, make_str("to"), $4, $5, $6); }
                ;
 
-index_opt_unique:  UNIQUE      { $$ = make_str("unique"); }
-               | /*EMPTY*/     { $$ = EMPTY; }
+RevokeRoleStmt:
+               REVOKE privilege_list FROM name_list opt_granted_by opt_drop_behavior
+                       { $$ = cat_str(6, make_str("revoke"), $2, make_str("from"), $4, $5, $6); }
                ;
 
-access_method_clause:  USING access_method     { $$ = cat2_str(make_str("using"), $2); }
-               | /*EMPTY*/                     { $$ = EMPTY; }
+opt_grant_admin_option: WITH ADMIN OPTION      { $$ = make_str("with admin option"); }
+               | /*EMPTY*/                     { $$ = EMPTY; }
                ;
 
-index_params:  index_list                      { $$ = $1; }
-               | func_index                    { $$ = $1; }
+opt_granted_by: GRANTED BY RoleId       { $$ = cat2_str(make_str("granted by"), $3); }
+               | /*EMPTY*/              { $$ = EMPTY; }
                ;
 
-index_list:  index_list ',' index_elem         { $$ = cat_str(3, $1, make_str(","), $3); }
-               | index_elem                    { $$ = $1; }
+/*****************************************************************************
+ *
+ *             QUERY:
+ *             QUERY: CREATE INDEX
+ *
+ * Note: we can't factor CONCURRENTLY into a separate production without
+ * making it a reserved word.
+ *
+ * Note: we cannot put TABLESPACE clause after WHERE clause unless we are
+ * willing to make TABLESPACE a fully reserved word.
+ *
+ *****************************************************************************/
+
+IndexStmt:     CREATE index_opt_unique INDEX index_name ON qualified_name
+                               access_method_clause '(' index_params ')' opt_definition OptTableSpace where_clause
+                       { $$ = cat_str(13, make_str("create"), $2, make_str("index"), $4, make_str("on"), $6, $7, make_str("("), $9, make_str(")"), $11, $12, $13); }
+               | CREATE index_opt_unique INDEX CONCURRENTLY index_name ON qualified_name
+                               access_method_clause '(' index_params ')' opt_definition OptTableSpace where_clause
+                       { $$ = cat_str(13, make_str("create"), $2, make_str("index concurrently"), $5, make_str("on"), $7, $8, make_str("("), $10, make_str(")"), $12, $13, $14); }
                ;
 
-func_index:  func_name '(' name_list ')' opt_class
-                               {
-                                       $$ = cat_str(5, $1, make_str("("), $3, ")", $5);
-                               }
-                 ;
+index_opt_unique:  UNIQUE      { $$ = make_str("unique"); }
+               | /*EMPTY*/             { $$ = EMPTY; }
+               ;
 
-index_elem:  attr_name opt_class
-                               {
-                                       $$ = cat2_str($1, $2);
-                               }
+access_method_clause:  USING access_method
+                       { $$ = cat2_str(make_str("using"), $2); }
+               | /*EMPTY*/
+                       { $$ = EMPTY; }
                ;
 
-opt_class:  class                      {
-                                        /*
-                                          * Release 7.0 removed network_ops, timespan_ops, and
-                                          * datetime_ops, so we suppress it from being passed to
-                                          * the parser so the default *_ops is used.  This can be
-                                          * removed in some later release.  bjm 2000/02/07
-                                          *
-                                          * Release 7.1 removes lztext_ops, so suppress that too
-                                          * for a while.  tgl 2000/07/30
-                                          */
-                                        if (strcmp($1, "network_ops") != 0 &&
-                                            strcmp($1, "timespan_ops") != 0 && 
-                                            strcmp($1, "datetime_ops") != 0 &&
-                                            strcmp($1, "lztext_ops") != 0)
-                                               $$ = $1;
-                                        else
-                                               $$ = EMPTY;
-                                       }
-               | USING class                   { $$ = cat2_str(make_str("using"), $2); }
-               | /*EMPTY*/                     { $$ = EMPTY; }
+index_params:  index_elem                      { $$ = $1; }
+               | index_params ',' index_elem   { $$ = cat_str(3, $1, make_str(","), $3); }
                ;
 
+index_elem:  ColId opt_class opt_asc_desc opt_nulls_order
+                       { $$ = cat_str(4, $1, $2, $3, $4); }
+               | func_expr opt_class opt_asc_desc opt_nulls_order
+                       { $$ = cat_str(4, $1, $2, $3, $4); }
+               | '(' a_expr ')' opt_class opt_asc_desc opt_nulls_order
+                       { $$ = cat_str(6, make_str("("), $2, make_str(")"), $4, $5, $6); }
+               ;
 
-/*****************************************************************************
- *
- *             QUERY:
- *                             execute recipe <recipeName>
- *
- *****************************************************************************/
-/* NOT USED
-RecipeStmt:  EXECUTE RECIPE recipe_name
-                               {
-                                       $$ = cat2_str(make_str("execute recipe"), $3);
-                               }
+opt_class:     any_name        { $$ = $1; }
+               | USING any_name        { $$ = cat2_str(make_str("using"), $2); }
+               | /*EMPTY*/             { $$ = EMPTY; }
                ;
-*/
-/*****************************************************************************
- *
- *             QUERY:
- *                             create [or replace] function <fname>
- *                                             [(<type-1> { , <type-n>})]
- *                                             returns <type-r>
- *                                             as <filename or code in language as appropriate>
- *                                             language <lang> [with parameters]
- *
- *****************************************************************************/
 
-ProcedureStmt: CREATE opt_or_replace FUNCTION func_name func_args
-                        RETURNS func_return AS func_as LANGUAGE ColId_or_Sconst opt_with
-                               {
-                                       $$ = cat_str(12, make_str("create"), $2, make_str("function"), $4, $5, make_str("returns"), $7, make_str("as"), $9, make_str("language"), $11, $12);
-                               }
+opt_asc_desc:  ASC             { $$ = make_str("asc"); }
+               | DESC          { $$ = make_str("desc"); } 
+               | /*EMPTY*/     { $$ = EMPTY; }
+               ;
 
-opt_or_replace:  OR REPLACE                            { $$ = make_str("or replace"); }
-               | /*EMPTY*/                                             { $$ = EMPTY; }
+opt_nulls_order:       NULLS_FIRST             { $$ = make_str("nulls first"); }
+                       | NULLS_LAST            { $$ = make_str("nulls last"); } 
+                       | /*EMPTY*/     { $$ = EMPTY; }
+                       ;
+
+CreateFunctionStmt:    CREATE opt_or_replace FUNCTION func_name func_args
+                                       RETURNS func_return createfunc_opt_list opt_definition
+                       { $$ = cat_str(8, make_str("create"), $2, make_str("function"), $4, $5, make_str("returns"), $7, $8); }
+               | CREATE opt_or_replace FUNCTION func_name func_args
+                                       RETURNS TABLE '(' table_func_column_list ')' createfunc_opt_list opt_definition
+                       { $$ = cat_str(9, make_str("create"), $2, make_str("function"), $4, $5, make_str("returns table ("), $9, make_str(")"), $11, $12); }
+               | CREATE opt_or_replace FUNCTION func_name func_args
+                                       createfunc_opt_list opt_definition
+                       { $$ = cat_str(6, make_str("create"), $2, make_str("function"), $4, $5, $6, $7); }
                ;
 
-opt_with:  WITH definition                     { $$ = cat2_str(make_str("with"), $2); }
-               | /*EMPTY*/                     { $$ = EMPTY; }
+opt_or_replace:  OR REPLACE            { $$ = make_str("or replace"); }
+               | /*EMPTY*/                             { $$ = EMPTY; }
                ;
 
-func_args:  '(' func_args_list ')'             { $$ = cat_str(3, make_str("("), $2, make_str(")")); }
-               | '(' ')'                       { $$ = make_str("()"); }
+func_args:     '(' func_args_list ')'
+                       { $$ = cat_str(3, make_str("("), $2, make_str(")")); }
+               | '(' ')'
+                       { $$ = make_str("()"); }
                ;
 
-func_args_list:  func_arg                              { $$ = $1; }
+func_args_list:  func_arg
+                       { $$ = $1; }
                | func_args_list ',' func_arg
-                               {       $$ = cat_str(3, $1, make_str(","), $3); }
-               ;
-
-func_arg:  opt_arg func_type
-                               {
-                                       /* We can catch over-specified arguments here if we want to,
-                                        * but for now better to silently swallow typmod, etc.
-                                        * - thomas 2000-03-22
-                                        */
-                                       $$ = cat2_str($1, $2);
-                               }
-               | func_type
-                               {
-                                       $$ = $1;
-                               }
-               ;
+                       { $$ = cat_str(3, $1, make_str(","), $3); }
+               ;
 
-opt_arg:  IN    { $$ = make_str("in"); }
-       | OUT   { 
-                 mmerror(PARSE_ERROR, ET_WARNING, "Currently unsupported CREATE FUNCTION/OUT will be passed to backend");
+func_arg:  arg_class param_name func_type              { $$ = cat_str(3, $1, $2, $3); }
+               | param_name arg_class func_type        { $$ = cat_str(3, $1, $2, $3); }
+               | param_name func_type                  { $$ = cat2_str($1, $2); }
+               | arg_class func_type                   { $$ = cat2_str($1, $2); }
+               | func_type                             { $$ = $1; }
+               ;
 
-                 $$ = make_str("out");
-               }
-       | INOUT { 
-                 mmerror(PARSE_ERROR, ET_WARNING, "Currently unsupported CREATE FUNCTION/INOUT will be passed to backend");
+arg_class:  IN_P               { $$ = make_str("in"); }
+               | OUT_P         { $$ = make_str("out"); }
+               | INOUT         { $$ = make_str("inout"); }
+               | IN_P OUT_P    { $$ = make_str("in out"); }
+               | VARIADIC      { $$ = make_str("variadic"); }
+               ;
 
-                 $$ = make_str("inout");
-               }
-       ;
+func_as: StringConst
+                       { $$ = $1; }
+               | StringConst ',' StringConst
+                       { $$ = cat_str(3, $1, make_str(","), $3); }
+               ;
 
-func_as: StringConst                           { $$ = $1; }
-               | StringConst ',' StringConst   { $$ = cat_str(3, $1, make_str(","), $3); }
+param_name:    type_function_name      { $$ = $1; };
 
 func_return:  func_type
-                               {
-                                       /* We can catch over-specified arguments here if we want to,
-                                        * but for now better to silently swallow typmod, etc.
-                                        * - thomas 2000-03-22
-                                        */
-                                       $$ = $1;
-                                }
+               {
+                       /* We can catch over-specified arguments here if we want to,
+                        * but for now better to silently swallow typmod, etc.
+                        * - thomas 2000-03-22
+                        */
+                       $$ = $1;
+               }
                ;
 
 func_type:     Typename
-                               {
-                                       $$ = $1;
-                               }
-               | type_name '.' ColId '%' TYPE_P   
-                               {
-                                       $$ = cat_str(4, $1, make_str("."), $3, make_str("% type"));
-                               }
+                       { $$ = $1; }
+               | type_function_name attrs '%' TYPE_P
+                       { $$ = cat_str(3, $1, $2, make_str("% type")); }
+               | SETOF type_function_name attrs '%' TYPE_P
+                       { $$ = cat_str(4, make_str("setof"), $2, $3, make_str("% type")); }
+               ;
+
+
+createfunc_opt_list: createfunc_opt_item
+                       { $$ = $1; }
+               | createfunc_opt_list createfunc_opt_item
+                       { $$ = cat2_str($1, $2); }
+               ;
+
+common_func_opt_item:
+               CALLED ON NULL_P INPUT_P
+                               { $$ = make_str("called on null input"); }
+               | RETURNS NULL_P ON NULL_P INPUT_P
+                               { $$ = make_str("returns null on null input"); }
+               | STRICT_P
+                               { $$ = make_str("strict"); }
+               | IMMUTABLE
+                               { $$ = make_str("immutable"); }
+               | STABLE
+                               { $$ = make_str("stable"); }
+               | VOLATILE
+                               { $$ = make_str("volatile"); }
+               | EXTERNAL SECURITY DEFINER
+                               { $$ = make_str("external security definer"); }
+               | EXTERNAL SECURITY INVOKER
+                               { $$ = make_str("external security invoker"); }
+               | SECURITY DEFINER
+                               { $$ = make_str("security definer"); }
+               | SECURITY INVOKER
+                               { $$ = make_str("security invoker"); }
+               | COST NumConst
+                               { $$ = cat2_str(make_str("cost"), $2); }
+               | ROWS NumConst
+                               { $$ = cat2_str(make_str("rows"), $2); }
+               | SetResetClause
+                               { $$ = $1; }
+               ;
+
+createfunc_opt_item: AS func_as
+                               { $$ = cat2_str(make_str("as"), $2); }
+               | LANGUAGE ColId_or_Sconst
+                               { $$ = cat2_str(make_str("language"), $2); }
+               | common_func_opt_item
+                               { $$ = $1; }
+               ;
+
+opt_definition: WITH definition        { $$ = cat2_str(make_str("with"), $2); }
+               | /*EMPTY*/     { $$ = EMPTY; }
+               ;
+
+table_func_column:      param_name func_type   { $$ = cat2_str($1, $2); }
+                       ;
+
+table_func_column_list:
+                       table_func_column                               { $$ = $1; }
+                       | table_func_column_list ',' table_func_column  { $$ = cat_str(3, $1, make_str(","), $3); }
+                       ; 
+
+AlterFunctionStmt:
+               ALTER FUNCTION function_with_argtypes alterfunc_opt_list opt_restrict
+                       { $$ = cat_str(4, make_str("alter function"), $3, $4, $5); }
+               ;
+
+alterfunc_opt_list: common_func_opt_item                       { $$ = $1; }
+               | alterfunc_opt_list common_func_opt_item       { $$ = cat2_str($1, $2);}
+               ;
+
+opt_restrict:  RESTRICT        { $$ = make_str("restrict"); }
+               | /*EMPTY*/       { $$ = EMPTY; }
                ;
 
 /*****************************************************************************
  *
  *             QUERY:
  *
- *             DROP FUNCTION funcname (arg1, arg2, ...)
- *             DROP AGGREGATE aggname (aggtype)
- *             DROP OPERATOR opname (leftoperand_typ rightoperand_typ) 
+ *                        DROP FUNCTION funcname (arg1, arg2, ...)
+ *                        DROP AGGREGATE (arg1, ...) [ RESTRICT | CASCADE ]
+ *                        DROP OPERATOR opname (leftoperand_typ rightoperand_typ)
  *
  *****************************************************************************/
 
-RemoveFuncStmt:  DROP FUNCTION func_name func_args   
-                               {
-                                       $$ = cat_str(3, make_str("drop function"), $3, $4);
-                               }
-               ;
-
-RemoveAggrStmt:  DROP AGGREGATE func_name '(' aggr_argtype ')'
-                               {
-                                               $$ = cat_str(5, make_str("drop aggregate"), $3, make_str("("), $5, make_str(")"));
-                               }
-               | DROP AGGREGATE func_name aggr_argtype
-                               {
-                                               /* Obsolete syntax, but must support for awhile */
-                                               $$ = cat_str(3, make_str("drop aggregate"), $3, $4);
-                               }
+RemoveFuncStmt:  DROP FUNCTION func_name func_args opt_drop_behavior
+                       { $$ = cat_str(4, make_str("drop function"), $3, $4, $5); }
+               | DROP FUNCTION IF_P EXISTS func_name func_args opt_drop_behavior
+                       { $$ = cat_str(4, make_str("drop function if exists"), $5, $6, $7); }
                ;
 
-aggr_argtype:  Typename                        { $$ = $1; }
-               | '*'                   { $$ = make_str("*"); }
+RemoveAggrStmt:  DROP AGGREGATE func_name aggr_args opt_drop_behavior
+                       { $$ = cat_str(4, make_str("drop aggregate"), $3, $4, $5); }
+               | DROP AGGREGATE IF_P EXISTS func_name aggr_args opt_drop_behavior
+                       { $$ = cat_str(4, make_str("drop aggregate if exists"), $5, $6, $7); }
                ;
 
-
-RemoveOperStmt:  DROP OPERATOR all_Op '(' oper_argtypes ')'
-                               {
-                                       $$ = cat_str(5, make_str("drop operator"), $3, make_str("("), $5, make_str(")"));
-                               }
+RemoveOperStmt:  DROP OPERATOR all_Op '(' oper_argtypes ')' opt_drop_behavior
+                       { $$ = cat_str(6, make_str("drop operator"), $3, make_str("("), $5, make_str(")"), $7); }
+               | DROP OPERATOR IF_P EXISTS any_operator '(' oper_argtypes ')' opt_drop_behavior
+                       { $$ = cat_str(6, make_str("drop operator if exists"), $5, make_str("("), $7, make_str(")"), $9); }
                ;
 
 oper_argtypes: Typename
-                               {
-                                  mmerror(PARSE_ERROR, ET_ERROR, "parser: argument type missing (use NONE for unary operators)");
-                               }
+                       {
+                               mmerror(PARSE_ERROR, ET_ERROR, "parser: argument type missing (use NONE for unary operators)");
+                               $$ = make_str("none");
+                       }
                | Typename ',' Typename
-                               { $$ = cat_str(3, $1, make_str(","), $3); }
+                       { $$ = cat_str(3, $1, make_str(","), $3); }
                | NONE ',' Typename                     /* left unary */
-                               { $$ = cat2_str(make_str("none,"), $3); }
+                       { $$ = cat2_str(make_str("none,"), $3); }
                | Typename ',' NONE                     /* right unary */
-                               { $$ = cat2_str($1, make_str(", none")); }
+                       { $$ = cat2_str($1, make_str(", none")); }
+               ;
+
+any_operator:
+               all_Op
+                       { $$ = $1; }
+               | ColId '.' any_operator
+                       { $$ = cat_str(3, $1, make_str("."), $3); }
+               ;
+
+CreateCastStmt:                CREATE CAST '(' Typename AS Typename ')'
+                               WITH FUNCTION function_with_argtypes cast_context
+                       { $$ = cat_str(6, make_str("create cast ("), $4, make_str("as"), $6, make_str(") with function"), $10); }
+               | CREATE CAST '(' Typename AS Typename ')'
+                               WITHOUT FUNCTION cast_context
+                       { $$ = cat_str(6, make_str("create cast ("), $4, make_str("as"), $6, make_str(") without function"), $10); }
+               ;
+
+cast_context: AS ASSIGNMENT   { $$ = make_str("as assignment"); }
+               | /*EMPTY*/     { $$ = EMPTY; }
+               ;
+
+
+DropCastStmt: DROP CAST opt_if_exists  '(' Typename AS Typename ')' opt_drop_behavior
+                       { $$ = cat_str(8, make_str("drop cast"), $3, make_str("("), $5, make_str("as"), $7, make_str(")"), $9); }
+               ;
+
+opt_if_exists: IF_P EXISTS     { $$ = make_str("if exists"); }
+               | /* EMPTY */   { $$ = EMPTY; }
                ;
 
 /*****************************************************************************
  *
- *              QUERY:
+ *                             QUERY:
  *
- *              REINDEX type <typename> [FORCE] [ALL]
+ *                             REINDEX type <typename> [FORCE] [ALL]
  *
  *****************************************************************************/
-ReindexStmt:  REINDEX reindex_type name opt_force
-                                {
-                                       $$ = cat_str(4, make_str("reindex"), $2, $3, $4);
-                               }
+ReindexStmt:  REINDEX reindex_type qualified_name opt_force
+                       { $$ = cat_str(4, make_str("reindex"), $2, $3, $4); }
+               | REINDEX SYSTEM_P name opt_force
+                       { $$ = cat_str(3, make_str("reindex system"), $3, $4); }
+               | REINDEX DATABASE name opt_force
+                       { $$ = cat_str(3, make_str("reindex database"), $3, $4); }
+               ;
+
+reindex_type:  INDEX           { $$ = make_str("index"); }
+               | TABLE         { $$ = make_str("table"); }
+               ;
 
-reindex_type:   INDEX          { $$ = make_str("index"); }
-                | TABLE                { $$ = make_str("table"); }
-                | DATABASE     { $$ = make_str("database"); }
-                ;
-opt_force:      FORCE          { $$ = make_str("force"); }
-                | /* EMPTY */  { $$ = EMPTY; }
-                ;
+opt_force: FORCE                       { $$ = make_str("force"); }
+               | /* EMPTY */           { $$ = EMPTY; }
+               ;
 
 /*****************************************************************************
  *
@@ -2117,157 +2839,281 @@ opt_force:      FORCE         { $$ = make_str("force"); }
  *
  *****************************************************************************/
 
-RenameStmt:  ALTER TABLE relation_expr RENAME opt_column opt_name TO name
-                               {
-                                       $$ = cat_str(7, make_str("alter table"), $3, make_str("rename"), $5, $6, make_str("to"), $8);
-                               }
+RenameStmt:  ALTER AGGREGATE func_name aggr_args RENAME TO name
+                       { $$ = cat_str(5, make_str("alter aggregate"), $3, $4, make_str("rename to"), $7); }
+               | ALTER CONVERSION_P any_name RENAME TO name
+                       { $$ = cat_str(4, make_str("alter conversion"), $3, make_str("rename to"), $6); }
+               | ALTER DATABASE database_name RENAME TO database_name
+                       { $$ = cat_str(4, make_str("alter database"), $3, make_str("rename to"), $6); }
+               | ALTER FUNCTION function_with_argtypes RENAME TO name
+                       { $$ = cat_str(4, make_str("alter function"), $3, make_str("rename to"), $6); }
+               | ALTER GROUP_P RoleId RENAME TO RoleId
+                       { $$ = cat_str(4, make_str("alter group"), $3, make_str("rename to"), $6); }
+               | ALTER opt_procedural LANGUAGE name RENAME TO name
+                       { $$ = cat_str(6, make_str("alter"), $2, make_str("language"), $4, make_str("rename to"), $7); }
+               | ALTER OPERATOR CLASS any_name USING access_method RENAME TO name
+                       { $$ = cat_str(6, make_str("alter operator class"), $4, make_str("using"), $6, make_str("rename to"), $9); }
+               | ALTER OPERATOR FAMILY any_name USING access_method RENAME TO name
+                       { $$ = cat_str(6, make_str("alter operator family"), $4, make_str("using"), $6, make_str("rename to"), $9); }
+               | ALTER SCHEMA name RENAME TO name
+                       { $$ = cat_str(4, make_str("alter schema"), $3, make_str("rename to"), $6); }
+               | ALTER TABLE relation_expr RENAME TO name
+                       { $$ = cat_str(4, make_str("alter table"), $3, make_str("rename to"), $6); }
+               | ALTER TABLE relation_expr SET SCHEMA name
+                       { $$ = cat_str(4, make_str("alter table"), $3, make_str("set schema"), $6); }
+               | ALTER SEQUENCE relation_expr RENAME TO name
+                       { $$ = cat_str(4, make_str("alter sequence"), $3, make_str("rename to"), $6); }
+               | ALTER VIEW relation_expr RENAME TO name
+                       { $$ = cat_str(4, make_str("alter view"), $3, make_str("rename to"), $6); }
+               | ALTER INDEX relation_expr RENAME TO name
+                       { $$ = cat_str(4, make_str("alter index"), $3, make_str("rename to"), $6); }
+               | ALTER TABLE relation_expr RENAME opt_column name TO name
+                       { $$ = cat_str(7, make_str("alter table"), $3, make_str("rename"), $5, $6, make_str("to"), $8); }
+               | ALTER TRIGGER name ON relation_expr RENAME TO name
+                       { $$ = cat_str(6, make_str("alter trigger"), $3, make_str("on"), $5, make_str("rename to"), $8); }
+               | ALTER USER RoleId RENAME TO RoleId
+                       { $$ = cat_str(4, make_str("alter user"), $3, make_str("rename to"), $6); }
+               | ALTER TABLESPACE name RENAME TO name
+                       { $$ = cat_str(4, make_str("alter tablespace"), $3, make_str("rename to"), $6); }
+               | ALTER TEXT_P SEARCH PARSER any_name RENAME TO name
+                       { $$ = cat_str(4, make_str("alter text search parser"), $5, make_str("rename to"), $8); }
+               | ALTER TEXT_P SEARCH DICTIONARY any_name RENAME TO name
+                       { $$ = cat_str(4, make_str("alter text search dictionary"), $5, make_str("rename to"), $8); }
+               | ALTER TEXT_P SEARCH TEMPLATE any_name RENAME TO name
+                       { $$ = cat_str(4, make_str("alter text search template"), $5, make_str("rename to"), $8); }
+               | ALTER TEXT_P SEARCH CONFIGURATION any_name RENAME TO name
+                       { $$ = cat_str(4, make_str("alter text search configuration"), $5, make_str("rename to"), $8); }
+               | ALTER TYPE_P any_name RENAME TO name
+                       { $$ = cat_str(4, make_str("alter type"), $3, make_str("rename to"), $6); }
+               ;
+
+opt_column:  COLUMN                    { $$ = make_str("column"); }
+               | /*EMPTY*/                     { $$ = EMPTY; }
                ;
 
-opt_name:  name                                                        { $$ = $1; }
-               | /*EMPTY*/                                     { $$ = EMPTY; }
+/*****************************************************************************
+ *
+ * ALTER THING name SET SCHEMA name
+ *
+ *****************************************************************************/
+
+AlterObjectSchemaStmt:
+               ALTER AGGREGATE func_name aggr_args SET SCHEMA name
+                       { $$ = cat_str(5, make_str("alter aggregate"), $3, $4, make_str("set schema"), $7); }
+               | ALTER DOMAIN_P any_name SET SCHEMA name
+                       { $$ = cat_str(4, make_str("alter domain"), $3, make_str("set schema"), $6); }
+               | ALTER FUNCTION function_with_argtypes SET SCHEMA name
+                       { $$ = cat_str(4, make_str("alter function"), $3, make_str("set schema"), $6); }
+               | ALTER SEQUENCE relation_expr SET SCHEMA name
+                       { $$ = cat_str(4, make_str("alter sequence"), $3, make_str("set schema"), $6); }
+               | ALTER VIEW relation_expr SET SCHEMA name
+                       { $$ = cat_str(4, make_str("alter sequence"), $3, make_str("set schema"), $6); }
+               | ALTER TYPE_P any_name SET SCHEMA name
+                       { $$ = cat_str(4, make_str("alter type"), $3, make_str("set schema"), $6); }
                ;
 
-opt_column:  COLUMN                                    { $$ = make_str("column"); }
-               | /*EMPTY*/                             { $$ = EMPTY; }
+/*****************************************************************************
+ *
+ * ALTER THING name OWNER TO newname
+ *
+ *****************************************************************************/
+
+AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
+                       { $$ = cat_str(5, make_str("alter aggregate"), $3, $4, make_str("owner to"), $7); }
+               | ALTER CONVERSION_P any_name OWNER TO RoleId
+                       { $$ = cat_str(4, make_str("alter conversion"), $3, make_str("owner to"), $6); }
+               | ALTER DATABASE database_name OWNER TO RoleId
+                       { $$ = cat_str(4, make_str("alter database"), $3, make_str("owner to"), $6); }
+               | ALTER DOMAIN_P database_name OWNER TO RoleId
+                       { $$ = cat_str(4, make_str("alter domain"), $3, make_str("owner to"), $6); }
+               | ALTER FUNCTION function_with_argtypes OWNER TO RoleId
+                       { $$ = cat_str(4, make_str("alter function"), $3, make_str("owner to"), $6); }
+               | ALTER opt_procedural LANGUAGE name OWNER TO RoleId
+                       { $$ = cat_str(6, make_str("alter"), $2, make_str("language"), $4, make_str("owner to"), $7); }
+               | ALTER OPERATOR any_operator '(' oper_argtypes ')' OWNER TO RoleId
+                       { $$ = cat_str(6, make_str("alter operator"), $3, make_str("("), $5, make_str(") owner to"), $9); }
+               | ALTER OPERATOR CLASS any_name USING access_method OWNER TO RoleId
+                       { $$ = cat_str(6, make_str("alter operator class"), $4, make_str("using"), $6, make_str("owner to"), $9); }
+               | ALTER OPERATOR FAMILY any_name USING access_method OWNER TO RoleId
+                       { $$ = cat_str(6, make_str("alter operator family"), $4, make_str("using"), $6, make_str("owner to"), $9); }
+               | ALTER SCHEMA name OWNER TO RoleId
+                       { $$ = cat_str(4, make_str("alter schema"), $3, make_str("owner to"), $6); }
+               | ALTER TYPE_P any_name OWNER TO RoleId
+                       { $$ = cat_str(4, make_str("alter type"), $3, make_str("owner to"), $6); }
+               | ALTER TABLESPACE name OWNER TO RoleId
+                       { $$ = cat_str(4, make_str("alter tablespace"), $3, make_str("owner to"), $6); }
+               | ALTER TEXT_P SEARCH DICTIONARY any_name OWNER TO RoleId
+                       { $$ = cat_str(4, make_str("alter text search dictionary"), $5, make_str("owner to"), $8); }
+               | ALTER TEXT_P SEARCH CONFIGURATION any_name OWNER TO RoleId
+                       { $$ = cat_str(4, make_str("alter text search configuration"), $5, make_str("owner to"), $8); }
                ;
 
 
 /*****************************************************************************
  *
- *             QUERY:  Define Rewrite Rule , Define Tuple Rule
- *                             Define Rule <old rules >
- *
- *             only rewrite rule is supported -- ay 9/94
+ *             QUERY:  Define Rewrite Rule
  *
  *****************************************************************************/
 
-RuleStmt:  CREATE RULE name AS
+RuleStmt:  CREATE opt_or_replace RULE name AS
                   { QueryIsRule=1; }
-                  ON event TO event_object where_clause
+                  ON event TO qualified_name where_clause
                   DO opt_instead RuleActionList
-                               {
-                                       QueryIsRule=0;
-                                       $$ = cat_str(10, make_str("create rule"), $3, make_str("as on"), $7, make_str("to"), $9, $10, make_str("do"), $12, $13);
-                               }
+               {
+                       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);
+               }
                ;
 
-RuleActionList:  NOTHING                               { $$ = make_str("nothing"); }
-               | RuleActionStmt                        { $$ = $1; }
-               | '(' RuleActionMulti ')'               { $$ = cat_str(3, make_str("("), $2, make_str(")")); }
-                ;
+RuleActionList:  NOTHING                               { $$ = make_str("nothing"); }
+               | RuleActionStmt                                { $$ = $1; }
+               | '(' RuleActionMulti ')'               { $$ = cat_str(3, make_str("("), $2, make_str(")")); }
+                               ;
 
 /* the thrashing around here is to discard "empty" statements... */
 RuleActionMulti:  RuleActionMulti ';' RuleActionStmtOrEmpty
-                                {  $$ = cat_str(3, $1, make_str(";"), $3); }
+                       {  $$ = cat_str(3, $1, make_str(";"), $3); }
                | RuleActionStmtOrEmpty
-                               { $$ = cat2_str($1, make_str(";")); }
+                       { $$ = cat2_str($1, make_str(";")); }
                ;
 
 RuleActionStmt:   SelectStmt
                | InsertStmt
-                | UpdateStmt
-                | DeleteStmt
+               | UpdateStmt
+               | DeleteStmt
                | NotifyStmt
-                ;
-RuleActionStmtOrEmpty: RuleActionStmt  { $$ = $1; }
-               |       /*EMPTY*/        { $$ = EMPTY; }
-               ;
+               ;
 
-event_object:  relation_name '.' attr_name
-                               {
-                                       $$ = make3_str($1, make_str("."), $3);
-                               }
-               | relation_name
-                               {
-                                       $$ = $1;
-                               }
+RuleActionStmtOrEmpty: RuleActionStmt  { $$ = $1; }
+               | /*EMPTY*/                                             { $$ = EMPTY; }
                ;
 
 /* change me to select, update, etc. some day */
-event: SELECT                                  { $$ = make_str("select"); }
+event: SELECT                          { $$ = make_str("select"); }
                | UPDATE                        { $$ = make_str("update"); }
-               | DELETE                        { $$ = make_str("delete"); }
+               | DELETE_P                      { $$ = make_str("delete"); }
                | INSERT                        { $$ = make_str("insert"); }
-                ;
+               | TRUNCATE                      { $$ = make_str("truncate"); }
+               ;
 
-opt_instead:  INSTEAD                                  { $$ = make_str("instead"); }
-               | /*EMPTY*/                             { $$ = EMPTY; }
+opt_instead:  INSTEAD          { $$ = make_str("instead"); }
+               | ALSO          { $$ = make_str("also"); }
+               | /*EMPTY*/                     { $$ = EMPTY; }
                ;
 
+DropRuleStmt:  DROP RULE name ON qualified_name opt_drop_behavior
+                       { $$ = cat_str(5, make_str("drop rule"), $3, make_str("on"), $5, $6);}
+               | DROP RULE IF_P EXISTS name ON qualified_name opt_drop_behavior
+                       { $$ = cat_str(5, make_str("drop rule if exists"), $5, make_str("on"), $7, $8);}
+               ;
 
 /*****************************************************************************
  *
  *             QUERY:
- *                             NOTIFY <relation_name>  can appear both in rule bodies and
+ *                             NOTIFY <qualified_name> can appear both in rule bodies and
  *                             as a query-level command
  *
  *****************************************************************************/
 
-NotifyStmt:  NOTIFY relation_name
-                               {
-                                       $$ = cat2_str(make_str("notify"), $2);
-                               }
+NotifyStmt:  NOTIFY ColId
+                       { $$ = cat2_str(make_str("notify"), $2); }
                ;
 
-ListenStmt:  LISTEN relation_name
-                               {
-                                       $$ = cat2_str(make_str("listen"), $2);
-                                }
-;
+ListenStmt:  LISTEN ColId
+                       { $$ = cat2_str(make_str("listen"), $2); }
+               ;
 
-UnlistenStmt:  UNLISTEN relation_name
-                               {
-                                       $$ = cat2_str(make_str("unlisten"), $2);
-                                }
+UnlistenStmt:  UNLISTEN ColId
+                       { $$ = cat2_str(make_str("unlisten"), $2); }
                | UNLISTEN '*'
-                               {
-                                       $$ = make_str("unlisten *");
-                                }
-;
+                       { $$ = make_str("unlisten *"); }
+               ;
+
 
 /*****************************************************************************
  *
- *              Transactions:
+ *                             Transactions:
  *
  *       BEGIN / COMMIT / ROLLBACK
- *      (also older versions END / ABORT)
+ *             (also older versions END / ABORT)
  *
  *****************************************************************************/
-TransactionStmt:  ABORT_TRANS opt_trans        { $$ = make_str("rollback"); }
-       | BEGIN_TRANS opt_trans         { $$ = make_str("begin transaction"); }
-       | COMMIT opt_trans              { $$ = make_str("commit"); }
-       | COMMIT opt_trans opt_chain    { $$ = cat2_str(make_str("commit"), $3); }
-       | END_TRANS opt_trans           { $$ = make_str("commit"); }
-       | ROLLBACK opt_trans            { $$ = make_str("rollback"); }
-       | ROLLBACK opt_trans opt_chain  { $$ = cat2_str(make_str("rollback"), $3); }
-       ;
+TransactionStmt:  ABORT_P opt_transaction       { $$ = make_str("rollback"); }
+               | BEGIN_P opt_transaction transaction_mode_list_or_empty { $$ = cat2_str(make_str("begin transaction"), $3); }
+               | START TRANSACTION transaction_mode_list_or_empty       { $$ = cat2_str(make_str("start transaction"), $3); }
+               | COMMIT opt_transaction                         { $$ = make_str("commit"); }
+               | END_P opt_transaction                          { $$ = make_str("commit"); }
+               | ROLLBACK opt_transaction                       { $$ = make_str("rollback"); }
+               | SAVEPOINT ColId                                        { $$ = cat2_str(make_str("savepoint"), $2); }
+               | RELEASE SAVEPOINT ColId                        { $$ = cat2_str(make_str("release savepoint"), $3); }
+               | RELEASE ColId                                          { $$ = cat2_str(make_str("release"), $2); }
+               | ROLLBACK opt_transaction TO SAVEPOINT ColId            { $$ = cat_str(4, make_str("rollback"), $2, make_str("to savepoint"), $5); }
+               | ROLLBACK opt_transaction TO ColId      { $$ = cat_str(4, make_str("rollback"), $2, make_str("to"), $4); }
+               | PREPARE TRANSACTION StringConst        { $$ = cat2_str(make_str("prepare transaction"), $3); }
+               | COMMIT PREPARED StringConst            { $$ = cat2_str(make_str("commit prepared"), $3); }
+               | ROLLBACK PREPARED StringConst          { $$ = cat2_str(make_str("rollback prepared"), $3); }
+               ;
+
+opt_transaction: WORK  { $$ = EMPTY; }
+               | TRANSACTION   { $$ = EMPTY; }
+               | /*EMPTY*/             { $$ = EMPTY; }
+               ;
 
-opt_trans: WORK        { $$ = EMPTY; }
-       | TRANSACTION   { $$ = EMPTY; }
-       | /*EMPTY*/     { $$ = EMPTY; }
-                ;
+transaction_mode_item:
+               ISOLATION LEVEL iso_level
+                       { $$ = cat2_str(make_str("isolation level"), $3); }
+               | READ ONLY     { $$ = make_str("read only"); }
+               | READ WRITE    { $$ = make_str("read write"); }
+               ;
 
-opt_chain: AND NO CHAIN        { $$ = make_str("and no chain"); }
-       | AND CHAIN             {
-                                 mmerror(PARSE_ERROR, ET_WARNING, "Currently unsupported COMMIT/CHAIN will be passed to backend");
+transaction_mode_list:
+               transaction_mode_item                                   { $$ = $1; }
+               | transaction_mode_list ',' transaction_mode_item       { $$ = cat_str(3, $1, make_str(","), $3); }
+               | transaction_mode_list transaction_mode_item           { $$ = cat_str(3, $1, make_str(" "), $2); }
+               ;
 
-                                 $$ = make_str("and chain");
-                               }
-       ;
+transaction_mode_list_or_empty:
+               transaction_mode_list   { $$ = $1; }
+               | /* EMPTY */           { $$ = EMPTY; }
+               ;
 
 /*****************************************************************************
  *
- *             QUERY:
- *                             define view <viewname> '('target-list ')' [where <quals> ]
+ *     QUERY:
+ *             CREATE [ OR REPLACE ] [ TEMP ] VIEW <viewname> '('target-list ')'
+ *                     AS <query> [ WITH [ CASCADED | LOCAL ] CHECK OPTION ]
  *
  *****************************************************************************/
 
-ViewStmt:  CREATE VIEW name opt_column_list AS SelectStmt
-                               {
-                                       $$ = cat_str(5, make_str("create view"), $3, $4, make_str("as"), $6);
-                               }
+ViewStmt:  CREATE OptTemp VIEW qualified_name opt_column_list AS SelectStmt opt_check_option
+                       { $$ = cat_str(8, make_str("create"), $2, make_str("view"), $4, $5, make_str("as"), $7, $8); }
+               | CREATE OR REPLACE OptTemp VIEW qualified_name opt_column_list AS SelectStmt opt_check_option
+                       { $$ = cat_str(8, make_str("create or replace"), $4, make_str("view"), $6, $7, make_str("as"), $9, $10); }
                ;
 
+/*
+ * We use merged tokens here to avoid creating shift/reduce conflicts against
+ * a whole lot of other uses of WITH.
+ */
+opt_check_option:
+                   WITH_CHECK OPTION
+                  { 
+                       mmerror(PARSE_ERROR, ET_ERROR, "WITH CHECK OPTION not implemented");
+                       $$ = EMPTY;
+                  }
+                   | WITH_CASCADED CHECK OPTION
+                  { 
+                       mmerror(PARSE_ERROR, ET_ERROR, "WITH CHECK OPTION not implemented");
+                       $$ = EMPTY;
+                  }
+                  | WITH_LOCAL CHECK OPTION
+                  {
+                       mmerror(PARSE_ERROR, ET_ERROR, "WITH CHECK OPTION not implemented");
+                       $$ = EMPTY;
+                  }
+                  | /* EMPTY */
+                  { $$ = EMPTY; } 
+                  ;
 
 /*****************************************************************************
  *
@@ -2277,9 +3123,7 @@ ViewStmt:  CREATE VIEW name opt_column_list AS SelectStmt
  *****************************************************************************/
 
 LoadStmt:  LOAD file_name
-                               {
-                                       $$ = cat2_str(make_str("load"), $2);
-                               }
+                       { $$ = cat2_str(make_str("load"), $2); }
                ;
 
 
@@ -2291,91 +3135,160 @@ LoadStmt:  LOAD file_name
  *****************************************************************************/
 
 CreatedbStmt:  CREATE DATABASE database_name WITH createdb_opt_list
-                       {
-                               $$ = cat_str(4, make_str("create database"), $3, make_str("with"), $5);
-                       }
+                       { $$ = cat_str(4, make_str("create database"), $3, make_str("with"), $5); }
                | CREATE DATABASE database_name
-                               {
-                               $$ = cat2_str(make_str("create database"), $3);
-                       }
+                       { $$ = cat2_str(make_str("create database"), $3); }
                ;
 
-createdb_opt_list:  createdb_opt_item
-                               { $$ = $1; }
-                | createdb_opt_list createdb_opt_item
-                               { $$ = cat2_str($1, $2); }
-                ;                
-
-createdb_opt_item:  LOCATION opt_equal StringConst     { $$ = cat_str(3,make_str("location"), $2, $3); }
-               | LOCATION opt_equal DEFAULT            { $$ = cat_str(3, make_str("location"), $2, make_str("default")); }
-               | TEMPLATE opt_equal name               { $$ = cat_str(3, make_str("template"), $2, $3); }
-               | TEMPLATE opt_equal DEFAULT            { $$ = cat_str(3, make_str("template"), $2, make_str("default")); }
-               | ENCODING opt_equal PosIntStringConst  
-                       {
-                               $$ = cat_str(3, make_str("encoding"), $2, $3);
-                       }
+createdb_opt_list:     createdb_opt_item
+                       { $$ = $1; }
+               | createdb_opt_list createdb_opt_item
+                       { $$ = cat2_str($1, $2); }
+               ;
+
+createdb_opt_item:     TABLESPACE opt_equal name
+                       { $$ = cat_str(3,make_str("tablespace"), $2, $3); }
+               | TABLESPACE opt_equal DEFAULT
+                       { $$ = cat_str(3, make_str("tablespace"), $2, make_str("default")); }
+               | LOCATION opt_equal StringConst
+                       { $$ = cat_str(3,make_str("location"), $2, $3); }
+               | LOCATION opt_equal DEFAULT
+                       { $$ = cat_str(3, make_str("location"), $2, make_str("default")); }
+               | TEMPLATE opt_equal name
+                       { $$ = cat_str(3, make_str("template"), $2, $3); }
+               | TEMPLATE opt_equal DEFAULT
+                       { $$ = cat_str(3, make_str("template"), $2, make_str("default")); }
+               | ENCODING opt_equal PosIntStringConst
+                       { $$ = cat_str(3, make_str("encoding"), $2, $3); }
                | ENCODING opt_equal DEFAULT
-                       {
-                               $$ = cat_str(3, make_str("encoding"), $2, make_str("default"));
-                       }
-               | OWNER opt_equal name  
-                       {
-                               $$ = cat_str(3, make_str("owner"), $2, $3);
-                       }
+                       { $$ = cat_str(3, make_str("encoding"), $2, make_str("default")); }
+               | CONNECTION LIMIT opt_equal PosIntConst
+                       { $$ = cat_str(3, make_str("connection limit"), $3, $4); }
+               | OWNER opt_equal name
+                       { $$ = cat_str(3, make_str("owner"), $2, $3); }
                | OWNER opt_equal DEFAULT
-                       {
-                               $$ = cat_str(3, make_str("owner"), $2, make_str("default"));
-                       }
-                ;
+                       { $$ = cat_str(3, make_str("owner"), $2, make_str("default")); }
+               ;
+
+opt_equal: '='                                 { $$ = make_str("="); }
+               | /* EMPTY */                   { $$ = EMPTY; }
+               ;
 
-opt_equal: '='         { $$ = make_str("="); }
-       | /* EMPTY */   { $$ = EMPTY; }
-       ;
 
 /*****************************************************************************
  *
- *              ALTER DATABASE
+ *                             ALTER DATABASE
  *
  *
  *****************************************************************************/
 
-AlterDatabaseSetStmt: ALTER DATABASE database_name VariableSetStmt
-                       {
-                               $$ = cat_str(3, make_str("alter database"), $3, $4);
-                       }
-                       | ALTER DATABASE database_name VariableResetStmt
-                       {
-                               $$ = cat_str(3, make_str("alter database"), $3, $4);
-                       }
-                       ;
-       
+AlterDatabaseStmt: ALTER DATABASE database_name opt_with alterdb_opt_list
+                       { $$ = cat_str(4, make_str("alter database"), $3, $4, $5); }
+               ;
+
+AlterDatabaseSetStmt: ALTER DATABASE database_name SetResetClause
+                       { $$ = cat_str(3, make_str("alter database"), $3, $4); }
+               ;
+
+alterdb_opt_list:
+               alterdb_opt_list alterdb_opt_item       { $$ = cat2_str($1, $2);}
+               | /* EMPTY */                           { $$ = EMPTY; }
+               ;
+
+alterdb_opt_item:
+               CONNECTION LIMIT opt_equal PosIntConst { $$ = cat_str(3, make_str("connection limit"), $3, $4); }
+               ;
+
 /*****************************************************************************
  *
- *             DROP DATABASE
+ *             DROP DATABASE [ IF EXISTS ]
  *
  *
  *****************************************************************************/
 
-DropdbStmt:    DROP DATABASE database_name
-                               {
-                                       $$ = cat2_str(make_str("drop database"), $3);
-                               }
+DropdbStmt: DROP DATABASE database_name
+                       { $$ = cat2_str(make_str("drop database"), $3); }
+               | DROP DATABASE IF_P EXISTS database_name
+                       { $$ = cat2_str(make_str("drop database if exists"), $5); }
                ;
 
 
 /*****************************************************************************
  *
- *             QUERY:
- *                             cluster <index_name> on <relation_name>
+ * Manipulate a domain
  *
  *****************************************************************************/
 
-ClusterStmt:  CLUSTER index_name ON relation_name
-                               {
-                                  $$ = cat_str(4, make_str("cluster"), $2, make_str("on"), $4);
-                               }
-               ;
+CreateDomainStmt:  CREATE DOMAIN_P any_name opt_as Typename ColQualList
+               {
+                       $$ = cat_str(5, make_str("create domain"), $3, $4, $5, $6);
+               }
+               ;
+
+AlterDomainStmt:
+               ALTER DOMAIN_P any_name alter_column_default
+                       { $$ = cat_str(3, make_str("alter domain"), $3, $4); }
+               | ALTER DOMAIN_P any_name DROP NOT NULL_P
+                       { $$ = cat_str(3, make_str("alter domain"), $3, make_str("drop not null")); }
+               | ALTER DOMAIN_P any_name SET NOT NULL_P
+                       { $$ = cat_str(3, make_str("alter domain"), $3, make_str("set not null")); }
+               | ALTER DOMAIN_P any_name ADD_P TableConstraint
+                       { $$ = cat_str(4, make_str("alter domain"), $3, make_str("add"), $5); }
+               | ALTER DOMAIN_P any_name DROP CONSTRAINT name opt_drop_behavior
+                       { $$ = cat_str(5, make_str("alter domain"), $3, make_str("drop constraint"), $6, $7); }
+               ;
+
+opt_as:        AS      {$$ = make_str("as"); }
+               | /* EMPTY */   {$$ = EMPTY; }
+               ;
+
+AlterTSDictionaryStmt:
+               ALTER TEXT_P SEARCH DICTIONARY any_name definition
+                       { $$ = cat_str(3, make_str("alter text search dictionary"), $5, $6); }
+               ;
+
+AlterTSConfigurationStmt:
+               ALTER TEXT_P SEARCH CONFIGURATION any_name ADD_P MAPPING FOR name_list WITH any_name_list
+                       { $$ = cat_str(6, make_str("alter text search configuration"), $5, make_str("add mapping for"), $9, make_str("with"), $11); }
+               | ALTER TEXT_P SEARCH CONFIGURATION any_name ALTER MAPPING FOR name_list WITH any_name_list
+                       { $$ = cat_str(6, make_str("alter text search configuration"), $5, make_str("alter mapping for"), $9, make_str("with"), $11); }
+               | ALTER TEXT_P SEARCH CONFIGURATION any_name ALTER MAPPING REPLACE any_name WITH any_name
+                       { $$ = cat_str(6, make_str("alter text search configuration"), $5, make_str("alter mapping replace"), $9, make_str("with"), $11); }
+               | ALTER TEXT_P SEARCH CONFIGURATION any_name ALTER MAPPING FOR name_list REPLACE any_name WITH any_name
+                       { $$ = cat_str(8, make_str("alter text search configuration"), $5, make_str("alter mapping for"), $9, make_str("replace"), $11, make_str("with"), $13); }
+               | ALTER TEXT_P SEARCH CONFIGURATION any_name DROP MAPPING FOR name_list
+                       { $$ = cat_str(4, make_str("alter text search configuration"), $5, make_str("drop mapping for"), $9); }
+               | ALTER TEXT_P SEARCH CONFIGURATION any_name DROP MAPPING IF_P EXISTS FOR name_list
+                       { $$ = cat_str(4, make_str("alter text search configuration"), $5, make_str("drop mapping if exists for"), $11); }
+               ;
+
+CreateConversionStmt:
+          CREATE opt_default CONVERSION_P any_name FOR StringConst
+          TO StringConst FROM any_name
+                  { $$ = cat_str(10, make_str("create"), $2, make_str("conversion"), $4, make_str("for"), $6, make_str("to"), $8, make_str("from"), $10); }
+          ;
 
+/*****************************************************************************
+ *
+ *             QUERY:
+ *                            cluster <index_name> on <qualified_name>
+ *                             cluster <qualified_name>
+ *                             cluster
+ *
+ *****************************************************************************/
+
+ClusterStmt:  CLUSTER qualified_name cluster_index_specification
+                               { $$ = cat_str(3,make_str("cluster"), $2, $3); }
+               | CLUSTER
+                               { $$ = make_str("cluster"); }
+               | CLUSTER qualified_name ON qualified_name
+                               { $$ = cat_str(4, make_str("cluster"), $2, make_str("on"), $4); }
+               ;
+
+cluster_index_specification:
+               USING index_name        { $$ = cat2_str(make_str("using"), $2); }
+               | /*EMPTY*/             { $$ = EMPTY; }
+               ;
 
 /*****************************************************************************
  *
@@ -2386,47 +3299,39 @@ ClusterStmt:  CLUSTER index_name ON relation_name
  *****************************************************************************/
 
 VacuumStmt:  VACUUM opt_full opt_freeze opt_verbose
-                               {
-                                       $$ = cat_str(4, make_str("vacuum"), $2, $3, $4);
-                               }
-               | VACUUM opt_full opt_freeze opt_verbose relation_name
-                               {
-                                       $$ = cat_str(5, make_str("vacuum"), $2, $3, $4, $5);
-                               }
+                       { $$ = cat_str(4, make_str("vacuum"), $2, $3, $4); }
+               | VACUUM opt_full opt_freeze opt_verbose qualified_name
+                       { $$ = cat_str(5, make_str("vacuum"), $2, $3, $4, $5); }
                | VACUUM opt_full opt_freeze opt_verbose AnalyzeStmt
-                               {
-                                       $$ = cat_str(5, make_str("vacuum"), $2, $3, $4, $5);
-                               }
+                       { $$ = cat_str(5, make_str("vacuum"), $2, $3, $4, $5); }
                ;
 
 AnalyzeStmt:  analyze_keyword opt_verbose
-                               {
-                                       $$ = cat_str(2, $1, $2);
-                               }
-               | analyze_keyword opt_verbose relation_name opt_name_list
-                               {
-                                       $$ = cat_str(4, $1, $2, $3, $4);
-                               }
+                       { $$ = cat_str(2, $1, $2); }
+               | analyze_keyword opt_verbose qualified_name opt_name_list
+                       { $$ = cat_str(4, $1, $2, $3, $4); }
                ;
 
-analyze_keyword:  ANALYZE                                      { $$ = make_str("analyze"); }
-               | ANALYSE                                                       { $$ = make_str("analyse"); }
+analyze_keyword:  ANALYZE              { $$ = make_str("analyze"); }
+               | ANALYSE               { $$ = make_str("analyse"); }
                ;
 
-opt_verbose:  VERBOSE                                  { $$ = make_str("verbose"); }
-               | /*EMPTY*/                                             { $$ = EMPTY; }
+opt_verbose:  VERBOSE                  { $$ = make_str("verbose"); }
+               | /*EMPTY*/                             { $$ = EMPTY; }
                ;
 
-opt_full:  FULL                                                        { $$ = make_str("full"); }
-               | /*EMPTY*/                                             { $$ = EMPTY; }
+opt_full:  FULL                                        { $$ = make_str("full"); }
+               | /*EMPTY*/                             { $$ = EMPTY; }
                ;
 
-opt_freeze:  FREEZE                                            { $$ = make_str("freeze"); }
-               | /*EMPTY*/                                     { $$ = EMPTY; }
+opt_freeze:  FREEZE                            { $$ = make_str("freeze"); }
+               | /*EMPTY*/                             { $$ = EMPTY; }
                ;
 
-opt_name_list:  '(' name_list ')'              { $$ = cat_str(3, make_str("("), $2, make_str(")")); }
-               | /*EMPTY*/                             { $$ = EMPTY; }
+opt_name_list: '(' name_list ')'
+                       { $$ = cat_str(3, make_str("("), $2, make_str(")")); }
+               | /*EMPTY*/
+                       { $$ = EMPTY; }
                ;
 
 
@@ -2437,35 +3342,67 @@ opt_name_list:  '(' name_list ')'               { $$ = cat_str(3, make_str("("), $2, make_str
  *
  *****************************************************************************/
 
-ExplainStmt:  EXPLAIN opt_verbose OptimizableStmt
-                               {
-                                       $$ = cat_str(3, make_str("explain"), $2, $3);
-                               }
-               | EXPLAIN analyze_keyword opt_verbose OptimizableStmt
-                               {
-                                       $$ = cat_str(4, make_str("explain"), $2, $3, $4);
-                               }
+ExplainStmt:  EXPLAIN opt_analyze opt_verbose ExplainableStmt
+                       { $$ = cat_str(4, make_str("explain"), $2, $3, $4); }
                ;
 
+ExplainableStmt:
+               SelectStmt
+               | InsertStmt
+               | UpdateStmt
+               | DeleteStmt
+               | DeclareCursorStmt
+               | ExecuteStmt
+               ;
+opt_analyze:
+               analyze_keyword                 { $$ = $1; }
+               | /* EMPTY */                   { $$ = EMPTY; }
+               ;
 
-/*****************************************************************************
- *                                                                                                                                                      *
- *             Optimizable Stmts:                                                                                                       *
- *                                                                                                                                                      *
- *             one of the five queries processed by the planner                                         *
- *                                                                                                                                                      *
- *             [ultimately] produces query-trees as specified                                           *
- *             in the query-spec document in ~postgres/ref                                                      *
- *                                                                                                                                                      *
- *****************************************************************************/
+PrepareStmt: PREPARE prepared_name prep_type_clause AS PreparableStmt
+               {
+                       $$.name = $2;
+                       $$.type = $3;
+                       $$.stmt = cat_str(3, make_str("\""), $5, make_str("\""));
+               }
+               | PREPARE prepared_name FROM execstring /* ECPG addon */
+               {
+                       $$.name = $2;
+                       $$.type = NULL;
+                       $$.stmt = $4;
+               }
+               ;
 
-OptimizableStmt:  SelectStmt
-               | CursorStmt
-               | UpdateStmt
+PreparableStmt:
+               SelectStmt
                | InsertStmt
+               | UpdateStmt
                | DeleteStmt
                ;
 
+prep_type_clause: '(' type_list ')'    { $$ = cat_str(3, make_str("("), $2, make_str(")")); }
+               | /* EMPTY */           { $$ = EMPTY; }
+                       ;
+
+ExecuteStmt: EXECUTE prepared_name execute_param_clause execute_rest /* execute_rest is an ecpg addon */
+                       {
+                               /* $$ = cat_str(3, make_str("ECPGprepared_statement("), connection, $2, make_str("__LINE__)"));*/
+                               $$ = $2;
+                       }
+               | CREATE OptTemp TABLE create_as_target AS
+                       EXECUTE prepared_name execute_param_clause
+                       { $$ = cat_str(7, make_str("create"), $2, make_str("table"), $4,  make_str("as execute"), $7, $8); }
+               ;
+
+execute_param_clause: '(' expr_list ')'        { $$ = cat_str(3, make_str("("), $2, make_str(")")); }
+               | /* EMPTY */           { $$ = EMPTY; }
+               ;
+
+DeallocateStmt: DEALLOCATE prepared_name               { $$ = $2; }
+               | DEALLOCATE PREPARE prepared_name      { $$ = $3; }
+               | DEALLOCATE ALL                        { $$ = make_str("all"); }
+               | DEALLOCATE PREPARE ALL                { $$ = make_str("all"); }
+               ;
 
 /*****************************************************************************
  *
@@ -2474,57 +3411,33 @@ OptimizableStmt:  SelectStmt
  *
  *****************************************************************************/
 
-/* This rule used 'opt_column_list' between 'relation_name' and 'insert_rest'
- * originally. When the second rule of 'insert_rest' was changed to use
- * the new 'SelectStmt' rule (for INTERSECT and EXCEPT) it produced a shift/reduce
- * conflict. So I just changed the rules 'InsertStmt' and 'insert_rest' to accept
- * the same statements without any shift/reduce conflicts */
-InsertStmt:  INSERT INTO relation_name insert_rest
-                               {
-                                       $$ = cat_str(3, make_str("insert into"), $3, $4);
-                               }
+InsertStmt:  INSERT INTO qualified_name insert_rest returning_clause
+                       { $$ = cat_str(4, make_str("insert into"), $3, $4, $5); }
                ;
 
-insert_rest:  VALUES '(' target_list ')'
-                               {
-                                       $$ = cat_str(3, make_str("values("), $3, make_str(")"));
-                               }
+insert_rest:  
+               SelectStmt
+                       { $$ = $1; }
+               | '(' insert_column_list ')' SelectStmt
+                       { $$ = cat_str(4, make_str("("), $2, make_str(")"), $4); }
                | DEFAULT VALUES
-                               {
-                                       $$ = make_str("default values");
-                               }
-               | SelectStmt
-                               {
-                                       $$ = $1;
-                               }
-               | '(' columnList ')' VALUES '(' target_list ')'
-                               {
-                                       $$ = cat_str(5, make_str("("), $2, make_str(") values ("), $6, make_str(")"));
-                               }
-               | '(' columnList ')' SelectStmt
-                               {
-                                       $$ = cat_str(4, make_str("("), $2, make_str(")"), $4);
-                               }
+                       { $$ = make_str("default values"); }
                ;
 
-opt_column_list:  '(' columnList ')'                   { $$ = cat_str(3, make_str("("), $2, make_str(")")); }
-               | /*EMPTY*/                             { $$ = EMPTY; }
+insert_column_list: insert_column_list ',' insert_column_item
+                       { $$ = cat_str(3, $1, make_str(","), $3); }
+               | insert_column_item
+                       { $$ = $1; }
                ;
 
-columnList:
-                 columnList ',' columnElem
-                               { $$ = cat_str(3, $1, make_str(","), $3); }
-               | columnElem
-                               { $$ = $1; }
+insert_column_item:  ColId opt_indirection
+                       { $$ = cat2_str($1, $2); }
                ;
 
-columnElem:  ColId opt_indirection
-                               {
-                                       $$ = cat2_str($1, $2);
-                               }
+returning_clause:  RETURNING target_list       { $$ = cat2_str(make_str("returning"), $2); }
+               | /* EMPTY */                   { $$ = EMPTY; }
                ;
 
-
 /*****************************************************************************
  *
  *             QUERY:
@@ -2532,23 +3445,25 @@ columnElem:  ColId opt_indirection
  *
  *****************************************************************************/
 
-DeleteStmt:  DELETE FROM relation_expr where_clause
-                               {
-                                       $$ = cat_str(3, make_str("delete from"), $3, $4);
-                               }
+DeleteStmt:  DELETE_P FROM relation_expr_opt_alias using_clause where_or_current_clause returning_clause
+                       { $$ = cat_str(5, make_str("delete from"), $3, $4, $5, $6); }
                ;
 
-LockStmt:  LOCK_P opt_table relation_name_list opt_lock
-                               {
-                                       $$ = cat_str(4, make_str("lock"), $2, $3, $4);
-                               }
+using_clause: USING from_list  { $$ = cat2_str(make_str("using"), $2); }
+                       | /* EMPTY */           { $$ = EMPTY; }
+               ;
+
+LockStmt:  LOCK_P opt_table qualified_name_list opt_lock opt_nowait
+                       { $$ = cat_str(5, make_str("lock"), $2, $3, $4, $5); }
                ;
 
-opt_lock:  IN lock_type MODE            { $$ = cat_str(3, make_str("in"), $2, make_str("mode")); }
-                | /*EMPTY*/             { $$ = EMPTY;}
-                ;
+opt_lock:  IN_P lock_type MODE
+                       { $$ = cat_str(3, make_str("in"), $2, make_str("mode")); }
+               | /*EMPTY*/
+                       { $$ = EMPTY;}
+               ;
 
-lock_type:  ACCESS SHARE               { $$ = make_str("access share"); }
+lock_type:     ACCESS SHARE            { $$ = make_str("access share"); }
                | ROW SHARE                             { $$ = make_str("access share"); }
                | ROW EXCLUSIVE                 { $$ = make_str("row exclusive"); }
                | SHARE UPDATE EXCLUSIVE { $$ = make_str("share update exclusive"); }
@@ -2558,6 +3473,10 @@ lock_type:  ACCESS SHARE         { $$ = make_str("access share"); }
                | ACCESS EXCLUSIVE              { $$ = make_str("access exclusive"); }
                ;
 
+opt_nowait:    NOWAIT                   { $$ = make_str("nowait"); }
+               | /* EMPTY */           { $$ = EMPTY; }
+               ;
+
 /*****************************************************************************
  *
  *             QUERY:
@@ -2565,15 +3484,37 @@ lock_type:  ACCESS SHARE                { $$ = make_str("access share"); }
  *
  *****************************************************************************/
 
-UpdateStmt:  UPDATE relation_expr
-                         SET update_target_list
-                         from_clause
-                         where_clause
-                               {
-                                       $$ = cat_str(6, make_str("update"), $2, make_str("set"), $4, $5, $6);
-                               }
+UpdateStmt:  UPDATE relation_expr_opt_alias
+                               SET set_clause_list
+                               from_clause
+                               where_or_current_clause
+                               returning_clause
+                       {$$ = cat_str(7, make_str("update"), $2, make_str("set"), $4, $5, $6, $7); }
+               ;
+
+set_clause_list:
+               set_clause                              { $$ = $1; }
+               | set_clause_list ',' set_clause        { $$ = cat_str(3, $1, make_str(","), $3); }
+               ;
+
+set_clause:
+               single_set_clause               { $$ = $1; }
+               | multiple_set_clause           { $$ = $1; }
                ;
 
+single_set_clause:
+               set_target '=' ctext_expr       { $$ = cat_str(3, $1, make_str("="), $3); };
+
+multiple_set_clause:
+               '(' set_target_list ')' '=' ctext_row   { $$ = cat_str(4, make_str("("), $2, make_str(")="), $5); };
+
+set_target:
+               ColId opt_indirection           { $$ = cat2_str($1, $2); };
+
+set_target_list:
+               set_target                              { $$ = $1; }
+               | set_target_list ',' set_target        { $$ = cat_str(3, $1, make_str(","), $3); }
+               ;
 
 /*****************************************************************************
  *
@@ -2581,43 +3522,54 @@ UpdateStmt:  UPDATE relation_expr
  *                             CURSOR STATEMENTS
  *
  *****************************************************************************/
-CursorStmt:  DECLARE name opt_cursor CURSOR FOR SelectStmt
-                               {
-                                       struct cursor *ptr, *this;
-       
-                                       for (ptr = cur; ptr != NULL; ptr = ptr->next)
-                                       {
-                                               if (strcmp($2, ptr->name) == 0)
-                                               {
-                                                       /* re-definition is a bug */
-                                                       sprintf(errortext, "cursor %s already defined", $2);
-                                                       mmerror(PARSE_ERROR, ET_ERROR, errortext);
-                                               }
-                                       }
-                        
-                                       this = (struct cursor *) mm_alloc(sizeof(struct cursor));
-
-                                       /* initial definition */
-                                       this->next = cur;
-                                       this->name = $2;
-                                       this->connection = connection;
-                                       this->command =  cat_str(5, make_str("declare"), mm_strdup($2), $3, make_str("cursor for"), $6);
-                                       this->argsinsert = argsinsert;
-                                       this->argsresult = argsresult;
-                                       argsinsert = argsresult = NULL;
-                                                                                       
-                                       cur = this;
-                                       
-                                       $$ = cat_str(3, make_str("/*"), mm_strdup(this->command), make_str("*/"));
-                               }
+DeclareCursorStmt:  DECLARE name cursor_options CURSOR opt_hold FOR SelectStmt
+               {
+                       struct cursor *ptr, *this;
+
+                       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->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("*/"));
+               }
                ;
 
-opt_cursor:  BINARY                    { $$ = make_str("binary"); }
-               | INSENSITIVE           { $$ = make_str("insensitive"); }
-               | SCROLL                        { $$ = make_str("scroll"); }
-               | INSENSITIVE SCROLL    { $$ = make_str("insensitive scroll"); }
-               | /*EMPTY*/             { $$ = EMPTY; }
-               ;
+cursor_options:  /* EMPTY */           { $$ = EMPTY; }
+               | cursor_options BINARY         { $$ = cat2_str($1, make_str("binary")); }
+               | cursor_options INSENSITIVE    { $$ = cat2_str($1, make_str("insensitive")); }
+               | cursor_options SCROLL         { $$ = cat2_str($1, make_str("scroll")); }
+               | cursor_options NO SCROLL      { $$ = cat2_str($1, make_str("no scroll")); }
+               ;
+
+opt_hold:      /* EMPTY */
+               {
+                       if (compat == ECPG_COMPAT_INFORMIX_SE && autocommit == true)
+                               $$ = make_str("with hold");
+                       else
+                                $$ = EMPTY;
+               }
+               | WITH HOLD                     { $$ = make_str("with hold"); }
+               | WITHOUT HOLD                  { $$ = make_str("without hold"); }
+               ;
 
 /*****************************************************************************
  *
@@ -2626,76 +3578,53 @@ opt_cursor:  BINARY                     { $$ = make_str("binary"); }
  *
  *****************************************************************************/
 
-SelectStmt: select_no_parens                    %prec UMINUS
-               { $$ = $1; }
-       |       select_with_parens              %prec UMINUS
-               { $$ = $1; }
-       ;
+SelectStmt: select_no_parens           %prec UMINUS
+                       { $$ = $1; }
+               |       select_with_parens              %prec UMINUS
+                       { $$ = $1; }
+               ;
 
-select_with_parens: '(' select_no_parens ')' 
-                        {
-                                $$ = cat_str(3, make_str("("), $2, make_str(")"));
-                        }
-                | '(' select_with_parens ')'
-                        {
-                                $$ = cat_str(3, make_str("("), $2, make_str(")"));
-                        }
-                ;       
-
-select_no_parens:      simple_select
-                       {
-                               $$ = $1;
-                       }
-               | select_clause sort_clause opt_for_update_clause opt_select_limit
-                       {
-                               $$ = cat_str(4, $1, $2, $3, $4);
-                       }
-               | select_clause for_update_clause opt_select_limit
-                       {
-                               $$ = cat_str(3, $1, $2, $3);
-                       }
-               | select_clause select_limit  
-                       {
-                               $$ = cat2_str($1, $2);
-                       }
+select_with_parens: '(' select_no_parens ')'
+                       { $$ = cat_str(3, make_str("("), $2, make_str(")")); }
+               | '(' select_with_parens ')'
+                       { $$ = cat_str(3, make_str("("), $2, make_str(")")); }
+               ;
 
-select_clause: simple_select
-                        {
-                                $$ = $1;
+select_no_parens:         simple_select
+                       { $$ = $1; }
+               | select_clause sort_clause
+                       { $$ = cat2_str($1, $2); }
+               | select_clause opt_sort_clause for_locking_clause opt_select_limit
+                       { $$ = cat_str(4, $1, $2, $3, $4); }
+               | select_clause opt_sort_clause select_limit opt_for_locking_clause
+                       { $$ = cat_str(4, $1, $2, $3, $4); }
+               ;
 
-                        }
-                | select_with_parens 
-                        {
-                               $$ = $1; 
-                        }
+select_clause: simple_select           { $$ = $1; }
+               | select_with_parens            { $$ = $1; }
                ;
 
-simple_select:     SELECT opt_distinct target_list
-                         into_clause from_clause where_clause
-                         group_clause having_clause
-                               {
-                                       $$ = cat_str(8, make_str("select"), $2, $3, $4, $5, $6, $7, $8);
-                               }
-                               | select_clause UNION opt_all select_clause
-                               {
-                                       $$ = cat_str(4, $1, make_str("union"), $3, $4); 
-                               }
-                               | select_clause INTERSECT opt_all select_clause 
-                               { 
-                                       $$ = cat_str(4, $1, make_str("intersect"), $3, $4);
-                               }
-                               | select_clause EXCEPT opt_all select_clause 
-                               { 
-                                   $$ = cat_str(4, $1, make_str("except"), $3, $4);
-                               } 
+simple_select: SELECT opt_distinct target_list
+                                       into_clause from_clause where_clause
+                                       group_clause having_clause
+                       { $$ = cat_str(8, make_str("select"), $2, $3, $4, $5, $6, $7, $8); }
+               | values_clause
+                       { $$ = $1; }
+               | select_clause UNION opt_all select_clause
+                       { $$ = cat_str(4, $1, make_str("union"), $3, $4); }
+               | select_clause INTERSECT opt_all select_clause
+                       { $$ = cat_str(4, $1, make_str("intersect"), $3, $4); }
+               | select_clause EXCEPT opt_all select_clause
+                       { $$ = cat_str(4, $1, make_str("except"), $3, $4); }
                ;
 
-into_clause:  INTO OptTempTableName    {
-                                               FoundInto = 1;
-                                               $$= cat2_str(make_str("into"), $2);
-                                       }
-               | ecpg_into             { $$ = EMPTY; }
-               | /*EMPTY*/             { $$ = EMPTY; } 
+into_clause:  INTO OptTempTableName
+               {
+                       FoundInto = 1;
+                       $$= cat2_str(make_str("into"), $2);
+               }
+               | ecpg_into                     { $$ = EMPTY; }
+               | /*EMPTY*/                     { $$ = EMPTY; }
                ;
 
 /*
@@ -2705,109 +3634,85 @@ into_clause:  INTO OptTempTableName    {
  * The result is a cons cell (not a true list!) containing
  * a boolean and a table name.
  */
-OptTempTableName:  TEMPORARY opt_table relation_name
-                       {
-                               $$ = cat_str(3, make_str("temporary"), $2, $3);
-                       }
-                       | TEMP opt_table relation_name
-                       {
-                               $$ = cat_str(3, make_str("temp"), $2, $3);
-                       }
-                       | LOCAL TEMPORARY opt_table relation_name
-                       {
-                               $$ = cat_str(3, make_str("local temporary"), $3, $4);
-                       }
-                       | LOCAL TEMP opt_table relation_name
-                       {
-                               $$ = cat_str(3, make_str("local temp"), $3, $4);
-                       }
-                       | GLOBAL TEMPORARY opt_table relation_name
-                        {
-                               mmerror(PARSE_ERROR, ET_WARNING, "Currently unsupported CREATE TABLE / GLOBAL TEMPORARY will be passed to backend");
-                               $$ = cat_str(3, make_str("global temporary"), $3, $4);
-                        }
-                       | GLOBAL TEMP opt_table relation_name
-                        {
-                               mmerror(PARSE_ERROR, ET_WARNING, "Currently unsupported CREATE TABLE / GLOBAL TEMP will be passed to backend");
-                               $$ = cat_str(3, make_str("global temp"), $3, $4);
-                        }
-                       | TABLE relation_name
-                       {
-                               $$ = cat2_str(make_str("table"), $2);
-                       }
-                       | relation_name
-                       {
-                               $$ = $1;
-                       }
-                ;
+OptTempTableName:  TEMPORARY opt_table qualified_name
+                       { $$ = cat_str(3, make_str("temporary"), $2, $3); }
+               | TEMP opt_table qualified_name
+                       { $$ = cat_str(3, make_str("temp"), $2, $3); }
+               | LOCAL TEMPORARY opt_table qualified_name
+                       { $$ = cat_str(3, make_str("local temporary"), $3, $4); }
+               | LOCAL TEMP opt_table qualified_name
+                       { $$ = cat_str(3, make_str("local temp"), $3, $4); }
+               | GLOBAL TEMPORARY opt_table qualified_name
+                       { $$ = cat_str(3, make_str("global temporary"), $3, $4); }
+               | GLOBAL TEMP opt_table qualified_name
+                       { $$ = cat_str(3, make_str("global temp"), $3, $4); }
+               | TABLE qualified_name
+                       { $$ = cat2_str(make_str("table"), $2); }
+               | qualified_name
+                       { $$ = $1; }
+               ;
 
-opt_table:  TABLE                                      { $$ = make_str("table"); }
+opt_table:     TABLE                           { $$ = make_str("table"); }
                | /*EMPTY*/                             { $$ = EMPTY; }
                ;
 
-opt_all:  ALL                                          { $$ = make_str("all"); }
+opt_all:  ALL                                  { $$ = make_str("all"); }
                | /*EMPTY*/                             { $$ = EMPTY; }
                ;
 
-opt_distinct:  DISTINCT                                        { $$ = make_str("distinct"); }
-               | DISTINCT ON '(' expr_list ')'         { $$ = cat_str(3, make_str("distinct on ("), $4, make_str(")")); }
-               | ALL                                   { $$ = make_str("all"); }
-               | /*EMPTY*/                             { $$ = EMPTY; }
+opt_distinct:  DISTINCT
+                       { $$ = make_str("distinct"); }
+               | DISTINCT ON '(' expr_list ')'
+                       { $$ = cat_str(3, make_str("distinct on ("), $4, make_str(")")); }
+               | ALL
+                       { $$ = make_str("all"); }
+               | /*EMPTY*/
+                       { $$ = EMPTY; }
                ;
 
-sort_clause:  ORDER BY sortby_list     { 
-                                               $$ = cat2_str(make_str("order by"), $3);
-                                       }
+opt_sort_clause:       sort_clause     { $$ = $1; }
+               | /* EMPTY */           { $$ = EMPTY; }
                ;
 
-sortby_list:  sortby                                   { $$ = $1; }
-               | sortby_list ',' sortby                { $$ = cat_str(3, $1, make_str(","), $3); }
+sort_clause:  ORDER BY sortby_list
+                       { $$ = cat2_str(make_str("order by"), $3); }
                ;
 
-sortby: a_expr OptUseOp
-                               {
-                                        $$ = cat2_str($1, $2);
-                                }
+sortby_list:  sortby                                   { $$ = $1; }
+               | sortby_list ',' sortby                { $$ = cat_str(3, $1, make_str(","), $3); }
                ;
 
-OptUseOp:  USING all_Op                                { $$ = cat2_str(make_str("using"), $2); }
-               | ASC                           { $$ = make_str("asc"); }
-               | DESC                          { $$ = make_str("desc"); }
-               | /*EMPTY*/                     { $$ = EMPTY; }
+sortby: a_expr USING qual_all_Op opt_nulls_order
+                       { $$ = cat_str(4, $1, make_str("using"), $3, $4); }
+               | a_expr opt_asc_desc opt_nulls_order
+                       { $$ = cat_str(3, $1, $2, $3); }
                ;
 
-select_limit:      LIMIT select_limit_value OFFSET select_offset_value
-                       { $$ = cat_str(4, make_str("limit"), $2, make_str("offset"), $4); }
+select_limit:  LIMIT select_limit_value OFFSET select_offset_value
+                  { $$ = cat_str(4, make_str("limit"), $2, make_str("offset"), $4); }
                | OFFSET select_offset_value LIMIT select_limit_value
-                       { $$ = cat_str(4, make_str("offset"), $2, make_str("limit"), $4); }
-                | LIMIT select_limit_value
-                       { $$ = cat2_str(make_str("limit"), $2); }
-                | OFFSET select_offset_value
-                       { $$ = cat2_str(make_str("offset"), $2); }
+                  { $$ = cat_str(4, make_str("offset"), $2, make_str("limit"), $4); }
+               | LIMIT select_limit_value
+                  { $$ = cat2_str(make_str("limit"), $2); }
+               | OFFSET select_offset_value
+                  { $$ = cat2_str(make_str("offset"), $2); }
                | LIMIT select_limit_value ',' select_offset_value
-                      { mmerror(PARSE_ERROR, ET_WARNING, "No longer supported LIMIT #,# syntax passed to backend."); }
-                ;
+                  {
+                       mmerror(PARSE_ERROR, ET_WARNING, "no longer supported LIMIT #,# syntax passed to backend");
+                       $$ = cat_str(4, make_str("limit"), $2, make_str(","), $4);
+                  }
+               ;
 
-opt_select_limit:      select_limit    { $$ = $1; }  
-                       | /*EMPTY*/     { $$ = EMPTY; } 
-                       ;
+opt_select_limit:      select_limit    { $$ = $1; }
+               | /*EMPTY*/                                     { $$ = EMPTY; }
+               ;
 
-select_limit_value:    PosIntConst     { 
-                                               if (atoi($1) < 0)
-                                                       mmerror(PARSE_ERROR, ET_ERROR, "LIMIT must not be negative");
-                                               $$ = $1;
-                                       }
-                       | ALL   { $$ = make_str("all"); }
-                       | PARAM { $$ = make_name(); }
-               ;
+select_limit_value: a_expr     { $$ = $1; }
+               | ALL           { $$ = make_str("all"); }
+               ;
 
-select_offset_value:   PosIntConst     {
-                                               if (atoi($1) < 0)
-                                                       mmerror(PARSE_ERROR, ET_ERROR, "OFFSET must not be negative");
-                                               $$ = $1;
-                                       }
-                       | PARAM { $$ = make_name(); }
-               ;
+select_offset_value: a_expr { $$ = $1; }
+               ;
 
 /*
  *     jimmy bell-style recursive queries aren't supported in the
@@ -2816,97 +3721,100 @@ select_offset_value:   PosIntConst     {
  *     ...however, recursive addattr and rename supported.  make special
  *     cases for these.
  */
-relation_name_list:  name_list { $$ = $1; };
+group_clause:  GROUP_P BY expr_list
+                       { $$ = cat2_str(make_str("group by"), $3); }
+               | /*EMPTY*/
+                       { $$ = EMPTY; }
+               ;
 
-name_list:  name
-                               {       $$ = $1; }
-               | name_list ',' name
-                               {       $$ = cat_str(3, $1, make_str(","), $3); }
+having_clause: HAVING a_expr
+                       { $$ = cat2_str(make_str("having"), $2); }
+               | /*EMPTY*/
+                       { $$ = EMPTY; }
                ;
 
-group_clause:  GROUP BY expr_list                      { $$ = cat2_str(make_str("group by"), $3); }
-               | /*EMPTY*/                             { $$ = EMPTY; }
+for_locking_clause:
+               for_locking_items       { $$ = $1; }
+               | FOR READ ONLY         { $$ = make_str("for read only");}
                ;
 
-having_clause:  HAVING a_expr
-                               {
-                                       $$ = cat2_str(make_str("having"), $2);
-                               }
-               | /*EMPTY*/             { $$ = EMPTY; }
+opt_for_locking_clause:        
+               for_locking_clause      { $$ = $1; }
+               | /* EMPTY */           { $$ = EMPTY; }
                ;
 
-for_update_clause:  FOR UPDATE update_list
-               {
-                       $$ = make_str("for update"); 
-               }
-               | FOR READ ONLY
-               {
-                       $$ = make_str("for read only");
-               }
+for_locking_items:
+               for_locking_item                        { $$ = $1; }
+               | for_locking_items for_locking_item    { $$ = cat2_str($1, $2); }
                ;
 
-opt_for_update_clause: for_update_clause                { $$ = $1; }
-               | /* EMPTY */                           { $$ = EMPTY; }
-                ;
-
-update_list:  OF name_list
-              {
-                       $$ = cat2_str(make_str("of"), $2);
-             }
-              | /* EMPTY */
-              {
-                        $$ = EMPTY;
-              }
-              ;
+for_locking_item:
+               FOR UPDATE locked_rels_list opt_nowait
+                       { $$ = cat_str(3, make_str("for update"), $3, $4); }
+               | FOR SHARE locked_rels_list opt_nowait
+                       { $$ = cat_str(3, make_str("for share"), $3, $4); }
+               ;
+
+locked_rels_list:
+               OF name_list            { $$ = cat2_str(make_str("of"), $2); }
+               | /* EMPTY */           { $$ = EMPTY; }
+               ;
+
+values_clause:  VALUES ctext_row
+                       { $$ = cat2_str(make_str("values"), $2); }
+               | values_clause ',' ctext_row
+                       { $$ = cat_str(3, $1, make_str(","), $3); }
+               ;
 
 /*****************************************************************************
  *
  *     clauses common to all Optimizable Stmts:
- *             from_clause     - allow list of both JOIN expressions and table names
+ *             from_clause - allow list of both JOIN expressions and table names
  *             where_clause    - qualifications for joins or restrictions
  *
  *****************************************************************************/
 
-from_clause:    FROM from_list         { $$ = cat2_str(make_str("from"), $2); }
-               | /* EMPTY */           { $$ = EMPTY; }
+from_clause:   FROM from_list          { $$ = cat2_str(make_str("from"), $2); }
+               | /* EMPTY */                           { $$ = EMPTY; }
                ;
 
-from_list:  from_list ',' table_ref    { $$ = cat_str(3, $1, make_str(","), $3); }
-                | table_ref            { $$ = $1; }
-                ;
+from_list:     from_list ',' table_ref { $$ = cat_str(3, $1, make_str(","), $3); }
+               | table_ref                                     { $$ = $1; }
+               ;
 
 /*
- * table_ref is where an alias clause can be attached.  Note we cannot make
+ * table_ref is where an alias clause can be attached. Note we cannot make
  * alias_clause have an empty production because that causes parse conflicts
  * between table_ref := '(' joined_table ')' alias_clause
  * and joined_table := '(' joined_table ')'.  So, we must have the
  * redundant-looking productions here instead.
- */        
-table_ref:  relation_expr 
-                {
-                       $$ = $1;
-                }
-       | relation_expr alias_clause 
-               {
-                       $$= cat2_str($1, $2);
-               }
-       | select_with_parens
-               {
-                       mmerror(PARSE_ERROR, ET_ERROR, "sub-SELECT in FROM must have an alias");        
-               }
-       | select_with_parens alias_clause 
-               {
-                       $$=cat2_str($1, $2);
-               }
-       | joined_table  
-               {
-                        $$ = $1;
-                }  
-       | '(' joined_table ')' alias_clause   
-                {
-                        $$=cat_str(4, make_str("("), $2, make_str(")"), $4);
-                }             
-       ;
+ */
+table_ref:     relation_expr
+                       { $$ = $1; }
+               | relation_expr alias_clause
+                       { $$ = cat2_str($1, $2); }
+               | func_table
+                       { $$ = $1; }
+               | func_table alias_clause
+                       { $$ = cat2_str($1, $2); }
+               | func_table AS '(' TableFuncElementList ')'
+                       { $$ = cat_str(4, $1, make_str("as ("), $4, make_str(")")); }
+               | func_table AS ColId '(' TableFuncElementList ')'
+                       { $$ = cat_str(6, $1, make_str("as"), $3, make_str("("), $5, make_str(")"));}
+               | func_table ColId '(' TableFuncElementList ')'
+                       { $$ = cat_str(5, $1, $2, make_str("("), $4, make_str(")")); }
+               | select_with_parens
+                       {
+                               mmerror(PARSE_ERROR, ET_ERROR, "sub-SELECT in FROM must have an alias");
+                               $$ = $1;
+                       }
+               | select_with_parens alias_clause
+                       { $$ = cat2_str($1, $2); }
+               | joined_table
+                       { $$ = $1; }
+               | '(' joined_table ')' alias_clause
+                       { $$ = cat_str(4, make_str("("), $2, make_str(")"), $4); }
+               ;
 
 /*
  * It may seem silly to separate joined_table from table_ref, but there is
@@ -2916,44 +3824,28 @@ table_ref:  relation_expr
  * treat 'JOIN' and 'join_type JOIN' separately, rather than allowing
  * join_type to expand to empty; if we try it, the parser generator can't
  * figure out when to reduce an empty join_type right after table_ref.
- *                                                        
- * Note that a CROSS JOIN is the same as an unqualified       
+ *
+ * Note that a CROSS JOIN is the same as an unqualified
  * INNER JOIN, and an INNER JOIN/ON has the same shape
  * but a qualification expression to limit membership.
  * A NATURAL JOIN implicitly matches column names between
  * tables and the shape is determined by which columns are
  * in common. We'll collect columns during the later transformations.
- */       
+ */
 
-joined_table:  '(' joined_table ')'   
-               {
-                       $$ = cat_str(3, make_str("("), $2, make_str(")"));
-                } 
-               | table_ref CROSS JOIN table_ref 
-               {
-                       $$ = cat_str(3, $1, make_str("cross join"), $4);
-               }
-               | table_ref UNIONJOIN table_ref    
-                {
-                        $$ = cat_str(3, $1, make_str("unionjoin"), $3);
-                }                                 
-               | table_ref join_type JOIN table_ref join_qual 
-                {
-                        $$ = cat_str(5, $1, $2, make_str("join"), $4, $5);
-                }   
-               | table_ref JOIN table_ref join_qual   
-                {
-                        $$ = cat_str(4, $1, make_str("join"), $3, $4);
-                }   
-               | table_ref NATURAL join_type JOIN table_ref   
-               {
-                        $$ = cat_str(5, $1, make_str("natural"), $3, make_str("join"), $5);
-                }  
-               | table_ref NATURAL JOIN table_ref     
-               {
-                        $$ = cat_str(3, $1, make_str("natural join"), $4);
-                }  
-                ;
+joined_table:  '(' joined_table ')'
+                       { $$ = cat_str(3, make_str("("), $2, make_str(")")); }
+               | table_ref CROSS JOIN table_ref
+                       { $$ = cat_str(3, $1, make_str("cross join"), $4); }
+               | table_ref join_type JOIN table_ref join_qual
+                       { $$ = cat_str(5, $1, $2, make_str("join"), $4, $5); }
+               | table_ref JOIN table_ref join_qual
+                       { $$ = cat_str(4, $1, make_str("join"), $3, $4); }
+               | table_ref NATURAL join_type JOIN table_ref
+                       { $$ = cat_str(5, $1, make_str("natural"), $3, make_str("join"), $5); }
+               | table_ref NATURAL JOIN table_ref
+                       { $$ = cat_str(3, $1, make_str("natural join"), $4); }
+               ;
 
 alias_clause:  AS ColId '(' name_list ')'
                        { $$ = cat_str(5, make_str("as"), $2, make_str("("), $4, make_str(")")); }
@@ -2965,48 +3857,70 @@ alias_clause:  AS ColId '(' name_list ')'
                        { $$ = $1; }
                ;
 
-join_type:  FULL join_outer            { $$ = cat2_str(make_str("full"), $2); }
-               | LEFT join_outer       { $$ = cat2_str(make_str("left"), $2); }
-                | RIGHT join_outer      { $$ = cat2_str(make_str("right"), $2); }
-                | INNER_P               { $$ = make_str("inner"); }
+join_type:     FULL join_outer         { $$ = cat2_str(make_str("full"), $2); }
+               | LEFT join_outer               { $$ = cat2_str(make_str("left"), $2); }
+               | RIGHT join_outer              { $$ = cat2_str(make_str("right"), $2); }
+               | INNER_P                               { $$ = make_str("inner"); }
                ;
 
 /* OUTER is just noise... */
-join_outer:  OUTER_P                           { $$ = make_str("outer"); }
-               | /*EMPTY*/                     { $$ = EMPTY;  /* no qualifiers */ }
+join_outer:  OUTER_P                   { $$ = make_str("outer"); }
+               | /*EMPTY*/                             { $$ = EMPTY;  /* no qualifiers */ }
                ;
 
 /* JOIN qualification clauses
  * Possibilities are:
- *  USING ( column list ) allows only unqualified column names,
- *                        which must match between tables.
- *  ON expr allows more general qualifications.
+ *     USING ( column list ) allows only unqualified column names,
+ *                                               which must match between tables.
+ *     ON expr allows more general qualifications.
  */
 
-join_qual:  USING '(' name_list ')'                   { $$ = cat_str(3, make_str("using ("), $3, make_str(")")); }
-               | ON a_expr                            { $$ = cat2_str(make_str("on"), $2); }
-                ;
+join_qual:     USING '(' name_list ')'
+                       { $$ = cat_str(3, make_str("using ("), $3, make_str(")")); }
+               | ON a_expr
+                       { $$ = cat2_str(make_str("on"), $2); }
+               ;
 
-relation_expr: relation_name
-                               {
-                                       /* normal relations */
-                                       $$ = $1;
-                               }
-               | relation_name '*'
-                               {
-                                       /* inheritance query */
-                                       $$ = cat2_str($1, make_str("*"));
-                               }
-               | ONLY relation_name
-                               {
-                                       /* inheritance query */
-                                       $$ = cat2_str(make_str("ONLY "), $2);
-                               }
+relation_expr: qualified_name
+                       { /* normal relations */ $$ = $1; }
+               | qualified_name '*'
+                       { /* inheritance query */ $$ = cat2_str($1, make_str("*")); }
+               | ONLY qualified_name
+                       { /* inheritance query */ $$ = cat2_str(make_str("only "), $2); }
+               | ONLY '(' qualified_name ')'
+                       { /* inheritance query */ $$ = cat_str(3, make_str("only ("), $3, make_str(")")); }
+               ;
+
+relation_expr_opt_alias: relation_expr                                 %prec UMINUS
+               { $$ = $1; }
+               | relation_expr ColId
+               { $$ = cat2_str($1, $2); }
+               | relation_expr AS ColId
+               { $$ = cat_str(3, $1, make_str("as"), $3); }
+               ;
+
+func_table:  func_expr         { $$ = $1; }
+               ;
+
+where_clause:  WHERE a_expr            { $$ = cat2_str(make_str("where"), $2); }
+               | /*EMPTY*/                             { $$ = EMPTY;  /* no qualifiers */ }
+               ;
 
-where_clause:  WHERE a_expr                    { $$ = cat2_str(make_str("where"), $2); }
+where_or_current_clause:  WHERE a_expr                 { $$ = cat2_str(make_str("where"), $2); }
+               | WHERE CURRENT_P OF name               { $$ = cat2_str(make_str("where current of"), $4); }
+               | WHERE CURRENT_P OF PARAM              { $$ = make_str("where current of param"); }
                | /*EMPTY*/                             { $$ = EMPTY;  /* no qualifiers */ }
                ;
 
+TableFuncElementList: TableFuncElement
+                       { $$ = $1; }
+               | TableFuncElementList ',' TableFuncElement
+                       { $$ = cat_str(3, $1, make_str(","), $3); }
+               ;
+
+TableFuncElement:      ColId Typename  { $$ = cat2_str($1, $2); }
+               ;
+
 /*****************************************************************************
  *
  *     Type syntax
@@ -3018,228 +3932,211 @@ where_clause:  WHERE a_expr                   { $$ = cat2_str(make_str("where"), $2); }
  *****************************************************************************/
 
 Typename:  SimpleTypename opt_array_bounds
-                               {
-                                       $$ = cat2_str($1, $2.str);
-                               }
-               | SETOF SimpleTypename
-                               {
-                                       $$ = cat2_str(make_str("setof"), $2);
-                               }
+                       { $$ = cat2_str($1, $2.str); }
+               | SETOF SimpleTypename opt_array_bounds
+                       { $$ = cat_str(3, make_str("setof"), $2, $3); }
+               | SimpleTypename ARRAY '[' PosIntConst ']'
+                       { $$ = cat_str(4, $1, make_str("array ["), $4, make_str("]")); }
+               | SETOF SimpleTypename ARRAY '[' PosIntConst ']'
+                       { $$ = cat_str(5, make_str("setof"), $2, make_str("array ["), $5, make_str("]")); }
                ;
 
 
 opt_array_bounds:  '[' ']' opt_array_bounds
-                       {
-                            $$.index1 = 0;
-                            $$.index2 = $3.index1;
-                            $$.str = cat2_str(make_str("[]"), $3.str);
-                        }
+               {
+                       $$.index1 = make_str("0");
+                       $$.index2 = $3.index1;
+                       $$.str = cat2_str(make_str("[]"), $3.str);
+               }
                | '[' Iresult ']' opt_array_bounds
-                       {
-                           char *txt = mm_alloc(20L);
-
-                           sprintf (txt, "%d", $2);
-                            $$.index1 = $2;
-                            $$.index2 = $4.index1;
-                            $$.str = cat_str(4, make_str("["), txt, make_str("]"), $4.str);
-                        }
+               {
+                       $$.index1 = strdup($2);
+                       $$.index2 = $4.index1;
+                       $$.str = cat_str(4, make_str("["), $2, make_str("]"), $4.str);
+               }
                | /* EMPTY */
-                       {
-                            $$.index1 = -1;
-                            $$.index2 = -1;
-                            $$.str= EMPTY;
-                        }
-               ;
-
-Iresult:       PosIntConst             { $$ = atol($1); }
-       |       '(' Iresult ')'         { $$ = $2; }
-       |       Iresult '+' Iresult     { $$ = $1 + $3; }
-       |       Iresult '-' Iresult     { $$ = $1 - $3; }
-       |       Iresult '*' Iresult     { $$ = $1 * $3; }
-       |       Iresult '/' Iresult     { $$ = $1 / $3; }
-       |       Iresult '%' Iresult     { $$ = $1 % $3; }
-       ;
+               {
+                       $$.index1 = make_str("-1");
+                       $$.index2 = make_str("-1");
+                       $$.str= EMPTY;
+               }
+               ;
 
-SimpleTypename:  ConstTypename                                 { $$ = $1; }
-               | ConstInterval opt_interval                    { $$ = cat2_str($1, $2); }
-              | ConstInterval '(' PosIntConst ')' opt_interval { $$ = cat_str(5, $1, make_str("("), $3, make_str(")"), $5); }
-               ;  
+Iresult:       PosIntConst             { $$ = $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); }
+               | Sconst                { $$ = $1; }
+               | ColId                 { $$ = $1; }
+               ;
+
+SimpleTypename:  GenericType           { $$ = $1; }
+               | ConstDatetime         { $$ = $1; }
+               | Numeric               { $$ = $1; }
+               | Bit                   { $$ = $1; }
+               | Character             { $$ = $1; }
+               | ConstInterval opt_interval
+                       { $$ = cat2_str($1, $2); }
+               | ConstInterval '(' PosIntConst ')' opt_interval
+                       { $$ = cat_str(5, $1, make_str("("), $3, make_str(")"), $5); }
+               ;
 
-ConstTypename:  Generic        { $$ = $1; }
-               | ConstDatetime { $$ = $1; }
-               | Numeric       { $$ = $1; }
-               | Bit           { $$ = $1; }
-               | Character     { $$ = $1; }
+ConstTypename: Numeric                 { $$ = $1; }
+               | ConstBit              { $$ = $1; }
+               | ConstCharacter        { $$ = $1; }
+               | ConstDatetime         { $$ = $1; }
                ;
 
-Generic:  type_name                            { $$ = $1; }
+GenericType:   type_function_name opt_type_modifiers           { $$ = cat2_str($1, $2); }
+               | type_function_name attrs opt_type_modifiers   { $$ = cat_str(3, $1, $2, $3); }
                ;
 
+opt_type_modifiers: '(' expr_list ')'  { $$ = cat_str(3, make_str("("), $2, make_str(")")); }
+               | /* EMPTY */           { $$ = EMPTY; }
+               ;
+               
 /* SQL92 numeric data types
  * Check FLOAT() precision limits assuming IEEE floating types.
  * Provide real DECIMAL() and NUMERIC() implementations now - Jan 1998-12-30
  * - thomas 1997-09-18
  */
-Numeric:  FLOAT opt_float
-                               {
-                                       $$ = cat2_str(make_str("float"), $2);
-                               }
-               | DOUBLE PRECISION
-                               {
-                                       $$ = make_str("double precision");
-                               }
-               | DECIMAL opt_decimal
-                               {
-                                       $$ = cat2_str(make_str("decimal"), $2);
-                               }
-               | DEC opt_decimal
-                               {
-                                       $$ = cat2_str(make_str("dec"), $2);
-                               }
-               | NUMERIC opt_numeric
-                               {
-                                       $$ = cat2_str(make_str("numeric"), $2);
-                               }
-               ;
-
-opt_float:  '(' PosIntConst ')'
-                               {
-                                       $$ = cat_str(3, make_str("("), $2, make_str(")"));
-                               }
-               | /*EMPTY*/
-                               {
-                                       $$ = EMPTY;
-                               }
-               ;
-
-opt_numeric:  '(' PosIntConst ',' PosIntConst ')'
-                               {
-                                       $$ = cat_str(5, make_str("("), $2, make_str(","), $4, make_str(")"));
-                               }
-               | '(' PosIntConst ')'
-                               {
-                                       $$ = cat_str(3, make_str("("), $2, make_str(")"));
-                               }
-               | /*EMPTY*/
-                               {
-                                       $$ = EMPTY;
-                               }
-               ;
-
-opt_decimal:  '(' PosIntConst ',' PosIntConst ')'
-                               {
-                                       $$ = cat_str(5, make_str("("), $2, make_str(","), $4, make_str(")"));
-                               }
-               | '(' PosIntConst ')'
-                               {
-                                       $$ = cat_str(3, make_str("("), $2, make_str(")"));
-                               }
+Numeric:  INT_P
+                       { $$ = make_str("int"); }
+               | INTEGER
+                       { $$ = make_str("integer"); }
+               | SMALLINT
+                       { $$ = make_str("smallint"); }
+               | BIGINT
+                       { $$ = make_str("bigint"); }
+               | REAL
+                       { $$ = make_str("real"); }
+               | FLOAT_P opt_float
+                       { $$ = cat2_str(make_str("float"), $2); }
+               | DOUBLE_P PRECISION
+                       { $$ = make_str("double precision"); }
+               | DECIMAL_P opt_type_modifiers
+                       { $$ = cat2_str(make_str("decimal"), $2); }
+               | DEC opt_type_modifiers
+                       { $$ = cat2_str(make_str("dec"), $2); }
+               | NUMERIC opt_type_modifiers
+                       { $$ = cat2_str(make_str("numeric"), $2); }
+               | BOOLEAN_P
+                       { $$ = make_str("boolean"); }
+               ;
+
+opt_float:     '(' PosIntConst ')'
+                       { $$ = cat_str(3, make_str("("), $2, make_str(")")); }
                | /*EMPTY*/
-                               {
-                                       $$ = EMPTY;
-                               }
+                       { $$ = EMPTY; }
                ;
 
 /*
  * SQL92 bit-field data types
  * The following implements BIT() and BIT VARYING().
  */
-Bit:  bit '(' PosIntConst ')'
-                               {
-                                       $$ = cat_str(4, $1, make_str("("), $3, make_str(")"));
-                               }
-                | bit
-                               {
-                                       $$ = $1;
-                               }
+
+Bit:   BitWithLength           { $$ = $1; }
+               | BitWithoutLength      { $$ = $1; }
                ;
 
-bit:  BIT opt_varying
-                               {
-                                       $$ = cat2_str(make_str("bit"), $2);
-                               }
+ConstBit:      BitWithLength   { $$ = $1; }
+               | BitWithoutLength      { $$ = $1; }
+               ;
 
-/* 
+BitWithLength:  BIT opt_varying '(' expr_list ')'
+                       { $$ = cat_str(5, make_str("bit"), $2, make_str("("), $4, make_str(")")); }
+               ;
+
+BitWithoutLength: BIT opt_varying
+                       { $$ = cat2_str(make_str("bit"), $2); }
+               ;
+
+/*
  * SQL92 character data types
  * The following implements CHAR() and VARCHAR().
  *                                                             - ay 6/95
  */
-Character:  character '(' PosIntConst ')' opt_charset
-                               {
-                                       $$ = cat_str(5, $1, make_str("("), $3, make_str(")"), $5);
-                               }
-               | character opt_charset
-                               {
-                                       $$ = cat2_str($1, $2);
-                               }
+Character:     CharacterWithLength             { $$ = $1; }
+               | CharacterWithoutLength        { $$ = $1; }
                ;
 
-character:  CHARACTER opt_varying 
-                               {
-                                       $$ = cat2_str(make_str("character"), $2);
-                               }
-               | CHAR opt_varying                      { $$ = cat2_str(make_str("char"), $2); }
-               | VARCHAR                               { $$ = make_str("varchar"); }
-               | NATIONAL CHARACTER opt_varying        { $$ = cat2_str(make_str("national character"), $3); }
-               | NATIONAL CHAR opt_varying             { $$ = cat2_str(make_str("national char"), $3); }
-               | NCHAR opt_varying                     { $$ = cat2_str(make_str("nchar"), $2); }
+ConstCharacter:        CharacterWithLength     { $$ = $1; }
+               | CharacterWithoutLength        { $$ = $1; }
                ;
 
-opt_varying:  VARYING                  { $$ = make_str("varying"); }
-               | /*EMPTY*/                     { $$ = EMPTY; }
+CharacterWithLength: character '(' PosIntConst ')' opt_charset
+                       { $$ = cat_str(5, $1, make_str("("), $3, make_str(")"), $5); }
                ;
 
-opt_charset:  CHARACTER SET ColId      { $$ = cat2_str(make_str("character set"), $3); }
-               | /*EMPTY*/                             { $$ = EMPTY; }
+CharacterWithoutLength: character opt_charset
+                       { $$ = cat2_str($1, $2); }
                ;
 
-opt_collate:  COLLATE ColId            { $$ = cat2_str(make_str("collate"), $2); }
-               | /*EMPTY*/                                     { $$ = EMPTY; }
+character:     CHARACTER opt_varying
+                       { $$ = cat2_str(make_str("character"), $2); }
+               | CHAR_P opt_varying
+                       { $$ = cat2_str(make_str("char"), $2); }
+               | VARCHAR
+                       { $$ = make_str("varchar"); }
+               | NATIONAL CHARACTER opt_varying
+                       { $$ = cat2_str(make_str("national character"), $3); }
+               | NATIONAL CHAR_P opt_varying
+                       { $$ = cat2_str(make_str("national char"), $3); }
+               | NCHAR opt_varying
+                       { $$ = cat2_str(make_str("nchar"), $2); }
                ;
 
-ConstDatetime:  TIMESTAMP '(' PosIntConst ')' opt_timezone
-                               {
-                                       $$ = cat_str(4, make_str("timestamp("), $3, make_str(")"), $5);
-                               }
+opt_varying:  VARYING
+                       { $$ = make_str("varying"); }
+               | /*EMPTY*/
+                       { $$ = EMPTY; }
+               ;
+
+opt_charset:  CHARACTER SET ColId
+                       { $$ = cat2_str(make_str("character set"), $3); }
+               | /*EMPTY*/
+                       { $$ = EMPTY; }
+               ;
+
+ConstDatetime: TIMESTAMP '(' PosIntConst ')' opt_timezone
+                       { $$ = cat_str(4, make_str("timestamp("), $3, make_str(")"), $5); }
                | TIMESTAMP opt_timezone
-                               {
-                                       $$ = cat2_str(make_str("timestamp"), $2);
-                               }
+                       { $$ = cat2_str(make_str("timestamp"), $2); }
                | TIME '(' PosIntConst ')' opt_timezone
-                               {
-                                       $$ = cat_str(4, make_str("time("), $3, make_str(")"), $5);
-                               }
+                       { $$ = cat_str(4, make_str("time("), $3, make_str(")"), $5); }
                | TIME opt_timezone
-                               {
-                                       $$ = cat2_str(make_str("time"), $2);
-                               }
+                       { $$ = cat2_str(make_str("time"), $2); }
                ;
 
 ConstInterval: INTERVAL
-                               {
-                                       $$ = make_str("interval");
-                               }
+                       { $$ = make_str("interval"); }
                ;
 
-opt_timezone:  WITH TIME ZONE                          { $$ = make_str("with time zone"); }
-               | WITHOUT TIME ZONE                             { $$ = make_str("without time zone"); }
-               | /*EMPTY*/                                     { $$ = EMPTY; }
+opt_timezone:  WITH TIME ZONE
+                       { $$ = make_str("with time zone"); }
+               | WITHOUT TIME ZONE
+                       { $$ = make_str("without time zone"); }
+               | /*EMPTY*/
+                       { $$ = EMPTY; }
                ;
 
-opt_interval:  YEAR_P                          { $$ = make_str("year"); }
-               | MONTH_P                       { $$ = make_str("month"); }
-               | DAY_P                         { $$ = make_str("day"); }
-               | HOUR_P                        { $$ = make_str("hour"); }
-               | MINUTE_P                      { $$ = make_str("minute"); }
-               | SECOND_P                      { $$ = make_str("second"); }
+opt_interval:  YEAR_P                  { $$ = make_str("year"); }
+               | MONTH_P                               { $$ = make_str("month"); }
+               | DAY_P                                 { $$ = make_str("day"); }
+               | HOUR_P                                { $$ = make_str("hour"); }
+               | MINUTE_P                              { $$ = make_str("minute"); }
+               | SECOND_P                              { $$ = make_str("second"); }
                | YEAR_P TO MONTH_P             { $$ = make_str("year to month"); }
                | DAY_P TO HOUR_P               { $$ = make_str("day to hour"); }
                | DAY_P TO MINUTE_P             { $$ = make_str("day to minute"); }
                | DAY_P TO SECOND_P             { $$ = make_str("day to second"); }
-               | HOUR_P TO MINUTE_P            { $$ = make_str("hour to minute"); }
-               | MINUTE_P TO SECOND_P          { $$ = make_str("minute to second"); }
-               | HOUR_P TO SECOND_P            { $$ = make_str("hour to second"); }
-               | /*EMPTY*/                     { $$ = EMPTY; }
+               | HOUR_P TO MINUTE_P    { $$ = make_str("hour to minute"); }
+               | MINUTE_P TO SECOND_P  { $$ = make_str("minute to second"); }
+               | HOUR_P TO SECOND_P    { $$ = make_str("hour to second"); }
+               | /*EMPTY*/                             { $$ = EMPTY; }
                ;
 
 
@@ -3249,71 +4146,6 @@ opt_interval:  YEAR_P                            { $$ = make_str("year"); }
  *
  *****************************************************************************/
 
-/* Expressions using row descriptors
- * Define row_descriptor to allow yacc to break the reduce/reduce conflict
- *  with singleton expressions.
- */
-row_expr: '(' row_descriptor ')' IN select_with_parens
-                               {
-                                       $$ = cat_str(4, make_str("("), $2, make_str(") in "), $5);
-                               }
-               | '(' row_descriptor ')' NOT IN select_with_parens
-                               {
-                                       $$ = cat_str(4, make_str("("), $2, make_str(") not in "), $6);
-                               }
-               | '(' row_descriptor ')' all_Op sub_type select_with_parens
-                               {
-                                       $$ = cat_str(6, make_str("("), $2, make_str(")"), $4, $5, $6);
-                               }
-               | '(' row_descriptor ')' all_Op select_with_parens
-                               {
-                                       $$ = cat_str(5, make_str("("), $2, make_str(")"), $4, $5);
-                               }
-               | '(' row_descriptor ')' all_Op '(' row_descriptor ')'
-                               {
-                                       $$ = cat_str(7, make_str("("), $2, make_str(")"), $4, make_str("("), $6, make_str(")"));
-                               }
-               | '(' row_descriptor ')' OVERLAPS '(' row_descriptor ')'
-                               {
-                                       $$ = cat_str(5, make_str("("), $2, make_str(") overlaps ("), $6, make_str(")"));
-                               }
-               ;
-
-row_descriptor:  row_list ',' a_expr
-                               {
-                                       $$ = cat_str(3, $1, make_str(","), $3);
-                               }
-               ;
-
-sub_type:  ANY                  { $$ = make_str("ANY"); }
-         | SOME                 { $$ = make_str("SOME"); }
-         | ALL                  { $$ = make_str("ALL"); }
-              ;
-
-
-row_list:  row_list ',' a_expr
-                               {
-                                       $$ = cat_str(3, $1, make_str(","), $3);
-                               }
-               | a_expr
-                               {
-                                       $$ = $1;
-                               }
-               ;
-
-all_Op:  Op | MathOp;
-
-MathOp:        '+'                             { $$ = make_str("+"); }
-               | '-'                   { $$ = make_str("-"); }
-               | '*'                   { $$ = make_str("*"); }
-               | '%'                   { $$ = make_str("%"); }
-                | '^'                   { $$ = make_str("^"); }
-               | '/'                   { $$ = make_str("/"); }
-               | '<'                   { $$ = make_str("<"); }
-               | '>'                   { $$ = make_str(">"); }
-               | '='                   { $$ = make_str("="); }
-               ;
-
 /* General expressions
  * This is the heart of the expression syntax.
  *
@@ -3331,129 +4163,139 @@ MathOp:       '+'                             { $$ = make_str("+"); }
  */
 
 a_expr:  c_expr
-                               {       $$ = $1; }
+                       { $$ = $1; }
                | a_expr TYPECAST Typename
-                               {       $$ = cat_str(3, $1, make_str("::"), $3); }
-               | a_expr AT TIME ZONE c_expr 
-                               {       $$ = cat_str(3, $1, make_str("at time zone"), $5); }
+                       { $$ = cat_str(3, $1, make_str("::"), $3); }
+               | a_expr AT TIME ZONE a_expr
+                       { $$ = cat_str(3, $1, make_str("at time zone"), $5); }
                /*
-                 * These operators must be called out explicitly in order to make use
-                 * of yacc/bison's automatic operator-precedence handling.  All other
-                 * operator names are handled by the generic productions using "Op",
-                 * below; and all those operators will have the same precedence.
-                 *
-                 * If you add more explicitly-known operators, be sure to add them
-                 * also to b_expr and to the MathOp list above.
-                 */
+                * These operators must be called out explicitly in order to make use
+                * of yacc/bison's automatic operator-precedence handling.  All other
+                * operator names are handled by the generic productions using "Op",
+                * below; and all those operators will have the same precedence.
+                *
+                * If you add more explicitly-known operators, be sure to add them
+                * also to b_expr and to the MathOp list above.
+                */
                | '+' a_expr %prec UMINUS
-                               {       $$ = cat2_str(make_str("+"), $2); }
+                       { $$ = cat2_str(make_str("+"), $2); }
                | '-' a_expr %prec UMINUS
-                               {       $$ = cat2_str(make_str("-"), $2); }
-               | '%' a_expr
-                               {       $$ = cat2_str(make_str("%"), $2); }
-               | '^' a_expr
-                               {       $$ = cat2_str(make_str("^"), $2); }
-               | a_expr '%'
-                               {       $$ = cat2_str($1, make_str("%")); }
-               | a_expr '^'
-                               {       $$ = cat2_str($1, make_str("^")); }
+                       { $$ = cat2_str(make_str("-"), $2); }
                | a_expr '+' a_expr
-                               {       $$ = cat_str(3, $1, make_str("+"), $3); }
+                       { $$ = cat_str(3, $1, make_str("+"), $3); }
                | a_expr '-' a_expr
-                               {       $$ = cat_str(3, $1, make_str("-"), $3); }
+                       { $$ = cat_str(3, $1, make_str("-"), $3); }
                | a_expr '*' a_expr
-                               {       $$ = cat_str(3, $1, make_str("*"), $3); }
+                       { $$ = cat_str(3, $1, make_str("*"), $3); }
                | a_expr '/' a_expr
-                               {       $$ = cat_str(3, $1, make_str("/"), $3); }
+                       { $$ = cat_str(3, $1, make_str("/"), $3); }
                | a_expr '%' a_expr
-                               {       $$ = cat_str(3, $1, make_str("%"), $3); }
+                       { $$ = cat_str(3, $1, make_str("%"), $3); }
                | a_expr '^' a_expr
-                               {       $$ = cat_str(3, $1, make_str("^"), $3); }
+                       { $$ = cat_str(3, $1, make_str("^"), $3); }
                | a_expr '<' a_expr
-                               {       $$ = cat_str(3, $1, make_str("<"), $3); }
+                       { $$ = cat_str(3, $1, make_str("<"), $3); }
                | a_expr '>' a_expr
-                               {       $$ = cat_str(3, $1, make_str(">"), $3); }
+                       { $$ = cat_str(3, $1, make_str(">"), $3); }
                | a_expr '=' a_expr
-                               {       $$ = cat_str(3, $1, make_str("="), $3); }
-               | a_expr Op a_expr
-                               {       $$ = cat_str(3, $1, $2, $3); }
-               | Op a_expr
-                               {       $$ = cat2_str($1, $2); }
-               | a_expr Op             %prec POSTFIXOP
-                               {       $$ = cat2_str($1, $2); }
+                       { $$ = cat_str(3, $1, make_str("="), $3); }
+               | a_expr qual_Op a_expr         %prec Op
+                       { $$ = cat_str(3, $1, $2, $3); }
+               | qual_Op a_expr                %prec Op
+                       { $$ = cat2_str($1, $2); }
+               | a_expr qual_Op                %prec POSTFIXOP
+                       { $$ = cat2_str($1, $2); }
                | a_expr AND a_expr
-                               {       $$ = cat_str(3, $1, make_str("and"), $3); }
+                       { $$ = cat_str(3, $1, make_str("and"), $3); }
                | a_expr OR a_expr
-                               {       $$ = cat_str(3, $1, make_str("or"), $3); }
+                       { $$ = cat_str(3, $1, make_str("or"), $3); }
                | NOT a_expr
-                               {       $$ = cat2_str(make_str("not"), $2); }
+                       { $$ = cat2_str(make_str("not"), $2); }
                | a_expr LIKE a_expr
-                               {       $$ = cat_str(3, $1, make_str("like"), $3); }
+                       { $$ = cat_str(3, $1, make_str("like"), $3); }
                | a_expr LIKE a_expr ESCAPE a_expr
-                               {       $$ = cat_str(5, $1, make_str("like"), $3, make_str("escape"), $5); }
+                       { $$ = cat_str(5, $1, make_str("like"), $3, make_str("escape"), $5); }
                | a_expr NOT LIKE a_expr
-                               {       $$ = cat_str(3, $1, make_str("not like"), $4); }
+                       { $$ = cat_str(3, $1, make_str("not like"), $4); }
                | a_expr NOT LIKE a_expr ESCAPE a_expr
-                               {       $$ = cat_str(5, $1, make_str("not like"), $4, make_str("escape"), $6); }
+                       { $$ = cat_str(5, $1, make_str("not like"), $4, make_str("escape"), $6); }
                | a_expr ILIKE a_expr
-                               {       $$ = cat_str(3, $1, make_str("ilike"), $3); }
+                       { $$ = cat_str(3, $1, make_str("ilike"), $3); }
                | a_expr ILIKE a_expr ESCAPE a_expr
-                               {       $$ = cat_str(5, $1, make_str("ilike"), $3, make_str("escape"), $5); }
+                       { $$ = cat_str(5, $1, make_str("ilike"), $3, make_str("escape"), $5); }
                | a_expr NOT ILIKE a_expr
-                               {       $$ = cat_str(3, $1, make_str("not ilike"), $4); }
+                       { $$ = cat_str(3, $1, make_str("not ilike"), $4); }
                | a_expr NOT ILIKE a_expr ESCAPE a_expr
-                               {       $$ = cat_str(5, $1, make_str("not ilike"), $4, make_str("escape"), $6); }
+                       { $$ = cat_str(5, $1, make_str("not ilike"), $4, make_str("escape"), $6); }
+               | a_expr SIMILAR TO a_expr      %prec SIMILAR
+                       { $$ = cat_str(3, $1, make_str("similar to"), $4); }
+               | a_expr SIMILAR TO a_expr ESCAPE a_expr
+                       { $$ = cat_str(5, $1, make_str("similar to"), $4, make_str("escape"), $6); }
+               | a_expr NOT SIMILAR TO a_expr  %prec SIMILAR
+                       { $$ = cat_str(3, $1, make_str("not similar to"), $5); }
+               | a_expr NOT SIMILAR TO a_expr ESCAPE a_expr
+                       { $$ = cat_str(5, $1, make_str("not similar to"), $5, make_str("escape"), $7); }
                | a_expr ISNULL
-                               {       $$ = cat2_str($1, make_str("isnull")); }
+                       { $$ = cat2_str($1, make_str("isnull")); }
                | a_expr IS NULL_P
-                               {       $$ = cat2_str($1, make_str("is null")); }
+                       { $$ = cat2_str($1, make_str("is null")); }
                | a_expr NOTNULL
-                               {       $$ = cat2_str($1, make_str("notnull")); }
+                       { $$ = cat2_str($1, make_str("notnull")); }
                | a_expr IS NOT NULL_P
-                               {       $$ = cat2_str($1, make_str("is not null")); }
+                       { $$ = cat2_str($1, make_str("is not null")); }
+               | row OVERLAPS row
+                       { $$ = cat_str(3, $1, make_str("overlaps"), $3); }
                /* IS TRUE, IS FALSE, etc used to be function calls
-                *  but let's make them expressions to allow the optimizer
-                *  a chance to eliminate them if a_expr is a constant string.
+                *      but let's make them expressions to allow the optimizer
+                *      a chance to eliminate them if a_expr is a constant string.
                 * - thomas 1997-12-22
                 *
-                *  Created BooleanTest Node type, and changed handling
-                *  for NULL inputs
+                *      Created BooleanTest Node type, and changed handling
+                *      for NULL inputs
                 * - jec 2001-06-18
                 */
                | a_expr IS TRUE_P
-                               {       $$ = cat2_str($1, make_str("is true")); }
+                       { $$ = cat2_str($1, make_str("is true")); }
                | a_expr IS NOT TRUE_P
-                               {       $$ = cat2_str($1, make_str("is not true")); }
+                       { $$ = cat2_str($1, make_str("is not true")); }
                | a_expr IS FALSE_P
-                               {       $$ = cat2_str($1, make_str("is false")); }
+                       { $$ = cat2_str($1, make_str("is false")); }
                | a_expr IS NOT FALSE_P
-                               {       $$ = cat2_str($1, make_str("is not false")); }
+                       { $$ = cat2_str($1, make_str("is not false")); }
                | a_expr IS UNKNOWN
-                               {       $$ = cat2_str($1, make_str("is unknown")); }
+                       { $$ = cat2_str($1, make_str("is unknown")); }
                | a_expr IS NOT UNKNOWN
-                               {       $$ = cat2_str($1, make_str("is not unknown")); }
-               | a_expr BETWEEN b_expr AND b_expr      %prec BETWEEN
-                               {
-                                       $$ = cat_str(5, $1, make_str("between"), $3, make_str("and"), $5); 
-                               }
-               | a_expr NOT BETWEEN b_expr AND b_expr  %prec BETWEEN
-                               {
-                                       $$ = cat_str(5, $1, make_str("not between"), $4, make_str("and"), $6); 
-                               }
-               | a_expr IN in_expr 
-                               {
-                                       $$ = cat_str(3, $1, make_str(" in"), $3); 
-                               }
-               | a_expr NOT IN in_expr
-                               {
-                                       $$ = cat_str(3, $1, make_str(" not in "), $4); 
-                               }
-               | a_expr all_Op sub_type select_with_parens     %prec Op
-                               {
-                                       $$ = cat_str(4, $1, $2, $3, $4); 
-                               }
-               | row_expr
-                               {       $$ = $1; }
+                       { $$ = cat2_str($1, make_str("is not unknown")); }
+               | a_expr IS DISTINCT FROM a_expr %prec IS
+                       { $$ = cat_str(3, $1, make_str("is distinct from"), $5); }
+               | a_expr IS NOT DISTINCT FROM a_expr %prec IS
+                       { $$ = cat_str(3, $1, make_str("is not distinct from"), $6); }
+               | a_expr IS OF '(' type_list ')' %prec IS
+                       { $$ = cat_str(4, $1, make_str("is of ("), $5, make_str(")")); }
+               | a_expr IS NOT OF '(' type_list ')' %prec IS
+                       { $$ = cat_str(4, $1, make_str("is not of ("), $6, make_str(")")); }
+               | a_expr BETWEEN opt_asymmetric b_expr AND b_expr       %prec BETWEEN
+                       { $$ = cat_str(6, $1, make_str("between"), $3, $4, make_str("and"), $6); }
+               | a_expr NOT BETWEEN opt_asymmetric b_expr AND b_expr   %prec BETWEEN
+                       { $$ = cat_str(6, $1, make_str("not between"), $4, $5, make_str("and"), $7); }
+               | a_expr BETWEEN SYMMETRIC b_expr AND b_expr    %prec BETWEEN
+                       { $$ = cat_str(5, $1, make_str("between symmetric"), $4, make_str("and"), $6); }
+               | a_expr NOT BETWEEN SYMMETRIC b_expr AND b_expr        %prec BETWEEN
+                       { $$ = cat_str(5, $1, make_str("not between symmetric"), $5, make_str("and"), $7); }
+               | a_expr IN_P in_expr
+                       { $$ = cat_str(3, $1, make_str("in"), $3); }
+               | a_expr NOT IN_P in_expr
+                       { $$ = cat_str(3, $1, make_str("not in"), $4); }
+               | a_expr subquery_Op sub_type select_with_parens %prec Op
+                       { $$ = cat_str(4, $1, $2, $3, $4); }
+               | a_expr subquery_Op sub_type '(' a_expr ')' %prec Op
+                       { $$ = cat_str(6, $1, $2, $3, make_str("("), $5, make_str(")")); }
+               | UNIQUE select_with_parens 
+                       { $$ = cat2_str(make_str("unique"), $2); }
+               | a_expr IS DOCUMENT_P
+                       { $$ = cat2_str($1, make_str("is document")); }
+               | a_expr IS NOT DOCUMENT_P
+                       { $$ = cat2_str($1, make_str("is not document")); }
                ;
 
 /* Restricted expressions
@@ -3465,473 +4307,731 @@ a_expr:  c_expr
  * just eliminate all the boolean-keyword-operator productions from b_expr.
  */
 b_expr:  c_expr
-                               {
-                                       $$ = $1;
-                               }
+                       { $$ = $1; }
                | b_expr TYPECAST Typename
-                               {
-                                       $$ = cat_str(3, $1, make_str("::"), $3);
-                               }
+                       { $$ = cat_str(3, $1, make_str("::"), $3); }
                | '-' b_expr %prec UMINUS
-                               {       $$ = cat2_str(make_str("-"), $2); }
-               | '%' b_expr
-                               {       $$ = cat2_str(make_str("%"), $2); }
-               | '^' b_expr
-                               {       $$ = cat2_str(make_str("^"), $2); }
-               | b_expr '%'
-                               {       $$ = cat2_str($1, make_str("%")); }
-               | b_expr '^'
-                               {       $$ = cat2_str($1, make_str("^")); }
+                       { $$ = cat2_str(make_str("-"), $2); }
                | b_expr '+' b_expr
-                               {       $$ = cat_str(3, $1, make_str("+"), $3); }
+                       { $$ = cat_str(3, $1, make_str("+"), $3); }
                | b_expr '-' b_expr
-                               {       $$ = cat_str(3, $1, make_str("-"), $3); }
+                       { $$ = cat_str(3, $1, make_str("-"), $3); }
                | b_expr '*' b_expr
-                               {       $$ = cat_str(3, $1, make_str("*"), $3); }
+                       { $$ = cat_str(3, $1, make_str("*"), $3); }
                | b_expr '/' b_expr
-                               {       $$ = cat_str(3, $1, make_str("/"), $3); }
+                       { $$ = cat_str(3, $1, make_str("/"), $3); }
                | b_expr '%' b_expr
-                               {       $$ = cat_str(3, $1, make_str("%"), $3); }
+                       { $$ = cat_str(3, $1, make_str("%"), $3); }
                | b_expr '^' b_expr
-                               {       $$ = cat_str(3, $1, make_str("^"), $3); }
+                       { $$ = cat_str(3, $1, make_str("^"), $3); }
                | b_expr '<' b_expr
-                               {       $$ = cat_str(3, $1, make_str("<"), $3); }
+                       { $$ = cat_str(3, $1, make_str("<"), $3); }
                | b_expr '>' b_expr
-                               {       $$ = cat_str(3, $1, make_str(">"), $3); }
+                       { $$ = cat_str(3, $1, make_str(">"), $3); }
                | b_expr '=' b_expr
-                               {       $$ = cat_str(3, $1, make_str("="), $3); }
+                       { $$ = cat_str(3, $1, make_str("="), $3); }
                | b_expr Op b_expr
-                               {       $$ = cat_str(3, $1, $2, $3); }
-               | Op b_expr
-                               {       $$ = cat2_str($1, $2); }
-               | b_expr Op             %prec POSTFIXOP
-                               {       $$ = cat2_str($1, $2); }
+                       { $$ = cat_str(3, $1, $2, $3); }
+               | qual_Op b_expr                %prec Op
+                       { $$ = cat2_str($1, $2); }
+               | b_expr qual_Op                %prec POSTFIXOP
+                       { $$ = cat2_str($1, $2); }
+               | b_expr IS DISTINCT FROM b_expr %prec IS
+                       { $$ = cat_str(3, $1, make_str("is distinct from"), $5); }
+               | b_expr IS NOT DISTINCT FROM b_expr %prec IS
+                       { $$ = cat_str(3, $1, make_str("is not distinct from"), $6); }
+               | b_expr IS OF '(' b_expr ')' %prec IS
+                       { $$ = cat_str(4, $1, make_str("is of ("), $5, make_str(")")); }
+               | b_expr IS NOT OF '(' b_expr ')' %prec IS
+                       { $$ = cat_str(4, $1, make_str("is not of ("), $6, make_str(")")); }
+               | b_expr IS DOCUMENT_P
+                       { $$ = cat2_str($1, make_str("is document")); }
+               | b_expr IS NOT DOCUMENT_P
+                       { $$ = cat2_str($1, make_str("is not document")); }
                ;
 
 /*
  * Productions that can be used in both a_expr and b_expr.
  *
  * Note: productions that refer recursively to a_expr or b_expr mostly
- * cannot appear here.  However, it's OK to refer to a_exprs that occur
+ * cannot appear here. However, it's OK to refer to a_exprs that occur
  * inside parentheses, such as function arguments; that cannot introduce
  * ambiguity to the b_expr syntax.
  */
-c_expr:  attr
-                               {       $$ = $1;  }
-               | ColId opt_indirection
-                               {       $$ = cat2_str($1, $2);  }
+c_expr: columnref
+                       { $$ = $1;      }
                | AexprConst
-                               {       $$ = $1;  }
-               | '(' a_expr ')'
-                               {       $$ = cat_str(3, make_str("("), $2, make_str(")")); }
-               | CAST '(' a_expr AS Typename ')'
-                               {       $$ = cat_str(5, make_str("cast("), $3, make_str("as"), $5, make_str(")")); }
+                       { $$ = $1;      }
+               | PARAM opt_indirection
+                       { $$ = cat2_str(make_str("param"), $2); }
+               | '(' a_expr ')' opt_indirection
+                       { $$ = cat_str(4, make_str("("), $2, make_str(")"), $4); }
                | case_expr
-                               {       $$ = $1; }
-               | func_name '(' ')'
-                               {       $$ = cat2_str($1, make_str("()"));  }
+                       { $$ = $1; }
+               | func_expr
+                       { $$ = $1; }
+               | select_with_parens    %prec UMINUS
+                       { $$ = $1; }
+               | EXISTS select_with_parens
+                       { $$ = cat2_str(make_str("exists"), $2); }
+               | ARRAY select_with_parens
+                       { $$ = cat2_str(make_str("array"), $2); }
+               | ARRAY array_expr
+                       { $$ = cat2_str(make_str("array"), $2); }
+               | row
+                       { $$ = $1; }
+               ;
+
+/*
+ * func_expr is split out from c_expr just so that we have a classification
+ * for "everything that is a function call or looks like one".  This isn't
+ * very important, but it saves us having to document which variants are
+ * legal in the backwards-compatible functional-index syntax for CREATE INDEX.
+ * (Note that many of the special SQL functions wouldn't actually make any
+ * sense as functional index entries, but we ignore that consideration here.)
+ */
+func_expr:      func_name '(' ')'
+                       { $$ = cat2_str($1, make_str("()"));    }
                | func_name '(' expr_list ')'
-                               {       $$ = cat_str(4, $1, make_str("("), $3, make_str(")"));  }
+                       { $$ = cat_str(4, $1, make_str("("), $3, make_str(")"));        }
+               | func_name '(' VARIADIC a_expr ')'
+                       { $$ = cat_str(4, $1, make_str("( variadic "), $4, make_str(")"));      }
+               | func_name '(' expr_list ',' VARIADIC a_expr ')'
+                       { $$ = cat_str(6, $1, make_str("("), $3, make_str(", variadic "), $6, make_str(")"));   }
                | func_name '(' ALL expr_list ')'
-                               {       $$ = cat_str(4, $1, make_str("( all"), $4, make_str(")"));  }
+                       { $$ = cat_str(4, $1, make_str("( all"), $4, make_str(")"));    }
                | func_name '(' DISTINCT expr_list ')'
-                               {       $$ = cat_str(4, $1, make_str("( distinct"), $4, make_str(")"));  }
+                       { $$ = cat_str(4, $1, make_str("( distinct"), $4, make_str(")"));  }
                | func_name '(' '*' ')'
-                               {       $$ = cat2_str($1, make_str("(*)")); }
+                       { $$ = cat2_str($1, make_str("(*)")); }
                | CURRENT_DATE
-                               {       $$ = make_str("current_date"); }
-               | CURRENT_TIME opt_empty_parentheses
-                               {       $$ = cat2_str(make_str("current_time"), $2); }
+                       { $$ = make_str("current_date"); }
+               | CURRENT_TIME
+                       { $$ = make_str("current_time"); }
                | CURRENT_TIME '(' PosIntConst ')'
-                               {
-                                       $$ = make_str("current_time");
-                               }
-               | CURRENT_TIMESTAMP opt_empty_parentheses
-                               {       $$ = cat2_str(make_str("current_timestamp"), $2); }
+                       { $$ = cat_str(3, make_str("current_time ("), $3, make_str(")")); }
+               | CURRENT_TIMESTAMP
+                       { $$ = make_str("current_timestamp"); }
                | CURRENT_TIMESTAMP '(' PosIntConst ')'
-                               {
-                                       $$ = make_str("current_timestamp");
-                               }
-               | CURRENT_USER opt_empty_parentheses
-                               {       $$ = cat2_str(make_str("current_user"), $2); }
-               | SESSION_USER opt_empty_parentheses
-                               {       $$ = cat2_str(make_str("session_user"), $2); }
-               | USER opt_empty_parentheses
-                               {       $$ = cat2_str(make_str("user"), $2); }
+                       { $$ = cat_str(3, make_str("current_timestamp ("), $3, make_str(")")); }
+               | LOCALTIME
+                       { $$ = make_str("localtime"); }
+               | LOCALTIME '(' PosIntConst ')'
+                       { $$ = cat_str(3, make_str("localtime ("), $3, make_str(")")); }
+               | LOCALTIMESTAMP
+                       { $$ = make_str("local_timestamp"); }
+               | LOCALTIMESTAMP '(' PosIntConst ')'
+                       { $$ = cat_str(3, make_str("locale_timestamp ("), $3, make_str(")")); }
+               | CURRENT_ROLE
+                       { $$ = make_str("current_role"); }
+               | CURRENT_USER
+                       { $$ = make_str("current_user"); }
+               | SESSION_USER
+                       { $$ = make_str("session_user"); }
+               | USER
+                       { $$ = make_str("user"); }
+               | CAST '(' a_expr AS Typename ')'
+                       { $$ = cat_str(5, make_str("cast("), $3, make_str("as"), $5, make_str(")")); }
                | EXTRACT '(' extract_list ')'
-                               {       $$ = cat_str(3, make_str("extract("), $3, make_str(")")); }
+                       { $$ = cat_str(3, make_str("extract("), $3, make_str(")")); }
+               | OVERLAY '(' overlay_list ')'
+                       { $$ = cat_str(3, make_str("overlay("), $3, make_str(")")); }
                | POSITION '(' position_list ')'
-                               {       $$ = cat_str(3, make_str("position("), $3, make_str(")")); }
+                       { $$ = cat_str(3, make_str("position("), $3, make_str(")")); }
                | SUBSTRING '(' substr_list ')'
-                               {       $$ = cat_str(3, make_str("substring("), $3, make_str(")")); }
+                       { $$ = cat_str(3, make_str("substring("), $3, make_str(")")); }
+               | TREAT '(' a_expr AS Typename ')'
+                       { $$ = cat_str(5, make_str("treat("), $3, make_str("as"), $5, make_str(")")); }
                /* various trim expressions are defined in SQL92 - thomas 1997-07-19 */
                | TRIM '(' BOTH trim_list ')'
-                               {       $$ = cat_str(3, make_str("trim(both"), $4, make_str(")")); }
+                       { $$ = cat_str(3, make_str("trim(both"), $4, make_str(")")); }
                | TRIM '(' LEADING trim_list ')'
-                               {       $$ = cat_str(3, make_str("trim(leading"), $4, make_str(")")); }
+                       { $$ = cat_str(3, make_str("trim(leading"), $4, make_str(")")); }
                | TRIM '(' TRAILING trim_list ')'
-                               {       $$ = cat_str(3, make_str("trim(trailing"), $4, make_str(")")); }
+                       { $$ = cat_str(3, make_str("trim(trailing"), $4, make_str(")")); }
                | TRIM '(' trim_list ')'
-                               {       $$ = cat_str(3, make_str("trim("), $3, make_str(")")); }
-               | select_with_parens    %prec UMINUS 
-                               {       $$ = $1; }
-               | EXISTS select_with_parens
-                               {       $$ = cat2_str(make_str("exists"), $2); }
+                       { $$ = cat_str(3, make_str("trim("), $3, make_str(")")); }
+               | NULLIF '(' a_expr ',' a_expr ')'
+                       { $$ = cat_str(5, make_str("nullif("), $3, make_str(","), $5, make_str(")")); }
+               | COALESCE '(' expr_list ')'
+                       { $$ = cat_str(3, make_str("coalesce("), $3, make_str(")")); }
+               | GREATEST '(' expr_list ')'
+                       { $$ = cat_str(3, make_str("greatest("), $3, make_str(")")); }
+               | LEAST '(' expr_list ')'
+                       { $$ = cat_str(3, make_str("least("), $3, make_str(")")); }
+               | XMLCONCAT '(' expr_list ')'
+                       { $$ = cat_str(3, make_str("xmlconcat("), $3, make_str(")")); }
+               | XMLELEMENT '(' NAME_P ColLabel ')'
+                       { $$ = cat_str(3, make_str("xmlelement( name"), $4, make_str(")")); }
+               | XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ')'
+                       { $$ = cat_str(5, make_str("xmlelement( name"), $4, make_str(","), $6, make_str(")")); }
+               | XMLELEMENT '(' NAME_P ColLabel ',' expr_list ')'
+                       { $$ = cat_str(5, make_str("xmlelement( name"), $4, make_str(","), $6, make_str(")")); }
+               | XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ',' expr_list ')'
+                       { $$ = cat_str(7, make_str("xmlelement( name"), $4, make_str(","), $6, make_str(","), $8, make_str(")")); }
+               | XMLFOREST '(' xml_attribute_list ')'
+                       { $$ = cat_str(3, make_str("xmlforest("), $3, make_str(")")); }
+               | XMLPARSE '(' document_or_content a_expr xml_whitespace_option ')'
+                       { $$ = cat_str(5, make_str("xmlparse("), $3, $4, $5, make_str(")")); }
+               | XMLPI '(' NAME_P ColLabel ')'
+                       { $$ = cat_str(3, make_str("xmlpi( name"), $4, make_str(")")); }
+               | XMLPI '(' NAME_P ColLabel ',' a_expr ')'
+                       { $$ = cat_str(5, make_str("xmlpi( name"), $4, make_str(","), $6, make_str(")")); }
+               | XMLROOT '(' a_expr ',' xml_root_version opt_xml_root_standalone  ')'
+                       { $$ = cat_str(6, make_str("xmlroot("), $3, make_str(","), $5, $6, make_str(")")); }
                ;
-/* 
- * This used to use ecpg_expr, but since there is no shift/reduce conflict
- * anymore, we can remove ecpg_expr. - MM
+
+/*
+ * SQL/XML support
  */
-opt_indirection:  '[' a_expr ']' opt_indirection
-                               {
-                                       $$ = cat_str(4, make_str("["), $2, make_str("]"), $4);
-                               }
-               | '[' a_expr ':' a_expr ']' opt_indirection
-                               {
-                                       $$ = cat_str(6, make_str("["), $2, make_str(":"), $4, make_str("]"), $6);
-                               }
-               | /* EMPTY */
-                               {       $$ = EMPTY; }
+
+xml_root_version: VERSION_P a_expr
+                       { $$ = cat2_str(make_str("version"), $2); }
+               | VERSION_P NO VALUE_P
+                       { $$ = make_str("version no value"); }
                ;
 
-expr_list:  a_expr
+opt_xml_root_standalone: ',' STANDALONE_P YES_P
+                               { $$ = make_str(", standalone yes"); }
+                       | ',' STANDALONE_P NO
+                               { $$ = make_str(", standalone no"); }
+                       | ',' STANDALONE_P NO VALUE_P
+                               { $$ = make_str(", standalone no value"); }
+                       | /*EMPTY*/
+                               { $$ = EMPTY; }
+                       ;
+
+xml_attributes:        XMLATTRIBUTES '(' xml_attribute_list ')'
+                               { $$ = cat_str(3, make_str("xmlattributes("), $3, make_str(")")); }
+                       ;
+
+xml_attribute_list:    xml_attribute_el
                                { $$ = $1; }
-               | expr_list ',' a_expr
+                       | xml_attribute_list ',' xml_attribute_el
                                { $$ = cat_str(3, $1, make_str(","), $3); }
-               | expr_list USING a_expr
-                               { $$ = cat_str(3, $1, make_str("using"), $3); }
+                       ;
+
+xml_attribute_el: a_expr AS ColLabel
+                       { $$ = cat_str(3, $1, make_str("as"), $3); }
+               | a_expr
+                       { $$ = $1; }
+               ;
+
+document_or_content: DOCUMENT_P                { $$ = make_str("document"); }
+                       | CONTENT_P     { $$ = make_str("content"); }
+                       ;
+
+xml_whitespace_option: PRESERVE WHITESPACE_P   { $$ = make_str("preserve whitespace"); }
+                       | STRIP_P WHITESPACE_P  { $$ = make_str("strip whitespace"); }
+                       | /*EMPTY*/             { $$ = EMPTY; }
+                       ;
+
+row: ROW '(' expr_list ')'
+                       { $$ = cat_str(3, make_str("row ("), $3, make_str(")")); }
+               | ROW '(' ')'
+                       { $$ = make_str("row()"); }
+               | '(' expr_list ',' a_expr ')'
+                       { $$ = cat_str(5, make_str("("), $2, make_str(","), $4, make_str(")")); }
+               ;
+
+sub_type:  ANY         { $$ = make_str("ANY"); }
+               | SOME          { $$ = make_str("SOME"); }
+               | ALL           { $$ = make_str("ALL"); }
+               ;
+
+all_Op:  Op                            { $$ = $1; }
+               | MathOp                        { $$ = $1; }
+               ;
+
+MathOp: '+'                            { $$ = make_str("+"); }
+               | '-'                   { $$ = make_str("-"); }
+               | '*'                   { $$ = make_str("*"); }
+               | '%'                   { $$ = make_str("%"); }
+               | '^'                   { $$ = make_str("^"); }
+               | '/'                   { $$ = make_str("/"); }
+               | '<'                   { $$ = make_str("<"); }
+               | '>'                   { $$ = make_str(">"); }
+               | '='                   { $$ = make_str("="); }
+               ;
+
+qual_Op:  Op                           { $$ = $1; }
+               | OPERATOR '(' any_operator ')' { $$ = cat_str(3, make_str("operator ("), $3, make_str(")")); }
+               ;
+
+qual_all_Op:  all_Op                           { $$ = $1; }
+               | OPERATOR '(' any_operator ')' { $$ = cat_str(3, make_str("operator ("), $3, make_str(")")); }
+               ;
+
+subquery_Op:  all_Op                           { $$ = $1; }
+               | OPERATOR '(' any_operator ')' { $$ = cat_str(3, make_str("operator ("), $3, make_str(")")); }
+               | LIKE                          { $$ = make_str("like"); }
+               | NOT LIKE                      { $$ = make_str("not like"); }
+               | ILIKE                         { $$ = make_str("ilike"); }
+               | NOT ILIKE                     { $$ = make_str("not ilike"); }
+               ;
+
+expr_list:     a_expr
+                       { $$ = $1; }
+               | expr_list ',' a_expr
+                       { $$ = cat_str(3, $1, make_str(","), $3); }
+               ;
+
+type_list:      Typename
+                       { $$ = $1; }
+               | type_list ',' Typename
+                       { $$ = cat_str(3, $1, ',', $3); }
+               ;
+
+array_expr: '[' expr_list ']'                  { $$ = cat_str(3, make_str("["), $2, make_str("]")); }
+               | '[' array_expr_list ']'       { $$ = cat_str(3, make_str("["), $2, make_str("]")); }
+               | '[' ']'                       { $$ = make_str("[]"); }
+               ;
+
+array_expr_list: array_expr                            { $$ = $1; }
+               | array_expr_list ',' array_expr        { $$ = cat_str(3, $1, make_str(","), $3); }
                ;
 
 extract_list:  extract_arg FROM a_expr
-                               {
-                                       $$ = cat_str(3, $1, make_str("from"), $3);
-                               }
+                       { $$ = cat_str(3, $1, make_str("from"), $3); }
                | /* EMPTY */
-                               {       $$ = EMPTY; }
+                       { $$ = EMPTY; }
                ;
 
-/* Allow delimited string SCONST in extract_arg as an SQL extension.
- * - thomas 2001-04-12
- */
+extract_arg:  ident                            { $$ = $1; }
+               | YEAR_P                                { $$ = make_str("year"); }
+               | MONTH_P                               { $$ = make_str("month"); }
+               | DAY_P                                 { $$ = make_str("day"); }
+               | HOUR_P                                { $$ = make_str("hour"); }
+               | MINUTE_P                              { $$ = make_str("minute"); }
+               | SECOND_P                              { $$ = make_str("second"); }
+               | StringConst                   { $$ = $1; }
+               ;
+
+overlay_list:
+               a_expr overlay_placing substr_from substr_for
+                       { $$ = cat_str(4, $1, 42, $3, $4); }
+               | a_expr overlay_placing substr_from
+                       { $$ = cat_str(3, $1, $2, $3); }
+               ;
 
-extract_arg:  IDENT                                            { $$ = $1; }
-               | YEAR_P                                                { $$ = make_str("year"); }
-               | MONTH_P                                               { $$ = make_str("month"); }
-               | DAY_P                                                 { $$ = make_str("day"); }
-               | HOUR_P                                                { $$ = make_str("hour"); }
-               | MINUTE_P                                              { $$ = make_str("minute"); }
-               | SECOND_P                                              { $$ = make_str("second"); }
-               | StringConst                                   { $$ = $1; }
+overlay_placing:
+               PLACING a_expr          { $$ = cat2_str(make_str("placing"), $2); }
                ;
 
 /* position_list uses b_expr not a_expr to avoid conflict with general IN */
-position_list:  b_expr IN b_expr
-                               {       $$ = cat_str(3, $1, make_str("in"), $3); }
+position_list: b_expr IN_P b_expr
+                       { $$ = cat_str(3, $1, make_str("in"), $3); }
                | /* EMPTY */
-                               {       $$ = EMPTY; }
+                       { $$ = EMPTY; }
                ;
 
 substr_list:  a_expr substr_from substr_for
-                               {
-                                       $$ = cat_str(3, $1, $2, $3);
-                               }
-               | a_expr substr_for substr_from 
-                               {
-                                        $$ = cat_str(3, $1, $2, $3);
-                                }  
-               | a_expr substr_from  
-                               {
-                                        $$ = cat2_str($1, $2);
-                                }  
+                       { $$ = cat_str(3, $1, $2, $3); }
+               | a_expr substr_for substr_from
+                       { $$ = cat_str(3, $1, $2, $3); }
+               | a_expr substr_from
+                       { $$ = cat2_str($1, $2); }
                | a_expr substr_for
-                               {
-                                        $$ = cat2_str($1, $2);
-                                }  
+                       { $$ = cat2_str($1, $2); }
                | expr_list
-                               {
-                                       $$ = $1;
-                               }
+                       { $$ = $1; }
                | /* EMPTY */
-                               {       $$ = EMPTY; }
+                       { $$ = EMPTY; }
                ;
 
 substr_from:  FROM a_expr
-                               {       $$ = cat2_str(make_str("from"), $2); }
+                       { $$ = cat2_str(make_str("from"), $2); }
                ;
 
 substr_for:  FOR a_expr
-                               {       $$ = cat2_str(make_str("for"), $2); }
+                       { $$ = cat2_str(make_str("for"), $2); }
                ;
 
-trim_list:  a_expr FROM expr_list
-                               { $$ = cat_str(3, $1, make_str("from"), $3); }
+trim_list:     a_expr FROM expr_list
+                       { $$ = cat_str(3, $1, make_str("from"), $3); }
                | FROM expr_list
-                               { $$ = cat2_str(make_str("from"), $2); }
+                       { $$ = cat2_str(make_str("from"), $2); }
                | expr_list
-                               { $$ = $1; }
+                       { $$ = $1; }
                ;
 
 in_expr:  select_with_parens
-                               {
-                                       $$ = $1;
-                               }
-               | '(' in_expr_nodes ')'
-                               {       $$ = cat_str(3, make_str("("), $2, make_str(")")); }
-               ;
-
-in_expr_nodes:  a_expr
-                               {       $$ = $1; }
-               | in_expr_nodes ',' a_expr
-                               {       $$ = cat_str(3, $1, make_str(","), $3);}
+                       { $$ = $1; }
+               | '(' expr_list ')'
+                       { $$ = cat_str(3, make_str("("), $2, make_str(")")); }
                ;
 
 /* Case clause
  * Define SQL92-style case clause.
- * Allow all four forms described in the standard:
- * - Full specification
- *  CASE WHEN a = b THEN c ... ELSE d END
- * - Implicit argument
- *  CASE a WHEN b THEN c ... ELSE d END
- * - Conditional NULL
- *  NULLIF(x,y)
- *  same as CASE WHEN x = y THEN NULL ELSE x END
- * - Conditional substitution from list, use first non-null argument
- *  COALESCE(a,b,...)
- * same as CASE WHEN a IS NOT NULL THEN a WHEN b IS NOT NULL THEN b ... END
- * - thomas 1998-11-09
  */
-case_expr:  CASE case_arg when_clause_list case_default END_TRANS
-                                { $$ = cat_str(5, make_str("case"), $2, $3, $4, make_str("end")); }
-                | NULLIF '(' a_expr ',' a_expr ')'
-                                {
-                                       $$ = cat_str(5, make_str("nullif("), $3, make_str(","), $5, make_str(")"));
-                                }
-                | COALESCE '(' expr_list ')'
-                                {
-                                       $$ = cat_str(3, make_str("coalesce("), $3, make_str(")"));
-                               }
+case_expr:     CASE case_arg when_clause_list case_default END_P
+                       { $$ = cat_str(5, make_str("case"), $2, $3, $4, make_str("end")); }
                ;
 
 when_clause_list:  when_clause_list when_clause
-                               { $$ = cat2_str($1, $2); }
-               | when_clause
-                               { $$ = $1; }
-               ;
+                       { $$ = cat2_str($1, $2); }
+               | when_clause
+                       { $$ = $1; }
+               ;
 
 when_clause:  WHEN a_expr THEN a_expr
-                               {
-                                       $$ = cat_str(4, make_str("when"), $2, make_str("then"), $4);
-                               }
-               ;
+                       { $$ = cat_str(4, make_str("when"), $2, make_str("then"), $4); }
+               ;
 
-case_default:  ELSE a_expr             { $$ = cat2_str(make_str("else"), $2); }
-               | /*EMPTY*/             { $$ = EMPTY; }
-               ;
+case_default:  ELSE a_expr
+                       { $$ = cat2_str(make_str("else"), $2); }
+               | /*EMPTY*/
+                       { $$ = EMPTY; }
+               ;
 
-case_arg:  a_expr              {
-                                       $$ = $1;
-                               }
-               | /*EMPTY*/
-                               {       $$ = EMPTY; }
-               ;
+case_arg:  a_expr                      { $$ = $1; }
+               | /*EMPTY*/             { $$ = EMPTY; }
+               ;
 
-attr:  relation_name '.' attrs opt_indirection
-                               {
-                                       $$ = cat_str(4, $1, make_str("."), $3, $4);
-                               }
-               | ParamNo '.' attrs opt_indirection
-                               {
-                                       $$ = cat_str(4, $1, make_str("."), $3, $4);
-                               }
+columnref: relation_name               { $$ = $1; }
+               | relation_name indirection     { $$ = cat2_str($1, $2); }
                ;
 
-attrs:   attr_name
-                               { $$ = $1; }
-               | attrs '.' attr_name
-                               { $$ = cat_str(3, $1, make_str("."), $3); }
-               | attrs '.' '*'
-                               { $$ = make2_str($1, make_str(".*")); }
+indirection_el:
+               '.' attr_name                   { $$ = cat2_str(make_str("."), $2); }
+               | '.' '*'                       { $$ = make_str(".*"); }
+               | '[' a_expr ']'                { $$ = cat_str(3, make_str("["), $2, make_str("]")); }
+               | '[' a_expr ':' a_expr ']'     { $$ = cat_str(5, make_str("["), $2, make_str(":"), $4, make_str("]")); }
+               ;
+
+indirection:   indirection_el          { $$ = $1; }
+               | indirection indirection_el    { $$ = cat2_str($1, $2); }
                ;
 
-opt_empty_parentheses: '(' ')'         { $$ = make_str("()"); }
-                | /*EMPTY*/    { $$ = EMPTY; }
+opt_indirection:
+               /*EMPTY*/                               { $$ = EMPTY; }
+               | opt_indirection indirection_el        { $$ = cat2_str($1, $2);}
+               ;
+
+opt_asymmetric: ASYMMETRIC     { $$ = make_str("asymmetric"); }
+               | /*EMPTY*/             { $$ = EMPTY; }
+               ;
+
+ctext_expr:
+               a_expr          { $$ = $1; }
+               | DEFAULT       { $$ = make_str("default"); }
+               ;
+
+ctext_expr_list:
+                ctext_expr                             { $$ = $1; }
+                |  ctext_expr_list ',' ctext_expr      { $$ = cat_str(3, $1, make_str(","), $3); }
+                ;
+
+ctext_row: '(' ctext_expr_list ')'     { $$ = cat_str(3, make_str("("), $2, make_str(")"));};
 
 /*****************************************************************************
  *
- *     target lists
+ *     target lists for SELECT
  *
  *****************************************************************************/
 
-/* Target lists as found in SELECT ... and INSERT VALUES ( ... ) */
 target_list:  target_list ',' target_el
-                               {       $$ = cat_str(3, $1, make_str(","), $3);  }
+                       { $$ = cat_str(3, $1, make_str(","), $3);  }
                | target_el
-                               {       $$ = $1;  }
+                       { $$ = $1;      }
                ;
 
-/* AS is not optional because shift/red conflict with unary ops */
-target_el:  a_expr AS ColLabel
-                               {
-                                       $$ = cat_str(3, $1, make_str("as"), $3);
-                               }
+target_el:     a_expr AS ColLabel
+                       { $$ = cat_str(3, $1, make_str("as"), $3); }
+               /*
+                * We support omitting AS only for column labels that aren't
+                * any known keyword.  There is an ambiguity against postfix
+                * operators: is "a ! b" an infix expression, or a postfix
+                * expression and a column label?  We prefer to resolve this
+                * as an infix expression, which we accomplish by assigning
+                * IDENT a precedence higher than POSTFIXOP.
+                */
+               | a_expr IDENT
+                       { $$ = cat_str(3, $1, make_str("as"), $2); }
                | a_expr
+                       { $$ = $1; }
+               | '*'
+                       { $$ = make_str("*"); }
+               ;
+
+/* INFORMIX workaround, no longer needed
+update_target_list:  '(' inf_col_list ')' '=' '(' inf_val_list ')'
+               {
+                       struct inf_compat_col *ptrc;
+                       struct inf_compat_val *ptrv;
+                       char *cols = make_str( "(" );
+                       char *vals = make_str( "(" );
+
+                       for (ptrc = informix_col, ptrv = informix_val; ptrc != NULL && ptrv != NULL; ptrc = ptrc->next, ptrv = ptrv->next)
+                       {
+                               if ( ptrc->next != NULL )
                                {
-                                       $$ = $1;
-                               }
-               | relation_name '.' '*'
-                               {
-                                       $$ = make2_str($1, make_str(".*"));
+                                       cols = cat_str(4, cols, ptrc->name, ptrc->indirection, make_str(",") );
                                }
-               | '*'
+                               else
                                {
-                                       $$ = make_str("*");
+                                       cols = cat_str(4, cols, ptrc->name, ptrc->indirection, make_str(")") );
                                }
+                               if (ptrv->next != NULL )
+                                       vals = cat_str(3, vals, ptrv->val, make_str("," ) );
+                               else
+                                       vals = cat_str( 3, vals, ptrv->val, make_str(")") );
+                       }
+                       $$ = cat_str( 3, cols, make_str("="), vals );
+               } 
                ;
 
-/* Target list as found in UPDATE table SET ... */
-update_target_list:  update_target_list ',' update_target_el
-                               {       $$ = cat_str(3, $1, make_str(","),$3);  }
-               | update_target_el
-                               {       $$ = $1;  }
-               | '*'           { $$ = make_str("*"); }
+inf_col_list: ColId opt_indirection
+               {
+                       struct inf_compat_col *ptr = mm_alloc(sizeof(struct inf_compat_col));
+
+                       ptr->name = $1;
+                       ptr->indirection = $2;
+                       ptr->next = NULL;
+                       informix_col = ptr;
+               }
+               | ColId opt_indirection ',' inf_col_list
+               {
+                       struct inf_compat_col *ptr = mm_alloc(sizeof(struct inf_compat_col));
+
+                       ptr->name = $1;
+                       ptr->indirection = $2;
+                       ptr->next = informix_col;
+                       informix_col = ptr;
+               }
                ;
 
-update_target_el:  ColId opt_indirection '=' a_expr
-                               {
-                                       $$ = cat_str(4, $1, $2, make_str("="), $4);
-                               }
+inf_val_list: a_expr
+               {
+                       struct inf_compat_val *ptr = mm_alloc(sizeof(struct inf_compat_val));
+
+                       ptr->val = $1;
+                       ptr->next = NULL;
+                       informix_val = ptr;
+               }
+               | a_expr ',' inf_val_list
+               {
+                       struct inf_compat_val *ptr = mm_alloc(sizeof(struct inf_compat_val));
+
+                       ptr->val = $1;
+                       ptr->next = informix_val;
+                       informix_val = ptr;
+               }
                ;
+*/
 
 /*****************************************************************************
  *
- *     Names and constants
+ *        Names and constants
  *
  *****************************************************************************/
 
-relation_name: SpecialRuleRelation
-                               {
-                                       $$ = $1;
-                               }
-               | ColId
-                               {
-                                       $$ = $1;
-                               }
+relation_name:  SpecialRuleRelation    { $$ = $1; }
+               | ColId                 { $$ = $1; }
                ;
 
+qualified_name_list:  qualified_name
+                               { $$ = $1; }
+               | qualified_name_list ',' qualified_name
+                               { $$ = cat_str(3, $1, make_str(","), $3); }
+               ;
+
+qualified_name: relation_name
+               { $$ = $1; }
+               | relation_name indirection
+               { $$ = cat2_str($1, $2); }
+               ;
+
+name_list:  name
+                       { $$ = $1; }
+               | name_list ',' name
+                       { $$ = cat_str(3, $1, make_str(","), $3); }
+               ;
+
+
 name:                          ColId                   { $$ = $1; };
-database_name:                 ColId                   { $$ = $1; };
-access_method:                 ColId                   { $$ = $1; };
-attr_name:                             ColId                   { $$ = $1; };
-class:                                 ColId                   { $$ = $1; };
-index_name:                            ColId                   { $$ = $1; };
+database_name:         ColId                   { $$ = $1; };
+access_method:         ColId                   { $$ = $1; };
+attr_name:                     ColLabel                { $$ = $1; };
+index_name:                    ColId                   { $$ = $1; };
+
+file_name:                     StringConst             { $$ = $1; };
+
+func_name: type_function_name
+                       { $$ = $1; }
+               | relation_name indirection
+                       { $$ = cat2_str($1, $2); }
+               ;
 
-file_name:                             StringConst                     { $$ = $1; };
 
 /* Constants
  * Include TRUE/FALSE for SQL3 support. - thomas 1997-10-24
  */
 AexprConst:  PosAllConst
-                               {
-                                       $$ = $1;
-                               }
+                       { $$ = $1; }
                | ConstTypename StringConst
-                               {
-                                       $$ = cat2_str($1, $2);
-                               }
-               | ConstInterval StringConst opt_interval 
-                               {
-                                       $$ = cat_str(3, $1, $2, $3);
-                               }
+                       { $$ = cat2_str($1, $2); }
+               | ConstInterval StringConst opt_interval
+                       { $$ = cat_str(3, $1, $2, $3); }
                | ConstInterval  '(' PosIntConst ')' StringConst opt_interval
-                               {
-                                       $$ = cat_str(6, $1, make_str("("), $3, make_str(")"), $5, $6);
-                               }
-               | ParamNo
-                               {       $$ = $1;  }
+                       { $$ = cat_str(6, $1, make_str("("), $3, make_str(")"), $5, $6); }
                | TRUE_P
-                               {
-                                       $$ = make_str("true");
-                               }
+                       { $$ = make_str("true"); }
                | FALSE_P
-                               {
-                                       $$ = make_str("false");
-                               }
+                       { $$ = make_str("false"); }
                | NULL_P
-                               {
-                                       $$ = make_str("null");
-                               }
+                       { $$ = make_str("null"); }
                | civarind
-                               { $$ = make_str("?"); }
+                       { $$ = $1; }
                ;
 
-ParamNo:  PARAM opt_indirection
-                               {
-                                       $$ = cat2_str(make_name(), $2);
-                               }
-               ;
+Iconst:  ICONST                                { $$ = make_name();};
+Fconst:  FCONST                                { $$ = make_name();};
+Bconst:  BCONST                                { $$ = make_name();};
+Xconst:  XCONST                                { $$ = make_name();};
+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
+               {
+                       /* escaped quote starting with E */
+                       $$ = (char *)mm_alloc(strlen($1) + 4);
+                       $$[0]='E';
+                       $$[1]='\'';
+                       strcpy($$+2, $1);
+                       $$[strlen($1)+2]='\'';
+                       $$[strlen($1)+3]='\0';
+                       free($1);
+               }
+       | NCONST
+               {
+                       /* escaped quote starting with rNE */
+                       $$ = (char *)mm_alloc(strlen($1) + 4);
+                       $$[0]='N';
+                       $$[1]='\'';
+                       strcpy($$+2, $1);
+                       $$[strlen($1)+2]='\'';
+                       $$[strlen($1)+3]='\0';
+                       free($1);
+               }
+       | DOLCONST
+               {
+                       $$ = $1; 
+               }
+       ;
 
-Iconst:  ICONST                                 { $$ = make_name();};
-Fconst:  FCONST                                 { $$ = make_name();};
-Bitconst:  BITCONST                             { $$ = make_name();};
-Sconst:  SCONST                                 {
-                                                       $$ = (char *)mm_alloc(strlen($1) + 3);
-                                                       $$[0]='\'';
-                                                       strcpy($$+1, $1);
-                                                       $$[strlen($1)+2]='\0';
-                                                       $$[strlen($1)+1]='\'';
-                                                       free($1);
-                                               }
 PosIntConst:   Iconst          { $$ = $1; }
-               | civar         { $$ = make_str("?"); }
+               | civar         { $$ = $1; }
                ;
 
 IntConst:      PosIntConst             { $$ = $1; }
                | '-' PosIntConst       { $$ = cat2_str(make_str("-"), $2); }
                ;
 
+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; }
+               ;
+
+AllConstVar:   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; }
+               | '-' 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;
+               }
+               | 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;
+               }
+               ;
+
 StringConst:   Sconst          { $$ = $1; }
-               | civar         { $$ = make_str("?"); }
+               | civar         { $$ = $1; }
                ;
 
-PosIntStringConst:     Iconst          { $$ = $1; }
-                       | Sconst          { $$ = $1; }  
-                       | civar         { $$ = make_str("?"); }
-                       ;
+PosIntStringConst:     Iconst  { $$ = $1; }
+               | Sconst        { $$ = $1; }
+               | civar         { $$ = $1; }
+               ;
 
-NumConst:      Fconst        { $$ = $1; }
-                | Iconst        { $$ = $1; }
-                | '-' Fconst    { $$ = cat2_str(make_str("-"), $2); }
-                | '-' Iconst    { $$ = cat2_str(make_str("-"), $2); }
-               | civar         { $$ = make_str("?"); }
+NumConst:      Fconst                  { $$ = $1; }
+               | Iconst                { $$ = $1; }
+               | '-' Fconst            { $$ = cat2_str(make_str("-"), $2); }
+               | '-' Iconst            { $$ = cat2_str(make_str("-"), $2); }
+               | civar                 { $$ = $1; }
                ;
 
-AllConst:      Sconst          { $$ = $1; }
-               | NumConst      { $$ = $1; }
+AllConst:      Sconst                  { $$ = $1; }
+               | NumConst              { $$ = $1; }
                ;
 
-PosAllConst:   Sconst          { $$ = $1; }
-               | Fconst        { $$ = $1; }
-               | Iconst        { $$ = $1; }
-               | Bitconst      { $$ = $1; }
-               | civar         { $$ = make_str("?"); }
+PosAllConst:   Sconst                  { $$ = $1; }
+               | Fconst                { $$ = $1; }
+               | Iconst                { $$ = $1; }
+               | Bconst                { $$ = $1; }
+               | Xconst                { $$ = $1; }
+               | func_name Sconst      { $$ = cat2_str($1, $2); }
+               | func_name '(' expr_list ')' Sconst
+                                       { $$ = cat_str(5, $1, make_str("("), $3, make_str(")"), $5); }
+               | civar                 { $$ = $1; }
                ;
 
-UserId:  ColId                                  { $$ = $1;};
+RoleId:  ColId         { $$ = $1;};
 
 SpecialRuleRelation:  OLD
-                               {
-                                       if (!QueryIsRule)
-                                               mmerror(PARSE_ERROR, ET_ERROR, "OLD used in non-rule query");
+               {
+                       if (!QueryIsRule)
+                               mmerror(PARSE_ERROR, ET_ERROR, "OLD used in non-rule query");
 
-                                       $$ = make_str("old");
-                               }
+                       $$ = make_str("old");
+               }
                | NEW
-                               {
-                                       if (!QueryIsRule)
-                                               mmerror(PARSE_ERROR, ET_ERROR, "NEW used in non-rule query");
+               {
+                       if (!QueryIsRule)
+                               mmerror(PARSE_ERROR, ET_ERROR, "NEW used in non-rule query");
 
-                                       $$ = make_str("new");
-                               }
+                       $$ = make_str("new");
+               }
                ;
 
 /*
@@ -3939,349 +5039,446 @@ SpecialRuleRelation:  OLD
  */
 
 /*
- * the exec sql connect statement: connect to the given database 
+ * 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
                {
-                       $$ = 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"));
+                       /* 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: <tcp|unix>: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);
 
-connection_target: database_name opt_server opt_port
-                {
-                 /* old style: dbname[@server][:port] */
-                 if (strlen($2) > 0 && *($2) != '@')
-                 {
-                   sprintf(errortext, "Expected '@', found '%s'", $2);
-                   mmerror(PARSE_ERROR, ET_ERROR, errortext);
-                 }
+                       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(make_str("\""), make3_str($1, $2, $3), make_str("\""));
+                       $$ = make3_str(make3_str(make_str("\""), $1, make_str(":")), $3, make3_str(make3_str($4, make_str("/"), $6),    $7, make_str("\"")));
                }
-        |  db_prefix ':' server opt_port '/' database_name opt_options
-                {
-                 /* new style: <tcp|unix>:postgresql://server[:port][/dbname] */
-                 if (strncmp($1, "unix:postgresql", strlen("unix:postgresql")) != 0 && strncmp($1, "tcp:postgresql", strlen("tcp:postgresql")) != 0)
-                 {
-                   sprintf(errortext, "only protocols 'tcp' and 'unix' and database type 'postgresql' are supported");
-                    mmerror(PARSE_ERROR, ET_ERROR, errortext);
-                 }
-
-                  if (strncmp($3, "//", strlen("//")) != 0)
-                 {
-                   sprintf(errortext, "Expected '://', found '%s'", $3);
-                   mmerror(PARSE_ERROR, ET_ERROR, errortext);
-                 }
-
-                 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)
-                 {
-                   sprintf(errortext, "unix domain sockets only work on 'localhost' but not on '%9.9s'", $3 + strlen("//"));
-                    mmerror(PARSE_ERROR, ET_ERROR, errortext);
-                 }
-       
-                 $$ = make3_str(make3_str(make_str("\""), $1, make_str(":")), $3, make3_str(make3_str($4, make_str("/"), $6),  $7, make_str("\"")));
+               | char_variable
+               {
+                       $$ = $1;
                }
-       | StringConst
+               | Sconst
                {
-                 if ($1[0] == '\"')
+                       /* We can only process double quoted strings not single quotes ones,
+                        * so we change the quotes.
+                        * Note, that the rule for Sconst adds these single quotes. */
+                       $1[0] = '\"';
+                       $1[strlen($1)-1] = '\"';
                        $$ = $1;
-                 else if (strcmp($1, "?") == 0) /* variable */
-                  {
-                        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);
-                  }
-                 else
-                       $$ = make3_str(make_str("\""), $1, make_str("\""));
                }
+               ;
+
+opt_database_name: database_name               { $$ = $1; }
+               | /*EMPTY*/                     { $$ = EMPTY; }
+               ;
 
 db_prefix: ident cvariable
-                {
-                 if (strcmp($2, "postgresql") != 0 && strcmp($2, "postgres") != 0)
-                 {
-                   sprintf(errortext, "Expected 'postgresql', found '%s'", $2);
-                   mmerror(PARSE_ERROR, ET_ERROR, errortext);  
-                 }
-
-                 if (strcmp($1, "tcp") != 0 && strcmp($1, "unix") != 0)
-                 {
-                   sprintf(errortext, "Illegal connection type %s", $1);
-                   mmerror(PARSE_ERROR, ET_ERROR, errortext);
-                 }
-
-                 $$ = make3_str($1, make_str(":"), $2);
+               {
+                       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)
-                 {
-                   sprintf(errortext, "Expected '@' or '://', found '%s'", $1);
-                   mmerror(PARSE_ERROR, ET_ERROR, errortext);
-                 }
+               {
+                       if (strcmp($1, "@") != 0 && strcmp($1, "//") != 0)
+                               mmerror(PARSE_ERROR, ET_ERROR, "expected \"@\" or \"://\", found \"%s\"", $1);
 
-                 $$ = make2_str($1, $2);
-               }
+                       $$ = make2_str($1, $2);
+               }
+               ;
 
-opt_server: server { $$ = $1; }
-        | /* empty */ { $$ = EMPTY; }
+opt_server: server                     { $$ = $1; }
+               | /*EMPTY*/                     { $$ = EMPTY; }
+               ;
 
-server_name: ColId   { $$ = $1; }
-        | ColId '.' server_name { $$ = make3_str($1, make_str("."), $3); }
-       | IP                    { $$ = make_name(); }
+server_name: ColId                                     { $$ = $1; }
+               | ColId '.' server_name         { $$ = make3_str($1, make_str("."), $3); }
+               | IP                                            { $$ = make_name(); }
+               ;
 
-opt_port: ':' PosIntConst { $$ = make2_str(make_str(":"), $2); }
-        | /* empty */ { $$ = EMPTY; }
+opt_port: ':' PosIntConst      { $$ = make2_str(make_str(":"), $2); }
+               | /*EMPTY*/     { $$ = EMPTY; }
+               ;
 
-opt_connection_name: AS connection_target { $$ = $2; }
-        | /* empty */ { $$ = make_str("NULL"); }
+opt_connection_name: AS connection_object      { $$ = $2; }
+               | /*EMPTY*/                     { $$ = make_str("NULL"); }
+               ;
 
-opt_user: USER ora_user { $$ = $2; }
-          | /* empty */ { $$ = make_str("NULL,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
                {
-                        $$ = 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: UserId       {
-                        if ($1[0] == '\"')
+                       if ($1[0] == '\"')
                                $$ = $1;
-                         else
+                       else
                                $$ = make3_str(make_str("\""), $1, make_str("\""));
-                       }
-        | StringConst   { 
-                         if ($1[0] == '\"')
+               }
+               | StringConst
+               {
+                       if ($1[0] == '\"')
                                $$ = $1;
-                         else if (strcmp($1, "?") == 0) /* variable */
-                         {
-                               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);
-                         }
-                         else
-                               $$ = make3_str(make_str("\""), $1, make_str("\""));
+                       else if ($1[1] == '$') /* variable */
+                       {
+                               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);
                        }
+                       else
+                               $$ = make3_str(make_str("\""), $1, make_str("\""));
+               }
+               ;
 
 char_variable: cvariable
-               { /* check if we have a char variable */
+               {
+                       /* check if we have a string variable */
                        struct variable *p = find_variable($1);
                        enum ECPGttype type = p->type->type;
 
-                       /* 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");
-                                break;
-                        }
+                       /* 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 ColId
+opt_options: Op connect_options
                {
                        if (strlen($1) == 0)
                                mmerror(PARSE_ERROR, ET_ERROR, "incomplete statement");
-                               
+
                        if (strcmp($1, "?") != 0)
-                       {
-                               sprintf(errortext, "unrecognised token '%s'", $1);
-                               mmerror(PARSE_ERROR, ET_ERROR, errortext);
-                       }
-                       
+                               mmerror(PARSE_ERROR, ET_ERROR, "unrecognized token \"%s\"", $1);
+
                        $$ = make2_str(make_str("?"), $2);
                }
-       | /* empty */ { $$ = EMPTY; }
+               | /*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); }
+               | '=' IDENT
+                       { $$ = make2_str(make_str("="), $2); }
+               ;
 /*
  * Declare a prepared cursor. The syntax is different from the standard
  * declare statement, so we create a new rule.
  */
-ECPGCursorStmt:  DECLARE name opt_cursor CURSOR FOR ident
-                               {
-                                       struct cursor *ptr, *this;
-                                       struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable));
+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 */
-                                                       sprintf(errortext, "cursor %s already defined", $2);
-                                                       mmerror(PARSE_ERROR, ET_ERROR, errortext);
-                                               }
-                                       }
-
-                                       this = (struct cursor *) mm_alloc(sizeof(struct cursor));
-
-                                       /* initial definition */
-                                       this->next = cur;
-                                       this->name = $2;
-                                       this->connection = connection;
-                                       this->command =  cat_str(4, make_str("declare"), mm_strdup($2), $3, make_str("cursor for ?"));
-                                       this->argsresult = NULL;
-
-                                       thisquery->type = &ecpg_query;
-                                       thisquery->brace_level = 0;
-                                       thisquery->next = NULL;
-                                       thisquery->name = (char *) mm_alloc(sizeof("ECPGprepared_statement(\"\")") + strlen($6));
-                                       sprintf(thisquery->name, "ECPGprepared_statement(\"%s\")", $6);
-
-                                       this->argsinsert = NULL;
-                                       add_variable(&(this->argsinsert), thisquery, &no_indicator); 
-
-                                       cur = this;
-                                       
-                                       $$ = cat_str(3, make_str("/*"), mm_strdup(this->command), make_str("*/"));
-                               }
+                       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;
+                       };
 /*
- * the exec sql deallocate prepare command to deallocate a previously
- * prepared statement
+ * variable decalartion outside exec sql declare block
  */
-ECPGDeallocate:        SQL_DEALLOCATE SQL_PREPARE ident        { $$ = cat_str(3, make_str("ECPGdeallocate(__LINE__, \""), $3, make_str("\");")); };
+ECPGVarDeclaration: single_vt_declaration;
+
+single_vt_declaration: type_declaration                { $$ = $1; }
+               | var_declaration               { $$ = $1; }
+               ;
+
+precision:     NumConst        { $$ = $1; };
+
+opt_scale:     ',' NumConst    { $$ = $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 the exec sql declare block
+ * variable declaration inside exec sql declare block
  */
 ECPGDeclaration: sql_startdeclare
-       {
-               fputs("/* exec sql begin declare section */", yyout);
-       }
-       variable_declarations sql_enddeclare
-       {
-               fprintf(yyout, "%s/* exec sql end declare section */", $3);
-               free($3);
-               output_line_number();
-       };
+               { 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_TRANS DECLARE SQL_SECTION ';' {};
+sql_startdeclare: ecpgstart BEGIN_P DECLARE SQL_SECTION ';' {};
 
-sql_enddeclare: ecpgstart END_TRANS DECLARE SQL_SECTION ';' {};
+sql_enddeclare: ecpgstart END_P DECLARE SQL_SECTION ';' {};
 
-variable_declarations:  /* empty */ { $$ = EMPTY; }
-                       | declarations { $$ = $1; }
-                       ;
+var_type_declarations: /*EMPTY*/                       { $$ = EMPTY; }
+               | vt_declarations                       { $$ = $1; }
+               | CPP_LINE                              { $$ = $1; }
+               ;
 
-declarations:  declaration { $$ = $1; }
-                       | declarations declaration { $$ = cat2_str($1, $2); }
-                       ;
+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); }
+               ;
 
-declaration: storage_clause storage_modifier
+type_declaration: S_TYPEDEF
        {
-               actual_storage[struct_level] = cat2_str(mm_strdup($1), mm_strdup($2));
-               actual_startline[struct_level] = hashline_number();
+               /* reset this variable so we see if there was */
+               /* an initializer specified */
+               initializer = 0;
        }
-       type
+       var_type opt_pointer ECPGColLabelCommon opt_array_bounds ';'
        {
-               actual_type[struct_level].type_enum = $4.type_enum;
-               actual_type[struct_level].type_dimension = $4.type_dimension;
-               actual_type[struct_level].type_index = $4.type_index;
+               add_typedef($5, $6.index1, $6.index2, $3.type_enum, $3.type_dimension, $3.type_index, initializer, *$4 ? 1 : 0);
 
-               /* we do not need the string "varchar" for output */
-               /* so replace it with an empty string */
-               if ($4.type_enum == ECPGt_varchar)
+               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
                {
-                       free($4.type_str);
-                       $4.type_str=EMPTY;
+                       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(6, actual_startline[struct_level], $1, $2, $4.type_str, $6, make_str(";\n"));
-       };
+               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"); }
-        | /* empty */          { $$ = EMPTY; }
-       ;
+               | 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"); }
-        | /* empty */            { $$ = EMPTY; }
-       ;
+storage_modifier : S_CONST     { $$ = make_str("const"); }
+               | S_VOLATILE            { $$ = make_str("volatile"); }
+               ;
 
-type: simple_type
+var_type:      simple_type
                {
                        $$.type_enum = $1;
-                       $$.type_str = mm_strdup(ECPGtype_name($1));
-                       $$.type_dimension = -1;
-                       $$.type_index = -1;
+                       $$.type_str = mm_strdup(ecpg_type_name($1));
+                       $$.type_dimension = make_str("-1");
+                       $$.type_index = make_str("-1");
+                       $$.type_sizeof = NULL;
                }
-       | struct_type
+               | struct_union_type
                {
-                       $$.type_enum = ECPGt_struct;
                        $$.type_str = $1;
-                       $$.type_dimension = -1;
-                       $$.type_index = -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;
+                       }
                }
-       | union_type
+               | enum_type
                {
-                       $$.type_enum = ECPGt_union;
                        $$.type_str = $1;
-                       $$.type_dimension = -1;
-                       $$.type_index = -1;
+                       $$.type_enum = ECPGt_int;
+                       $$.type_dimension = make_str("-1");
+                       $$.type_index = make_str("-1");
+                       $$.type_sizeof = NULL;
                }
-       | enum_type
+               | ECPGColLabelCommon '(' precision opt_scale ')'
                {
-                       $$.type_str = $1;
-                       $$.type_enum = ECPGt_int;
-                       $$.type_dimension = -1;
-                       $$.type_index = -1;
+                       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;
                }
-       | ECPGColLabel
+               | 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
@@ -4289,23 +5486,74 @@ type: simple_type
                        if (strcmp($1, "varchar") == 0)
                        {
                                $$.type_enum = ECPGt_varchar;
-                               $$.type_str = make_str("varchar");
-                               $$.type_dimension = -1;
-                               $$.type_index = -1;
+                               $$.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 = -1;
-                               $$.type_index = -1;
+                               $$.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 = -1;
-                               $$.type_index = -1;
+                               $$.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
                        {
@@ -4316,184 +5564,286 @@ type: simple_type
                                $$.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 */
 
-enum_type: SQL_ENUM opt_symbol enum_definition
-       {
-               $$ = cat_str(3, make_str("enum"), $2, $3);
-       }
-       |  SQL_ENUM symbol
-       {
-               $$ = cat2_str(make_str("enum"), $2);
-       }
-       ;
+                               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_definition: '{' c_list '}'        { $$ = cat_str(3, make_str("{"), $2, make_str("}")); };
+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); }
+               ;
 
-struct_type: s_struct '{' variable_declarations '}'
-       {
-           ECPGfree_struct_member(struct_member_list[struct_level]);
-           free(actual_storage[struct_level--]);
-           $$ = cat_str(4, $1, make_str("{"), $3, make_str("}"));
-       };
+enum_definition: '{' c_list '}'
+                       { $$ = cat_str(3, make_str("{"), $2, make_str("}")); };
 
-union_type: s_union '{' variable_declarations '}'
-       {
-           ECPGfree_struct_member(struct_member_list[struct_level]);
-           free(actual_storage[struct_level--]);
-           $$ = cat_str(4, $1, make_str("{"), $3, 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;
 
-s_struct: SQL_STRUCT opt_symbol
-        {
-            struct_member_list[struct_level++] = NULL;
-           $$ = cat2_str(make_str("struct"), $2);
-           ECPGstruct_sizeof = cat_str(3, make_str("sizeof("), strdup($$), make_str(")"));
-            if (struct_level >= STRUCT_DEPTH)
-                 mmerror(PARSE_ERROR, ET_ERROR, "Too many levels in nested structure definition");
-       };
+                       /* 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);
+                       }
 
-s_union: UNION opt_symbol
-        {
-            struct_member_list[struct_level++] = NULL;
-            if (struct_level >= STRUCT_DEPTH)
-                 mmerror(PARSE_ERROR, ET_ERROR, "Too many levels in nested structure definition");
+                       this = (struct typedefs *) mm_alloc(sizeof(struct typedefs));
 
-           $$ = cat2_str(make_str("union"), $2);
-       };
+                       /* 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("}"));
+               }
+               ;
 
-simple_type: unsigned_type             { $$=$1; }
-       |       opt_signed signed_type  { $$=$2; }
-       ;
+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"); }
+               ;
 
-unsigned_type: SQL_UNSIGNED SQL_SHORT                          { $$ = ECPGt_unsigned_short; }
-               | SQL_UNSIGNED SQL_SHORT SQL_INT                { $$ = ECPGt_unsigned_short; }
-               | SQL_UNSIGNED                                  { $$ = ECPGt_unsigned_int; }
-               | SQL_UNSIGNED SQL_INT                          { $$ = ECPGt_unsigned_int; }
+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 SQL_INT                 { $$ = ECPGt_unsigned_long; }
-               | SQL_UNSIGNED SQL_LONG SQL_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; 
+                       $$ = ECPGt_unsigned_long_long;
 #else
-                                                                 $$ = ECPGt_unsigned_long;
+                       $$ = ECPGt_unsigned_long;
 #endif
-                                                               }
-               | SQL_UNSIGNED SQL_LONG SQL_LONG SQL_INT        { 
+               }
+               | SQL_UNSIGNED SQL_LONG SQL_LONG INT_P
+               {
 #ifdef HAVE_LONG_LONG_INT_64
-                                                                 $$ = ECPGt_unsigned_long_long; 
+                       $$ = ECPGt_unsigned_long_long;
 #else
-                                                                 $$ = ECPGt_unsigned_long;
+                       $$ = ECPGt_unsigned_long;
 #endif
-                                                               }
-               | SQL_UNSIGNED CHAR                             { $$ = ECPGt_unsigned_char; }
+               }
+               | SQL_UNSIGNED CHAR_P                   { $$ = ECPGt_unsigned_char; }
                ;
 
-signed_type: SQL_SHORT                 { $$ = ECPGt_short; }
-           | SQL_SHORT SQL_INT         { $$ = ECPGt_short; }
-           | SQL_INT                   { $$ = ECPGt_int; }
-           | SQL_LONG                  { $$ = ECPGt_long; }
-           | SQL_LONG SQL_INT          { $$ = ECPGt_long; }
-           | SQL_LONG SQL_LONG         { 
+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; 
+                       $$ = ECPGt_long_long;
 #else
-                                                                 $$ = ECPGt_long;
+                       $$ = ECPGt_long;
 #endif
-                                                               }
-           | SQL_LONG SQL_LONG SQL_INT { 
+               }
+               | SQL_LONG SQL_LONG INT_P
+               {
 #ifdef HAVE_LONG_LONG_INT_64
-                                                                 $$ = ECPGt_long_long; 
+                       $$ = ECPGt_long_long;
 #else
-                                                                 $$ = ECPGt_long;
+                       $$ = ECPGt_long;
 #endif
-                                                               }
-           | SQL_BOOL                  { $$ = ECPGt_bool; }
-           | CHAR                      { $$ = ECPGt_char; }
-          ;
+               }
+               | SQL_BOOL                                      { $$ = ECPGt_bool; }
+               | CHAR_P                                        { $$ = ECPGt_char; }
+               | DOUBLE_P                                      { $$ = ECPGt_double; }
+               ;
 
-opt_signed:    SQL_SIGNED
-       |       /* EMPTY */
-       ;
+opt_signed: SQL_SIGNED
+               |       /* EMPTY */
+               ;
 
-variable_list: variable 
-       {
-               $$ = $1;
-       }
-       | variable_list ',' variable
-       {
-               $$ = cat_str(3, $1, make_str(","), $3);
-       }
-       ;
+variable_list: variable
+                       { $$ = $1; }
+               | variable_list ',' variable
+                       { $$ = cat_str(3, $1, make_str(","), $3); }
+               ;
 
-variable: opt_pointer ECPGColLabel opt_array_bounds opt_initializer
+variable: opt_pointer ECPGColLabel opt_array_bounds opt_bit_field opt_initializer
                {
                        struct ECPGtype * type;
-                        int dimension = $3.index1; /* dimension of array */
-                        int length = $3.index2;    /* lenght of string */
-                        char dim[14L], ascii_len[12];
+                       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));
+                       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 (dimension < 0)
-                                   type = ECPGmake_struct_type(struct_member_list[struct_level], actual_type[struct_level].type_enum, ECPGstruct_sizeof);
-                               else
-                                   type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level], actual_type[struct_level].type_enum, ECPGstruct_sizeof), dimension); 
-
-                               $$ = cat_str(4, $1, mm_strdup($2), $3.str, $4);
-                               break;
-                           case ECPGt_varchar:
-                               if (dimension < 0)
-                                   type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length);
-                               else
-                                   type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length), dimension);
-
-                               switch(dimension)
-                               {
-                                  case 0:
-                                 case -1:
-                                  case 1:
-                                      *dim = '\0';
-                                      break;
-                                  default:
-                                      sprintf(dim, "[%d]", dimension);
-                                      break;
-                               }
-                              sprintf(ascii_len, "%d", length);
-
-                               if (length == 0)
-                                  mmerror(PARSE_ERROR, ET_ERROR, "pointer to varchar are not implemented");
-
-                              if (dimension == 0)
-                                  $$ = cat_str(7, mm_strdup(actual_storage[struct_level]), make2_str(make_str(" struct varchar_"), mm_strdup($2)), make_str(" { int len; char arr["), mm_strdup(ascii_len), make_str("]; } *"), mm_strdup($2), $4);
-                              else
-                                   $$ = cat_str(8, mm_strdup(actual_storage[struct_level]), make2_str(make_str(" struct varchar_"), mm_strdup($2)), make_str(" { int len; char arr["), mm_strdup(ascii_len), make_str("]; } "), mm_strdup($2), mm_strdup(dim), $4);
-
-                               break;
-                           case ECPGt_char:
-                           case ECPGt_unsigned_char:
-                               if (dimension == -1)
-                                   type = ECPGmake_simple_type(actual_type[struct_level].type_enum, length);
-                               else
-                                   type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, length), dimension);
-
-                              $$ = cat_str(4, $1, mm_strdup($2), $3.str, $4);
-                               break;
-                           default:
-                               if (dimension < 0)
-                                   type = ECPGmake_simple_type(actual_type[struct_level].type_enum, 1);
-                               else
-                                   type = ECPGmake_array_type(ECPGmake_simple_type(actual_type[struct_level].type_enum, 1), dimension);
-
-                              $$ = cat_str(4, $1, mm_strdup($2), $3.str, $4);
-                               break;
+                               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 <var>[] = "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)
@@ -4502,590 +5852,596 @@ variable: opt_pointer ECPGColLabel opt_array_bounds opt_initializer
                                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_initializer: /*EMPTY*/
+                       { $$ = EMPTY; }
+               | '=' c_term
+               {
+                       initializer = 1;
+                       $$ = cat2_str(make_str("="), $2);
+               }
+               ;
 
-opt_pointer: /* empty */       { $$ = EMPTY; }
-       | '*'                   { $$ = make_str("*"); }
-       | '*' '*'               { $$ = make_str("**"); }
-       ;
+opt_pointer: /*EMPTY*/                         { $$ = EMPTY; }
+               | '*'                                           { $$ = make_str("*"); }
+               | '*' '*'                                       { $$ = make_str("**"); }
+               ;
 
 /*
- * As long as the prepare statement is not supported by the backend, we will
- * try to simulate it here so we get dynamic SQL 
+ * We try to simulate the correct DECLARE syntax here so we get dynamic SQL
  */
 ECPGDeclare: DECLARE STATEMENT ident
-       {
-               /* this is only supported for compatibility */
-               $$ = cat_str(3, make_str("/* declare statement"), $3, make_str("*/"));
-       };
+               {
+                       /* 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 
+ * the exec sql disconnect statement: disconnect from the given database
  */
 ECPGDisconnect: SQL_DISCONNECT dis_name { $$ = $2; }
+               ;
 
-dis_name: connection_object    { $$ = $1; }
-       | CURRENT       { $$ = make_str("\"CURRENT\""); }
-       | ALL           { $$ = make_str("\"ALL\""); }
-       | /* empty */   { $$ = make_str("\"CURRENT\""); }
-       ;
+dis_name: connection_object                    { $$ = $1; }
+               | CURRENT_P                     { $$ = make_str("\"CURRENT\""); }
+               | ALL                           { $$ = make_str("\"ALL\""); }
+               | /* EMPTY */                   { $$ = make_str("\"CURRENT\""); }
+               ;
 
-connection_object: connection_target { $$ = $1; }
-       | DEFAULT       { $$ = make_str("\"DEFAULT\""); }
-       ;
+connection_object: database_name               { $$ = make3_str(make_str("\""), $1, make_str("\"")); }
+               | DEFAULT                       { $$ = make_str("\"DEFAULT\""); }
+               | char_variable                 { $$ = $1; }
+               ;
+
+execute_rest:  ecpg_using ecpg_into    { $$ = EMPTY; }
+               | ecpg_into ecpg_using  { $$ = EMPTY; }
+               | ecpg_using            { $$ = EMPTY; }
+               | ecpg_into             { $$ = EMPTY; }
+               | /* EMPTY */           { $$ = EMPTY; }
+               ;
+
+execstring: char_variable
+                       { $$ = $1; }
+               |       CSTRING
+                       { $$ = make3_str(make_str("\""), $1, make_str("\"")); }
+               ;
+
+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; }
+               ;
 
 /*
- * execute a given string as sql command
+ * the exec sql free command to deallocate a previously
+ * prepared statement
  */
-ECPGExecute : EXECUTE IMMEDIATE execstring
-       { 
-               struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable));
+ECPGFree:      SQL_FREE name   { $$ = $2; }
+               | SQL_FREE ALL  { $$ = make_str("all"); }
+               ;
 
-               thisquery->type = &ecpg_query;
-               thisquery->brace_level = 0;
-               thisquery->next = NULL;
-               thisquery->name = $3;
+/*
+ * open is an open cursor, at the moment this has to be removed
+ */
+ECPGOpen: SQL_OPEN name opt_ecpg_using { $$ = $2; };
 
-               add_variable(&argsinsert, thisquery, &no_indicator); 
+opt_ecpg_using: /*EMPTY*/      { $$ = EMPTY; }
+               | ecpg_using            { $$ = $1; }
+               ;
 
-               $$ = make_str("?");
-       }
-       | EXECUTE ident 
-       {
-               struct variable *thisquery = (struct variable *)mm_alloc(sizeof(struct variable));
+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;
+               }
+               ;
 
-               thisquery->type = &ecpg_query;
-               thisquery->brace_level = 0;
-               thisquery->next = NULL;
-               thisquery->name = (char *) mm_alloc(sizeof("ECPGprepared_statement(\"\")") + strlen($2));
-               sprintf(thisquery->name, "ECPGprepared_statement(\"%s\")", $2);
+opt_sql: /*EMPTY*/ | SQL_SQL;
 
-               add_variable(&argsinsert, thisquery, &no_indicator); 
-       } ecpg_using opt_ecpg_into
+ecpg_into: INTO into_list              { $$ = EMPTY; }
+               | into_descriptor       { $$ = $1; }
+               ;
+
+using_list: UsingConst | UsingConst ',' using_list;
+
+UsingConst: AllConst
+               {
+                       if ($1[1] != '$') /* found a constant */
+                       {
+                               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);
+                       }
+               }
+               | civarind { $$ = EMPTY; }
+               ;
+
+
+/*
+ * 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
        {
-               $$ = make_str("?");
+               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);
        }
        ;
 
-execstring:    char_variable   { $$ = $1; }
-       |       CSTRING         { $$ = make3_str(make_str("\""), $1, make_str("\"")); }
+opt_output:    SQL_OUTPUT      { $$ = make_str("output"); }
+       |       /* EMPTY */     { $$ = EMPTY; }
        ;
 
 /*
- * the exec sql free command to deallocate a previously
- * prepared statement
+ * dynamic SQL: descriptor based access
+ *     originall written by Christof Petig <christof.petig@wtal.de>
+ *                     and Peter Eisentraut <peter.eisentraut@credativ.de>
  */
-ECPGFree:      SQL_FREE ident  { $$ = $2; };
 
 /*
- * open is an open cursor, at the moment this has to be removed
+ * allocate a descriptor
  */
-ECPGOpen: SQL_OPEN name ecpg_using { $$ = $2; };
+ECPGAllocateDescr:     SQL_ALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar
+               {
+                       add_descriptor($3,connection);
+                       $$ = $3;
+               }
+               ;
 
-ecpg_using: /* empty */                { $$ = EMPTY; }
-       | USING variablelist    {
-                                       /* mmerror ("open cursor with variables not implemented yet"); */
-                                       $$ = EMPTY;
-                               }
-       ;
 
-opt_sql: /* empty */ | SQL_SQL;
+/*
+ * deallocate a descriptor
+ */
+ECPGDeallocateDescr:   DEALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar
+               {
+                       drop_descriptor($3,connection);
+                       $$ = $3;
+               }
+               ;
 
-ecpg_into: INTO into_list      {
-                                       $$ = EMPTY;
-                               }
-       | INTO opt_sql SQL_DESCRIPTOR quoted_ident_stringvar
-                               {
-                                       add_variable(&argsresult, descriptor_variable($4,0), &no_indicator);
-                                       $$ = EMPTY;
-                               }
-       ;
+/*
+ * 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; }
+               ;
 
-opt_ecpg_into: /* empty */             { $$ = EMPTY; } 
-               | ecpg_into             { $$ = $1; }
+ECPGSetDescHeaderItems: ECPGSetDescHeaderItem
+               | ECPGSetDescHeaderItems ',' ECPGSetDescHeaderItem
                ;
 
-variable: civarind | civar 
-variablelist: variable | variable ',' variablelist;
+ECPGSetDescHeaderItem: desc_header_item '=' IntConstVar
+               {
+                       push_assignment($3, $1);
+               }
+               ;
 
-/*
- * As long as the prepare statement is not supported by the backend, we will
- * try to simulate it here so we get dynamic SQL 
- */
-ECPGPrepare: SQL_PREPARE ident FROM execstring
-       {
-               $$ = cat2_str(make3_str(make_str("\""), $2, make_str("\",")), $4);
-       };
 
-/*
- * dynamic SQL: descriptor based access
- *     written by Christof Petig <christof.petig@wtal.de>
- */
+desc_header_item:      SQL_COUNT                       { $$ = ECPGd_count; }
+               ;
 
 /*
- * deallocate a descriptor
+ * manipulate a descriptor
  */
-ECPGDeallocateDescr:   SQL_DEALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar
-               {
-                       drop_descriptor($3,connection);
-                       $$ = $3;
-               };
 
-/*
- * allocate a descriptor
- */
-ECPGAllocateDescr:     SQL_ALLOCATE SQL_DESCRIPTOR quoted_ident_stringvar
-               {
-                       add_descriptor($3,connection);
-                       $$ = $3;
-               };
+ECPGGetDescriptor:     SQL_GET SQL_DESCRIPTOR quoted_ident_stringvar VALUE_P IntConstVar ECPGGetDescItems
+                       {  $$.str = $5; $$.name = $3; }
+               ;
 
-/*
- * read from descriptor
- */
+ECPGGetDescItems: ECPGGetDescItem
+               | ECPGGetDescItems ',' ECPGGetDescItem
+               ;
 
-ECPGGetDescHeaderItem: cvariable '=' desc_header_item  { push_assignment($1, $3); };
+ECPGGetDescItem: cvariable '=' descriptor_item { push_assignment($1, $3); };
 
-desc_header_item:      SQL_COUNT               { $$ = ECPGd_count; };
 
-ECPGGetDescItem: cvariable '=' descriptor_item  { push_assignment($1, $3); };
+ECPGSetDescriptor:     SET SQL_DESCRIPTOR quoted_ident_stringvar VALUE_P IntConstVar ECPGSetDescItems
+                       {  $$.str = $5; $$.name = $3; }
+               ;
 
-descriptor_item:       SQL_CARDINALITY { $$ = ECPGd_cardinality; }
-               |       SQL_DATA                        { $$ = 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; }
-               |       SQL_NAME                        { $$ = 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; }
+ECPGSetDescItems: ECPGSetDescItem
+               | ECPGSetDescItems ',' ECPGSetDescItem
                ;
 
-ECPGGetDescHeaderItems: ECPGGetDescHeaderItem
-       | ECPGGetDescHeaderItems ',' ECPGGetDescHeaderItem
-       ;
-ECPGGetDescItems: ECPGGetDescItem
-       | ECPGGetDescItems ',' ECPGGetDescItem
-       ;
-ECPGGetDescriptorHeader:       SQL_GET SQL_DESCRIPTOR quoted_ident_stringvar ECPGGetDescHeaderItems
-               {  $$ = $3; };
-
-ECPGGetDescriptor:     SQL_GET SQL_DESCRIPTOR quoted_ident_stringvar SQL_VALUE cvariable ECPGGetDescItems
-               {  $$.str = $5; $$.name = $3; }
-       |       SQL_GET SQL_DESCRIPTOR quoted_ident_stringvar SQL_VALUE Iconst ECPGGetDescItems
-               {  $$.str = $5; $$.name = $3; }
-       ;
+ECPGSetDescItem: descriptor_item '=' AllConstVar
+               {
+                       push_assignment($3, $1);
+               }
+               ;
 
-/*
- * for compatibility with ORACLE we will also allow the keyword RELEASE
- * after a transaction statement to disconnect from the database.
- */
 
-ECPGRelease: TransactionStmt SQL_RELEASE
-       {
-               if (strcmp($1, "begin") == 0)
-                        mmerror(PARSE_ERROR, ET_ERROR, "RELEASE does not make sense when beginning a transaction");
-
-               fprintf(yyout, "ECPGtrans(__LINE__, %s, \"%s\");",
-                               connection ? connection : "NULL", $1);
-               whenever_action(0);
-               fprintf(yyout, "ECPGdisconnect(__LINE__, \"\");"); 
-               whenever_action(0);
-               free($1);
-       };
+descriptor_item:       SQL_CARDINALITY                 { $$ = ECPGd_cardinality; }
+               | SQL_DATA                              { $$ = 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 to_equal on_off
-                       {
-                               $$ = $4;
-                        };
-
-on_off:        ON              { $$ = make_str("on"); }
-       | OFF           { $$ = make_str("off"); }
-       ;
+ECPGSetAutocommit:     SET SQL_AUTOCOMMIT '=' on_off   { $$ = $4; }
+               |  SET SQL_AUTOCOMMIT TO on_off   { $$ = $4; }
+               ;
 
-to_equal:      TO | '=';
+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 SQL_CONNECTION to_equal connection_object
-                       {
-                               $$ = $4;
-                        };
+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;
-       }
-       ColLabel IS type opt_type_array_bounds opt_reference
-       {
-               /* add entry to list */
-               struct typedefs *ptr, *this;
-               int dimension = $6.index1;
-               int length = $6.index2;
-
-               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");
+                       /* reset this variable so we see if there was */
+                       /* an initializer specified */
+                       initializer = 0;
                }
-               else
+               ECPGColLabelCommon IS var_type opt_array_bounds opt_reference
                {
-                       for (ptr = types; ptr != NULL; ptr = ptr->next)
-                       {
-                               if (strcmp($3, ptr->name) == 0)
-                               {
-                                       /* re-definition is a bug */
-                                       sprintf(errortext, "Type %s already defined", $3);
-                                       mmerror(PARSE_ERROR, ET_ERROR, errortext);
-                               }
-                       }
-
-                       adjust_array($5.type_enum, &dimension, &length, $5.type_dimension, $5.type_index, *$7?1:0);
+                       add_typedef($3, $6.index1, $6.index2, $5.type_enum, $5.type_dimension, $5.type_index, initializer, *$7 ? 1 : 0);
 
-                               this = (struct typedefs *) mm_alloc(sizeof(struct typedefs));
-
-                       /* initial definition */
-                       this->next = types;
-                       this->name = $3;
-                       this->type = (struct this_type *) mm_alloc(sizeof(struct this_type));
-                       this->type->type_enum = $5.type_enum;
-                       this->type->type_str = mm_strdup($3);
-                       this->type->type_dimension = dimension; /* dimension of array */
-                       this->type->type_index = length;    /* lenght of string */
-                       this->struct_member_list = ($5.type_enum == ECPGt_struct || $5.type_enum == ECPGt_union) ?
-                               struct_member_list[struct_level] : NULL;
-
-                       if ($5.type_enum != ECPGt_varchar &&
-                           $5.type_enum != ECPGt_char &&
-                           $5.type_enum != ECPGt_unsigned_char &&
-                           this->type->type_index >= 0)
-                                   mmerror(PARSE_ERROR, ET_ERROR, "No multi-dimensional array support for simple data types");
-
-                       types = this;
+                       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(";"));
                }
-
-               $$ = 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("*/"));
-       };
-
-opt_type_array_bounds:  '[' ']' opt_type_array_bounds
-                       {
-                            $$.index1 = 0;
-                            $$.index2 = $3.index1;
-                            $$.str = cat2_str(make_str("[]"), $3.str);
-                        }
-               | '(' ')' opt_type_array_bounds
-                       {
-                            $$.index1 = 0;
-                            $$.index2 = $3.index1;
-                            $$.str = cat2_str(make_str("[]"), $3.str);
-                        }
-               | '[' Iresult ']' opt_type_array_bounds
-                       {
-                           char *txt = mm_alloc(20L);
-
-                           sprintf (txt, "%d", $2);
-                            $$.index1 = $2;
-                            $$.index2 = $4.index1;
-                            $$.str = cat_str(4, make_str("["), txt, make_str("]"), $4.str);
-                        }
-               | '(' Iresult ')' opt_type_array_bounds
-                       {
-                           char *txt = mm_alloc(20L);
-
-                           sprintf (txt, "%d", $2);
-                            $$.index1 = $2;
-                            $$.index2 = $4.index1;
-                            $$.str = cat_str(4, make_str("["), txt, make_str("]"), $4.str);
-                        }
-               | /* EMPTY */
-                       {
-                            $$.index1 = -1;
-                            $$.index2 = -1;
-                            $$.str= EMPTY;
-                        }
                ;
 
-opt_reference: SQL_REFERENCE { $$ = make_str("reference"); }
-       | /* empty */        { $$ = EMPTY; }
-       ;
+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 type opt_type_array_bounds opt_reference
-       {
-               struct variable *p = find_variable($3);
-               int dimension = $6.index1;
-               int 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");
+                       /* reset this variable so we see if there was */
+                       /* an initializer specified */
+                       initializer = 0;
                }
-               else
+               ColLabel IS var_type opt_array_bounds opt_reference
                {
-                       adjust_array($5.type_enum, &dimension, &length, $5.type_dimension, $5.type_index, *$7?1:0);
+                       struct variable *p = find_variable($3);
+                       char *dimension = $6.index1;
+                       char *length = $6.index2;
+                       struct ECPGtype * type;
 
-                       switch ($5.type_enum)
+                       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
                        {
-                          case ECPGt_struct:
-                          case ECPGt_union:
-                               if (dimension < 0)
-                                   type = ECPGmake_struct_type(struct_member_list[struct_level], $5.type_enum, ECPGstruct_sizeof);
-                               else
-                                   type = ECPGmake_array_type(ECPGmake_struct_type(struct_member_list[struct_level], $5.type_enum, ECPGstruct_sizeof), dimension); 
-                               break;
-                          case ECPGt_varchar:
-                               if (dimension == -1)
-                                   type = ECPGmake_simple_type($5.type_enum, length);
-                               else
-                                   type = ECPGmake_array_type(ECPGmake_simple_type($5.type_enum, length), dimension);
-
-                               break;
-                          case ECPGt_char:
-                          case ECPGt_unsigned_char:
-                               if (dimension == -1)
-                                   type = ECPGmake_simple_type($5.type_enum, length);
-                               else
-                                   type = ECPGmake_array_type(ECPGmake_simple_type($5.type_enum, length), dimension);
-
-                               break;
-                          default:
-                               if (length >= 0)
-                                   mmerror(PARSE_ERROR, ET_ERROR, "No multi-dimensional array support for simple data types");
-
-                               if (dimension < 0)
-                                   type = ECPGmake_simple_type($5.type_enum, 1);
-                               else
-                                   type = ECPGmake_array_type(ECPGmake_simple_type($5.type_enum, 1), dimension);
-
-                               break;
-                       }       
-
-                       ECPGfree_type(p->type);
-                       p->type = type;
-               }
+                               adjust_array($5.type_enum, &dimension, &length, $5.type_dimension, $5.type_index, *$7?1:0, false);
 
-               $$ = 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("*/"));
-       };
+                               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 = $<action>3.code;
-               when_error.command = $<action>3.command;
-               $$ = cat_str(3, make_str("/* exec sql whenever sqlerror "), $3.str, make_str("; */\n"));
-       }
-       | SQL_WHENEVER NOT SQL_FOUND action
-       {
-               when_nf.code = $<action>4.code;
-               when_nf.command = $<action>4.command;
-               $$ = cat_str(3, make_str("/* exec sql whenever not found "), $4.str, make_str("; */\n"));
-       }
-       | SQL_WHENEVER SQL_SQLWARNING action
-       {
-               when_warn.code = $<action>3.code;
-               when_warn.command = $<action>3.command;
-               $$ = cat_str(3, make_str("/* exec sql whenever sql_warning "), $3.str, make_str("; */\n"));
-       }
-       ;
+               {
+                       when_error.code = $<action>3.code;
+                       when_error.command = $<action>3.command;
+                       $$ = cat_str(3, make_str("/* exec sql whenever sqlerror "), $3.str, make_str("; */"));
+               }
+               | SQL_WHENEVER NOT SQL_FOUND action
+               {
+                       when_nf.code = $<action>4.code;
+                       when_nf.command = $<action>4.command;
+                       $$ = cat_str(3, make_str("/* exec sql whenever not found "), $4.str, make_str("; */"));
+               }
+               | SQL_WHENEVER SQL_SQLWARNING action
+               {
+                       when_warn.code = $<action>3.code;
+                       when_warn.command = $<action>3.command;
+                       $$ = cat_str(3, make_str("/* exec sql whenever sql_warning "), $3.str, make_str("; */"));
+               }
+               ;
 
-action : SQL_CONTINUE
-       {
-               $<action>$.code = W_NOTHING;
-               $<action>$.command = NULL;
-               $<action>$.str = make_str("continue");
-       }
-       | SQL_SQLPRINT
-       {
-               $<action>$.code = W_SQLPRINT;
-               $<action>$.command = NULL;
-               $<action>$.str = make_str("sqlprint");
-       }
-       | SQL_STOP
-       {
-               $<action>$.code = W_STOP;
-               $<action>$.command = NULL;
-               $<action>$.str = make_str("stop");
-       }
-       | SQL_GOTO name
-       {
-               $<action>$.code = W_GOTO;
-               $<action>$.command = strdup($2);
-               $<action>$.str = cat2_str(make_str("goto "), $2);
-       }
-       | SQL_GO TO name
-       {
-               $<action>$.code = W_GOTO;
-               $<action>$.command = strdup($3);
-               $<action>$.str = cat2_str(make_str("goto "), $3);
-       }
-       | DO name '(' c_args ')'
-       {
-               $<action>$.code = W_DO;
-               $<action>$.command = cat_str(4, $2, make_str("("), $4, make_str(")"));
-               $<action>$.str = cat2_str(make_str("do"), mm_strdup($<action>$.command));
-       }
-       | DO SQL_BREAK
-       {
-               $<action>$.code = W_BREAK;
-               $<action>$.command = NULL;
-               $<action>$.str = make_str("break");
-       }
-       | SQL_CALL name '(' c_args ')'
-       {
-               $<action>$.code = W_DO;
-               $<action>$.command = cat_str(4, $2, make_str("("), $4, make_str(")"));
-               $<action>$.str = cat2_str(make_str("call"), mm_strdup($<action>$.command));
-       }
-       ;
+action : CONTINUE_P
+               {
+                       $<action>$.code = W_NOTHING;
+                       $<action>$.command = NULL;
+                       $<action>$.str = make_str("continue");
+               }
+               | SQL_SQLPRINT
+               {
+                       $<action>$.code = W_SQLPRINT;
+                       $<action>$.command = NULL;
+                       $<action>$.str = make_str("sqlprint");
+               }
+               | SQL_STOP
+               {
+                       $<action>$.code = W_STOP;
+                       $<action>$.command = NULL;
+                       $<action>$.str = make_str("stop");
+               }
+               | SQL_GOTO name
+               {
+                       $<action>$.code = W_GOTO;
+                       $<action>$.command = strdup($2);
+                       $<action>$.str = cat2_str(make_str("goto "), $2);
+               }
+               | SQL_GO TO name
+               {
+                       $<action>$.code = W_GOTO;
+                       $<action>$.command = strdup($3);
+                       $<action>$.str = cat2_str(make_str("goto "), $3);
+               }
+               | DO name '(' c_args ')'
+               {
+                       $<action>$.code = W_DO;
+                       $<action>$.command = cat_str(4, $2, make_str("("), $4, make_str(")"));
+                       $<action>$.str = cat2_str(make_str("do"), mm_strdup($<action>$.command));
+               }
+               | DO SQL_BREAK
+               {
+                       $<action>$.code = W_BREAK;
+                       $<action>$.command = NULL;
+                       $<action>$.str = make_str("break");
+               }
+               | SQL_CALL name '(' c_args ')'
+               {
+                       $<action>$.code = W_DO;
+                       $<action>$.command = cat_str(4, $2, make_str("("), $4, make_str(")"));
+                       $<action>$.str = cat2_str(make_str("call"), mm_strdup($<action>$.command));
+               }
+               | SQL_CALL name
+               {
+                       $<action>$.code = W_DO;
+                       $<action>$.command = cat2_str($2, make_str("()"));
+                       $<action>$.str = cat2_str(make_str("call"), mm_strdup($<action>$.command));
+               }
+               ;
 
 /* some other stuff for ecpg */
 
 /* additional unreserved keywords */
-ECPGKeywords:  SQL_BREAK               { $$ = make_str("break"); }
-               | SQL_CALL                              { $$ = make_str("call"); }
-               | SQL_CARDINALITY               { $$ = make_str("cardinality"); }
-               | SQL_CONNECT                   { $$ = make_str("connect"); }
-               | SQL_CONTINUE                  { $$ = make_str("continue"); }
-               | SQL_COUNT                             { $$ = make_str("count"); }
-               | SQL_DATA                              { $$ = make_str("data"); }
+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_DATA                                              { $$ = make_str("data"); }
                | SQL_DATETIME_INTERVAL_CODE    { $$ = make_str("datetime_interval_code"); }
                | SQL_DATETIME_INTERVAL_PRECISION       { $$ = make_str("datetime_interval_precision"); }
-               | SQL_DEALLOCATE                { $$ = make_str("deallocate"); }
-               | SQL_DISCONNECT                { $$ = make_str("disconnect"); }
-               | 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_NAME                              { $$ = make_str("name"); }
-               | SQL_NULLABLE                  { $$ = make_str("nullable"); }
-               | SQL_OCTET_LENGTH              { $$ = make_str("octet_length"); }
-               | SQL_OPEN                              { $$ = make_str("open"); }
-               | SQL_PREPARE                   { $$ = make_str("prepare"); }
-               | SQL_RELEASE                   { $$ = make_str("release"); }
+               | 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_SQLERROR                  { $$ = make_str("sqlerror"); }
-               | SQL_SQLPRINT                  { $$ = make_str("sqlprint"); }
-               | SQL_SQLWARNING                { $$ = make_str("sqlwarning"); }
-               | SQL_STOP                              { $$ = make_str("stop"); }
-               | SQL_VAR                               { $$ = make_str("var"); }
-               | SQL_WHENEVER                  { $$ = make_str("whenever"); }
+               | 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"); }
                ;
 
-/* additional keywords that can be SQL type names (but not ECPGColLabels) */
-ECPGTypeName:  SQL_BOOL                { $$ = make_str("bool"); }
-               | SQL_INT                       { $$ = make_str("int"); }
-               | SQL_LONG                      { $$ = make_str("long"); }
-               | SQL_SHORT                     { $$ = make_str("short"); }
-               | SQL_STRUCT            { $$ = make_str("struct"); }
-               | SQL_SIGNED            { $$ = make_str("signed"); }
-               | SQL_UNSIGNED          { $$ = make_str("unsigned"); }
+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"); }
                ;
 
-opt_symbol:    symbol          { $$ = $1; }
-               | /*EMPTY*/     { $$ = EMPTY; }
+/* 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; };
+symbol: ColLabel                                       { $$ = $1; }
+               ;
 
 /*
  * Name classification hierarchy.
  *
  * IDENT is the lexeme returned by the lexer for identifiers that match
  * no known keyword.  In most cases, we can accept certain keywords as
- * names, not only IDENTs.  We prefer to accept as many such keywords
+ * names, not only IDENTs.     We prefer to accept as many such keywords
  * as possible to minimize the impact of "reserved words" on programmers.
  * So, we divide names into several possible classes.  The classification
  * is chosen in part to make keywords acceptable as names wherever possible.
  */
 
-/* Column identifier --- names that can be column, table, etc names.
- */
-ColId:  ident                                                  { $$ = $1; }
-               | unreserved_keyword                    { $$ = $1; }
-               | col_name_keyword                              { $$ = $1; }
-               | ECPGKeywords                  { $$ = $1; }
-               | CHAR                                                  { $$ = make_str("char"); }
+ECPGColId: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"); }
                ;
-
-/* Type identifier --- names that can be type names.
+/* Column identifier --- names that can be column, table, etc names.
  */
-type_name:  ident                                              { $$ = $1; }
-               | unreserved_keyword                    { $$ = $1; }
-               | ECPGKeywords                  { $$ = $1; }
-               | ECPGTypeName                                  { $$ = $1; }
-               ;
-
-/* Function identifier --- names that can be function names.
+ColId: ident                                   { $$ = $1; }
+               | unreserved_keyword            { $$ = $1; }
+               | col_name_keyword              { $$ = $1; }
+               | ECPGKeywords                  { $$ = $1; }
+               | ECPGCKeywords                 { $$ = $1; }
+               | CHAR_P                        { $$ = make_str("char"); }
+               | VALUES                        { $$ = make_str("values"); }
+               ;
+/* Type/function identifier --- names that can be type names.
  */
-func_name:  ident                                              { $$ = $1; }
-               | unreserved_keyword                    { $$ = $1; }
-               | func_name_keyword                             { $$ = $1; }
-               | ECPGKeywords                  { $$ = $1; }
+type_function_name:    ident                                   { $$ = $1; }
+               | unreserved_keyword            { $$ = $1; }
+               | type_func_name_keyword                { $$ = $1; }
+               | ECPGKeywords                          { $$ = $1; }
+               | ECPGTypeName                          { $$ = $1; }
+               | ECPGCKeywords                         { $$ = $1; }
                ;
 
 /* Column label --- allowed labels in "AS" clauses.
  * This presently includes *all* Postgres keywords.
  */
-ColLabel:  ECPGColLabel                                        { $$ = $1; }
-               | ECPGTypeName                                  { $$ = $1; }
-               | CHAR                                                  { $$ = make_str("char"); }
-               | UNION                                                 { $$ = make_str("union"); }
+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:  ident                     { $$ = $1; }
+               | col_name_keyword              { $$ = $1; }
+               | type_func_name_keyword        { $$ = $1; }
+               | ECPGKeywords_vanames          { $$ = $1; }
                ;
 
-ECPGColLabel:  ident                                   { $$ = $1; }
-               | unreserved_keyword                    { $$ = $1; }
-               | col_name_keyword                              { $$ = $1; }
-               | func_name_keyword                             { $$ = $1; }
-               | reserved_keyword                              { $$ = $1; }
-               | ECPGKeywords                  { $$ = $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
@@ -5098,163 +6454,256 @@ ECPGColLabel:  ident                                  { $$ = $1; }
 
 /* "Unreserved" keywords --- available for use as any kind of name.
  */
-unreserved_keyword:
-                 ABORT_TRANS                                   { $$ = make_str("abort"); }
-               | ABSOLUTE                                              { $$ = make_str("absolute"); }
-               | ACCESS                                                { $$ = make_str("access"); }
-               | ACTION                                                { $$ = make_str("action"); }
-               | ADD                                                   { $$ = make_str("add"); }
-               | AFTER                                                 { $$ = make_str("after"); }
-               | AGGREGATE                                             { $$ = make_str("aggregate"); }
-               | ALTER                                                 { $$ = make_str("alter"); }
-               | AT                                                    { $$ = make_str("at"); }
-               | AUTHORIZATION                                 { $$ = make_str("authorization"); }
-               | BACKWARD                                              { $$ = make_str("backward"); }
-               | BEFORE                                                { $$ = make_str("before"); }
-               | BEGIN_TRANS                                   { $$ = make_str("begin"); }
-               | BY                                                    { $$ = make_str("by"); }
-               | CACHE                                                 { $$ = make_str("cache"); }
-               | CASCADE                                               { $$ = make_str("cascade"); }
-               | CHAIN                                                 { $$ = make_str("chain"); }
-               | CHARACTERISTICS                               { $$ = make_str("characteristics"); }
-               | CHECKPOINT                                    { $$ = make_str("checkpoint"); }
-               | CLOSE                                                 { $$ = make_str("close"); }
-               | CLUSTER                                               { $$ = make_str("cluster"); }
-               | COMMENT                                               { $$ = make_str("comment"); }
-               | COMMIT                                                { $$ = make_str("commit"); }
-               | COMMITTED                                             { $$ = make_str("committed"); }
-               | CONSTRAINTS                                   { $$ = make_str("constraints"); }
-               | COPY                                                  { $$ = make_str("copy"); }
-               | CREATE                                                { $$ = make_str("create"); }
-               | CREATEDB                                              { $$ = make_str("createdb"); }
-               | CREATEUSER                                    { $$ = make_str("createuser"); }
-               | CURSOR                                                { $$ = make_str("cursor"); }
-               | CYCLE                                                 { $$ = make_str("cycle"); }
-               | DATABASE                                              { $$ = make_str("database"); }
-               | DAY_P                                                 { $$ = make_str("day"); }
-               | DECLARE                                               { $$ = make_str("declare"); }
-               | DEFERRED                                              { $$ = make_str("deferred"); }
-               | DELETE                                                { $$ = make_str("delete"); }
-               | DELIMITERS                                    { $$ = make_str("delimiters"); }
-               | DOUBLE                                                { $$ = make_str("double"); }
-               | DROP                                                  { $$ = make_str("drop"); }
-               | EACH                                                  { $$ = make_str("each"); }
-               | ENCODING                                              { $$ = make_str("encoding"); }
-               | ENCRYPTED                                             { $$ = make_str("encrypted"); }
-               | ESCAPE                                                { $$ = make_str("escape"); }
-               | EXCLUSIVE                                             { $$ = make_str("exclusive"); }
-               | EXECUTE                                               { $$ = make_str("execute"); }
-               | EXPLAIN                                               { $$ = make_str("explain"); }
-               | FETCH                                                 { $$ = make_str("fetch"); }
-               | FORCE                                                 { $$ = make_str("force"); }
-               | FORWARD                                               { $$ = make_str("forward"); }
-               | FUNCTION                                              { $$ = make_str("function"); }
-               | GLOBAL                                                { $$ = make_str("global"); }
-               | GRANT                                                 { $$ = make_str("grant"); }
-               | HANDLER                                               { $$ = make_str("handler"); }
-               | HOUR_P                                                { $$ = make_str("hour"); }
-               | IMMEDIATE                                             { $$ = make_str("immediate"); }
-               | INCREMENT                                             { $$ = make_str("increment"); }
-               | INDEX                                                 { $$ = make_str("index"); }
-               | INHERITS                                              { $$ = make_str("inherits"); }
-               | INOUT                                                 { $$ = make_str("inout"); }
-               | INSENSITIVE                                   { $$ = make_str("insensitive"); }
-               | INSERT                                                { $$ = make_str("insert"); }
-               | INSTEAD                                               { $$ = make_str("instead"); }
-               | ISOLATION                                             { $$ = make_str("isolation"); }
-               | KEY                                                   { $$ = make_str("key"); }
-               | LANGUAGE                                              { $$ = make_str("language"); }
-               | LANCOMPILER                                   { $$ = make_str("lancompiler"); }
-               | 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"); }
-               | 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"); }
-               | NAMES                                                 { $$ = make_str("names"); }
-               | NATIONAL                                              { $$ = make_str("national"); }
-               | NEXT                                                  { $$ = make_str("next"); }
-               | NO                                                    { $$ = make_str("no"); }
-               | NOCREATEDB                                    { $$ = make_str("nocreatedb"); }
-               | NOCREATEUSER                                  { $$ = make_str("nocreateuser"); }
-               | NOTHING                                               { $$ = make_str("nothing"); }
-               | NOTIFY                                                { $$ = make_str("notify"); }
-               | OF                                                    { $$ = make_str("of"); }
-               | OIDS                                                  { $$ = make_str("oids"); }
-               | OPERATOR                                              { $$ = make_str("operator"); }
-               | OPTION                                                { $$ = make_str("option"); }
-               | OUT                                                   { $$ = make_str("out"); }
-               | OWNER                                                 { $$ = make_str("owner"); }
-               | PARTIAL                                               { $$ = make_str("partial"); }
-               | PASSWORD                                              { $$ = make_str("password"); }
-               | PATH_P                                                { $$ = make_str("path"); }
-               | PENDANT                                               { $$ = make_str("pendant"); }
-               | PRECISION                                             { $$ = make_str("precision"); }
-               | PRIOR                                                 { $$ = make_str("prior"); }
-               | PRIVILEGES                                    { $$ = make_str("privileges"); }
-               | PROCEDURAL                                    { $$ = make_str("procedural"); }
-               | PROCEDURE                                             { $$ = make_str("procedure"); }
-               | READ                                                  { $$ = make_str("read"); }
-               | REINDEX                                               { $$ = make_str("reindex"); }
-               | RELATIVE                                              { $$ = make_str("relative"); }
-               | RENAME                                                { $$ = make_str("rename"); }
-               | REPLACE                                               { $$ = make_str("replace"); }
-               | RESET                                                 { $$ = make_str("reset"); }
-               | RESTRICT                                              { $$ = make_str("restrict"); }
-               | RETURNS                                               { $$ = make_str("returns"); }
-               | REVOKE                                                { $$ = make_str("revoke"); }
-               | ROLLBACK                                              { $$ = make_str("rollback"); }
-               | ROW                                                   { $$ = make_str("row"); }
-               | RULE                                                  { $$ = make_str("rule"); }
-               | SCHEMA                                                { $$ = make_str("schema"); }
-               | SCROLL                                                { $$ = make_str("scroll"); }
-               | SECOND_P                                              { $$ = make_str("second"); }
-               | SESSION                                               { $$ = make_str("session"); }
-               | SEQUENCE                                              { $$ = make_str("sequence"); }
-               | SERIALIZABLE                                  { $$ = make_str("serializable"); }
-               | SET                                                   { $$ = make_str("set"); }
-               | SHARE                                                 { $$ = make_str("share"); }
-               | SHOW                                                  { $$ = make_str("show"); }
-               | START                                                 { $$ = make_str("start"); }
-               | STATEMENT                                             { $$ = make_str("statement"); }
-               | STATISTICS                                    { $$ = make_str("statistics"); }
-               | STDIN                                                 { $$ = make_str("stdin"); }
-               | STDOUT                                                { $$ = make_str("stdout"); }
-               | STORAGE                                               { $$ = make_str("storage"); }
-               | SYSID                                                 { $$ = make_str("sysid"); }
-               | TEMP                                                  { $$ = make_str("temp"); }
-               | TEMPLATE                                              { $$ = make_str("template"); }
-               | TEMPORARY                                             { $$ = make_str("temporary"); }
-               | TOAST                                                 { $$ = make_str("toast"); }
-               | TRANSACTION                                   { $$ = make_str("transaction"); }
-               | TRIGGER                                               { $$ = make_str("trigger"); }
-               | TRUNCATE                                              { $$ = make_str("truncate"); }
-               | TRUSTED                                               { $$ = make_str("trusted"); }
-               | TYPE_P                                                { $$ = make_str("type"); }
-               | UNENCRYPTED                                   { $$ = make_str("unencrypted"); }
-               | UNKNOWN                                               { $$ = make_str("unknown"); }
-               | UNLISTEN                                              { $$ = make_str("unlisten"); }
-               | UNTIL                                                 { $$ = make_str("until"); }
-               | UPDATE                                                { $$ = make_str("update"); }
-               | USAGE                                                 { $$ = make_str("usage"); }
-               | VACUUM                                                { $$ = make_str("vacuum"); }
-               | VALID                                                 { $$ = make_str("valid"); }
-               | VALUES                                                { $$ = make_str("values"); }
-               | VARYING                                               { $$ = make_str("varying"); }
-               | VERSION                                               { $$ = make_str("version"); }
-               | VIEW                                                  { $$ = make_str("view"); }
-               | WITH                                                  { $$ = make_str("with"); }
-               | WITHOUT                                               { $$ = make_str("without"); }
-               | WORK                                                  { $$ = make_str("work"); }
-               | YEAR_P                                                { $$ = make_str("year"); }
-               | ZONE                                                  { $$ = make_str("zone"); }
+/* 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"); }
+               | CURSOR                        { $$ = make_str("cursor"); }
+               | CYCLE                         { $$ = make_str("cycle"); }
+               | 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"); }
+               | 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"); }
+               | WITH                          { $$ = make_str("with"); }
+               | 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"); }
                ;
 
 /* Column identifier --- keywords that can be column, table, etc names.
@@ -5268,29 +6717,55 @@ unreserved_keyword:
  * looks too much like a function call for an LR(1) parser.
  */
 col_name_keyword:
-                 BIT                                                   { $$ = make_str("bit"); }
+               BIGINT                  { $$ = make_str("bigint");}
+               | BIT                   { $$ = make_str("bit"); }
 /* CHAR must be excluded from ECPGColLabel because of conflict with UNSIGNED
-               | CHAR                                                  { $$ = make_str("char"); }
+               | CHAR_P                { $$ = make_str("char"); }
  */
-               | CHARACTER                                             { $$ = make_str("character"); }
-               | COALESCE                                              { $$ = make_str("coalesce"); }
-               | DEC                                                   { $$ = make_str("dec"); }
-               | DECIMAL                                               { $$ = make_str("decimal"); }
-               | EXISTS                                                { $$ = make_str("exists"); }
-               | EXTRACT                                               { $$ = make_str("extract"); }
-               | FLOAT                                                 { $$ = make_str("float"); }
-               | INTERVAL                                              { $$ = make_str("interval"); }
-               | NCHAR                                                 { $$ = make_str("nchar"); }
-               | NONE                                                  { $$ = make_str("none"); }
-               | NULLIF                                                { $$ = make_str("nullif"); }
-               | NUMERIC                                               { $$ = make_str("numeric"); }
-               | POSITION                                              { $$ = make_str("position"); }
-               | SETOF                                                 { $$ = make_str("setof"); }
-               | SUBSTRING                                             { $$ = make_str("substring"); }
-               | TIME                                                  { $$ = make_str("time"); }
-               | TIMESTAMP                                             { $$ = make_str("timestamp"); }
-               | TRIM                                                  { $$ = make_str("trim"); }
-               | VARCHAR                                               { $$ = make_str("varchar"); }
+               | CHARACTER             { $$ = make_str("character"); }
+               | COALESCE              { $$ = make_str("coalesce"); }
+               | DEC                   { $$ = make_str("dec"); }
+               | DECIMAL_P             { $$ = make_str("decimal"); }
+               | EXISTS                { $$ = make_str("exists"); }
+               | EXTRACT               { $$ = make_str("extract"); }
+               | FLOAT_P               { $$ = make_str("float"); }
+               | GREATEST              { $$ = make_str("greatest"); }
+               | INOUT                 { $$ = make_str("inout"); }
+/* INT must be excluded from ECPGColLabel because of conflict
+               | INT_P                 { $$ = make_str("int"); }
+ */
+               | INTEGER               { $$ = make_str("integer"); }
+               | INTERVAL              { $$ = make_str("interval"); }
+               | LEAST                 { $$ = make_str("least"); }
+               | NATIONAL              { $$ = make_str("national"); }
+               | NCHAR                 { $$ = make_str("nchar"); }
+               | NONE                  { $$ = make_str("none"); }
+               | NULLIF                { $$ = make_str("nullif"); }
+               | NUMERIC               { $$ = make_str("numeric"); }
+               | OUT_P                 { $$ = make_str("out"); }
+               | OVERLAY               { $$ = make_str("overlay"); }
+               | POSITION              { $$ = make_str("position"); }
+               | PRECISION             { $$ = make_str("precision"); }
+               | REAL                  { $$ = make_str("real"); }
+               | ROW                   { $$ = make_str("row"); }
+               | SETOF                 { $$ = make_str("setof"); }
+               | SMALLINT              { $$ = make_str("smallint"); }
+               | SUBSTRING             { $$ = make_str("substring"); }
+               | TIME                  { $$ = make_str("time"); }
+               | TIMESTAMP             { $$ = make_str("timestamp"); }
+               | TREAT                 { $$ = make_str("treat"); }
+               | TRIM                  { $$ = make_str("trim"); }
+               /* VALUES creates a shift/reduce problem if listed here
+               | VALUES                { $$ = make_str("values"); } */
+               | VARCHAR               { $$ = make_str("varchar"); }
+               | XMLATTRIBUTES         { $$ = make_str("xmlattributes"); }
+               | XMLCONCAT             { $$ = make_str("xmlconcat"); }
+               | XMLELEMENT            { $$ = make_str("xmlelement"); }
+               | XMLFOREST             { $$ = make_str("xmlforest"); }
+               | XMLPARSE              { $$ = make_str("xmlparse"); }
+               | XMLPI                 { $$ = make_str("xmlpi"); }
+               | XMLROOT               { $$ = make_str("xmlroot"); }
+               | XMLSERIALIZE          { $$ = make_str("xmlserialize"); }
                ;
 
 /* Function identifier --- keywords that can be function names.
@@ -5301,29 +6776,29 @@ col_name_keyword:
  *
  * Do not include POSITION, SUBSTRING, etc here since they have explicit
  * productions in a_expr to support the goofy SQL9x argument syntax.
- *  - thomas 2000-11-28
+ *     - thomas 2000-11-28
  */
-func_name_keyword:
-                 BETWEEN                                               { $$ = make_str("between"); }
-               | BINARY                                                { $$ = make_str("binary"); }
-               | CROSS                                                 { $$ = make_str("cross"); }
-               | FREEZE                                                { $$ = make_str("freeze"); }
-               | FULL                                                  { $$ = make_str("full"); }
-               | ILIKE                                                 { $$ = make_str("ilike"); }
-               | IN                                                    { $$ = make_str("in"); }
-               | INNER_P                                               { $$ = make_str("inner"); }
-               | IS                                                    { $$ = make_str("is"); }
-               | ISNULL                                                { $$ = make_str("isnull"); }
-               | JOIN                                                  { $$ = make_str("join"); }
-               | LEFT                                                  { $$ = make_str("left"); }
-               | LIKE                                                  { $$ = make_str("like"); }
-               | NATURAL                                               { $$ = make_str("natural"); }
-               | NOTNULL                                               { $$ = make_str("notnull"); }
-               | OUTER_P                                               { $$ = make_str("outer"); }
-               | OVERLAPS                                              { $$ = make_str("overlaps"); }
-               | PUBLIC                                                { $$ = make_str("public"); }
-               | RIGHT                                                 { $$ = make_str("right"); }
-               | VERBOSE                                               { $$ = make_str("verbose"); }
+type_func_name_keyword:
+                 AUTHORIZATION         { $$ = make_str("authorization"); }
+               | BETWEEN               { $$ = make_str("between"); }
+               | BINARY                { $$ = make_str("binary"); }
+               | CROSS                 { $$ = make_str("cross"); }
+               | FREEZE                { $$ = make_str("freeze"); }
+               | FULL                  { $$ = make_str("full"); }
+               | ILIKE                 { $$ = make_str("ilike"); }
+               | INNER_P               { $$ = make_str("inner"); }
+               | IS                    { $$ = make_str("is"); }
+               | ISNULL                { $$ = make_str("isnull"); }
+               | JOIN                  { $$ = make_str("join"); }
+               | LEFT                  { $$ = make_str("left"); }
+               | LIKE                  { $$ = make_str("like"); }
+               | NATURAL               { $$ = make_str("natural"); }
+               | NOTNULL               { $$ = make_str("notnull"); }
+               | OUTER_P               { $$ = make_str("outer"); }
+               | OVERLAPS              { $$ = make_str("overlaps"); }
+               | RIGHT                 { $$ = make_str("right"); }
+               | SIMILAR               { $$ = make_str("similar"); }
+               | VERBOSE               { $$ = make_str("verbose"); }
                ;
 
 /* Reserved keyword --- these keywords are usable only as a ColLabel.
@@ -5333,229 +6808,279 @@ func_name_keyword:
  * forced to.
  */
 reserved_keyword:
-                 ALL                                                   { $$ = make_str("all"); }
-               | ANALYSE                                               { $$ = make_str("analyse"); } /* British */
-               | ANALYZE                                               { $$ = make_str("analyze"); }
-               | AND                                                   { $$ = make_str("and"); }
-               | ANY                                                   { $$ = make_str("any"); }
-               | AS                                                    { $$ = make_str("as"); }
-               | ASC                                                   { $$ = make_str("asc"); }
-               | BOTH                                                  { $$ = make_str("both"); }
-               | CASE                                                  { $$ = make_str("case"); }
-               | CAST                                                  { $$ = make_str("cast"); }
-               | CHECK                                                 { $$ = make_str("check"); }
-               | COLLATE                                               { $$ = make_str("collate"); }
-               | COLUMN                                                { $$ = make_str("column"); }
-               | CONSTRAINT                                    { $$ = make_str("constraint"); }
-               | CURRENT_DATE                                  { $$ = make_str("current_date"); }
-               | CURRENT_TIME                                  { $$ = make_str("current_time"); }
-               | CURRENT_TIMESTAMP                             { $$ = make_str("current_timestamp"); }
-               | CURRENT_USER                                  { $$ = make_str("current_user"); }
-               | DEFAULT                                               { $$ = make_str("default"); }
-               | DEFERRABLE                                    { $$ = make_str("deferrable"); }
-               | DESC                                                  { $$ = make_str("desc"); }
-               | DISTINCT                                              { $$ = make_str("distinct"); }
-               | DO                                                    { $$ = make_str("do"); }
-               | ELSE                                                  { $$ = make_str("else"); }
-               | END_TRANS                                             { $$ = make_str("end"); }
-               | EXCEPT                                                { $$ = make_str("except"); }
-               | FALSE_P                                               { $$ = make_str("false"); }
-               | FOR                                                   { $$ = make_str("for"); }
-               | FOREIGN                                               { $$ = make_str("foreign"); }
-               | FROM                                                  { $$ = make_str("from"); }
-               | GROUP                                                 { $$ = make_str("group"); }
-               | HAVING                                                { $$ = make_str("having"); }
-               | INITIALLY                                             { $$ = make_str("initially"); }
-               | INTERSECT                                             { $$ = make_str("intersect"); }
-               | INTO                                                  { $$ = make_str("into"); }
-               | LEADING                                               { $$ = make_str("leading"); }
-               | LIMIT                                                 { $$ = make_str("limit"); }
-               | NEW                                                   { $$ = make_str("new"); }
-               | NOT                                                   { $$ = make_str("not"); }
-               | NULL_P                                                { $$ = make_str("null"); }
-               | OFF                                                   { $$ = make_str("off"); }
-               | OFFSET                                                { $$ = make_str("offset"); }
-               | OLD                                                   { $$ = make_str("old"); }
-               | ON                                                    { $$ = make_str("on"); }
-               | ONLY                                                  { $$ = make_str("only"); }
-               | OR                                                    { $$ = make_str("or"); }
-               | ORDER                                                 { $$ = make_str("order"); }
-               | PRIMARY                                               { $$ = make_str("primary"); }
-               | REFERENCES                                    { $$ = make_str("references"); }
-               | SELECT                                                { $$ = make_str("select"); }
-               | SESSION_USER                                  { $$ = make_str("session_user"); }
-               | SOME                                                  { $$ = make_str("some"); }
-               | TABLE                                                 { $$ = make_str("table"); }
-               | THEN                                                  { $$ = make_str("then"); }
-               | TO                                                    { $$ = make_str("to"); }
-               | TRAILING                                              { $$ = make_str("trailing"); }
-               | TRUE_P                                                { $$ = make_str("true"); }
+                 ALL                           { $$ = make_str("all"); }
+               | ANALYSE                       { $$ = make_str("analyse"); } /* British */
+               | ANALYZE                       { $$ = make_str("analyze"); }
+               | AND                           { $$ = make_str("and"); }
+               | ANY                           { $$ = make_str("any"); }
+               | ARRAY                         { $$ = make_str("array"); }
+               | AS                            { $$ = make_str("as"); }
+               | ASC                           { $$ = make_str("asc"); }
+               | ASYMMETRIC            { $$ = make_str("asymmetric"); }
+               | BOTH                          { $$ = make_str("both"); }
+               | CASE                          { $$ = make_str("case"); }
+               | CAST                          { $$ = make_str("cast"); }
+               | CHECK                         { $$ = make_str("check"); }
+               | COLLATE                       { $$ = make_str("collate"); }
+               | COLUMN                        { $$ = make_str("column"); }
+               | CONSTRAINT            { $$ = make_str("constraint"); }
+               | CREATE                        { $$ = make_str("create"); }
+               | CURRENT_P                     { $$ = make_str("current"); }
+               | CURRENT_DATE          { $$ = make_str("current_date"); }
+               | CURRENT_TIME          { $$ = make_str("current_time"); }
+               | CURRENT_TIMESTAMP     { $$ = make_str("current_timestamp"); }
+               | CURRENT_ROLE          { $$ = make_str("current_role"); }
+               | CURRENT_USER          { $$ = make_str("current_user"); }
+               | DEFAULT                       { $$ = make_str("default"); }
+               | DEFERRABLE            { $$ = make_str("deferrable"); }
+               | DESC                          { $$ = make_str("desc"); }
+               | DISTINCT                      { $$ = make_str("distinct"); }
+               | DO                            { $$ = make_str("do"); }
+               | ELSE                          { $$ = make_str("else"); }
+               | END_P                         { $$ = make_str("end"); }
+               | EXCEPT                        { $$ = make_str("except"); }
+               | FALSE_P                       { $$ = make_str("false"); }
+               | FOR                           { $$ = make_str("for"); }
+               | FOREIGN                       { $$ = make_str("foreign"); }
+               | FROM                          { $$ = make_str("from"); }
+               | GRANT                         { $$ = make_str("grant"); }
+               | GROUP_P                       { $$ = make_str("group"); }
+               | HAVING                        { $$ = make_str("having"); }
+               | IN_P                          { $$ = make_str("in"); }
+               | INITIALLY                     { $$ = make_str("initially"); }
+               | INTERSECT                     { $$ = make_str("intersect"); }
+               | INTO                          { $$ = make_str("into"); }
+               | LEADING                       { $$ = make_str("leading"); }
+               | LIMIT                         { $$ = make_str("limit"); }
+               | NEW                           { $$ = make_str("new"); }
+               | NOT                           { $$ = make_str("not"); }
+               | NULL_P                        { $$ = make_str("null"); }
+               | OFF                           { $$ = make_str("off"); }
+               | OFFSET                        { $$ = make_str("offset"); }
+               | OLD                           { $$ = make_str("old"); }
+               | ON                            { $$ = make_str("on"); }
+               | ONLY                          { $$ = make_str("only"); }
+               | OR                            { $$ = make_str("or"); }
+               | ORDER                         { $$ = make_str("order"); }
+               | PRIMARY                       { $$ = make_str("primary"); }
+               | REFERENCES                    { $$ = make_str("references"); }
+               | RETURNING                     { $$ = make_str("returning"); }
+               | SELECT                        { $$ = make_str("select"); }
+               | SESSION_USER                  { $$ = make_str("session_user"); }
+               | SOME                          { $$ = make_str("some"); }
+               | SYMMETRIC                     { $$ = make_str("symmetric"); }
+               | TABLE                         { $$ = make_str("table"); }
+               | THEN                          { $$ = make_str("then"); }
+/* TO must be excluded from ECPGColLabel because of a conflict in variable name parsing
+               | TO                            { $$ = make_str("to"); }
+ */
+               | TRAILING                      { $$ = make_str("trailing"); }
+               | TRUE_P                        { $$ = make_str("true"); }
 /* UNION must be excluded from ECPGColLabel because of conflict with s_union
-               | UNION                                                 { $$ = make_str("union"); }
+               | UNION                         { $$ = make_str("union"); }
  */
-               | UNIQUE                                                { $$ = make_str("unique"); }
-               | USER                                                  { $$ = make_str("user"); }
-               | USING                                                 { $$ = make_str("using"); }
-               | WHEN                                                  { $$ = make_str("when"); }
-               | WHERE                                                 { $$ = make_str("where"); }
+               | UNIQUE                        { $$ = make_str("unique"); }
+               | USER                          { $$ = make_str("user"); }
+               | USING                         { $$ = make_str("using"); }
+               | VARIADIC                      { $$ = make_str("variadic"); }
+               | WHEN                          { $$ = make_str("when"); }
+               | WHERE                         { $$ = make_str("where"); }
                ;
 
 
-into_list : coutputvariable | into_list ',' coutputvariable;
+into_list : coutputvariable | into_list ',' coutputvariable
+               ;
 
-ecpgstart: SQL_START { reset_variables(); };
+ecpgstart: SQL_START   {
+                               reset_variables();
+                               pacounter = 1;
+                       }
+               ;
 
-c_args: /* empty */            { $$ = EMPTY; }
-       | c_list                { $$ = $1; }
-       ;
+c_args: /*EMPTY*/              { $$ = EMPTY; }
+               | c_list                { $$ = $1; }
+               ;
 
 coutputvariable: cvariable indicator
-       {
-               add_variable(&argsresult, find_variable($1), find_variable($2)); 
-       }
-       | cvariable
-       {
-               add_variable(&argsresult, find_variable($1), &no_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 ($2 != NULL && (find_variable($2))->type->type == ECPGt_array)
-                       mmerror(PARSE_ERROR, ET_ERROR, "arrays of indicators are not allowed on input");
+               {
+                       if (find_variable($2)->type->type == ECPGt_array)
+                               mmerror(PARSE_ERROR, ET_ERROR, "arrays of indicators are not allowed on input");
 
-               add_variable(&argsinsert, find_variable($1), ($2 == NULL) ? &no_indicator : find_variable($2)); 
-       };
+                       add_variable_to_head(&argsinsert, find_variable($1), find_variable($2));
+                       $$ = create_questionmarks($1, false);
+               }
+               ;
 
 civar: cvariable
-       {
-               add_variable(&argsinsert, find_variable($1), &no_indicator); 
-               $$ = $1;
-       };
-
-cvariable: CVARIABLE   { $$ = $1; }
-
-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; }
-       ;
-
-ident: IDENT           { $$ = $1; }
-       | CSTRING       { $$ = make3_str(make_str("\""), $1, make_str("\"")); }
-       ;
-
-quoted_ident_stringvar: IDENT  { $$ = make3_str(make_str("\""), $1, make_str("\"")); }
-       | CSTRING       { $$ = make3_str(make_str("\""), $1, make_str("\"")); }
-       | char_variable 
-               {       $$ = make3_str(make_str("("), $1, make_str(")"));
+               {
+                       add_variable_to_head(&argsinsert, find_variable($1), &no_indicator);
+                       $$ = create_questionmarks($1, false);
                }
-       ;
+               ;
 
-/*
- * C stuff
- */
+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; }
+               ;
 
-cpp_line: CPP_LINE     { $$ = $1; };
+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;
 
-c_stuff_item: c_anything       { $$ = $1; }
-       | '(' ')'                               { $$ = make_str("()"); }
-       | '(' c_stuff ')'
+                       for (; *ptr; ptr++)
                        {
-                               $$ = cat_str(3, make_str("("), $2, make_str(")"));
+                               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;
+               }
+               ;
+ident: IDENT                           { $$ = $1; }
+               | CSTRING               { $$ = make3_str(make_str("\""), $1, make_str("\"")); }
+               ;
 
-c_stuff: c_stuff_item  { $$ = $1; }
-       | c_stuff c_stuff_item
-                       {
-                               $$ = cat2_str($1, $2);
-                       }
-       ;
+quoted_ident_stringvar: name
+                       { $$ = make3_str(make_str("\""), $1, make_str("\"")); }
+               | char_variable
+                       { $$ = make3_str(make_str("("), $1, make_str(")")); }
+               ;
 
-c_list: c_term                 { $$ = $1; }
-       | c_list ',' c_term     { $$ = cat_str(3, $1, make_str(","), $3); }
-       ;
+/*
+ * C stuff
+ */
 
-c_term:  c_stuff               { $$ = $1; }
-       | '{' c_list '}'        { $$ = cat_str(3, make_str("{"), $2, make_str("}")); }
-       ;
+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:  IDENT                             { $$ = $1; }
+               | CSTRING                       { $$ = make3_str(make_str("\""), $1, make_str("\"")); }
+               | Iconst                        { $$ = $1; }
+               | Fconst                        { $$ = $1; }
+               | 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(":"); }
+               ;
 
-c_thing:       c_anything      { $$ = $1; }
-       |       '('             { $$ = make_str("("); }
-       |       ')'             { $$ = make_str(")"); }
-       |       ','             { $$ = make_str(","); }
-       |       ';'             { $$ = make_str(";"); }
-       ;
+%%
 
-c_anything:  IDENT     { $$ = $1; }
-       | CSTRING       { $$ = make3_str(make_str("\""), $1, make_str("\"")); }
-       | PosIntConst   { $$ = $1; }
-       | Fconst        { $$ = $1; }
-       | 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("-="); } 
-       | SQL_BOOL      { $$ = make_str("bool"); }
-       | SQL_ENUM      { $$ = make_str("enum"); }
-        | SQL_INT      { $$ = make_str("int"); }
-       | SQL_LONG      { $$ = make_str("long"); }
-       | SQL_SHORT     { $$ = make_str("short"); }
-       | SQL_SIGNED    { $$ = make_str("signed"); }
-        | SQL_STRUCT   { $$ = make_str("struct"); }
-       | SQL_UNSIGNED  { $$ = make_str("unsigned"); }
-       | CHAR          { $$ = make_str("char"); }
-       | DOUBLE        { $$ = make_str("double"); }
-       | FLOAT         { $$ = make_str("float"); }
-        | UNION                { $$ = make_str("union"); }
-       | VARCHAR       { $$ = make_str("varchar"); }
-        | '['          { $$ = make_str("["); }
-       | ']'           { $$ = make_str("]"); }
-       | '='           { $$ = make_str("="); }
-       ;
+void base_yyerror(const char * error)
+{
+       char buf[1024];
 
-blockstart : '{'
-       {
-           braces_open++;
-           $$ = make_str("{");
-       };
+       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);
+}
 
-blockend : '}'
-       {
-           remove_variables(braces_open--);
-           $$ = make_str("}");
-       };
+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
 
-void yyerror( char * error)
-{      char buf[1024];
-        snprintf(buf,sizeof buf,"%s at or near \"%s\"",error,yytext);
-        buf[sizeof(buf)-1]=0;
-       mmerror(PARSE_ERROR, ET_ERROR, buf);
-}
+#include "pgc.c"