提交 a1ee0662 编写于 作者: P Peter Eisentraut

Provide tunable knob for x = NULL -> x IS NULL transformation, default to off.

上级 fd5e9597
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/func.sgml,v 1.71 2001/09/10 02:46:18 ishii Exp $ -->
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/func.sgml,v 1.72 2001/09/20 14:20:26 petere Exp $ -->
<chapter id="functions">
<title>Functions and Operators</title>
......@@ -266,16 +266,24 @@
Do <emphasis>not</emphasis> use
<literal><replaceable>expression</replaceable> = NULL</literal>
because NULL is not <quote>equal to</quote> NULL. (NULL represents
an unknown value, so it is not known whether two unknown values are
equal.) <productname>Postgres</productname> presently converts
<literal>x = NULL</literal> clauses to <literal>x IS NULL</literal> to
allow some broken client applications (such as
<productname>Microsoft Access</productname>) to work, but this may
be discontinued in a future release.
an unknown value, and it is not known whether two unknown values are
equal.)
</para>
<para>
Boolean values can be tested using the constructs
Some applications may (incorrectly) require that
<literal><replaceable>expression</replaceable> = NULL</literal>
returns true if <replaceable>expression</replaceable> evaluates to
the NULL value. To support these applications, the run-time option
<varname>transform_null_equals</varname> can be turned on (e.g.,
<literal>SET transform_null_equals TO ON;</literal>).
<productname>PostgreSQL</productname> would then convert <literal>x
= NULL</literal> clauses to <literal>x IS NULL</literal>. This was
the default behavior in releases 6.5 through 7.1.
</para>
<para>
Boolean values can also be tested using the constructs
<synopsis>
<replaceable>expression</replaceable> IS TRUE
<replaceable>expression</replaceable> IS NOT TRUE
......
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.80 2001/09/16 16:11:09 petere Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.81 2001/09/20 14:20:27 petere Exp $
-->
<Chapter Id="runtime">
......@@ -1201,6 +1201,49 @@ dynamic_library_path = '/usr/local/lib/postgresql:/home/my_project/lib:$libdir'
</listitem>
</varlistentry>
<varlistentry>
<term><varname>TRANSFORM_NULL_EQUALS</varname> (<type>boolean</type>)</term>
<listitem>
<para>
When turned on, expressions of the form
<literal><replaceable>expr</> = NULL</literal> (or
<literal>NULL = <replaceable>expr</></literal>) are treated as
<literal><replaceable>expr</> IS NULL</literal>, that is, they
return true if <replaceable>expr</> evaluates to the NULL
value, and false otherwise. The correct behavior of
<literal><replaceable>expr</> = NULL</literal> is to always
return NULL (unknown). Therefore this option defaults to off.
</para>
<para>
However, filtered forms in <productname>Microsoft
Access</productname> generate queries that appear to use
<literal><replaceable>expr</> = NULL</literal> to test for
NULLs, so if you use that interface to access the database you
might want to turn this option on. Since expressions of the
form <literal><replaceable>expr</> = NULL</literal> always
return NULL (using the correct interpretation) they are not
very useful and do not appear often in normal applications, so
this option does little harm in practice. But new users are
frequently confused about the semantics of expressions
involving NULL, so we do not turn this option on by default.
</para>
<para>
Note that this option only affects the literal <literal>=</>
operator, not other comparison operators or other expressions
that are computationally equivalent to some expression
involving the equals operator (such as <literal>IN</literal>).
Thus, this option is not a general fix for bad programming.
</para>
<para>
Refer to the <citetitle>User's Guide</citetitle> for related
information.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>PORT</varname> (<type>integer</type>)</term>
<listitem>
......
......@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.251 2001/09/18 01:59:06 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.252 2001/09/20 14:20:27 petere Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
......@@ -89,7 +89,6 @@ static void insertSelectOptions(SelectStmt *stmt,
List *sortClause, List *forUpdate,
Node *limitOffset, Node *limitCount);
static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg);
static bool exprIsNullConstant(Node *arg);
static Node *doNegate(Node *n);
static void doNegateFloat(Value *v);
......@@ -4465,29 +4464,7 @@ a_expr: c_expr
| a_expr '>' a_expr
{ $$ = makeA_Expr(OP, ">", $1, $3); }
| a_expr '=' a_expr
{
/*
* Special-case "foo = NULL" and "NULL = foo" for
* compatibility with standards-broken products
* (like Microsoft's). Turn these into IS NULL exprs.
*/
if (exprIsNullConstant($3))
{
NullTest *n = makeNode(NullTest);
n->arg = $1;
n->nulltesttype = IS_NULL;
$$ = (Node *)n;
}
else if (exprIsNullConstant($1))
{
NullTest *n = makeNode(NullTest);
n->arg = $3;
n->nulltesttype = IS_NULL;
$$ = (Node *)n;
}
else
$$ = makeA_Expr(OP, "=", $1, $3);
}
{ $$ = makeA_Expr(OP, "=", $1, $3); }
| a_expr Op a_expr
{ $$ = makeA_Expr(OP, $2, $1, $3); }
......@@ -6137,7 +6114,7 @@ Oid param_type(int t)
/*
* Test whether an a_expr is a plain NULL constant or not.
*/
static bool
bool
exprIsNullConstant(Node *arg)
{
if (arg && IsA(arg, A_Const))
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.99 2001/08/09 18:28:17 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.100 2001/09/20 14:20:27 petere Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -34,9 +34,10 @@
int max_expr_depth = DEFAULT_MAX_EXPR_DEPTH;
static int expr_depth_counter = 0;
bool Transform_null_equals = false;
static Node *parser_typecast_constant(Value *expr, TypeName *typename);
static Node *parser_typecast_expression(ParseState *pstate,
Node *expr, TypeName *typename);
......@@ -157,14 +158,35 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
{
case OP:
{
Node *lexpr = transformExpr(pstate,
a->lexpr,
precedence);
Node *rexpr = transformExpr(pstate,
a->rexpr,
precedence);
result = (Node *) make_op(a->opname, lexpr, rexpr);
/*
* Special-case "foo = NULL" and "NULL = foo" for
* compatibility with standards-broken products
* (like Microsoft's). Turn these into IS NULL exprs.
*/
if (Transform_null_equals && strcmp(a->opname, "=")==0
&& (exprIsNullConstant(a->lexpr) || exprIsNullConstant(a->rexpr)))
{
NullTest *n = makeNode(NullTest);
n->nulltesttype = IS_NULL;
if (exprIsNullConstant(a->lexpr))
n->arg = a->rexpr;
else
n->arg = a->lexpr;
result = transformExpr(pstate, n, precedence);
}
else
{
Node *lexpr = transformExpr(pstate,
a->lexpr,
precedence);
Node *rexpr = transformExpr(pstate,
a->rexpr,
precedence);
result = (Node *) make_op(a->opname, lexpr, rexpr);
}
}
break;
case AND:
......
......@@ -4,7 +4,7 @@
* Support for grand unified configuration scheme, including SET
* command, configuration file, and command line options.
*
* $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.48 2001/09/12 14:06:37 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.49 2001/09/20 14:20:27 petere Exp $
*
* Copyright 2000 by PostgreSQL Global Development Group
* Written by Peter Eisentraut <peter_e@gmx.net>.
......@@ -247,12 +247,10 @@ static struct config_bool
{"show_source_port", PGC_SIGHUP, &ShowPortNumber, false, NULL},
{"sql_inheritance", PGC_USERSET, &SQL_inheritance, true, NULL},
{"australian_timezones", PGC_USERSET, &Australian_timezones, false, ClearDateCache},
{"fixbtree", PGC_POSTMASTER, &FixBTree, true, NULL},
{"password_encryption", PGC_USERSET, &Password_encryption, false, NULL},
{"transform_null_equals", PGC_USERSET, &Transform_null_equals, false, NULL},
{NULL, 0, NULL, false, NULL}
};
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: gramparse.h,v 1.15 2001/02/09 03:26:27 tgl Exp $
* $Id: gramparse.h,v 1.16 2001/09/20 14:20:28 petere Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -29,5 +29,6 @@ extern Oid param_type(int t);
extern int yyparse(void);
extern char *xlateSqlFunc(char *name);
extern char *xlateSqlType(char *name);
bool exprIsNullConstant(Node *arg);
#endif /* GRAMPARSE_H */
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: parse_expr.h,v 1.21 2001/01/24 19:43:27 momjian Exp $
* $Id: parse_expr.h,v 1.22 2001/09/20 14:20:28 petere Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -20,6 +20,7 @@
#define EXPR_RELATION_FIRST 2
extern int max_expr_depth;
extern bool Transform_null_equals;
extern Node *transformExpr(ParseState *pstate, Node *expr, int precedence);
extern Oid exprType(Node *expr);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册