Thread: Call for objections: revision of keyword classification

Call for objections: revision of keyword classification

From
Tom Lane
Date:
Since we've already seen two complaints about "timestamp" no longer
being an allowed column name in 7.2, I think it's probably time to
make a serious effort at trimming the reserved-word list a little.

The attached patch de-reserves all these former ColLabels:

ABORT        unrestricted
BIT        can be ColId, but not function name
CHAR        can be ColId, but not function name
CHARACTER    can be ColId, but not function name
CLUSTER        unrestricted
COPY        unrestricted
DEC        can be ColId, but not function name
DECIMAL        can be ColId, but not function name
EXPLAIN        unrestricted
FLOAT        can be ColId, but not function name
GLOBAL        unrestricted
INOUT        unrestricted
INTERVAL    can be ColId, but not function name
LISTEN        unrestricted
LOAD        unrestricted
LOCAL        unrestricted
LOCK        unrestricted
MOVE        unrestricted
NCHAR        can be ColId, but not function name
NUMERIC        can be ColId, but not function name
OUT        unrestricted
PRECISION    unrestricted
RESET        unrestricted
SETOF        can be ColId, but not type or function name
SHOW        unrestricted
TIME        can be ColId, but not function name
TIMESTAMP    can be ColId, but not function name
TRANSACTION    unrestricted
UNKNOWN        unrestricted
VACUUM        unrestricted
VARCHAR        can be ColId, but not function name

The ones that are now unrestricted were just low-hanging fruit (ie,
they probably should never have been in ColLabel in the first place).
The rest were fixed by recognizing that just because something couldn't
be a function name didn't mean it couldn't be used as a table or column
name.  This solves the fundamental shift/reduce conflict posed by cases
like "SELECT TIMESTAMP(3 ...", without also preventing people from
continuing to name their columns "timestamp".

The keyword classification now looks like:

TypeFuncId:    IDENT plus all fully-unrestricted keywords

ColId:        TypeFuncId plus type-name keywords that might be
        followed by '('; these can't be allowed to be
        function names, but they can be column names.

func_name:    TypeFuncId plus a few special-case ColLabels
        (this list could probably be extended further)

ColLabel:    ColId plus everything else

Comments?  I'd like to apply this, unless there are objections.
I suppose Peter might complain about having to redo the keyword
tables ;-)

            regards, tom lane
*** src/backend/parser/gram.y.orig    Mon Nov  5 00:00:14 2001
--- src/backend/parser/gram.y    Thu Nov  8 19:00:24 2001
***************
*** 257,264 ****
  %type <paramno> ParamNo

  %type <typnam>    Typename, SimpleTypename, ConstTypename
!                 GenericType, Numeric, Geometric, Character, ConstDatetime, ConstInterval, Bit
! %type <str>        character, datetime, bit
  %type <str>        extract_arg
  %type <str>        opt_charset, opt_collate
  %type <str>        opt_float
--- 257,264 ----
  %type <paramno> ParamNo

  %type <typnam>    Typename, SimpleTypename, ConstTypename
!                 GenericType, Numeric, Character, ConstDatetime, ConstInterval, Bit
! %type <str>        character, bit
  %type <str>        extract_arg
  %type <str>        opt_charset, opt_collate
  %type <str>        opt_float
***************
*** 268,274 ****
  %type <ival>    Iconst
  %type <str>        Sconst, comment_text
  %type <str>        UserId, opt_boolean, var_value, ColId_or_Sconst
! %type <str>        ColId, ColLabel, TokenId
  %type <node>    zone_value

  %type <node>    TableConstraint
--- 268,274 ----
  %type <ival>    Iconst
  %type <str>        Sconst, comment_text
  %type <str>        UserId, opt_boolean, var_value, ColId_or_Sconst
! %type <str>        ColId, TypeFuncId, ColLabel
  %type <node>    zone_value

  %type <node>    TableConstraint
***************
*** 1007,1017 ****
          ;


! constraints_set_namelist:    IDENT
                  {
                      $$ = makeList1($1);
                  }
!         | constraints_set_namelist ',' IDENT
                  {
                      $$ = lappend($1, $3);
                  }
--- 1007,1017 ----
          ;


! constraints_set_namelist:    ColId
                  {
                      $$ = makeList1($1);
                  }
!         | constraints_set_namelist ',' ColId
                  {
                      $$ = lappend($1, $3);
                  }
***************
*** 2007,2014 ****
                  }
          ;

  def_arg:  func_return                      {  $$ = (Node *)$1; }
-         | TokenId                        {  $$ = (Node *)makeString($1); }
          | all_Op                        {  $$ = (Node *)makeString($1); }
          | NumericOnly                    {  $$ = (Node *)$1; }
          | Sconst                        {  $$ = (Node *)makeString($1); }
--- 2007,2014 ----
                  }
          ;

+ /* Note: any simple identifier will be returned as a type name! */
  def_arg:  func_return                      {  $$ = (Node *)$1; }
          | all_Op                        {  $$ = (Node *)makeString($1); }
          | NumericOnly                    {  $$ = (Node *)$1; }
          | Sconst                        {  $$ = (Node *)makeString($1); }
***************
*** 2629,2639 ****
                  }
          ;

  func_type:    Typename
                  {
                      $$ = $1;
                  }
!         | IDENT '.' ColId '%' TYPE_P
                  {
                      $$ = makeNode(TypeName);
                      $$->name = $1;
--- 2629,2643 ----
                  }
          ;

+ /*
+  * We would like to make the second production here be ColId '.' ColId etc,
+  * but that causes reduce/reduce conflicts.  TypeFuncId is next best choice.
+  */
  func_type:    Typename
                  {
                      $$ = $1;
                  }
