]> granicus.if.org Git - postgresql/commitdiff
Provide tunable knob for x = NULL -> x IS NULL transformation, default to off.
authorPeter Eisentraut <peter_e@gmx.net>
Thu, 20 Sep 2001 14:20:28 +0000 (14:20 +0000)
committerPeter Eisentraut <peter_e@gmx.net>
Thu, 20 Sep 2001 14:20:28 +0000 (14:20 +0000)
doc/src/sgml/func.sgml
doc/src/sgml/runtime.sgml
src/backend/parser/gram.y
src/backend/parser/parse_expr.c
src/backend/utils/misc/guc.c
src/include/parser/gramparse.h
src/include/parser/parse_expr.h

index 89a9bd1f8ebb020f3b4badfdf0623ecafe8fe567..0dc19768c1cdb62f6e1cec44a2887b19aa866260 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $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>
    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
index 2f27788334624dc1469ec3b2b7d7ba60f9575215..eef78e17a35eee294017f4e6a7c29c0c759c1e5f 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$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>
index c1e331cf81918088aa1ba9f0d7bb5b835de550e2..24407902bd36d8fd899d6091e46d055738468db1 100644 (file)
@@ -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))
index 7639fd2db5c7cde2de356ba78266f335ae007b2a..badbe60f75a7fa03f352723fbcddf159d6bc50e5 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
 
 
 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:
index 5af9fc67ab27c16e00da4f7def480c51f3de3633..ebb7745347eb124e27d2a8a80f8895a1d94c3736 100644 (file)
@@ -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}
 };
index 88c00ce9f370eb7cfde0996dd1cadc6fe06b5952..ad045dd4b60bd4b53f6c5229f38e23e8aae25d7a 100644 (file)
@@ -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 */
index 4dfc2367fd501727511b1c3c2196e0a7a2c5c560..c51bf7cc044053a6ad969c089baaea6b2aa05556 100644 (file)
@@ -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);