Skip to content

Commit 117fa25

Browse files
committed
Clean up grammar's handling of NULL in expressions: a_expr_or_null is
gone, replaced by plain a_expr. The few places where we needed to distinguish NULL from a_expr are now handled by tests inside the actions rather than by separate productions. This allows us to accept queries like 'SELECT 1 + NULL' without requiring parentheses around the NULL.
1 parent e8be8ff commit 117fa25

File tree

1 file changed

+66
-61
lines changed

1 file changed

+66
-61
lines changed

src/backend/parser/gram.y

Lines changed: 66 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*
1212
*
1313
* IDENTIFICATION
14-
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.153 2000/03/01 05:18:19 tgl Exp $
14+
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.154 2000/03/12 00:39:52 tgl Exp $
1515
*
1616
* HISTORY
1717
* AUTHOR DATE MAJOR EVENT
@@ -77,6 +77,7 @@ static Node *makeTypeCast(Node *arg, TypeName *typename);
7777
static Node *makeRowExpr(char *opr, List *largs, List *rargs);
7878
static void mapTargetColumns(List *source, List *target);
7979
static void param_type_init(Oid *typev, int nargs);
80+
static bool exprIsNullConstant(Node *arg);
8081
static Node *doNegate(Node *n);
8182
static void doNegateFloat(Value *v);
8283

@@ -229,7 +230,7 @@ static void doNegateFloat(Value *v);
229230
%type <node> columnDef
230231
%type <defelt> def_elem
231232
%type <node> def_arg, columnElem, where_clause,
232-
a_expr, a_expr_or_null, b_expr, c_expr, AexprConst,
233+
a_expr, b_expr, c_expr, AexprConst,
233234
in_expr, having_clause
234235
%type <list> row_descriptor, row_list, in_expr_nodes
235236
%type <node> row_expr
@@ -873,8 +874,14 @@ AlterTableStmt:
873874
;
874875

875876
alter_column_action:
876-
SET DEFAULT a_expr { $$ = $3; }
877-
| SET DEFAULT NULL_P { $$ = NULL; }
877+
SET DEFAULT a_expr
878+
{
879+
/* Treat SET DEFAULT NULL the same as DROP DEFAULT */
880+
if (exprIsNullConstant($3))
881+
$$ = NULL;
882+
else
883+
$$ = $3;
884+
}
878885
| DROP DEFAULT { $$ = NULL; }
879886
;
880887

