]> granicus.if.org Git - postgresql/commitdiff
Fix problems with CURRENT_DATE and related functions being used in
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 20 Nov 1999 21:39:36 +0000 (21:39 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 20 Nov 1999 21:39:36 +0000 (21:39 +0000)
table defaults or rules: translate them to a function call so that
parse_coerce doesn't reduce them to a date or time constant immediately.
Also, eliminate a lot of redundancy in the expression grammar by
defining a new nonterminal com_expr, which contains all the productions
that can be shared by a_expr and b_expr.

src/backend/parser/gram.y

index 9aa9f93cd152f577442f23cabfa30d410bb8d03a..5a291dc867f34f42073369c640dc18cf07c33af9 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.114 1999/11/15 02:00:10 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.115 1999/11/20 21:39:36 tgl Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -212,11 +212,10 @@ static Node *doNegate(Node *n);
 %type <node>   columnDef, alter_clause
 %type <defelt> def_elem
 %type <node>   def_arg, columnElem, where_clause,
-                               a_expr, a_expr_or_null, b_expr, AexprConst,
+                               a_expr, a_expr_or_null, b_expr, com_expr, AexprConst,
                                in_expr, having_clause
 %type <list>   row_descriptor, row_list, in_expr_nodes
 %type <node>   row_expr
-%type <str>            row_op
 %type <node>   case_expr, case_arg, when_clause, case_default
 %type <list>   when_clause_list
 %type <ival>   sub_type
@@ -942,15 +941,18 @@ ColConstraint:
                                { $$ = $1; }
                ;
 
-/* DEFAULT NULL is already the default for Postgres.
+/*
+ * DEFAULT NULL is already the default for Postgres.
  * But define it here and carry it forward into the system
  * to make it explicit.
  * - thomas 1998-09-13
+ *
  * WITH NULL and NULL are not SQL92-standard syntax elements,
  * so leave them out. Use DEFAULT NULL to explicitly indicate
  * that a column may have that value. WITH NULL leads to
  * shift/reduce conflicts with WITH TIME ZONE anyway.
  * - thomas 1999-01-08
+ *
  * DEFAULT expression must be b_expr not a_expr to prevent shift/reduce
  * conflict on NOT (since NOT might start a subsequent NOT NULL constraint,
  * or be part of a_expr NOT LIKE or similar constructs).
@@ -1466,8 +1468,7 @@ def_type:  OPERATOR                                                       { $$ = OPERATOR; }
 def_name:  PROCEDURE                                           { $$ = "procedure"; }
                | JOIN                                                          { $$ = "join"; }
                | ColId                                                         { $$ = $1; }
-               | MathOp                                                        { $$ = $1; }
-               | Op                                                            { $$ = $1; }
+               | all_Op                                                        { $$ = $1; }
                ;
 
 definition:  '(' def_list ')'                          { $$ = $2; }
@@ -2065,20 +2066,6 @@ RemoveOperStmt:  DROP OPERATOR all_Op '(' oper_argtypes ')'
                                }
                ;
 
-all_Op:  Op | MathOp;
-
-MathOp:        '+'                             { $$ = "+"; }
-               | '-'                   { $$ = "-"; }
-               | '*'                   { $$ = "*"; }
-               | '/'                   { $$ = "/"; }
-               | '%'                   { $$ = "%"; }
-               | '^'                   { $$ = "^"; }
-               | '|'                   { $$ = "|"; }
-               | '<'                   { $$ = "<"; }
-               | '>'                   { $$ = ">"; }
-               | '='                   { $$ = "="; }
-               ;
-
 oper_argtypes: name
                                {
                                   elog(ERROR,"parser: argument type missing (use NONE for unary operators)");
@@ -2951,9 +2938,7 @@ sortby: a_expr OptUseOp
                                }
                ;
 
-OptUseOp:  USING Op                                                            { $$ = $2; }
-               | USING '<'                                                             { $$ = "<"; }
-               | USING '>'                                                             { $$ = ">"; }
+OptUseOp:  USING all_Op                                                        { $$ = $2; }
                | ASC                                                                   { $$ = "<"; }
                | DESC                                                                  { $$ = ">"; }
                | /*EMPTY*/                                                             { $$ = "<"; /*default*/ }
@@ -3578,7 +3563,7 @@ opt_interval:  datetime                                                   { $$ = lcons($1, NIL); }
 
 /*****************************************************************************
  *
- *     expression grammar, still needs some cleanup
+ *     expression grammar
  *
  *****************************************************************************/
 
@@ -3595,8 +3580,6 @@ a_expr_or_null:  a_expr
 /* Expressions using row descriptors
  * Define row_descriptor to allow yacc to break the reduce/reduce conflict
  *  with singleton expressions.
- * Eliminated lots of code by defining row_op and sub_type clauses.
- * - thomas 1998-05-09
  */
 row_expr: '(' row_descriptor ')' IN '(' SubSelect ')'
                                {
@@ -3618,7 +3601,7 @@ row_expr: '(' row_descriptor ')' IN '(' SubSelect ')'
                                        n->subselect = $7;
                                        $$ = (Node *)n;
                                }
-               | '(' row_descriptor ')' row_op sub_type '(' SubSelect ')'
+               | '(' row_descriptor ')' all_Op sub_type '(' SubSelect ')'
                                {
                                        SubLink *n = makeNode(SubLink);
                                        n->lefthand = $2;
@@ -3631,7 +3614,7 @@ row_expr: '(' row_descriptor ')' IN '(' SubSelect ')'
                                        n->subselect = $7;
                                        $$ = (Node *)n;
                                }
-               | '(' row_descriptor ')' row_op '(' SubSelect ')'
+               | '(' row_descriptor ')' all_Op '(' SubSelect ')'
                                {
                                        SubLink *n = makeNode(SubLink);
                                        n->lefthand = $2;
@@ -3644,7 +3627,7 @@ row_expr: '(' row_descriptor ')' IN '(' SubSelect ')'
                                        n->subselect = $6;
                                        $$ = (Node *)n;
                                }
-               | '(' row_descriptor ')' row_op '(' row_descriptor ')'
+               | '(' row_descriptor ')' all_Op '(' row_descriptor ')'
                                {
                                        $$ = makeRowExpr($4, $2, $6);
                                }
@@ -3666,45 +3649,67 @@ row_list:  row_list ',' a_expr
                                }
                ;
 
