Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit a1ee066

Browse files
committed
Provide tunable knob for x = NULL -> x IS NULL transformation, default to off.
1 parent fd5e959 commit a1ee066

File tree

7 files changed

+101
-51
lines changed

7 files changed

+101
-51
lines changed

doc/src/sgml/func.sgml

+16-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/func.sgml,v 1.71 2001/09/10 02:46:18 ishii Exp $ -->
1+
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/func.sgml,v 1.72 2001/09/20 14:20:26 petere Exp $ -->
22

33
<chapter id="functions">
44
<title>Functions and Operators</title>
@@ -266,16 +266,24 @@
266266
Do <emphasis>not</emphasis> use
267267
<literal><replaceable>expression</replaceable> = NULL</literal>
268268
because NULL is not <quote>equal to</quote> NULL. (NULL represents
269-
an unknown value, so it is not known whether two unknown values are
270-
equal.) <productname>Postgres</productname> presently converts
271-
<literal>x = NULL</literal> clauses to <literal>x IS NULL</literal> to
272-
allow some broken client applications (such as
273-
<productname>Microsoft Access</productname>) to work, but this may
274-
be discontinued in a future release.
269+
an unknown value, and it is not known whether two unknown values are
270+
equal.)
275271
</para>
276272

277273
<para>
278-
Boolean values can be tested using the constructs
274+
Some applications may (incorrectly) require that
275+
<literal><replaceable>expression</replaceable> = NULL</literal>
276+
returns true if <replaceable>expression</replaceable> evaluates to
277+
the NULL value. To support these applications, the run-time option
278+
<varname>transform_null_equals</varname> can be turned on (e.g.,
279+
<literal>SET transform_null_equals TO ON;</literal>).
280+
<productname>PostgreSQL</productname> would then convert <literal>x
281+
= NULL</literal> clauses to <literal>x IS NULL</literal>. This was
282+
the default behavior in releases 6.5 through 7.1.
283+
</para>
284+
285+
<para>
286+
Boolean values can also be tested using the constructs
279287
<synopsis>
280288
<replaceable>expression</replaceable> IS TRUE
281289
<replaceable>expression</replaceable> IS NOT TRUE

doc/src/sgml/runtime.sgml

+44-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.80 2001/09/16 16:11:09 petere Exp $
2+
$Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.81 2001/09/20 14:20:27 petere Exp $
33
-->
44

55
<Chapter Id="runtime">
@@ -1201,6 +1201,49 @@ dynamic_library_path = '/usr/local/lib/postgresql:/home/my_project/lib:$libdir'
12011201
</listitem>
12021202
</varlistentry>
12031203

1204+
<varlistentry>
1205+
<term><varname>TRANSFORM_NULL_EQUALS</varname> (<type>boolean</type>)</term>
1206+
<listitem>
1207+
<para>
1208+
When turned on, expressions of the form
1209+
<literal><replaceable>expr</> = NULL</literal> (or
1210+
<literal>NULL = <replaceable>expr</></literal>) are treated as
1211+
<literal><replaceable>expr</> IS NULL</literal>, that is, they
1212+
return true if <replaceable>expr</> evaluates to the NULL
1213+
value, and false otherwise. The correct behavior of
1214+
<literal><replaceable>expr</> = NULL</literal> is to always
1215+
return NULL (unknown). Therefore this option defaults to off.
1216+
</para>
1217+
1218+
<para>
1219+
However, filtered forms in <productname>Microsoft
1220+
Access</productname> generate queries that appear to use
1221+
<literal><replaceable>expr</> = NULL</literal> to test for
1222+
NULLs, so if you use that interface to access the database you
1223+
might want to turn this option on. Since expressions of the
1224+
form <literal><replaceable>expr</> = NULL</literal> always
1225+
return NULL (using the correct interpretation) they are not
1226+
very useful and do not appear often in normal applications, so
1227+
this option does little harm in practice. But new users are
1228+
frequently confused about the semantics of expressions
1229+
involving NULL, so we do not turn this option on by default.
1230+
</para>
1231+
1232+
<para>
1233+
Note that this option only affects the literal <literal>=</>
1234+
operator, not other comparison operators or other expressions
1235+
that are computationally equivalent to some expression
1236+
involving the equals operator (such as <literal>IN</literal>).
1237+
Thus, this option is not a general fix for bad programming.
1238+
</para>
1239+
1240+
<para>
1241+
Refer to the <citetitle>User's Guide</citetitle> for related
1242+
information.
1243+
</para>
1244+
</listitem>
1245+
</varlistentry>
1246+
12041247
<varlistentry>
12051248
<term><varname>PORT</varname> (<type>integer</type>)</term>
12061249
<listitem>

src/backend/parser/gram.y

+3-26
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.251 2001/09/18 01:59:06 tgl Exp $
14+
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.252 2001/09/20 14:20:27 petere Exp $
1515
*
1616
* HISTORY
1717
* AUTHOR DATE MAJOR EVENT
@@ -89,7 +89,6 @@ static void insertSelectOptions(SelectStmt *stmt,
8989
List *sortClause, List *forUpdate,
9090
Node *limitOffset, Node *limitCount);
9191
static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg);
92-
static bool exprIsNullConstant(Node *arg);
9392
static Node *doNegate(Node *n);
9493
static void doNegateFloat(Value *v);
9594