@@ -1155,22 +1162,20 @@ ColConstraintElem:
11551162
n->keys = NULL;
11561163
$$ = (Node *)n;
11571164
}
1158-
| DEFAULT NULL_P
1159-
{
1160-
Constraint *n = makeNode(Constraint);
1161-
n->contype = CONSTR_DEFAULT;
1162-
n->name = NULL;
1163-
n->raw_expr = NULL;
1164-
n->cooked_expr = NULL;
1165-
n->keys = NULL;
1166-
$$ = (Node *)n;
1167-
}
11681165
| DEFAULT b_expr
11691166
{
11701167
Constraint *n = makeNode(Constraint);
11711168
n->contype = CONSTR_DEFAULT;
11721169
n->name = NULL;
1173-
n->raw_expr = $2;
1170+
if (exprIsNullConstant($2))
1171+
{
1172+
/* DEFAULT NULL should be reported as empty expr */
1173+
n->raw_expr = NULL;
1174+
}
1175+
else
1176+
{
1177+
n->raw_expr = $2;
1178+
}
11741179
n->cooked_expr = NULL;
11751180
n->keys = NULL;
11761181
$$ = (Node *)n;
@@ -4017,16 +4022,6 @@ opt_interval: datetime { $$ = lcons($1, NIL); }
40174022
*
40184023
*****************************************************************************/
40194024

4020-
a_expr_or_null: a_expr
4021-
{ $$ = $1; }
4022-
| NULL_P
4023-
{
4024-
A_Const *n = makeNode(A_Const);
4025-
n->val.type = T_Null;
4026-
$$ = (Node *)n;
4027-
}
4028-
;
4029-
40304025
/* Expressions using row descriptors
40314026
* Define row_descriptor to allow yacc to break the reduce/reduce conflict
40324027
* with singleton expressions.
@@ -4137,17 +4132,6 @@ a_expr: c_expr
41374132
{ $$ = $1; }
41384133
| a_expr TYPECAST Typename
41394134
{ $$ = makeTypeCast($1, $3); }
4140-
/*
4141-
* Can't collapse this into prior rule by using a_expr_or_null;
4142-
* that creates reduce/reduce conflicts. Grumble.
4143-
*/
4144-
| NULL_P TYPECAST Typename
4145-
{
4146-
A_Const *n = makeNode(A_Const);
4147-
n->val.type = T_Null;
4148-
n->typename = $3;
4149-
$$ = (Node *)n;
4150-
}
41514135
/*
41524136
* These operators must be called out explicitly in order to make use
41534137
* of yacc/bison's automatic operator-precedence handling. All other
@@ -4193,15 +4177,20 @@ a_expr: c_expr
41934177
{ $$ = makeA_Expr(OP, "<", $1, $3); }
41944178
| a_expr '>' a_expr
41954179
{ $$ = makeA_Expr(OP, ">", $1, $3); }
4196-
4197-
| a_expr '=' NULL_P
4198-
{ $$ = makeA_Expr(ISNULL, NULL, $1, NULL); }
4199-
/* We allow this for standards-broken SQL products, like MS stuff */
4200-
| NULL_P '=' a_expr
4201-
{ $$ = makeA_Expr(ISNULL, NULL, $3, NULL); }
4202-
42034180
| a_expr '=' a_expr
4204-
{ $$ = makeA_Expr(OP, "=", $1, $3); }
4181+
{
4182+
/*
4183+
* Special-case "foo = NULL" and "NULL = foo" for
4184+
* compatibility with standards-broken products
4185+
* (like Microsoft's). Turn these into IS NULL exprs.
4186+
*/
4187+
if (exprIsNullConstant($3))
4188+
$$ = makeA_Expr(ISNULL, NULL, $1, NULL);
4189+
else if (exprIsNullConstant($1))
4190+
$$ = makeA_Expr(ISNULL, NULL, $3, NULL);
4191+
else
4192+
$$ = makeA_Expr(OP, "=", $1, $3);
4193+
}
42054194

42064195
| a_expr Op a_expr
42074196
{ $$ = makeA_Expr(OP, $2, $1, $3); }
@@ -4360,21 +4349,14 @@ a_expr: c_expr
43604349
*
43614350
* b_expr is a subset of the complete expression syntax defined by a_expr.
43624351
*
4363-
* Presently, AND, NOT, IS, IN, and NULL are the a_expr keywords that would
4352+
* Presently, AND, NOT, IS, and IN are the a_expr keywords that would
43644353
* cause trouble in the places where b_expr is used. For simplicity, we
43654354
* just eliminate all the boolean-keyword-operator productions from b_expr.
43664355
*/
43674356
b_expr: c_expr
43684357
{ $$ = $1; }
43694358
| b_expr TYPECAST Typename
43704359
{ $$ = makeTypeCast($1, $3); }
4371-
| NULL_P TYPECAST Typename
4372-
{
4373-
A_Const *n = makeNode(A_Const);
4374-
n->val.type = T_Null;
4375-
n->typename = $3;
4376-
$$ = (Node *)n;
4377-
}
43784360
| '-' b_expr %prec UMINUS
43794361
{ $$ = doNegate($2); }
43804362
| '%' b_expr
@@ -4442,9 +4424,9 @@ c_expr: attr
44424424
}
44434425
| AexprConst
44444426
{ $$ = $1; }
4445-
| '(' a_expr_or_null ')'
4427+
| '(' a_expr ')'
44464428
{ $$ = $2; }
4447-
| CAST '(' a_expr_or_null AS Typename ')'
4429+
| CAST '(' a_expr AS Typename ')'
44484430
{ $$ = makeTypeCast($3, $5); }
44494431
| case_expr
44504432
{ $$ = $1; }
@@ -4788,9 +4770,9 @@ opt_indirection: '[' a_expr ']' opt_indirection
47884770
{ $$ = NIL; }
47894771
;
47904772