-row_op:  Op                                                                    { $$ = $1; }
-               | '<'                                                           { $$ = "<"; }
-               | '='                                                           { $$ = "="; }
-               | '>'                                                           { $$ = ">"; }
-               | '+'                                                           { $$ = "+"; }
-               | '-'                                                           { $$ = "-"; }
-               | '*'                                                           { $$ = "*"; }
-               | '/'                                                           { $$ = "/"; }
-               | '%'                                                           { $$ = "%"; }
-               | '^'                                                           { $$ = "^"; }
-               | '|'                                                           { $$ = "|"; }
-               ;
-
 sub_type:  ANY                                                         { $$ = ANY_SUBLINK; }
                | ALL                                                           { $$ = ALL_SUBLINK; }
                ;
 
-/* General expressions
+all_Op:  Op | MathOp;
+
+MathOp:        '+'                             { $$ = "+"; }
+               | '-'                   { $$ = "-"; }
+               | '*'                   { $$ = "*"; }
+               | '/'                   { $$ = "/"; }
+               | '%'                   { $$ = "%"; }
+               | '^'                   { $$ = "^"; }
+               | '|'                   { $$ = "|"; }
+               | '<'                   { $$ = "<"; }
+               | '>'                   { $$ = ">"; }
+               | '='                   { $$ = "="; }
+               ;
+
+/*
+ * General expressions
  * This is the heart of the expression syntax.
- * Note that the BETWEEN clause looks similar to a boolean expression
- *  and so we must define b_expr which is almost the same as a_expr
- *  but without the boolean expressions.
- * All operations/expressions are allowed in a BETWEEN clause
- *  if surrounded by parens.
+ *
+ * We have two expression types: a_expr is the unrestricted kind, and
+ * b_expr is a subset that must be used in some places to avoid shift/reduce
+ * conflicts.  For example, we can't do BETWEEN as "BETWEEN a_expr AND a_expr"
+ * because that use of AND conflicts with AND as a boolean operator.  So,
+ * b_expr is used in BETWEEN and we remove boolean keywords from b_expr.
+ *
+ * Note that '(' a_expr ')' is a b_expr, so an unrestricted expression can
+ * always be used by surrounding it with parens.
+ *
+ * com_expr is all the productions that are common to a_expr and b_expr;
+ * it's factored out just to eliminate redundant coding.
  */