@@ -4465,29 +4464,7 @@ a_expr: c_expr
44654464
| a_expr '>' a_expr
44664465
{ $$ = makeA_Expr(OP, ">", $1, $3); }
44674466
| a_expr '=' a_expr
4468-
{
4469-
/*
4470-
* Special-case "foo = NULL" and "NULL = foo" for
4471-
* compatibility with standards-broken products
4472-
* (like Microsoft's). Turn these into IS NULL exprs.
4473-
*/
4474-
if (exprIsNullConstant($3))
4475-
{
4476-
NullTest *n = makeNode(NullTest);
4477-
n->arg = $1;
4478-
n->nulltesttype = IS_NULL;
4479-
$$ = (Node *)n;
4480-
}
4481-
else if (exprIsNullConstant($1))
4482-
{
4483-
NullTest *n = makeNode(NullTest);
4484-
n->arg = $3;
4485-
n->nulltesttype = IS_NULL;
4486-
$$ = (Node *)n;
4487-
}
4488-
else
4489-
$$ = makeA_Expr(OP, "=", $1, $3);
4490-
}
4467+
{ $$ = makeA_Expr(OP, "=", $1, $3); }
44914468

44924469
| a_expr Op a_expr
44934470
{ $$ = makeA_Expr(OP, $2, $1, $3); }
@@ -6137,7 +6114,7 @@ Oid param_type(int t)
61376114
/*
61386115
* Test whether an a_expr is a plain NULL constant or not.
61396116
*/
6140-
static bool
6117+
bool
61416118
exprIsNullConstant(Node *arg)
61426119
{
61436120
if (arg && IsA(arg, A_Const))

src/backend/parser/parse_expr.c

+32-10
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.99 2001/08/09 18:28:17 petere Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.100 2001/09/20 14:20:27 petere Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -34,9 +34,10 @@
3434

3535

3636
int max_expr_depth = DEFAULT_MAX_EXPR_DEPTH;
37-
3837
static int expr_depth_counter = 0;
3938

39+
bool Transform_null_equals = false;
40+
4041
static Node *parser_typecast_constant(Value *expr, TypeName *typename);
4142
static Node *parser_typecast_expression(ParseState *pstate,
4243
Node *expr, TypeName *typename);
@@ -157,14 +158,35 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
157158
{
158159
case OP:
159160
{
160-
Node *lexpr = transformExpr(pstate,
161-
a->lexpr,
162-
precedence);
163-
Node *rexpr = transformExpr(pstate,
164-
a->rexpr,
165-
precedence);
166-
167-
result = (Node *) make_op(a->opname, lexpr, rexpr);
161+
/*
162+
* Special-case "foo = NULL" and "NULL = foo" for
163+
* compatibility with standards-broken products
164+
* (like Microsoft's). Turn these into IS NULL exprs.
165+
*/
166+
if (Transform_null_equals && strcmp(a->opname, "=")==0
167+
&& (exprIsNullConstant(a->lexpr) || exprIsNullConstant(a->rexpr)))
168+
{
169+
NullTest *n = makeNode(NullTest);
170+
n->nulltesttype = IS_NULL;
171+
172+
if (exprIsNullConstant(a->lexpr))
173+
n->arg = a->rexpr;
174+
else
175+
n->arg = a->lexpr;
176+
177+
result = transformExpr(pstate, n, precedence);
178+
}
179+
else
180+
{
181+
Node *lexpr = transformExpr(pstate,
182+
a->lexpr,
183+
precedence);
184+
Node *rexpr = transformExpr(pstate,
185+
a->rexpr,
186+
precedence);
187+
188+
result = (Node *) make_op(a->opname, lexpr, rexpr);
189+
}
168190
}
169191
break;
170192
case AND:

src/backend/utils/misc/guc.c

+2-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* Support for grand unified configuration scheme, including SET
55
* command, configuration file, and command line options.
66
*
7-
* $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.48 2001/09/12 14:06:37 petere Exp $
7+
* $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.49 2001/09/20 14:20:27 petere Exp $
88
*
99
* Copyright 2000 by PostgreSQL Global Development Group
1010
* Written by Peter Eisentraut <peter_e@gmx.net>.
@@ -247,12 +247,10 @@ static struct config_bool
247247
{"show_source_port", PGC_SIGHUP, &ShowPortNumber, false, NULL},
248248

249249
{"sql_inheritance", PGC_USERSET, &SQL_inheritance, true, NULL},
250-
251250
{"australian_timezones", PGC_USERSET, &Australian_timezones, false, ClearDateCache},
252-
253251
{"fixbtree", PGC_POSTMASTER, &FixBTree, true, NULL},
254-
255252
{"password_encryption", PGC_USERSET, &Password_encryption, false, NULL},
253+
{"transform_null_equals", PGC_USERSET, &Transform_null_equals, false, NULL},
256254

257255
{NULL, 0, NULL, false, NULL}
258256
};

src/include/parser/gramparse.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $Id: gramparse.h,v 1.15 2001/02/09 03:26:27 tgl Exp $
10+
* $Id: gramparse.h,v 1.16 2001/09/20 14:20:28 petere Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -29,5 +29,6 @@ extern Oid param_type(int t);
2929
extern int yyparse(void);
3030
extern char *xlateSqlFunc(char *name);
3131
extern char *xlateSqlType(char *name);
32+
bool exprIsNullConstant(Node *arg);
3233

3334
#endif /* GRAMPARSE_H */

src/include/parser/parse_expr.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $Id: parse_expr.h,v 1.21 2001/01/24 19:43:27 momjian Exp $
10+
* $Id: parse_expr.h,v 1.22 2001/09/20 14:20:28 petere Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -20,6 +20,7 @@
2020
#define EXPR_RELATION_FIRST 2
2121

2222
extern int max_expr_depth;
23+
extern bool Transform_null_equals;
2324

2425
extern Node *transformExpr(ParseState *pstate, Node *expr, int precedence);
2526
extern Oid exprType(Node *expr);

0 commit comments

Comments
 (0)