Update keyword lists per suggestions by Peter. There are now four
authorTom Lane
Fri, 16 Nov 2001 04:08:33 +0000 (04:08 +0000)
committerTom Lane
Fri, 16 Nov 2001 04:08:33 +0000 (04:08 +0000)
mutually exclusive keyword lists spanning all known keywords ---
including AS.  Moved COALESCE and a few other ColLabels into the
can-be-ColId list.

src/backend/parser/gram.y
src/interfaces/ecpg/preproc/preproc.y

index 5a2324de20fdce78a8f51705e27c84215891c137..b3b09c068ff9e409c522f738c0ea64212d220fbc 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.274 2001/11/12 21:04:45 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.275 2001/11/16 04:08:33 tgl Exp $
  *
  * HISTORY
  *   AUTHOR            DATE            MAJOR EVENT
@@ -268,7 +268,8 @@ static void doNegateFloat(Value *v);
 %type    Iconst
 %type         Sconst, comment_text
 %type         UserId, opt_boolean, var_value, ColId_or_Sconst
-%type         ColId, TypeFuncId, ColLabel
+%type         ColId, ColLabel, type_name, func_name_keyword
+%type         col_name_keyword, unreserved_keyword, reserved_keyword
 %type    zone_value
 
 %type    TableConstraint
@@ -296,8 +297,8 @@ static void doNegateFloat(Value *v);
  * This gets annoying when trying to also retain Postgres' nice
  *  type-extensible features, but we don't really have a choice.
  * - thomas 1997-10-11
- * NOTE: Whenever possible, try to add new keywords to the ColId list,
- * or failing that, at least to the ColLabel list.
+ * NOTE: don't forget to add new keywords to the appropriate one of
+ * the reserved-or-not-so-reserved keyword lists, below.
  */
 
 /* Keywords (in SQL92 reserved words) */
@@ -2631,13 +2632,13 @@ func_return:  func_type
 
 /*
  * We would like to make the second production here be ColId '.' ColId etc,
- * but that causes reduce/reduce conflicts.  TypeFuncId is next best choice.
+ * but that causes reduce/reduce conflicts.  type_name is next best choice.
  */
 func_type: Typename
                {
                    $$ = $1;
                }