!         | TypeFuncId '.' ColId '%' TYPE_P
                  {
                      $$ = makeNode(TypeName);
                      $$->name = $1;
***************
*** 4064,4076 ****

  ConstTypename:  GenericType
          | Numeric
-         | Geometric
          | Bit
          | Character
          | ConstDatetime
          ;

! GenericType:  IDENT
                  {
                      $$ = makeNode(TypeName);
                      $$->name = xlateSqlType($1);
--- 4068,4079 ----

  ConstTypename:  GenericType
          | Numeric
          | Bit
          | Character
          | ConstDatetime
          ;

! GenericType:  TypeFuncId
                  {
                      $$ = makeNode(TypeName);
                      $$->name = xlateSqlType($1);
***************
*** 4086,4092 ****
  Numeric:  FLOAT opt_float
                  {
                      $$ = makeNode(TypeName);
!                     $$->name = xlateSqlType($2);
                      $$->typmod = -1;
                  }
          | DOUBLE PRECISION
--- 4089,4095 ----
  Numeric:  FLOAT opt_float
                  {
                      $$ = makeNode(TypeName);
!                     $$->name = $2; /* already xlated */
                      $$->typmod = -1;
                  }
          | DOUBLE PRECISION
***************
*** 4115,4128 ****
                  }
          ;

- Geometric:  PATH_P
-                 {
-                     $$ = makeNode(TypeName);
-                     $$->name = xlateSqlType("path");
-                     $$->typmod = -1;
-                 }
-         ;
-
  opt_float:  '(' Iconst ')'
                  {
                      if ($2 < 1)
--- 4118,4123 ----
***************
*** 4299,4311 ****
          | /*EMPTY*/                                { $$ = NULL; }
          ;

! ConstDatetime:  datetime
!                 {
!                     $$ = makeNode(TypeName);
!                     $$->name = xlateSqlType($1);
!                     $$->typmod = -1;
!                 }
!         | TIMESTAMP '(' Iconst ')' opt_timezone_x
                  {
                      $$ = makeNode(TypeName);
                      if ($5)
--- 4294,4300 ----
          | /*EMPTY*/                                { $$ = NULL; }
          ;

! ConstDatetime:  TIMESTAMP '(' Iconst ')' opt_timezone_x
                  {
                      $$ = makeNode(TypeName);
                      if ($5)
***************
*** 4371,4384 ****
                  }
          ;

- datetime:  YEAR_P                                { $$ = "year"; }
-         | MONTH_P                                { $$ = "month"; }
-         | DAY_P                                    { $$ = "day"; }
-         | HOUR_P                                { $$ = "hour"; }
-         | MINUTE_P                                { $$ = "minute"; }
-         | SECOND_P                                { $$ = "second"; }
-         ;
-
  /* XXX Make the default be WITH TIME ZONE for 7.2 to help with database upgrades
   * but revert this back to WITHOUT TIME ZONE for 7.3.
   * Do this by simply reverting opt_timezone_x to opt_timezone - thomas 2001-09-06
--- 4360,4365 ----
***************
*** 5270,5278 ****
   * - thomas 2001-04-12
   */

! extract_arg:  datetime                        { $$ = $1; }
!         | SCONST                            { $$ = $1; }
!         | IDENT                                { $$ = $1; }
          ;

  /* position_list uses b_expr not a_expr to avoid conflict with general IN */
--- 5251,5264 ----
   * - thomas 2001-04-12
   */

! extract_arg:  IDENT                        { $$ = $1; }
!         | YEAR_P                        { $$ = "year"; }
!         | MONTH_P                        { $$ = "month"; }
!         | DAY_P                            { $$ = "day"; }
!         | HOUR_P                        { $$ = "hour"; }
!         | MINUTE_P                        { $$ = "minute"; }
!         | SECOND_P                        { $$ = "second"; }
!         | SCONST                        { $$ = $1; }
          ;

  /* position_list uses b_expr not a_expr to avoid conflict with general IN */
***************
*** 5555,5586 ****
  attr_name:                ColId            { $$ = $1; };
  class:                    ColId            { $$ = $1; };
  index_name:                ColId            { $$ = $1; };
-
- /* Functions
-  * Include date/time keywords as SQL92 extension.
-  * Include TYPE as a SQL92 unreserved keyword. - thomas 1997-10-05
-  * Any tokens which show up as operators will screw up the parsing if
-  * allowed as identifiers, but are acceptable as ColLabels:
-  *  BETWEEN, IN, IS, ISNULL, NOTNULL, OVERLAPS
-  * Thanks to Tom Lane for pointing this out. - thomas 2000-03-29
-  * We need OVERLAPS allowed as a function name to enable the implementation
-  *  of argument type variations on the underlying implementation. These
-  *  variations are done as SQL-language entries in the pg_proc catalog.
-  * Do not include SUBSTRING here since it has explicit productions
-  *  in a_expr to support the goofy SQL9x argument syntax.
-  *  - thomas 2000-11-28
-  */
- func_name:  ColId                        { $$ = xlateSqlFunc($1); }
-         | BETWEEN                        { $$ = xlateSqlFunc("between"); }
-         | ILIKE                            { $$ = xlateSqlFunc("ilike"); }
-         | IN                            { $$ = xlateSqlFunc("in"); }
-         | IS                            { $$ = xlateSqlFunc("is"); }
-         | ISNULL                        { $$ = xlateSqlFunc("isnull"); }
-         | LIKE                            { $$ = xlateSqlFunc("like"); }
-         | NOTNULL                        { $$ = xlateSqlFunc("notnull"); }
-         | OVERLAPS                        { $$ = xlateSqlFunc("overlaps"); }
-         ;
-
  file_name:                Sconst            { $$ = $1; };

  /* Constants
--- 5541,5546 ----
***************
*** 5692,5718 ****
  Sconst:  SCONST                            { $$ = $1; };
  UserId:  ColId                            { $$ = $1; };

! /* Column identifier
!  * Include date/time keywords as SQL92 extension.
!  * Include TYPE as a SQL92 unreserved keyword. - thomas 1997-10-05
!  * Add other keywords. Note that as the syntax expands,
!  *  some of these keywords will have to be removed from this
!  *  list due to shift/reduce conflicts in yacc. If so, move
!  *  down to the ColLabel entity. - thomas 1997-11-06
!  */
! ColId:  IDENT                            { $$ = $1; }
!         | datetime                        { $$ = $1; }
!         | TokenId                        { $$ = $1; }
!         | NATIONAL                        { $$ = "national"; }
          | NONE                            { $$ = "none"; }
!         | PATH_P                        { $$ = "path"; }
          ;

! /* Parser tokens to be used as identifiers.
!  * Tokens involving data types should appear in ColId only,
!  * since they will conflict with real TypeName productions.
   */
! TokenId:  ABSOLUTE                        { $$ = "absolute"; }
          | ACCESS                        { $$ = "access"; }
          | ACTION                        { $$ = "action"; }
          | ADD                            { $$ = "add"; }
--- 5652,5729 ----
  Sconst:  SCONST                            { $$ = $1; };
  UserId:  ColId                            { $$ = $1; };

! /* Column identifier --- names 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.
!  *
!  * 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.
!  */
! ColId:  TypeFuncId                        { $$ = $1; }
!         | BIT                            { $$ = "bit"; }
!         | CHAR                            { $$ = "char"; }
!         | CHARACTER                        { $$ = "character"; }
!         | DEC                            { $$ = "dec"; }
!         | DECIMAL                        { $$ = "decimal"; }
!         | FLOAT                            { $$ = "float"; }
!         | INTERVAL                        { $$ = "interval"; }
!         | NCHAR                            { $$ = "nchar"; }
          | NONE                            { $$ = "none"; }
!         | NUMERIC                        { $$ = "numeric"; }
!         | SETOF                            { $$ = "setof"; }
!         | TIME                            { $$ = "time"; }
!         | TIMESTAMP                        { $$ = "timestamp"; }
!         | VARCHAR                        { $$ = "varchar"; }
!         ;
!
! /* 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"); }
          ;

! /* Type/func identifier --- names that can be type and function names
!  * (as well as ColIds --- ie, these are unreserved keywords).
!  *
!  * Every new keyword should be added to this list unless
!  * doing so produces a shift/reduce or reduce/reduce conflict.
!  * If so, make it a ColId, or failing that a ColLabel.
   */
! TypeFuncId:  IDENT                        { $$ = $1; }
!         | ABORT_TRANS                    { $$ = "abort"; }
!         | ABSOLUTE                        { $$ = "absolute"; }
          | ACCESS                        { $$ = "access"; }
          | ACTION                        { $$ = "action"; }
          | ADD                            { $$ = "add"; }
***************
*** 5731,5746 ****
--- 5742,5760 ----
          | CHARACTERISTICS                { $$ = "characteristics"; }
          | CHECKPOINT                    { $$ = "checkpoint"; }
          | CLOSE                            { $$ = "close"; }
+         | CLUSTER                        { $$ = "cluster"; }
          | COMMENT                        { $$ = "comment"; }
          | COMMIT                        { $$ = "commit"; }
          | COMMITTED                        { $$ = "committed"; }
          | CONSTRAINTS                    { $$ = "constraints"; }
+         | COPY                            { $$ = "copy"; }
          | CREATE                        { $$ = "create"; }
          | CREATEDB                        { $$ = "createdb"; }
          | CREATEUSER                    { $$ = "createuser"; }
          | CURSOR                        { $$ = "cursor"; }
          | CYCLE                            { $$ = "cycle"; }
          | DATABASE                        { $$ = "database"; }
+         | DAY_P                            { $$ = "day"; }
          | DECLARE                        { $$ = "declare"; }
          | DEFERRED                        { $$ = "deferred"; }
          | DELETE                        { $$ = "delete"; }
***************
*** 5753,5768 ****
--- 5767,5786 ----
          | ESCAPE                        { $$ = "escape"; }
          | EXCLUSIVE                        { $$ = "exclusive"; }
          | EXECUTE                        { $$ = "execute"; }
+         | EXPLAIN                        { $$ = "explain"; }
          | FETCH                            { $$ = "fetch"; }
          | FORCE                            { $$ = "force"; }
          | FORWARD                        { $$ = "forward"; }
          | FUNCTION                        { $$ = "function"; }
+         | GLOBAL                        { $$ = "global"; }
          | GRANT                            { $$ = "grant"; }
          | HANDLER                        { $$ = "handler"; }
+         | HOUR_P                        { $$ = "hour"; }
          | IMMEDIATE                        { $$ = "immediate"; }
          | INCREMENT                        { $$ = "increment"; }
          | INDEX                            { $$ = "index"; }
          | INHERITS                        { $$ = "inherits"; }
+         | INOUT                            { $$ = "inout"; }
          | INSENSITIVE                    { $$ = "insensitive"; }
          | INSERT                        { $$ = "insert"; }
          | INSTEAD                        { $$ = "instead"; }
***************
*** 5771,5782 ****
--- 5789,5808 ----
          | LANGUAGE                        { $$ = "language"; }
          | LANCOMPILER                    { $$ = "lancompiler"; }
          | LEVEL                            { $$ = "level"; }
+         | LISTEN                        { $$ = "listen"; }
+         | LOAD                            { $$ = "load"; }
+         | LOCAL                            { $$ = "local"; }
          | LOCATION                        { $$ = "location"; }
+         | LOCK_P                        { $$ = "lock"; }
          | MATCH                            { $$ = "match"; }
          | MAXVALUE                        { $$ = "maxvalue"; }
+         | MINUTE_P                        { $$ = "minute"; }
          | MINVALUE                        { $$ = "minvalue"; }
          | MODE                            { $$ = "mode"; }
+         | MONTH_P                        { $$ = "month"; }
+         | MOVE                            { $$ = "move"; }
          | NAMES                            { $$ = "names"; }
+         | NATIONAL                        { $$ = "national"; }
          | NEXT                            { $$ = "next"; }
          | NO                            { $$ = "no"; }
          | NOCREATEDB                    { $$ = "nocreatedb"; }
***************
*** 5787,5796 ****
--- 5813,5825 ----
          | OIDS                            { $$ = "oids"; }
          | OPERATOR                        { $$ = "operator"; }
          | OPTION                        { $$ = "option"; }
+         | OUT                            { $$ = "out"; }
          | OWNER                            { $$ = "owner"; }
          | PARTIAL                        { $$ = "partial"; }
          | PASSWORD                        { $$ = "password"; }
+         | PATH_P                        { $$ = "path"; }
          | PENDANT                        { $$ = "pendant"; }
+         | PRECISION                        { $$ = "precision"; }
          | PRIOR                            { $$ = "prior"; }
          | PRIVILEGES                    { $$ = "privileges"; }
          | PROCEDURAL                    { $$ = "procedural"; }
***************
*** 5800,5805 ****
--- 5829,5835 ----
          | RELATIVE                        { $$ = "relative"; }
          | RENAME                        { $$ = "rename"; }
          | REPLACE                        { $$ = "replace"; }
+         | RESET                            { $$ = "reset"; }
          | RESTRICT                        { $$ = "restrict"; }
          | RETURNS                        { $$ = "returns"; }
          | REVOKE                        { $$ = "revoke"; }
***************
*** 5808,5818 ****
--- 5838,5850 ----
          | RULE                            { $$ = "rule"; }
          | SCHEMA                        { $$ = "schema"; }
          | SCROLL                        { $$ = "scroll"; }
+         | SECOND_P                        { $$ = "second"; }
          | SESSION                        { $$ = "session"; }
          | SEQUENCE                        { $$ = "sequence"; }
          | SERIALIZABLE                    { $$ = "serializable"; }
          | SET                            { $$ = "set"; }
          | SHARE                            { $$ = "share"; }
+         | SHOW                            { $$ = "show"; }
          | START                            { $$ = "start"; }
          | STATEMENT                        { $$ = "statement"; }
          | STATISTICS                    { $$ = "statistics"; }
***************
*** 5823,5836 ****
--- 5855,5871 ----
          | TEMPLATE                        { $$ = "template"; }
          | TEMPORARY                        { $$ = "temporary"; }
          | TOAST                            { $$ = "toast"; }
+         | TRANSACTION                    { $$ = "transaction"; }
          | TRIGGER                        { $$ = "trigger"; }
          | TRUNCATE                        { $$ = "truncate"; }
          | TRUSTED                        { $$ = "trusted"; }
          | TYPE_P                        { $$ = "type"; }
          | UNENCRYPTED                    { $$ = "unencrypted"; }
+         | UNKNOWN                        { $$ = "unknown"; }
          | UNLISTEN                        { $$ = "unlisten"; }
          | UNTIL                            { $$ = "until"; }
          | UPDATE                        { $$ = "update"; }
+         | VACUUM                        { $$ = "vacuum"; }
          | VALID                            { $$ = "valid"; }
          | VALUES                        { $$ = "values"; }
          | VARYING                        { $$ = "varying"; }
***************
*** 5839,5859 ****
          | WITH                            { $$ = "with"; }
          | WITHOUT                        { $$ = "without"; }
          | WORK                            { $$ = "work"; }
          | ZONE                            { $$ = "zone"; }
          ;

! /* Column label
!  * Allowed labels in "AS" clauses.
!  * Include TRUE/FALSE SQL3 reserved words for Postgres backward
!  *  compatibility. Cannot allow this for column names since the
!  *  syntax would not distinguish between the constant value and
!  *  a column name. - thomas 1997-10-24
!  * Add other keywords to this list. Note that they appear here
!  *  rather than in ColId if there was a shift/reduce conflict
!  *  when used as a full identifier. - thomas 1997-11-06
   */
  ColLabel:  ColId                        { $$ = $1; }
-         | ABORT_TRANS                    { $$ = "abort"; }
          | ALL                            { $$ = "all"; }
          | ANALYSE                        { $$ = "analyse"; } /* British */
          | ANALYZE                        { $$ = "analyze"; }
--- 5874,5893 ----
          | WITH                            { $$ = "with"; }
          | WITHOUT                        { $$ = "without"; }
          | WORK                            { $$ = "work"; }
+         | YEAR_P                        { $$ = "year"; }
          | ZONE                            { $$ = "zone"; }
          ;

! /* Column label --- allowed labels in "AS" clauses.
!  *
!  * Keywords should appear here if they could not be distinguished
!  * from variable, type, or function names in some contexts.
!  *
!  * At present, every keyword except "AS" itself should appear in
!  * one of ColId, TypeFuncId, or ColLabel.  When adding a ColLabel,
!  * also consider whether it can be added to func_name.
   */
  ColLabel:  ColId                        { $$ = $1; }
          | ALL                            { $$ = "all"; }
          | ANALYSE                        { $$ = "analyse"; } /* British */
          | ANALYZE                        { $$ = "analyze"; }
***************
*** 5862,5887 ****
          | ASC                            { $$ = "asc"; }
          | BETWEEN                        { $$ = "between"; }
          | BINARY                        { $$ = "binary"; }
-         | BIT                            { $$ = "bit"; }
          | BOTH                            { $$ = "both"; }
          | CASE                            { $$ = "case"; }
          | CAST                            { $$ = "cast"; }
-         | CHAR                            { $$ = "char"; }
-         | CHARACTER                        { $$ = "character"; }
          | CHECK                            { $$ = "check"; }
-         | CLUSTER                        { $$ = "cluster"; }
          | COALESCE                        { $$ = "coalesce"; }
          | COLLATE                        { $$ = "collate"; }
          | COLUMN                        { $$ = "column"; }
          | CONSTRAINT                    { $$ = "constraint"; }
-         | COPY                            { $$ = "copy"; }
          | CROSS                            { $$ = "cross"; }
          | CURRENT_DATE                    { $$ = "current_date"; }
          | CURRENT_TIME                    { $$ = "current_time"; }
          | CURRENT_TIMESTAMP                { $$ = "current_timestamp"; }
          | CURRENT_USER                    { $$ = "current_user"; }
-         | DEC                            { $$ = "dec"; }
-         | DECIMAL                        { $$ = "decimal"; }
          | DEFAULT                        { $$ = "default"; }
          | DEFERRABLE                    { $$ = "deferrable"; }
          | DESC                            { $$ = "desc"; }
--- 5896,5914 ----
***************
*** 5891,5915 ****
          | END_TRANS                        { $$ = "end"; }
          | EXCEPT                        { $$ = "except"; }
          | EXISTS                        { $$ = "exists"; }
-         | EXPLAIN                        { $$ = "explain"; }
          | EXTRACT                        { $$ = "extract"; }
          | FALSE_P                        { $$ = "false"; }
-         | FLOAT                            { $$ = "float"; }
          | FOR                            { $$ = "for"; }
          | FOREIGN                        { $$ = "foreign"; }
          | FREEZE                        { $$ = "freeze"; }
          | FROM                            { $$ = "from"; }
          | FULL                            { $$ = "full"; }
-         | GLOBAL                        { $$ = "global"; }
          | GROUP                            { $$ = "group"; }
          | HAVING                        { $$ = "having"; }
          | ILIKE                            { $$ = "ilike"; }
          | IN                            { $$ = "in"; }
          | INITIALLY                        { $$ = "initially"; }
          | INNER_P                        { $$ = "inner"; }
-         | INOUT                            { $$ = "inout"; }
          | INTERSECT                        { $$ = "intersect"; }
-         | INTERVAL                        { $$ = "interval"; }
          | INTO                            { $$ = "into"; }
          | IS                            { $$ = "is"; }
          | ISNULL                        { $$ = "isnull"; }
--- 5918,5937 ----
***************
*** 5918,5936 ****
          | LEFT                            { $$ = "left"; }
          | LIKE                            { $$ = "like"; }
          | LIMIT                            { $$ = "limit"; }
-         | LISTEN                        { $$ = "listen"; }
-         | LOAD                            { $$ = "load"; }
-         | LOCAL                            { $$ = "local"; }
-         | LOCK_P                        { $$ = "lock"; }
-         | MOVE                            { $$ = "move"; }
          | NATURAL                        { $$ = "natural"; }
-         | NCHAR                            { $$ = "nchar"; }
          | NEW                            { $$ = "new"; }
          | NOT                            { $$ = "not"; }
          | NOTNULL                        { $$ = "notnull"; }
          | NULLIF                        { $$ = "nullif"; }
          | NULL_P                        { $$ = "null"; }
-         | NUMERIC                        { $$ = "numeric"; }
          | OFF                            { $$ = "off"; }
          | OFFSET                        { $$ = "offset"; }
          | OLD                            { $$ = "old"; }
--- 5940,5951 ----
***************
*** 5938,5975 ****
          | ONLY                            { $$ = "only"; }
          | OR                            { $$ = "or"; }
          | ORDER                            { $$ = "order"; }
-         | OUT                            { $$ = "out"; }
          | OUTER_P                        { $$ = "outer"; }
          | OVERLAPS                        { $$ = "overlaps"; }
          | POSITION                        { $$ = "position"; }
-         | PRECISION                        { $$ = "precision"; }
          | PRIMARY                        { $$ = "primary"; }
          | PUBLIC                        { $$ = "public"; }
          | REFERENCES                    { $$ = "references"; }
-         | RESET                            { $$ = "reset"; }
          | RIGHT                            { $$ = "right"; }
          | SELECT                        { $$ = "select"; }
          | SESSION_USER                    { $$ = "session_user"; }
-         | SETOF                            { $$ = "setof"; }
-         | SHOW                            { $$ = "show"; }
          | SOME                            { $$ = "some"; }
          | SUBSTRING                        { $$ = "substring"; }
          | TABLE                            { $$ = "table"; }
          | THEN                            { $$ = "then"; }
-         | TIME                            { $$ = "time"; }
-         | TIMESTAMP                        { $$ = "timestamp"; }
          | TO                            { $$ = "to"; }
          | TRAILING                        { $$ = "trailing"; }
-         | TRANSACTION                    { $$ = "transaction"; }
          | TRIM                            { $$ = "trim"; }
          | TRUE_P                        { $$ = "true"; }
          | UNION                            { $$ = "union"; }
          | UNIQUE                        { $$ = "unique"; }
-         | UNKNOWN                        { $$ = "unknown"; }
          | USER                            { $$ = "user"; }
          | USING                            { $$ = "using"; }
-         | VACUUM                        { $$ = "vacuum"; }
-         | VARCHAR                        { $$ = "varchar"; }
          | VERBOSE                        { $$ = "verbose"; }
          | WHEN                            { $$ = "when"; }
          | WHERE                            { $$ = "where"; }
--- 5953,5979 ----

Re: Call for objections: revision of keyword classification

From
Bruce Momjian
Date:
Seems fine to apply.  It would be nice if we had a more general system
for adding keywords and having them be column label/function name
capable.  Right now I know I need to add to keyword.c but I have no idea
if/when I need to add to the keyword list in gram.y.  Can we move the
keywords out into another file and somehow pull them into gram.y with
the proper attributes so they get into all the places they need to be
with little fiddling?

---------------------------------------------------------------------------

> Since we've already seen two complaints about "timestamp" no longer
> being an allowed column name in 7.2, I think it's probably time to
> make a serious effort at trimming the reserved-word list a little.

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

Re: Call for objections: revision of keyword classification

From
Tom Lane
Date:
Bruce Momjian <pgman@candle.pha.pa.us> writes:
> It would be nice if we had a more general system
> for adding keywords and having them be column label/function name
> capable.  Right now I know I need to add to keyword.c but I have no idea
> if/when I need to add to the keyword list in gram.y.

*Every* new keyword should be in one of the keyword lists in gram.y.

I tried to clean up the documentation of which list does which and why
in the proposed patch --- what do you think of it?

            regards, tom lane

Re: Call for objections: revision of keyword classification

From
Thomas Lockhart
Date:
> Since we've already seen two complaints about "timestamp" no longer
> being an allowed column name in 7.2, I think it's probably time to
> make a serious effort at trimming the reserved-word list a little.

Cool.

The only reservation I have (pun not *really* intended ;) is that the
SQL9x reserved words may continue to impact us into the future, so
freeing them up now may just postpone the pain until later. That
probably is not a good enough argument (*I* don't even like it) but any
extra flexibility we put in now is not guaranteed to last forever...

In either case, having reserved words which are also reserved in the SQL
standard will not keep folks from using PostgreSQL, and allowing them
will not be a difference maker in adoption either imho.

                        - Thomas

Re: Call for objections: revision of keyword classification

From
Tom Lane
Date:
Thomas Lockhart <lockhart@fourpalms.org> writes:
> The only reservation I have (pun not *really* intended ;) is that the
> SQL9x reserved words may continue to impact us into the future, so
> freeing them up now may just postpone the pain until later. That
> probably is not a good enough argument (*I* don't even like it) but any
> extra flexibility we put in now is not guaranteed to last forever...

Of course not, but we might as well do what we can while we can.

One positive point is that (I think) we are pretty close to SQL9x now
on datatype declaration syntax, so if we can make these words unreserved
or less-reserved today, it's not unreasonable to think they might be
able to stay that way indefinitely.

> In either case, having reserved words which are also reserved in the SQL
> standard will not keep folks from using PostgreSQL, and allowing them
> will not be a difference maker in adoption either imho.

No, it won't.  I'm mainly doing this to try to minimize the pain of
people porting forward from previous Postgres releases, in which
(some of) these words weren't reserved.  That seems a worthwhile
goal to me, even if in the long run they end up absorbing the pain
anyway.  Certain pain now vs maybe-or-maybe-not pain later is an
easy tradeoff ;-)

            regards, tom lane

Re: Call for objections: revision of keyword classification

From
Tom Lane
Date:
Bruce Momjian <pgman@candle.pha.pa.us> writes:
> Can we move the keywords out into another file and somehow pull them
> into gram.y with the proper attributes so they get into all the places
> they need to be with little fiddling?

Thinking about that, it seems like it might be nice to have a master
keyword file that contains just keywords and classifications:

    AS        Hard-reserved
    CASE        ColLabel
    ABSOLUTE    TypeFuncId
    BIT        ColId

and make some scripts that generate both keyword.c and the list
productions in gram.y automatically.  (Among other things, we could stop
trusting manual sorting of the keyword.c entries ...)  Peter's
documentation generator would no doubt be a lot happier too --- we
could add indications of SQL92 and SQL99 reserved status to this
master file, for example.

However, right offhand I don't see any equivalent of #include in the
Bison manual, so I'm not sure how the autogenerated list productions
could be included into the hand-maintained part of gram.y.  Thoughts?

            regards, tom lane

PS: no, I'm *not* suggesting we do this during beta.

Re: Call for objections: revision of keyword classification

From
Bruce Momjian
Date:
> Bruce Momjian <pgman@candle.pha.pa.us> writes:
> > Can we move the keywords out into another file and somehow pull them
> > into gram.y with the proper attributes so they get into all the places
> > they need to be with little fiddling?
>
> Thinking about that, it seems like it might be nice to have a master
> keyword file that contains just keywords and classifications:
>
>     AS        Hard-reserved
>     CASE        ColLabel
>     ABSOLUTE    TypeFuncId
>     BIT        ColId
>
> and make some scripts that generate both keyword.c and the list
> productions in gram.y automatically.  (Among other things, we could stop
> trusting manual sorting of the keyword.c entries ...)  Peter's
> documentation generator would no doubt be a lot happier too --- we
> could add indications of SQL92 and SQL99 reserved status to this
> master file, for example.
>
> However, right offhand I don't see any equivalent of #include in the
> Bison manual, so I'm not sure how the autogenerated list productions
> could be included into the hand-maintained part of gram.y.  Thoughts?

Yes, this is what I was suggesting;  a central file that can be pulled
in to generate the others.

Doesn't bison deal with #include?  I guess not.  The only other way is
to make a gram.y.pre, and have Makefile do the inclusions in the proper
spot, and run that new gram.y through bison.  The fact is, you have to
process the central file anyway so may as well just do the gram.y
replacements manually too.


--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

Re: Call for objections: revision of keyword classification

From
Tom Lane
Date:
Bruce Momjian <pgman@candle.pha.pa.us> writes:
> Doesn't bison deal with #include?  I guess not.  The only other way is
> to make a gram.y.pre, and have Makefile do the inclusions in the proper
> spot, and run that new gram.y through bison.

I was hoping to avoid that sort of kluge ... surely the bison designers
thought of include, and I'm just not seeing how it's done ...

            regards, tom lane

Re: Call for objections: revision of keyword classification

From
Tom Lane
Date:
Bruce Momjian <pgman@candle.pha.pa.us> writes:
> What does #include do?  Doesn't it work?

AFAICT it's only allowed in the C-code sections of gram.y, from which
it's just transposed into the output .c file (as indeed you'd want;
you wouldn't want your header files expanded when bison is run).

I'm not seeing anything that supports inclusion of a file in the
grammar-productions portion of gram.y.

            regards, tom lane

Re: Call for objections: revision of keyword classification

From
Bruce Momjian
Date:
> Bruce Momjian <pgman@candle.pha.pa.us> writes:
> > Doesn't bison deal with #include?  I guess not.  The only other way is
> > to make a gram.y.pre, and have Makefile do the inclusions in the proper
> > spot, and run that new gram.y through bison.
>
> I was hoping to avoid that sort of kluge ... surely the bison designers
> thought of include, and I'm just not seeing how it's done ...

What does #include do?  Doesn't it work?

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

Re: Call for objections: revision of keyword classification

From
"Marc G. Fournier"
Date:
How do some of the other RDBMSs handle this?  I've gotten into the habit
awhile ago of not using 'field types' as 'field names' that not using
something like 'timestamp' as a field name comes naturally ... ignoring
going from old-PgSQL to new-PgSQL ... what about PgSQL->Oracle?  I
personally like it when I see apps out there that strive to work with
different DBs, I'd hate to see it be us that makes life more difficult for
ppl to make choices because we 'softened restrictions' on reserved words,
allowing someone to create an app that works great under us, but is now a
headache to change to someone else's RDBMSs as a result ...

... if that makes any sense?

On Thu, 8 Nov 2001, Tom Lane wrote:

> Thomas Lockhart <lockhart@fourpalms.org> writes:
> > The only reservation I have (pun not *really* intended ;) is that the
> > SQL9x reserved words may continue to impact us into the future, so
> > freeing them up now may just postpone the pain until later. That
> > probably is not a good enough argument (*I* don't even like it) but any
> > extra flexibility we put in now is not guaranteed to last forever...
>
> Of course not, but we might as well do what we can while we can.
>
> One positive point is that (I think) we are pretty close to SQL9x now
> on datatype declaration syntax, so if we can make these words unreserved
> or less-reserved today, it's not unreasonable to think they might be
> able to stay that way indefinitely.
>
> > In either case, having reserved words which are also reserved in the SQL
> > standard will not keep folks from using PostgreSQL, and allowing them
> > will not be a difference maker in adoption either imho.
>
> No, it won't.  I'm mainly doing this to try to minimize the pain of
> people porting forward from previous Postgres releases, in which
> (some of) these words weren't reserved.  That seems a worthwhile
> goal to me, even if in the long run they end up absorbing the pain
> anyway.  Certain pain now vs maybe-or-maybe-not pain later is an
> easy tradeoff ;-)
>
>             regards, tom lane
>
> ---------------------------(end of broadcast)---------------------------
> TIP 6: Have you searched our list archives?
>
> http://archives.postgresql.org
>


Re: Call for objections: revision of keyword classification

From
Tom Lane
Date:
"Marc G. Fournier" <scrappy@hub.org> writes:
> I'd hate to see it be us that makes life more difficult for
> ppl to make choices because we 'softened restrictions' on reserved words,
> allowing someone to create an app that works great under us, but is now a
> headache to change to someone else's RDBMSs as a result ...

Well, I could see making a "strict SQL" mode that rejects *all* PG-isms,
but in the absence of such a thing I don't see much value to taking a
hard line just on the point of disallowing keywords as field names.
That seems unlikely to be anyone's worst porting headache ...

Your question is valid though: do other RDBMSs take a hard line on
how reserved keywords are?  I dunno.

            regards, tom lane

Re: Call for objections: revision of keyword classification

From
Bruce Momjian
Date:
> Bruce Momjian <pgman@candle.pha.pa.us> writes:
> > What does #include do?  Doesn't it work?
>
> AFAICT it's only allowed in the C-code sections of gram.y, from which
> it's just transposed into the output .c file (as indeed you'd want;
> you wouldn't want your header files expanded when bison is run).
>
> I'm not seeing anything that supports inclusion of a file in the
> grammar-productions portion of gram.y.

It would be very easy to simulate the #include in the action section
using a small awk script.  I can assist.

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

Re: Call for objections: revision of keyword classification

From
Thomas Lockhart
Date:
...
> Thinking about that, it seems like it might be nice to have a master
> keyword file that contains just keywords and classifications:
...
> and make some scripts that generate both keyword.c and the list
> productions in gram.y automatically.  (Among other things, we could stop
> trusting manual sorting of the keyword.c entries ...)  Peter's
> documentation generator would no doubt be a lot happier too --- we
> could add indications of SQL92 and SQL99 reserved status to this
> master file, for example.

istm that we would have a better time using gram.y as the definitive
source for this list. Trying to stuff gram.y from some other source file
moves the information another step away from bison, which is the
definitive arbiter of correct behavior and syntax. Complaints that
things are too hard to figure out won't get better by having more
indirection in the process, and no matter how we do it one will still
need to understand the relationships between tokens and productions.

We could have a perl script (haven't looked; maybe Peter's utility
already does this?) which rummages through gram.y and generates
keyword.c. And if we wanted to categorize what we implement wrt SQL9x
definitions, we should do a join from lists in SQL9x against our
keywords, rather than trying to maintain that relationship manually. We
could even find some database to do it for us ;)

                           - Thomas

Re: Call for objections: revision of keyword classification

From
Thomas Lockhart
Date:
> That's what we're doing now, more or less, and it's got glaring
> deficiencies.  It's nearly unintelligible (cf Bruce's complaint
> earlier in this thread) and it's horribly prone to human error.
> Here are just three depressingly-easy-to-make mistakes against
> which we have no mechanical check:

Zounds! How could this ever have worked??!! ;)

> What's worse is that the consequences of these mistakes are relatively
> subtle and could escape detection for awhile.  I'd like to see mistakes
> of this kind become procedurally impossible.

No disagreement with the goals...

> I believe Peter's already doing some form of this, but gram.y is a
> forbiddingly unfriendly form of storage for this information.  It'd
> be a lot easier and less mistake-prone to start from a *designed*
> keyword database and generate the appropriate lists in gram.y.

Certainly gram.y is forbidding to beginners and those who don't spend
much time in the code, but separating blocks of the code into external
files only increases the indirection. One still has to *understand* what
gram.y is doing, and no amount of reorganization will keep one from the
possibility of shift/reduce problems with new productions.

One possibility would be to put better comments into gram.y, and to back
those comments up with a validation script that *could* generate
keyword.c and other cross references. A bit more structure to the
comments and code would enable that I think.

> BTW, another thing in the back of my mind is that we should try to
> figure out some way to unify ecpg's SQL grammar with the backend's.
> Maintaining that thing is an even bigger headache than getting the
> backend's own parser right.

That would be nice. Unfortunately that would lead to the main parser
having the same machinations used in ecpg, with separate subroutine
calls for *every* production. Yuck. I wonder if some other structure
would be possible...

                      - Thomas

Re: Call for objections: revision of keyword classification

From
Tom Lane
Date:
Thomas Lockhart <lockhart@fourpalms.org> writes:
>> BTW, another thing in the back of my mind is that we should try to
>> figure out some way to unify ecpg's SQL grammar with the backend's.
>> Maintaining that thing is an even bigger headache than getting the
>> backend's own parser right.

> That would be nice. Unfortunately that would lead to the main parser
> having the same machinations used in ecpg, with separate subroutine
> calls for *every* production. Yuck.

The thing is that most of the actions in ecpg's grammar could easily be
generated mechanically.  My half-baked idea here is some sort of script
that would take the backend grammar, strip out the backend's actions and
replace 'em with mechanically-generated actions that reconstruct the
query string, and finally merge with a small set of hand-maintained
rules that reflect ecpg's distinctive features.

You're quite right that nothing like this will reduce the amount that
maintainers have to know.  But I think it could reduce the amount of
tedious, purely mechanical, and error-prone maintenance work that we
have to do to keep various files and lists in sync.

            regards, tom lane

Re: Call for objections: revision of keyword classification

From
Tom Lane
Date:
Thomas Lockhart <lockhart@fourpalms.org> writes:
>> Thinking about that, it seems like it might be nice to have a master
>> keyword file that contains just keywords and classifications:

> istm that we would have a better time using gram.y as the definitive
> source for this list.

That's what we're doing now, more or less, and it's got glaring
deficiencies.  It's nearly unintelligible (cf Bruce's complaint
earlier in this thread) and it's horribly prone to human error.
Here are just three depressingly-easy-to-make mistakes against
which we have no mechanical check:

    * keyword production mismatches token and action, eg

        | FOO            { $$ = "bar"; }

    * failure to add new keyword to any of the appropriate lists;

    * messing up the perfect sort order required in keyword.c.

What's worse is that the consequences of these mistakes are relatively
subtle and could escape detection for awhile.  I'd like to see mistakes
of this kind become procedurally impossible.

> We could have a perl script (haven't looked; maybe Peter's utility
> already does this?) which rummages through gram.y and generates
> keyword.c.

I believe Peter's already doing some form of this, but gram.y is a
forbiddingly unfriendly form of storage for this information.  It'd
be a lot easier and less mistake-prone to start from a *designed*
keyword database and generate the appropriate lists in gram.y.

BTW, another thing in the back of my mind is that we should try to
figure out some way to unify ecpg's SQL grammar with the backend's.
Maintaining that thing is an even bigger headache than getting the
backend's own parser right.

            regards, tom lane

Re: Call for objections: revision of keyword classification

From
Bruce Momjian
Date:
> One possibility would be to put better comments into gram.y, and to back
> those comments up with a validation script that *could* generate
> keyword.c and other cross references. A bit more structure to the
> comments and code would enable that I think.

A validation script is a good intermediate idea, similar to our
duplicate_oids we have in include/catalog.  It would make sure
keywords.c was sorted, and make sure each keyword appeared somewhere in
lists of allowed function/column name productions.

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

Re: Call for objections: revision of keyword classification

From
Tom Lane
Date:
Bruce Momjian <pgman@candle.pha.pa.us> writes:
> A validation script is a good intermediate idea,

IMHO a validation script would be *far* harder than the alternative
I'm proposing, because it'd have to parse and interpret gram.y and
keyword.c.  Building a correct-by-construction set of keyword lists
seems much easier than checking their rather messy representation
in those files.

            regards, tom lane

Re: Call for objections: revision of keyword classification

From
Bruce Momjian
Date:
> Bruce Momjian <pgman@candle.pha.pa.us> writes:
> > A validation script is a good intermediate idea,
>
> IMHO a validation script would be *far* harder than the alternative
> I'm proposing, because it'd have to parse and interpret gram.y and
> keyword.c.  Building a correct-by-construction set of keyword lists
> seems much easier than checking their rather messy representation
> in those files.

Agreed.  It just removed the indirection problem mentioned by Thomas.

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026