From c1dcd59c484a56f92a1dccab99b2473aad19ca92 Mon Sep 17 00:00:00 2001 From: "Thomas G. Lockhart" Date: Wed, 4 Feb 1998 06:11:48 +0000 Subject: [PATCH] Allow most expressions in BETWEEN clause. Allow all expressions if surrounded by parentheses (but not all are meaningful). Remove unused keywords ACL, APPEND, MERGE. Requires a "make clean" to recompile all code since keyword numeric assignments have changed with keyword removal. --- src/backend/parser/gram.y | 267 ++++++++++++++++++++++++++++++++-- src/backend/parser/keywords.c | 6 +- 2 files changed, 252 insertions(+), 21 deletions(-) diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index b3a6f73095..0100081a4a 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 1.103 1998/02/03 19:26:41 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 1.104 1998/02/04 06:11:46 thomas Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -188,7 +188,7 @@ Oid param_type(int t); /* used in parse_expr.c */ %type columnDef, alter_clause %type def_elem %type def_arg, columnElem, where_clause, - a_expr, a_expr_or_null, AexprConst, + a_expr, a_expr_or_null, b_expr, AexprConst, in_expr, in_expr_nodes, not_in_expr, not_in_expr_nodes, having_clause %type row_descriptor, row_list @@ -269,14 +269,14 @@ Oid param_type(int t); /* used in parse_expr.c */ %token TYPE_P /* Keywords for Postgres support (not in SQL92 reserved words) */ -%token ABORT_TRANS, ACL, AFTER, AGGREGATE, ANALYZE, - APPEND, BACKWARD, BEFORE, BINARY, CLUSTER, COPY, +%token ABORT_TRANS, AFTER, AGGREGATE, ANALYZE, + BACKWARD, BEFORE, BINARY, CLUSTER, COPY, DATABASE, DELIMITERS, DO, EXPLAIN, EXTEND, FORWARD, FUNCTION, HANDLER, INDEX, INHERITS, INSTEAD, ISNULL, - LANCOMPILER, LISTEN, LOAD, LOCK_P, LOCATION, MERGE, MOVE, + LANCOMPILER, LISTEN, LOAD, LOCK_P, LOCATION, MOVE, NEW, NONE, NOTHING, NOTNULL, OIDS, OPERATOR, PROCEDURAL, - RECIPE, RENAME, REPLACE, RESET, RETURNS, RULE, + RECIPE, RENAME, RESET, RETURNS, RULE, SEQUENCE, SETOF, SHOW, STDIN, STDOUT, TRUSTED, VACUUM, VERBOSE, VERSION @@ -3199,6 +3199,14 @@ row_list: row_list ',' a_expr } ; +/* + * 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 are allowed in a BETWEEN clause if surrounded by parens. + */ + a_expr: attr opt_indirection { $1->indirection = $2; @@ -3208,6 +3216,14 @@ a_expr: attr opt_indirection { $$ = $1; } | AexprConst { $$ = $1; } + | ColId + { + /* could be a column name or a relation_name */ + Ident *n = makeNode(Ident); + n->name = $1; + n->indirection = NULL; + $$ = (Node *)n; + } | '-' a_expr %prec UMINUS { $$ = makeA_Expr(OP, "-", NULL, $2); } | a_expr '+' a_expr @@ -3274,14 +3290,6 @@ a_expr: attr opt_indirection { $$ = makeA_Expr(OP, $1, NULL, $2); } | a_expr Op { $$ = makeA_Expr(OP, $2, $1, NULL); } - | ColId - { - /* could be a column name or a relation_name */ - Ident *n = makeNode(Ident); - n->name = $1; - n->indirection = NULL; - $$ = (Node *)n; - } | name '(' '*' ')' { /* cheap hack for aggregate (eg. count) */ @@ -3508,13 +3516,13 @@ a_expr: attr opt_indirection n->typename->name = xlateSqlType("bool"); $$ = makeA_Expr(OP, "=", $1,(Node *)n); } - | a_expr BETWEEN AexprConst AND AexprConst + | a_expr BETWEEN b_expr AND b_expr { $$ = makeA_Expr(AND, NULL, makeA_Expr(OP, ">=", $1, $3), makeA_Expr(OP, "<=", $1, $5)); } - | a_expr NOT BETWEEN AexprConst AND AexprConst + | a_expr NOT BETWEEN b_expr AND b_expr { $$ = makeA_Expr(OR, NULL, makeA_Expr(OP, "<", $1, $4), @@ -3796,6 +3804,233 @@ a_expr: attr opt_indirection { $$ = makeA_Expr(NOT, NULL, NULL, $2); } ; +/* + * 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. + */ + +b_expr: attr opt_indirection + { + $1->indirection = $2; + $$ = (Node *)$1; + } + | AexprConst + { $$ = $1; } + | ColId + { + /* could be a column name or a relation_name */ + Ident *n = makeNode(Ident); + n->name = $1; + n->indirection = NULL; + $$ = (Node *)n; + } + | '-' b_expr %prec UMINUS + { $$ = makeA_Expr(OP, "-", NULL, $2); } + | 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 '*' b_expr + { $$ = makeA_Expr(OP, "*", $1, $3); } + | ':' b_expr + { $$ = makeA_Expr(OP, ":", NULL, $2); } + | ';' b_expr + { $$ = makeA_Expr(OP, ";", NULL, $2); } + | '|' b_expr + { $$ = makeA_Expr(OP, "|", NULL, $2); } + | b_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_Param) { + ((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 b_expr AS Typename + { + $$ = (Node *)$2; + /* AexprConst can be either A_Const or ParamNo */ + if (nodeTag($2) == T_A_Const) { + ((A_Const *)$2)->typename = $4; + } else if (nodeTag($2) == T_Param) { + ((ParamNo *)$2)->typename = $4; + /* otherwise, try to transform to a function call */ + } else { + FuncCall *n = makeNode(FuncCall); + n->funcname = $4->name; + n->args = lcons($2,NIL); + $$ = (Node *)n; + } + } + | '(' a_expr ')' + { $$ = $2; } + | b_expr Op b_expr + { $$ = makeIndexable($2,$1,$3); } + | Op b_expr + { $$ = makeA_Expr(OP, $1, NULL, $2); } + | b_expr Op + { $$ = makeA_Expr(OP, $2, $1, NULL); } + | name '(' ')' + { + FuncCall *n = makeNode(FuncCall); + n->funcname = $1; + n->args = NIL; + $$ = (Node *)n; + } + | 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; + + $$ = (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; + + $$ = (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; + + 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; + + $$ = (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; + + if ($3 != 0) + elog(NOTICE,"CURRENT_TIMESTAMP(%d) precision not implemented; zero used instead",$3); + + $$ = (Node *)n; + } + | CURRENT_USER + { + FuncCall *n = makeNode(FuncCall); + n->funcname = "getpgusername"; + n->args = NIL; + $$ = (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; + } + ; + opt_indirection: '[' a_expr ']' opt_indirection { A_Indices *ai = makeNode(A_Indices); diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c index 2c556f2a8e..6567b015c0 100644 --- a/src/backend/parser/keywords.c +++ b/src/backend/parser/keywords.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.33 1998/02/03 16:04:05 thomas Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.34 1998/02/04 06:11:48 thomas Exp $ * *------------------------------------------------------------------------- */ @@ -30,7 +30,6 @@ static ScanKeyword ScanKeywords[] = { /* name value */ {"abort", ABORT_TRANS}, - {"acl", ACL}, {"action", ACTION}, {"add", ADD}, {"after", AFTER}, @@ -40,7 +39,6 @@ static ScanKeyword ScanKeywords[] = { {"analyze", ANALYZE}, {"and", AND}, {"any", ANY}, - {"append", APPEND}, {"archive", ARCHIVE}, {"as", AS}, {"asc", ASC}, @@ -128,7 +126,6 @@ static ScanKeyword ScanKeywords[] = { {"location", LOCATION}, {"lock", LOCK_P}, {"match", MATCH}, - {"merge", MERGE}, {"minute", MINUTE_P}, {"month", MONTH_P}, {"move", MOVE}, @@ -165,7 +162,6 @@ static ScanKeyword ScanKeywords[] = { {"recipe", RECIPE}, {"references", REFERENCES}, {"rename", RENAME}, - {"replace", REPLACE}, {"reset", RESET}, {"returns", RETURNS}, {"revoke", REVOKE}, -- 2.40.0