-       | TypeFuncId '.' ColId '%' TYPE_P
+       | type_name '.' ColId '%' TYPE_P
                {
                    $$ = makeNode(TypeName);
                    $$->name = $1;
@@ -4073,7 +4074,7 @@ ConstTypename:  GenericType
        | ConstDatetime
        ;
 
-GenericType:  TypeFuncId
+GenericType:  type_name
                {
                    $$ = makeNode(TypeName);
                    $$->name = xlateSqlType($1);
@@ -5658,22 +5659,61 @@ Iconst:  ICONST                         { $$ = $1; };
 Sconst:  SCONST                            { $$ = $1; };
 UserId:  ColId                         { $$ = $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
+ * 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; }
+       ;
+
+/* Type identifier --- names that can be type names.
+ */
+type_name:  IDENT                      { $$ = $1; }
+       | unreserved_keyword            { $$ = $1; }
+       ;
+
+/* Function identifier --- names that can be function names.
+ */
+func_name:  IDENT                      { $$ = xlateSqlFunc($1); }
+       | unreserved_keyword            { $$ = xlateSqlFunc($1); }
+       | func_name_keyword             { $$ = xlateSqlFunc($1); }
+       ;
+
+/* Column label --- allowed labels in "AS" clauses.
+ * This presently includes *all* Postgres keywords.
+ */
+ColLabel:  IDENT                       { $$ = $1; }
+       | unreserved_keyword            { $$ = $1; }
+       | col_name_keyword              { $$ = $1; }
+       | func_name_keyword             { $$ = $1; }
+       | reserved_keyword              { $$ = $1; }
+       ;
+
+
 /*
  * Keyword classification lists.  Generally, every keyword present in
- * the Postgres grammar should be in one of these lists.  (Presently,
- * "AS" is the sole exception: it is our only completely-reserved word.)
+ * the Postgres grammar should appear in exactly one of these lists.
  *
- * Put a new keyword into the earliest list (of TypeFuncId, ColId, ColLabel)
- * that it can go into without creating shift or reduce conflicts.  The
- * earlier lists define "less reserved" categories of keywords.  Notice that
- * each list includes by reference the ones before it.
+ * Put a new keyword into the first list that it can go into without causing
+ * shift or reduce conflicts.  The earlier lists define "less reserved"
+ * categories of keywords.
  */
 
-/* Type/func identifier --- names that can be type and function names
- * (as well as ColIds --- ie, these are completely unreserved keywords).
+/* "Unreserved" keywords --- available for use as any kind of name.
  */
-TypeFuncId:  IDENT                     { $$ = $1; }
-       | ABORT_TRANS                   { $$ = "abort"; }
+unreserved_keyword:
+         ABORT_TRANS                   { $$ = "abort"; }
        | ABSOLUTE                      { $$ = "absolute"; }
        | ACCESS                        { $$ = "access"; }
        | ACTION                        { $$ = "action"; }
@@ -5829,58 +5869,94 @@ TypeFuncId:  IDENT                      { $$ = $1; }
        | ZONE                          { $$ = "zone"; }
        ;
 
-/* Column identifier --- names that can be column, table, etc names.
+/* Column identifier --- keywords that can be column, table, etc names.
  *
- * This contains the TypeFuncId list plus those keywords that conflict
- * only with typename productions, not with other uses.  Note that
- * most of these keywords will in fact be recognized as type names too;
- * they just have to have special productions for the purpose.
+ * Many of these keywords will in fact be recognized as type or function
+ * names too; but they have special productions for the purpose, and so
+ * can't be treated as "generic" type or function names.
  *
- * Most of these cannot be in TypeFuncId (ie, are not also usable as function
- * names) because they can be followed by '(' in typename productions, which
- * looks too much like a function call for a LALR(1) parser.
+ * The type names appearing here are not usable as function names
+ * because they can be followed by '(' in typename productions, which
+ * looks too much like a function call for aLR(1) parser.
  */
-ColId:  TypeFuncId                     { $$ = $1; }
-       | BIT                           { $$ = "bit"; }
+col_name_keyword:
+         BIT                           { $$ = "bit"; }
        | CHAR                          { $$ = "char"; }
        | CHARACTER                     { $$ = "character"; }
+       | COALESCE                      { $$ = "coalesce"; }
        | DEC                           { $$ = "dec"; }
        | DECIMAL                       { $$ = "decimal"; }
+       | EXISTS                        { $$ = "exists"; }
+       | EXTRACT                       { $$ = "extract"; }
        | FLOAT                         { $$ = "float"; }
        | INTERVAL                      { $$ = "interval"; }
        | NCHAR                         { $$ = "nchar"; }
        | NONE                          { $$ = "none"; }
+       | NULLIF                        { $$ = "nullif"; }
        | NUMERIC                       { $$ = "numeric"; }
+       | POSITION                      { $$ = "position"; }
        | SETOF                         { $$ = "setof"; }
+       | SUBSTRING                     { $$ = "substring"; }
        | TIME                          { $$ = "time"; }
        | TIMESTAMP                     { $$ = "timestamp"; }
+       | TRIM                          { $$ = "trim"; }
        | VARCHAR                       { $$ = "varchar"; }
        ;
 
-/* Column label --- allowed labels in "AS" clauses.
+/* Function identifier --- keywords that can be function names.
+ *
+ * Most of these are keywords that are used as operators in expressions;
+ * in general such keywords can't be column names because they would be
+ * ambiguous with variables, but they are unambiguous as function identifiers.
+ *
+ * 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
+ */
+func_name_keyword:
+         BETWEEN                       { $$ = "between"; }
+       | BINARY                        { $$ = "binary"; }
+       | CROSS                         { $$ = "cross"; }
+       | FREEZE                        { $$ = "freeze"; }
+       | FULL                          { $$ = "full"; }
+       | ILIKE                         { $$ = "ilike"; }
+       | IN                            { $$ = "in"; }
+       | INNER_P                       { $$ = "inner"; }
+       | IS                            { $$ = "is"; }
+       | ISNULL                        { $$ = "isnull"; }
+       | JOIN                          { $$ = "join"; }
+       | LEFT                          { $$ = "left"; }
+       | LIKE                          { $$ = "like"; }
+       | NATURAL                       { $$ = "natural"; }
+       | NOTNULL                       { $$ = "notnull"; }
+       | OUTER_P                       { $$ = "outer"; }
+       | OVERLAPS                      { $$ = "overlaps"; }
+       | PUBLIC                        { $$ = "public"; }
+       | RIGHT                         { $$ = "right"; }
+       | VERBOSE                       { $$ = "verbose"; }
+       ;
+
+/* Reserved keyword --- these keywords are usable only as a ColLabel.
  *
  * Keywords appear here if they could not be distinguished from variable,
- * type, or function names in some contexts.
- * When adding a ColLabel, consider whether it can be added to func_name.
+ * type, or function names in some contexts.  Don't put things here unless
+ * forced to.
  */
-ColLabel:  ColId                       { $$ = $1; }
-       | ALL                           { $$ = "all"; }
+reserved_keyword:
+         ALL                           { $$ = "all"; }
        | ANALYSE                       { $$ = "analyse"; } /* British */
        | ANALYZE                       { $$ = "analyze"; }
        | AND                           { $$ = "and"; }
        | ANY                           { $$ = "any"; }
+       | AS                            { $$ = "as"; }
        | ASC                           { $$ = "asc"; }
-       | BETWEEN                       { $$ = "between"; }
-       | BINARY                        { $$ = "binary"; }
        | BOTH                          { $$ = "both"; }
        | CASE                          { $$ = "case"; }
        | CAST                          { $$ = "cast"; }
        | CHECK                         { $$ = "check"; }
-       | COALESCE                      { $$ = "coalesce"; }
        | COLLATE                       { $$ = "collate"; }
        | COLUMN                        { $$ = "column"; }
        | CONSTRAINT                    { $$ = "constraint"; }
-       | CROSS                         { $$ = "cross"; }
        | CURRENT_DATE                  { $$ = "current_date"; }
        | CURRENT_TIME                  { $$ = "current_time"; }
        | CURRENT_TIMESTAMP             { $$ = "current_timestamp"; }
@@ -5893,34 +5969,19 @@ ColLabel:  ColId                        { $$ = $1; }
        | ELSE                          { $$ = "else"; }
        | END_TRANS                     { $$ = "end"; }
        | EXCEPT                        { $$ = "except"; }
-       | EXISTS                        { $$ = "exists"; }
-       | EXTRACT                       { $$ = "extract"; }
        | FALSE_P                       { $$ = "false"; }
        | FOR                           { $$ = "for"; }
        | FOREIGN                       { $$ = "foreign"; }
-       | FREEZE                        { $$ = "freeze"; }
        | FROM                          { $$ = "from"; }
-       | FULL                          { $$ = "full"; }
        | GROUP                         { $$ = "group"; }
        | HAVING                        { $$ = "having"; }
-       | ILIKE                         { $$ = "ilike"; }
-       | IN                            { $$ = "in"; }
        | INITIALLY                     { $$ = "initially"; }
-       | INNER_P                       { $$ = "inner"; }
        | INTERSECT                     { $$ = "intersect"; }
        | INTO                          { $$ = "into"; }
-       | IS                            { $$ = "is"; }
-       | ISNULL                        { $$ = "isnull"; }
-       | JOIN                          { $$ = "join"; }
        | LEADING                       { $$ = "leading"; }
-       | LEFT                          { $$ = "left"; }
-       | LIKE                          { $$ = "like"; }
        | LIMIT                         { $$ = "limit"; }
-       | NATURAL                       { $$ = "natural"; }
        | NEW                           { $$ = "new"; }
        | NOT                           { $$ = "not"; }
-       | NOTNULL                       { $$ = "notnull"; }
-       | NULLIF                        { $$ = "nullif"; }
        | NULL_P                        { $$ = "null"; }
        | OFF                           { $$ = "off"; }
        | OFFSET                        { $$ = "offset"; }
@@ -5929,65 +5990,24 @@ ColLabel:  ColId                        { $$ = $1; }
        | ONLY                          { $$ = "only"; }
        | OR                            { $$ = "or"; }
        | ORDER                         { $$ = "order"; }
-       | OUTER_P                       { $$ = "outer"; }
-       | OVERLAPS                      { $$ = "overlaps"; }
-       | POSITION                      { $$ = "position"; }
        | PRIMARY                       { $$ = "primary"; }
-       | PUBLIC                        { $$ = "public"; }
        | REFERENCES                    { $$ = "references"; }
-       | RIGHT                         { $$ = "right"; }
        | SELECT                        { $$ = "select"; }
        | SESSION_USER                  { $$ = "session_user"; }
        | SOME                          { $$ = "some"; }
-       | SUBSTRING                     { $$ = "substring"; }
        | TABLE                         { $$ = "table"; }
        | THEN                          { $$ = "then"; }
        | TO                            { $$ = "to"; }
        | TRAILING                      { $$ = "trailing"; }
-       | TRIM                          { $$ = "trim"; }
        | TRUE_P                        { $$ = "true"; }
        | UNION                         { $$ = "union"; }
        | UNIQUE                        { $$ = "unique"; }
        | USER                          { $$ = "user"; }
        | USING                         { $$ = "using"; }
-       | VERBOSE                       { $$ = "verbose"; }
        | WHEN                          { $$ = "when"; }
        | WHERE                         { $$ = "where"; }
        ;
 
-/* Function identifier --- names that can be function names.
- *
- * This contains the TypeFuncId list plus some ColLabel keywords
- * that are used as operators in expressions; in general such keywords
- * can't be ColId because they would be ambiguous with variable names,
- * but they are unambiguous as function identifiers.
- *
- * 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
- */
-func_name:  TypeFuncId                 { $$ = xlateSqlFunc($1); }
-       | BETWEEN                       { $$ = xlateSqlFunc("between"); }
-       | BINARY                        { $$ = xlateSqlFunc("binary"); }
-       | CROSS                         { $$ = xlateSqlFunc("cross"); }
-       | FREEZE                        { $$ = xlateSqlFunc("freeze"); }
-       | FULL                          { $$ = xlateSqlFunc("full"); }
-       | ILIKE                         { $$ = xlateSqlFunc("ilike"); }
-       | IN                            { $$ = xlateSqlFunc("in"); }
-       | INNER_P                       { $$ = xlateSqlFunc("inner"); }
-       | IS                            { $$ = xlateSqlFunc("is"); }
-       | ISNULL                        { $$ = xlateSqlFunc("isnull"); }
-       | JOIN                          { $$ = xlateSqlFunc("join"); }
-       | LEFT                          { $$ = xlateSqlFunc("left"); }
-       | LIKE                          { $$ = xlateSqlFunc("like"); }
-       | NATURAL                       { $$ = xlateSqlFunc("natural"); }
-       | NOTNULL                       { $$ = xlateSqlFunc("notnull"); }
-       | OUTER_P                       { $$ = xlateSqlFunc("outer"); }
-       | OVERLAPS                      { $$ = xlateSqlFunc("overlaps"); }
-       | PUBLIC                        { $$ = xlateSqlFunc("public"); }
-       | RIGHT                         { $$ = xlateSqlFunc("right"); }
-       | VERBOSE                       { $$ = xlateSqlFunc("verbose"); }
-       ;
 
 SpecialRuleRelation:  OLD
                {
index 04296d42aab8d865301b1a455321b4401032540a..edb8941de87d68d3a51ebc2e8fa6e443f0281f81 100644 (file)
@@ -279,7 +279,7 @@ make_name(void)
 %type      key_match ColLabel SpecialRuleRelation ColId columnDef
 %type      ColConstraint ColConstraintElem drop_type Bitconst
 %type      OptTableElementList OptTableElement TableConstraint
-%type      ConstraintElem key_actions ColQualList TypeFuncId DropSchemaStmt
+%type      ConstraintElem key_actions ColQualList type_name DropSchemaStmt
 %type      target_list target_el update_target_list alias_clause
 %type      update_target_el opt_id relation_name database_name
 %type      access_method attr_name class index_name name func_name
@@ -357,7 +357,9 @@ make_name(void)
 %type      struct_type s_struct declaration declarations variable_declarations
 %type      s_union union_type ECPGSetAutocommit on_off
 %type     ECPGAllocateDescr ECPGDeallocateDescr symbol opt_symbol
-%type     ECPGGetDescriptorHeader ECPGTypeFuncId ECPGColId ECPGColLabel
+%type     ECPGGetDescriptorHeader ECPGColLabel
+%type     reserved_keyword unreserved_keyword
+%type     col_name_keyword func_name_keyword
 %type     ECPGTypeName variablelist cvariable
 
 %type   ECPGGetDescriptor
@@ -1964,7 +1966,7 @@ func_type:    Typename
                {
                    $$ = $1;
                }
-       | TypeFuncId '.' ColId '%' TYPE_P   
+       | type_name '.' ColId '%' TYPE_P   
                {
                    $$ = cat_str(4, $1, make_str("."), $3, make_str("% type"));
                }
@@ -2978,8 +2980,7 @@ ConstTypename:  Generic   { $$ = $1; }
        | Character { $$ = $1; }
        ;
 
-Generic:  TypeFuncId           { $$ = $1; }
-       | ECPGTypeName          { $$ = $1; }
+Generic:  type_name                { $$ = $1; }
        ;
 
 /* SQL92 numeric data types
@@ -4874,48 +4875,48 @@ action : SQL_CONTINUE
 
 /* some other stuff for ecpg */
 
-/* additional ColId entries */
-ECPGKeywords:    SQL_BREAK         { $$ = make_str("break"); }
-       | SQL_CALL          { $$ = make_str("call"); }
-       | SQL_CARDINALITY   { $$ = make_str("cardinality"); }
+/* 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"); }
+       | 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_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_NAME              { $$ = make_str("name"); }
        | SQL_NULLABLE          { $$ = make_str("nullable"); }
        | SQL_OCTET_LENGTH      { $$ = make_str("octet_length"); }
-       | SQL_OPEN          { $$ = make_str("open"); }
+       | SQL_OPEN              { $$ = make_str("open"); }
        | SQL_PREPARE           { $$ = make_str("prepare"); }
        | SQL_RELEASE           { $$ = make_str("release"); }
        | SQL_RETURNED_LENGTH       { $$ = make_str("returned_length"); }
        | SQL_RETURNED_OCTET_LENGTH { $$ = make_str("returned_octet_length"); }
-       | SQL_SCALE         { $$ = make_str("scale"); }
+       | 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_STOP              { $$ = make_str("stop"); }
+       | SQL_VAR               { $$ = make_str("var"); }
        | SQL_WHENEVER          { $$ = make_str("whenever"); }
-/*     | ECPGTypeName          { $$ = $1 }*/
        ;
 
-ECPGTypeName:    SQL_BOOL      { $$ = make_str("bool"); }
-       | SQL_INT       { $$ = make_str("int"); }
-       | SQL_LONG      { $$ = make_str("long"); }
-       | SQL_SHORT     { $$ = make_str("short"); }
+/* 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"); }
@@ -4928,25 +4929,72 @@ opt_symbol: symbol      { $$ = $1; }
 symbol:        ColLabel    { $$ = $1; };
 
 /*
- * Keyword classification lists.  Generally, every keyword present in
- * the Postgres grammar should be in one of these lists.  (Presently,
- * "AS" is the sole exception: it is our only completely-reserved word.)
- *
- * Put a new keyword into the earliest list (of TypeFuncId, ColId, ColLabel)
- * that it can go into without creating shift or reduce conflicts.  The
- * earlier lists define "less reserved" categories of keywords.  Notice that
- * each list includes by reference the ones before it.
+ * 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
+ * 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"); }
+       ;
+
+/* Type identifier --- names that can be type names.
+ */
+type_name:  ident                      { $$ = $1; }
+       | unreserved_keyword            { $$ = $1; }
+       | ECPGKeywords                  { $$ = $1; }
+       | ECPGTypeName                  { $$ = $1; }
+       ;
+
+/* Function identifier --- names that can be function names.
  */
+func_name:  ident                      { $$ = $1; }
+       | unreserved_keyword            { $$ = $1; }
+       | func_name_keyword             { $$ = $1; }
+       | ECPGKeywords                  { $$ = $1; }
+       ;
 
-/* Type/func identifier --- names that can be type and function names
- * (as well as ColIds --- ie, these are completely unreserved keywords).
+/* Column label --- allowed labels in "AS" clauses.
+ * This presently includes *all* Postgres keywords.
  */
-TypeFuncId:  ECPGTypeFuncId                { $$ = $1; }
+ColLabel:  ECPGColLabel                    { $$ = $1; }
+       | ECPGTypeName                  { $$ = $1; }
+       | CHAR                          { $$ = make_str("char"); }
+       | UNION                         { $$ = make_str("union"); }
+       ;
+
+ECPGColLabel:  ident                   { $$ = $1; }
+       | unreserved_keyword            { $$ = $1; }
+       | col_name_keyword              { $$ = $1; }
+       | func_name_keyword             { $$ = $1; }
+       | reserved_keyword              { $$ = $1; }
        | ECPGKeywords                  { $$ = $1; }
        ;
 
-ECPGTypeFuncId:  ident                 { $$ = $1; }
-       | ABORT_TRANS                   { $$ = make_str("abort"); }
+
+/*
+ * Keyword classification lists.  Generally, every keyword present in
+ * the Postgres grammar should appear in exactly one of these lists.
+ *
+ * Put a new keyword into the first list that it can go into without causing
+ * shift or reduce conflicts.  The earlier lists define "less reserved"
+ * categories of keywords.
+ */
+
+/* "Unreserved" keywords --- available for use as any kind of name.
+ */
+unreserved_keyword:
+         ABORT_TRANS                   { $$ = make_str("abort"); }
        | ABSOLUTE                      { $$ = make_str("absolute"); }
        | ACCESS                        { $$ = make_str("access"); }
        | ACTION                        { $$ = make_str("action"); }
@@ -5102,69 +5150,96 @@ ECPGTypeFuncId:  ident                  { $$ = $1; }
        | ZONE                          { $$ = make_str("zone"); }
        ;
 
-/* Column identifier --- names that can be column, table, etc names.
+/* Column identifier --- keywords that can be column, table, etc names.
  *
- * This contains the TypeFuncId list plus those keywords that conflict
- * only with typename productions, not with other uses.  Note that
- * most of these keywords will in fact be recognized as type names too;
- * they just have to have special productions for the purpose.
+ * Many of these keywords will in fact be recognized as type or function
+ * names too; but they have special productions for the purpose, and so
+ * can't be treated as "generic" type or function names.
  *
- * Most of these cannot be in TypeFuncId (ie, are not also usable as function
- * names) because they can be followed by '(' in typename productions, which
- * looks too much like a function call for a LALR(1) parser.
+ * The type names appearing here are not usable as function names
+ * because they can be followed by '(' in typename productions, which
+ * looks too much like a function call for aLR(1) parser.
  */
-ColId:  ECPGColId                      { $$ = $1; }
-       | CHAR                          { $$ = make_str("char"); }
-       ;
-
-ECPGColId:  TypeFuncId                 { $$ = $1; }
-       | BIT                           { $$ = make_str("bit"); }
+col_name_keyword:
+         BIT                           { $$ = make_str("bit"); }
 /* CHAR must be excluded from ECPGColLabel because of conflict with UNSIGNED
        | CHAR                          { $$ = 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"); }
        ;
 
-/* Column label --- allowed labels in "AS" clauses.
+/* Function identifier --- keywords that can be function names.
  *
- * Keywords appear here if they could not be distinguished from variable,
- * type, or function names in some contexts.
- * When adding a ColLabel, consider whether it can be added to func_name.
+ * Most of these are keywords that are used as operators in expressions;
+ * in general such keywords can't be column names because they would be
+ * ambiguous with variables, but they are unambiguous as function identifiers.
+ *
+ * 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
  */
-ColLabel:  ECPGColLabel                    { $$ = $1; }
-       | CHAR                          { $$ = make_str("char"); }
-       | UNION                         { $$ = make_str("union"); }
+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"); }
        ;
 
-ECPGColLabel:  ECPGColId               { $$ = $1; }
-       | ALL                           { $$ = make_str("all"); }
+/* Reserved keyword --- these keywords are usable only as a ColLabel.
+ *
+ * Keywords appear here if they could not be distinguished from variable,
+ * type, or function names in some contexts.  Don't put things here unless
+ * 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"); }
-       | BETWEEN                       { $$ = make_str("between"); }
-       | BINARY                        { $$ = make_str("binary"); }
        | BOTH                          { $$ = make_str("both"); }
        | CASE                          { $$ = make_str("case"); }
        | CAST                          { $$ = make_str("cast"); }
        | CHECK                         { $$ = make_str("check"); }
-       | COALESCE                      { $$ = make_str("coalesce"); }
        | COLLATE                       { $$ = make_str("collate"); }
        | COLUMN                        { $$ = make_str("column"); }
        | CONSTRAINT                    { $$ = make_str("constraint"); }
-       | CROSS                         { $$ = make_str("cross"); }
        | CURRENT_DATE                  { $$ = make_str("current_date"); }
        | CURRENT_TIME                  { $$ = make_str("current_time"); }
        | CURRENT_TIMESTAMP             { $$ = make_str("current_timestamp"); }
@@ -5177,34 +5252,19 @@ ECPGColLabel:  ECPGColId                { $$ = $1; }
        | ELSE                          { $$ = make_str("else"); }
        | END_TRANS                     { $$ = make_str("end"); }
        | EXCEPT                        { $$ = make_str("except"); }
-       | EXISTS                        { $$ = make_str("exists"); }
-       | EXTRACT                       { $$ = make_str("extract"); }
        | FALSE_P                       { $$ = make_str("false"); }
        | FOR                           { $$ = make_str("for"); }
        | FOREIGN                       { $$ = make_str("foreign"); }
-       | FREEZE                        { $$ = make_str("freeze"); }
        | FROM                          { $$ = make_str("from"); }
-       | FULL                          { $$ = make_str("full"); }
        | GROUP                         { $$ = make_str("group"); }
        | HAVING                        { $$ = make_str("having"); }
-       | ILIKE                         { $$ = make_str("ilike"); }
-       | IN                            { $$ = make_str("in"); }
        | INITIALLY                     { $$ = make_str("initially"); }
-       | INNER_P                       { $$ = make_str("inner"); }
        | INTERSECT                     { $$ = make_str("intersect"); }
        | INTO                          { $$ = make_str("into"); }
-       | IS                            { $$ = make_str("is"); }
-       | ISNULL                        { $$ = make_str("isnull"); }
-       | JOIN                          { $$ = make_str("join"); }
        | LEADING                       { $$ = make_str("leading"); }
-       | LEFT                          { $$ = make_str("left"); }
-       | LIKE                          { $$ = make_str("like"); }
        | LIMIT                         { $$ = make_str("limit"); }
-       | NATURAL                       { $$ = make_str("natural"); }
        | NEW                           { $$ = make_str("new"); }
        | NOT                           { $$ = make_str("not"); }
-       | NOTNULL                       { $$ = make_str("notnull"); }
-       | NULLIF                        { $$ = make_str("nullif"); }
        | NULL_P                        { $$ = make_str("null"); }
        | OFF                           { $$ = make_str("off"); }
        | OFFSET                        { $$ = make_str("offset"); }
@@ -5213,22 +5273,15 @@ ECPGColLabel:  ECPGColId                { $$ = $1; }
        | ONLY                          { $$ = make_str("only"); }
        | OR                            { $$ = make_str("or"); }
        | ORDER                         { $$ = make_str("order"); }
-       | OUTER_P                       { $$ = make_str("outer"); }
-       | OVERLAPS                      { $$ = make_str("overlaps"); }
-       | POSITION                      { $$ = make_str("position"); }
        | PRIMARY                       { $$ = make_str("primary"); }
-       | PUBLIC                        { $$ = make_str("public"); }
        | REFERENCES                    { $$ = make_str("references"); }
-       | RIGHT                         { $$ = make_str("right"); }
        | SELECT                        { $$ = make_str("select"); }
        | SESSION_USER                  { $$ = make_str("session_user"); }
        | SOME                          { $$ = make_str("some"); }
-       | SUBSTRING                     { $$ = make_str("substring"); }
        | TABLE                         { $$ = make_str("table"); }
        | THEN                          { $$ = make_str("then"); }
        | TO                            { $$ = make_str("to"); }
        | TRAILING                      { $$ = make_str("trailing"); }
-       | TRIM                          { $$ = make_str("trim"); }
        | TRUE_P                        { $$ = make_str("true"); }
 /* UNION must be excluded from ECPGColLabel because of conflict with s_union
        | UNION                         { $$ = make_str("union"); }
@@ -5236,44 +5289,10 @@ ECPGColLabel:  ECPGColId                { $$ = $1; }
        | UNIQUE                        { $$ = make_str("unique"); }
        | USER                          { $$ = make_str("user"); }
        | USING                         { $$ = make_str("using"); }
-       | VERBOSE                       { $$ = make_str("verbose"); }
        | WHEN                          { $$ = make_str("when"); }
        | WHERE                         { $$ = make_str("where"); }
        ;
 
-/* Function identifier --- names that can be function names.
- *
- * This contains the TypeFuncId list plus some ColLabel keywords
- * that are used as operators in expressions; in general such keywords
- * can't be ColId because they would be ambiguous with variable names,
- * but they are unambiguous as function identifiers.
- *
- * 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
- */
-func_name:  TypeFuncId                 { $$ = $1; }
-       | 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"); }
-       ;
 
 into_list : coutputvariable | into_list ',' coutputvariable;