-a_expr:  attr
-                               {       $$ = (Node *) $1;  }
-               | row_expr
+a_expr:  com_expr
                                {       $$ = $1;  }
-               | AexprConst
-                               {       $$ = $1;  }
-               | ColId opt_indirection
+               | a_expr TYPECAST Typename
                                {
-                                       /* could be a column name or a relation_name */
-                                       Ident *n = makeNode(Ident);
-                                       n->name = $1;
-                                       n->indirection = $2;
-                                       $$ = (Node *)n;
+                                       $$ = (Node *)$1;
+                                       /* AexprConst can be either A_Const or ParamNo */
+                                       if (nodeTag($1) == T_A_Const) {
+                                               ((A_Const *)$1)->typename = $3;
+                                       } else if (nodeTag($1) == T_ParamNo) {
+                                               ((ParamNo *)$1)->typename = $3;
+                                       /* otherwise, try to transform to a function call */
+                                       } else {
+                                               FuncCall *n = makeNode(FuncCall);
+                                               n->funcname = $3->name;
+                                               n->args = lcons($1,NIL);
+                                               $$ = (Node *)n;
+                                       }
                                }
+               /*
+                * These operators must be called out explicitly in order to make use
+                * of yacc/bison's automatic operator-precedence handling.  All other
+                * operator names are handled by the generic productions using "Op",
+                * below; and all those operators will have the same precedence.
+                *
+                * If you add more explicitly-known operators, be sure to add them
+                * also to b_expr and to the MathOp list above.
+                */
                | '-' a_expr %prec UMINUS
                                {       $$ = doNegate($2); }
                | '%' a_expr
@@ -3750,242 +3755,26 @@ a_expr:  attr
 
                | a_expr '=' a_expr
                                {       $$ = makeA_Expr(OP, "=", $1, $3); }
-               | a_expr TYPECAST Typename
-                               {
-                                       $$ = (Node *)$1;
-                                       /* AexprConst can be either A_Const or ParamNo */
-                                       if (nodeTag($1) == T_A_Const) {
-                                               ((A_Const *)$1)->typename = $3;
-                                       } else if (nodeTag($1) == T_ParamNo) {
-                                               ((ParamNo *)$1)->typename = $3;
-                                       /* otherwise, try to transform to a function call */
-                                       } else {
-                                               FuncCall *n = makeNode(FuncCall);
-                                               n->funcname = $3->name;
-                                               n->args = lcons($1,NIL);
-                                               $$ = (Node *)n;
-                                       }
-                               }
-               | CAST '(' a_expr AS Typename ')'
-                               {
-                                       $$ = (Node *)$3;
-                                       /* AexprConst can be either A_Const or ParamNo */
-                                       if (nodeTag($3) == T_A_Const) {
-                                               ((A_Const *)$3)->typename = $5;
-                                       } else if (nodeTag($3) == T_ParamNo) {
-                                               ((ParamNo *)$3)->typename = $5;
-                                       /* otherwise, try to transform to a function call */
-                                       } else {
-                                               FuncCall *n = makeNode(FuncCall);
-                                               n->funcname = $5->name;
-                                               n->args = lcons($3,NIL);
-                                               $$ = (Node *)n;
-                                       }
-                               }
-               | '(' a_expr_or_null ')'
-                               {       $$ = $2; }
+
                | a_expr Op a_expr
-                               {       $$ = makeA_Expr(OP, $2, $1, $3);        }
-               | a_expr LIKE a_expr
-                               {       $$ = makeA_Expr(OP, "~~", $1, $3); }
-               | a_expr NOT LIKE a_expr
-                               {       $$ = makeA_Expr(OP, "!~~", $1, $4); }
+                               {       $$ = makeA_Expr(OP, $2, $1, $3); }
                | Op a_expr
                                {       $$ = makeA_Expr(OP, $1, NULL, $2); }
                | a_expr Op
                                {       $$ = makeA_Expr(OP, $2, $1, NULL); }