4791-
expr_list: a_expr_or_null
4773+
expr_list: a_expr
47924774
{ $$ = lcons($1, NIL); }
4793-
| expr_list ',' a_expr_or_null
4775+
| expr_list ',' a_expr
47944776
{ $$ = lappend($1, $3); }
47954777
| expr_list USING a_expr
47964778
{ $$ = lappend($1, $3); }
@@ -4928,7 +4910,7 @@ when_clause_list: when_clause_list when_clause
49284910
{ $$ = lcons($1, NIL); }
49294911
;
49304912

4931-
when_clause: WHEN a_expr THEN a_expr_or_null
4913+
when_clause: WHEN a_expr THEN a_expr
49324914
{
49334915
CaseWhen *w = makeNode(CaseWhen);
49344916
w->expr = $2;
@@ -4937,7 +4919,7 @@ when_clause: WHEN a_expr THEN a_expr_or_null
49374919
}
49384920
;
49394921

4940-
case_default: ELSE a_expr_or_null { $$ = $2; }
4922+
case_default: ELSE a_expr { $$ = $2; }
49414923
| /*EMPTY*/ { $$ = NULL; }
49424924
;
49434925

@@ -4989,14 +4971,14 @@ target_list: target_list ',' target_el
49894971
;
49904972

49914973
/* AS is not optional because shift/red conflict with unary ops */
4992-
target_el: a_expr_or_null AS ColLabel
4974+
target_el: a_expr AS ColLabel
49934975
{
49944976
$$ = makeNode(ResTarget);
49954977
$$->name = $3;
49964978
$$->indirection = NULL;
49974979
$$->val = (Node *)$1;
49984980
}
4999-
| a_expr_or_null
4981+
| a_expr
50004982
{
50014983
$$ = makeNode(ResTarget);
50024984
$$->name = NULL;
@@ -5037,7 +5019,7 @@ update_target_list: update_target_list ',' update_target_el
50375019
{ $$ = lcons($1, NIL); }
50385020
;
50395021

5040-
update_target_el: ColId opt_indirection '=' a_expr_or_null
5022+
update_target_el: ColId opt_indirection '=' a_expr
50415023
{
50425024
$$ = makeNode(ResTarget);
50435025
$$->name = $1;
@@ -5142,6 +5124,12 @@ AexprConst: Iconst
51425124
n->typename->typmod = -1;
51435125
$$ = (Node *)n;
51445126
}
5127+
| NULL_P
5128+
{
5129+
A_Const *n = makeNode(A_Const);
5130+
n->val.type = T_Null;
5131+
$$ = (Node *)n;
5132+
}
51455133
;
51465134

51475135
ParamNo: PARAM opt_indirection
@@ -5532,6 +5520,23 @@ Oid param_type(int t)
55325520
return param_type_info[t - 1];
55335521
}
55345522

5523+
/*
5524+
* Test whether an a_expr is a plain NULL constant or not.
5525+
*/
5526+
static bool
5527+
exprIsNullConstant(Node *arg)
5528+
{
5529+
if (arg && IsA(arg, A_Const))
5530+
{
5531+
A_Const *con = (A_Const *) arg;
5532+
5533+
if (con->val.type == T_Null &&
5534+
con->typename == NULL)
5535+
return true;
5536+
}
5537+
return false;
5538+
}
5539+
55355540
/*
55365541
* doNegate --- handle negation of a numeric constant.
55375542
*

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy