diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2006-09-28 20:51:43 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2006-09-28 20:51:43 +0000 |
commit | f213131f2024bcb85aea7d2a7dfadef6a0ee1b31 (patch) | |
tree | 090a85694dfd64f735732bc49b8489835186d83b /src/backend/parser | |
parent | d3aa4a8e33bee5e5274615cfd461aac810d7bbc1 (diff) | |
download | postgresql-f213131f2024bcb85aea7d2a7dfadef6a0ee1b31.tar.gz postgresql-f213131f2024bcb85aea7d2a7dfadef6a0ee1b31.zip |
Fix IS NULL and IS NOT NULL tests on row-valued expressions to conform to
the SQL spec, viz IS NULL is true if all the row's fields are null, IS NOT
NULL is true if all the row's fields are not null. The former coding got
this right for a limited number of cases with IS NULL (ie, those where it
could disassemble a ROW constructor at parse time), but was entirely wrong
for IS NOT NULL. Per report from Teodor.
I desisted from changing the behavior for arrays, since on closer inspection
it's not clear that there's any support for that in the SQL spec. This
probably needs more consideration.
Diffstat (limited to 'src/backend/parser')
-rw-r--r-- | src/backend/parser/gram.y | 100 |
1 files changed, 21 insertions, 79 deletions
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index e0d52887958..69a2af46265 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.565 2006/09/03 22:37:05 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.566 2006/09/28 20:51:42 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -94,7 +94,6 @@ static Node *makeStringConst(char *str, TypeName *typename); static Node *makeIntConst(int val); static Node *makeFloatConst(char *str); static Node *makeAConst(Value *v); -static Node *makeRowNullTest(NullTestType test, RowExpr *row); static A_Const *makeBoolAConst(bool state); static FuncCall *makeOverlaps(List *largs, List *rargs, int location); static void check_qualified_name(List *names); @@ -7037,53 +7036,33 @@ a_expr: c_expr { $$ = $1; } * a ISNULL * a NOTNULL */ - | a_expr ISNULL - { - if (IsA($1, RowExpr)) - $$ = makeRowNullTest(IS_NULL, (RowExpr *) $1); - else - { - NullTest *n = makeNode(NullTest); - n->arg = (Expr *) $1; - n->nulltesttype = IS_NULL; - $$ = (Node *)n; - } - } | a_expr IS NULL_P { - if (IsA($1, RowExpr)) - $$ = makeRowNullTest(IS_NULL, (RowExpr *) $1); - else - { - NullTest *n = makeNode(NullTest); - n->arg = (Expr *) $1; - n->nulltesttype = IS_NULL; - $$ = (Node *)n; - } + NullTest *n = makeNode(NullTest); + n->arg = (Expr *) $1; + n->nulltesttype = IS_NULL; + $$ = (Node *)n; } - | a_expr NOTNULL + | a_expr ISNULL { - if (IsA($1, RowExpr)) - $$ = makeRowNullTest(IS_NOT_NULL, (RowExpr *) $1); - else - { - NullTest *n = makeNode(NullTest); - n->arg = (Expr *) $1; - n->nulltesttype = IS_NOT_NULL; - $$ = (Node *)n; - } + NullTest *n = makeNode(NullTest); + n->arg = (Expr *) $1; + n->nulltesttype = IS_NULL; + $$ = (Node *)n; } | a_expr IS NOT NULL_P { - if (IsA($1, RowExpr)) - $$ = makeRowNullTest(IS_NOT_NULL, (RowExpr *) $1); - else - { - NullTest *n = makeNode(NullTest); - n->arg = (Expr *) $1; - n->nulltesttype = IS_NOT_NULL; - $$ = (Node *)n; - } + NullTest *n = makeNode(NullTest); + n->arg = (Expr *) $1; + n->nulltesttype = IS_NOT_NULL; + $$ = (Node *)n; + } + | a_expr NOTNULL + { + NullTest *n = makeNode(NullTest); + n->arg = (Expr *) $1; + n->nulltesttype = IS_NOT_NULL; + $$ = (Node *)n; } | row OVERLAPS row { @@ -9082,43 +9061,6 @@ makeBoolAConst(bool state) return n; } -/* makeRowNullTest() - * Generate separate operator nodes for a single row descriptor test. - * - * Eventually this should be eliminated in favor of making the NullTest - * node type capable of handling it directly. - */ -static Node * -makeRowNullTest(NullTestType test, RowExpr *row) -{ - Node *result = NULL; - ListCell *arg; - - foreach(arg, row->args) - { - NullTest *n; - - n = makeNode(NullTest); - n->arg = (Expr *) lfirst(arg); - n->nulltesttype = test; - - if (result == NULL) - result = (Node *) n; - else if (test == IS_NOT_NULL) - result = (Node *) makeA_Expr(AEXPR_OR, NIL, result, (Node *)n, -1); - else - result = (Node *) makeA_Expr(AEXPR_AND, NIL, result, (Node *)n, -1); - } - - if (result == NULL) - { - /* zero-length rows? Generate constant TRUE or FALSE */ - result = (Node *) makeBoolAConst(test == IS_NULL); - } - - return result; -} - /* makeOverlaps() * Create and populate a FuncCall node to support the OVERLAPS operator. */ |