-               | func_name '(' '*' ')'
-                               {
-                                       /*
-                                        * For now, we transform AGGREGATE(*) into AGGREGATE(1).
-                                        *
-                                        * This does the right thing for COUNT(*) (in fact,
-                                        * any certainly-non-null expression would do for COUNT),
-                                        * and there are no other aggregates in SQL92 that accept
-                                        * '*' as parameter.
-                                        *
-                                        * XXX really, the '*' ought to be transformed to some
-                                        * special construct that wouldn't be acceptable as the
-                                        * input of a non-aggregate function, in case the given
-                                        * func_name matches a plain function.  This would also
-                                        * support a possible extension to let user-defined
-                                        * aggregates do something special with '*' as input.
-                                        */
-                                       FuncCall *n = makeNode(FuncCall);
-                                       A_Const *star = makeNode(A_Const);
-                                       star->val.type = T_Integer;
-                                       star->val.val.ival = 1;
-                                       n->funcname = $1;
-                                       n->args = lcons(star, NIL);
-                                       $$ = (Node *)n;
-                               }
-               | func_name '(' ')'
-                               {
-                                       FuncCall *n = makeNode(FuncCall);
-                                       n->funcname = $1;
-                                       n->args = NIL;
-                                       $$ = (Node *)n;
-                               }
-               | func_name '(' expr_list ')'
-                               {
-                                       FuncCall *n = makeNode(FuncCall);
-                                       n->funcname = $1;
-                                       n->args = $3;
-                                       $$ = (Node *)n;
-                               }
-               | CURRENT_DATE
-                               {
-                                       A_Const *n = makeNode(A_Const);
-                                       TypeName *t = makeNode(TypeName);
-
-                                       n->val.type = T_String;
-                                       n->val.val.str = "now";
-                                       n->typename = t;
-
-                                       t->name = xlateSqlType("date");
-                                       t->setof = FALSE;
-                                       t->typmod = -1;
-                                       $$ = (Node *)n;
-                               }
-               | CURRENT_TIME
-                               {
-                                       A_Const *n = makeNode(A_Const);
-                                       TypeName *t = makeNode(TypeName);
-
-                                       n->val.type = T_String;
-                                       n->val.val.str = "now";
-                                       n->typename = t;
-
-                                       t->name = xlateSqlType("time");
-                                       t->setof = FALSE;
-                                       t->typmod = -1;
-
-                                       $$ = (Node *)n;
-                               }
-               | CURRENT_TIME '(' Iconst ')'
-                               {
-                                       FuncCall *n = makeNode(FuncCall);
-                                       A_Const *s = makeNode(A_Const);
-                                       TypeName *t = makeNode(TypeName);
-
-                                       n->funcname = xlateSqlType("time");
-                                       n->args = lcons(s, NIL);
-
-                                       s->val.type = T_String;
-                                       s->val.val.str = "now";
-                                       s->typename = t;
-
-                                       t->name = xlateSqlType("time");
-                                       t->setof = FALSE;
-                                       t->typmod = -1;
-
-                                       if ($3 != 0)
-                                               elog(NOTICE,"CURRENT_TIME(%d) precision not implemented; zero used instead",$3);
-
-                                       $$ = (Node *)n;
-                               }
-               | CURRENT_TIMESTAMP
-                               {
-                                       A_Const *n = makeNode(A_Const);
-                                       TypeName *t = makeNode(TypeName);
-
-                                       n->val.type = T_String;
-                                       n->val.val.str = "now";
-                                       n->typename = t;
-
-                                       t->name = xlateSqlType("timestamp");
-                                       t->setof = FALSE;
-                                       t->typmod = -1;
-
-                                       $$ = (Node *)n;
-                               }
-               | CURRENT_TIMESTAMP '(' Iconst ')'
-                               {
-                                       FuncCall *n = makeNode(FuncCall);
-                                       A_Const *s = makeNode(A_Const);
-                                       TypeName *t = makeNode(TypeName);
 
-                                       n->funcname = xlateSqlType("timestamp");
-                                       n->args = lcons(s, NIL);
-
-                                       s->val.type = T_String;
-                                       s->val.val.str = "now";
-                                       s->typename = t;
-
-                                       t->name = xlateSqlType("timestamp");
-                                       t->setof = FALSE;
-                                       t->typmod = -1;
+               | a_expr AND a_expr
+                               {       $$ = makeA_Expr(AND, NULL, $1, $3); }
+               | a_expr OR a_expr
+                               {       $$ = makeA_Expr(OR, NULL, $1, $3); }
+               | NOT a_expr
+                               {       $$ = makeA_Expr(NOT, NULL, NULL, $2); }
 
-                                       if ($3 != 0)
-                                               elog(NOTICE,"CURRENT_TIMESTAMP(%d) precision not implemented; zero used instead",$3);
+               | a_expr LIKE a_expr
+                               {       $$ = makeA_Expr(OP, "~~", $1, $3); }
+               | a_expr NOT LIKE a_expr
+                               {       $$ = makeA_Expr(OP, "!~~", $1, $4); }
 
-                                       $$ = (Node *)n;
-                               }
-               | CURRENT_USER
-                               {
-                                       FuncCall *n = makeNode(FuncCall);
-                                       n->funcname = "getpgusername";
-                                       n->args = NIL;
-                                       $$ = (Node *)n;
-                               }
-               | USER
-                               {
-                                       FuncCall *n = makeNode(FuncCall);
-                                       n->funcname = "getpgusername";
-                                       n->args = NIL;
-                                       $$ = (Node *)n;
-                               }
-               | EXTRACT '(' extract_list ')'
-                               {
-                                       FuncCall *n = makeNode(FuncCall);
-                                       n->funcname = "date_part";
-                                       n->args = $3;
-                                       $$ = (Node *)n;
-                               }
-               | POSITION '(' position_list ')'
-                               {
-                                       FuncCall *n = makeNode(FuncCall);
-                                       n->funcname = "strpos";
-                                       n->args = $3;
-                                       $$ = (Node *)n;
-                               }
-               | SUBSTRING '(' substr_list ')'
-                               {
-                                       FuncCall *n = makeNode(FuncCall);
-                                       n->funcname = "substr";
-                                       n->args = $3;
-                                       $$ = (Node *)n;
-                               }
-               /* various trim expressions are defined in SQL92 - thomas 1997-07-19 */
-               | TRIM '(' BOTH trim_list ')'
-                               {
-                                       FuncCall *n = makeNode(FuncCall);
-                                       n->funcname = "btrim";
-                                       n->args = $4;
-                                       $$ = (Node *)n;
-                               }
-               | TRIM '(' LEADING trim_list ')'
-                               {
-                                       FuncCall *n = makeNode(FuncCall);
-                                       n->funcname = "ltrim";
-                                       n->args = $4;
-                                       $$ = (Node *)n;
-                               }
-               | TRIM '(' TRAILING trim_list ')'
-                               {
-                                       FuncCall *n = makeNode(FuncCall);
-                                       n->funcname = "rtrim";
-                                       n->args = $4;
-                                       $$ = (Node *)n;
-                               }
-               | TRIM '(' trim_list ')'
-                               {
-                                       FuncCall *n = makeNode(FuncCall);
-                                       n->funcname = "btrim";
-                                       n->args = $3;
-                                       $$ = (Node *)n;
-                               }
                | a_expr ISNULL
                                {       $$ = makeA_Expr(ISNULL, NULL, $1, NULL); }
                | a_expr IS NULL_P
@@ -4105,7 +3894,7 @@ a_expr:  attr
                                                $$ = n;
                                        }
                                }
-               | a_expr row_op sub_type '(' SubSelect ')'
+               | a_expr all_Op sub_type '(' SubSelect ')'
                                {
                                        SubLink *n = makeNode(SubLink);
                                        n->lefthand = lcons($1, NIL);
@@ -4115,53 +3904,36 @@ a_expr:  attr
                                        n->subselect = $5;
                                        $$ = (Node *)n;
                                }
-               | EXISTS '(' SubSelect ')'
-                               {
-                                       SubLink *n = makeNode(SubLink);
-                                       n->lefthand = NIL;
-                                       n->oper = NIL;
-                                       n->useor = false;
-                                       n->subLinkType = EXISTS_SUBLINK;
-                                       n->subselect = $3;
-                                       $$ = (Node *)n;
-                               }
-               | '(' SubSelect ')'
-                               {
-                                       SubLink *n = makeNode(SubLink);
-                                       n->lefthand = NIL;
-                                       n->oper = NIL;
-                                       n->useor = false;
-                                       n->subLinkType = EXPR_SUBLINK;
-                                       n->subselect = $2;
-                                       $$ = (Node *)n;
-                               }
-               | a_expr AND a_expr
-                               {       $$ = makeA_Expr(AND, NULL, $1, $3); }
-               | a_expr OR a_expr
-                               {       $$ = makeA_Expr(OR, NULL, $1, $3); }
-               | NOT a_expr
-                               {       $$ = makeA_Expr(NOT, NULL, NULL, $2); }
-               | case_expr
-                               {       $$ = $1; }
+               | row_expr
+                               {       $$ = $1;  }
                ;
 
-/* Restricted expressions
- * b_expr is a subset of the complete expression syntax
- *  defined by a_expr. b_expr is used in BETWEEN clauses
- *  to eliminate parser ambiguities stemming from the AND keyword,
- *  and also in POSITION clauses where the IN keyword gives trouble.
+/*
+ * Restricted expressions
+ *
+ * b_expr is a subset of the complete expression syntax defined by a_expr.
+ *
+ * Presently, AND, NOT, IS, IN, and NULL are the a_expr keywords that would
+ * cause trouble in the places where b_expr is used.  For simplicity, we
+ * just eliminate all the boolean-keyword-operator productions from b_expr.
  */
-b_expr:  attr
-                               {       $$ = (Node *) $1;  }
-               | AexprConst
+b_expr:  com_expr
                                {       $$ = $1;  }
-               | ColId opt_indirection
+               | b_expr TYPECAST Typename
                                {
-                                       /* could be a column name or a relation_name */
-                                       Ident *n = makeNode(Ident);
-                                       n->name = $1;
-                                       n->indirection = $2;
-                                       $$ = (Node *)n;
+                                       $$ = (Node *)$1;
+                                       /* AexprConst can be either A_Const or ParamNo */
+                                       if (nodeTag($1) == T_A_Const) {
+                                               ((A_Const *)$1)->typename = $3;
+                                       } else if (nodeTag($1) == T_ParamNo) {
+                                               ((ParamNo *)$1)->typename = $3;
+                                       /* otherwise, try to transform to a function call */
+                                       } else {
+                                               FuncCall *n = makeNode(FuncCall);
+                                               n->funcname = $3->name;
+                                               n->args = lcons($1,NIL);
+                                               $$ = (Node *)n;
+                                       }
                                }
                | '-' b_expr %prec UMINUS
                                {       $$ = doNegate($2); }
@@ -4195,23 +3967,44 @@ b_expr:  attr
                                {       $$ = makeA_Expr(OP, "^", $1, $3); }
                | b_expr '|' b_expr
                                {       $$ = makeA_Expr(OP, "|", $1, $3); }
-               | b_expr TYPECAST Typename
+               | b_expr '<' b_expr
+                               {       $$ = makeA_Expr(OP, "<", $1, $3); }
+               | b_expr '>' b_expr
+                               {       $$ = makeA_Expr(OP, ">", $1, $3); }
+               | b_expr '=' b_expr
+                               {       $$ = makeA_Expr(OP, "=", $1, $3); }
+
+               | b_expr Op b_expr
+                               {       $$ = makeA_Expr(OP, $2, $1, $3); }
+               | Op b_expr
+                               {       $$ = makeA_Expr(OP, $1, NULL, $2); }
+               | b_expr Op
+                               {       $$ = makeA_Expr(OP, $2, $1, NULL); }
+               ;
+
+/*
+ * Productions that can be used in both a_expr and b_expr.
+ *
+ * Note: productions that refer recursively to a_expr or b_expr mostly
+ * cannot appear here.  However, it's OK to refer to a_exprs that occur
+ * inside parentheses, such as function arguments; that cannot introduce
+ * ambiguity to the b_expr syntax.
+ */
+com_expr:  attr
+                               {       $$ = (Node *) $1;  }
+               | ColId opt_indirection
                                {
-                                       $$ = (Node *)$1;
-                                       /* AexprConst can be either A_Const or ParamNo */
-                                       if (nodeTag($1) == T_A_Const) {
-                                               ((A_Const *)$1)->typename = $3;
-                                       } else if (nodeTag($1) == T_ParamNo) {
-                                               ((ParamNo *)$1)->typename = $3;
-                                       /* otherwise, try to transform to a function call */
-                                       } else {
-                                               FuncCall *n = makeNode(FuncCall);
-                                               n->funcname = $3->name;
-                                               n->args = lcons($1,NIL);
-                                               $$ = (Node *)n;
-                                       }
+                                       /* could be a column name or a relation_name */
+                                       Ident *n = makeNode(Ident);
+                                       n->name = $1;
+                                       n->indirection = $2;
+                                       $$ = (Node *)n;
                                }
-               | CAST '(' b_expr AS Typename ')'
+               | AexprConst
+                               {       $$ = $1;  }
+               | '(' a_expr_or_null ')'
+                               {       $$ = $2; }
+               | CAST '(' a_expr AS Typename ')'
                                {
                                        $$ = (Node *)$3;
                                        /* AexprConst can be either A_Const or ParamNo */
@@ -4227,14 +4020,8 @@ b_expr:  attr
                                                $$ = (Node *)n;
                                        }
                                }
-               | '(' a_expr ')'
-                               {       $$ = $2; }
-               | b_expr Op b_expr
-                               {       $$ = makeA_Expr(OP, $2,$1,$3);  }
-               | Op b_expr
-                               {       $$ = makeA_Expr(OP, $1, NULL, $2); }
-               | b_expr Op
-                               {       $$ = makeA_Expr(OP, $2, $1, NULL); }
+               | case_expr
+                               {       $$ = $1; }
                | func_name '(' ')'
                                {
                                        FuncCall *n = makeNode(FuncCall);
@@ -4249,53 +4036,108 @@ b_expr:  attr
                                        n->args = $3;
                                        $$ = (Node *)n;
                                }
+               | func_name '(' '*' ')'
+                               {
+                                       /*
+                                        * For now, we transform AGGREGATE(*) into AGGREGATE(1).
+                                        *
+                                        * This does the right thing for COUNT(*) (in fact,
+                                        * any certainly-non-null expression would do for COUNT),
+                                        * and there are no other aggregates in SQL92 that accept
+                                        * '*' as parameter.
+                                        *
+                                        * XXX really, the '*' ought to be transformed to some
+                                        * special construct that wouldn't be acceptable as the
+                                        * input of a non-aggregate function, in case the given
+                                        * func_name matches a plain function.  This would also
+                                        * support a possible extension to let user-defined
+                                        * aggregates do something special with '*' as input.
+                                        */
+                                       FuncCall *n = makeNode(FuncCall);
+                                       A_Const *star = makeNode(A_Const);
+
+                                       star->val.type = T_Integer;
+                                       star->val.val.ival = 1;
+                                       n->funcname = $1;
+                                       n->args = lcons(star, NIL);
+                                       $$ = (Node *)n;
+                               }
                | CURRENT_DATE
                                {
-                                       A_Const *n = makeNode(A_Const);
+                                       /*
+                                        * Translate as "date('now'::text)".
+                                        *
+                                        * We cannot use "'now'::date" because coerce_type() will
+                                        * immediately reduce that to a constant representing
+                                        * today's date.  We need to delay the conversion until
+                                        * runtime, else the wrong things will happen when
+                                        * CURRENT_DATE is used in a column default value or rule.
+                                        *
+                                        * This could be simplified if we had a way to generate
+                                        * an expression tree representing runtime application
+                                        * of type-input conversion functions...
+                                        */
+                                       A_Const *s = makeNode(A_Const);
                                        TypeName *t = makeNode(TypeName);
+                                       FuncCall *n = makeNode(FuncCall);
 
-                                       n->val.type = T_String;
-                                       n->val.val.str = "now";
-                                       n->typename = t;
+                                       s->val.type = T_String;
+                                       s->val.val.str = "now";
+                                       s->typename = t;
 
-                                       t->name = xlateSqlType("date");
+                                       t->name = xlateSqlType("text");
                                        t->setof = FALSE;
                                        t->typmod = -1;
 
+                                       n->funcname = xlateSqlType("date");
+                                       n->args = lcons(s, NIL);
+
                                        $$ = (Node *)n;
                                }
                | CURRENT_TIME
                                {
-                                       A_Const *n = makeNode(A_Const);
+                                       /*
+                                        * Translate as "time('now'::text)".
+                                        * See comments for CURRENT_DATE.
+                                        */
+                                       A_Const *s = makeNode(A_Const);
                                        TypeName *t = makeNode(TypeName);
+                                       FuncCall *n = makeNode(FuncCall);
 
-                                       n->val.type = T_String;
-                                       n->val.val.str = "now";
-                                       n->typename = t;
+                                       s->val.type = T_String;
+                                       s->val.val.str = "now";
+                                       s->typename = t;
 
-                                       t->name = xlateSqlType("time");
+                                       t->name = xlateSqlType("text");
                                        t->setof = FALSE;
                                        t->typmod = -1;
 
+                                       n->funcname = xlateSqlType("time");
+                                       n->args = lcons(s, NIL);
+
                                        $$ = (Node *)n;
                                }
                | CURRENT_TIME '(' Iconst ')'
                                {
-                                       FuncCall *n = makeNode(FuncCall);
+                                       /*
+                                        * Translate as "time('now'::text)".
+                                        * See comments for CURRENT_DATE.
+                                        */
                                        A_Const *s = makeNode(A_Const);
                                        TypeName *t = makeNode(TypeName);
-
-                                       n->funcname = xlateSqlType("time");
-                                       n->args = lcons(s, NIL);
+                                       FuncCall *n = makeNode(FuncCall);
 
                                        s->val.type = T_String;
                                        s->val.val.str = "now";
                                        s->typename = t;
 
-                                       t->name = xlateSqlType("time");
+                                       t->name = xlateSqlType("text");
                                        t->setof = FALSE;
                                        t->typmod = -1;
 
+                                       n->funcname = xlateSqlType("time");
+                                       n->args = lcons(s, NIL);
+
                                        if ($3 != 0)
                                                elog(NOTICE,"CURRENT_TIME(%d) precision not implemented; zero used instead",$3);
 
@@ -4303,36 +4145,48 @@ b_expr:  attr
                                }
                | CURRENT_TIMESTAMP
                                {
-                                       A_Const *n = makeNode(A_Const);
+                                       /*
+                                        * Translate as "timestamp('now'::text)".
+                                        * See comments for CURRENT_DATE.
+                                        */
+                                       A_Const *s = makeNode(A_Const);
                                        TypeName *t = makeNode(TypeName);
+                                       FuncCall *n = makeNode(FuncCall);
 
-                                       n->val.type = T_String;
-                                       n->val.val.str = "now";
-                                       n->typename = t;
+                                       s->val.type = T_String;
+                                       s->val.val.str = "now";
+                                       s->typename = t;
 
-                                       t->name = xlateSqlType("timestamp");
+                                       t->name = xlateSqlType("text");
                                        t->setof = FALSE;
                                        t->typmod = -1;
 
+                                       n->funcname = xlateSqlType("timestamp");
+                                       n->args = lcons(s, NIL);
+
                                        $$ = (Node *)n;
                                }
                | CURRENT_TIMESTAMP '(' Iconst ')'
                                {
-                                       FuncCall *n = makeNode(FuncCall);
+                                       /*
+                                        * Translate as "timestamp('now'::text)".
+                                        * See comments for CURRENT_DATE.
+                                        */
                                        A_Const *s = makeNode(A_Const);
                                        TypeName *t = makeNode(TypeName);
-
-                                       n->funcname = xlateSqlType("timestamp");
-                                       n->args = lcons(s, NIL);
+                                       FuncCall *n = makeNode(FuncCall);
 
                                        s->val.type = T_String;
                                        s->val.val.str = "now";
                                        s->typename = t;
 
-                                       t->name = xlateSqlType("timestamp");
+                                       t->name = xlateSqlType("text");
                                        t->setof = FALSE;
                                        t->typmod = -1;
 
+                                       n->funcname = xlateSqlType("timestamp");
+                                       n->args = lcons(s, NIL);
+
                                        if ($3 != 0)
                                                elog(NOTICE,"CURRENT_TIMESTAMP(%d) precision not implemented; zero used instead",$3);
 
@@ -4352,6 +4206,13 @@ b_expr:  attr
                                        n->args = NIL;
                                        $$ = (Node *)n;
                                }
+               | EXTRACT '(' extract_list ')'
+                               {
+                                       FuncCall *n = makeNode(FuncCall);
+                                       n->funcname = "date_part";
+                                       n->args = $3;
+                                       $$ = (Node *)n;
+                               }
                | POSITION '(' position_list ')'
                                {
                                        FuncCall *n = makeNode(FuncCall);
@@ -4405,8 +4266,22 @@ b_expr:  attr
                                        n->subselect = $2;
                                        $$ = (Node *)n;
                                }
+               | EXISTS '(' SubSelect ')'
+                               {
+                                       SubLink *n = makeNode(SubLink);
+                                       n->lefthand = NIL;
+                                       n->oper = NIL;
+                                       n->useor = false;
+                                       n->subLinkType = EXISTS_SUBLINK;
+                                       n->subselect = $3;
+                                       $$ = (Node *)n;
+                               }
                ;
 
+/*
+ * Supporting nonterminals for expressions.
+ */
+
 opt_indirection:  '[' a_expr ']' opt_indirection
                                {
                                        A_Indices *ai = makeNode(A_Indices);