Add an "argisrow" field to NullTest nodes, following a plan made way back in
authorTom Lane <[email protected]>
Fri, 1 Jan 2010 23:03:10 +0000 (23:03 +0000)
committerTom Lane <[email protected]>
Fri, 1 Jan 2010 23:03:10 +0000 (23:03 +0000)
8.2beta but never carried out.  This avoids repetitive tests of whether the
argument is of scalar or composite type.  Also, be a bit more paranoid about
composite arguments in some places where we previously weren't checking.

14 files changed:
src/backend/executor/execQual.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/backend/optimizer/path/indxpath.c
src/backend/optimizer/plan/planagg.c
src/backend/optimizer/util/clauses.c
src/backend/optimizer/util/plancat.c
src/backend/optimizer/util/predtest.c
src/backend/parser/parse_expr.c
src/include/catalog/catversion.h
src/include/nodes/execnodes.h
src/include/nodes/primnodes.h

index d58e6321feaba778480e3fc7c84bce7c0e5bb269..8aea44e98a272954f8233bafd3d4bab3c62df465 100644 (file)
@@ -3475,7 +3475,7 @@ ExecEvalNullTest(NullTestState *nstate,
    if (isDone && *isDone == ExprEndResult)
        return result;          /* nothing to check */
 
-   if (nstate->argisrow && !(*isNull))
+   if (ntest->argisrow && !(*isNull))
    {
        HeapTupleHeader tuple;
        Oid         tupType;
@@ -4704,7 +4704,6 @@ ExecInitExpr(Expr *node, PlanState *parent)
 
                nstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalNullTest;
                nstate->arg = ExecInitExpr(ntest->arg, parent);
-               nstate->argisrow = type_is_rowtype(exprType((Node *) ntest->arg));
                nstate->argdesc = NULL;
                state = (ExprState *) nstate;
            }
index 2da3172031fc34ba3d33e03b666222f548b644fa..c6e17b46ffc7db97335daf93747ba2cb4d58f6b1 100644 (file)
@@ -1506,6 +1506,7 @@ _copyNullTest(NullTest *from)
 
    COPY_NODE_FIELD(arg);
    COPY_SCALAR_FIELD(nulltesttype);
+   COPY_SCALAR_FIELD(argisrow);
 
    return newnode;
 }
index 0de81897d7315aafcb49413f6b98341e6f65c8bb..3bf9d71fcbcedc23174460aa9791e1314e4a084c 100644 (file)
@@ -623,6 +623,7 @@ _equalNullTest(NullTest *a, NullTest *b)
 {
    COMPARE_NODE_FIELD(arg);
    COMPARE_SCALAR_FIELD(nulltesttype);
+   COMPARE_SCALAR_FIELD(argisrow);
 
    return true;
 }
index 789ecbd76e3ba26a4e0331208ef4327674b1f2f5..6a640a43ea122c9d6135d25387be1aab2381c270 100644 (file)
@@ -1229,6 +1229,7 @@ _outNullTest(StringInfo str, NullTest *node)
 
    WRITE_NODE_FIELD(arg);
    WRITE_ENUM_FIELD(nulltesttype, NullTestType);
+   WRITE_BOOL_FIELD(argisrow);
 }
 
 static void
index bb7e845aa1b0e1acb3db0bd556ab1886851192d1..00b65e264dd1845d81917e7002e5a96344d9f4e9 100644 (file)
@@ -963,6 +963,7 @@ _readNullTest(void)
 
    READ_NODE_FIELD(arg);
    READ_ENUM_FIELD(nulltesttype, NullTestType);
+   READ_BOOL_FIELD(argisrow);
 
    READ_DONE();
 }
index c300bce2d54b4e889cbf16f7fd438e0b9085d0a1..71aeea24580d9cd3df96cfa354dda32da0fbbe6b 100644 (file)
@@ -1256,7 +1256,8 @@ match_clause_to_indexcol(IndexOptInfo *index,
    {
        NullTest   *nt = (NullTest *) clause;
 
-       if (match_index_to_operand((Node *) nt->arg, indexcol, index))
+       if (!nt->argisrow &&
+           match_index_to_operand((Node *) nt->arg, indexcol, index))
            return true;
        return false;
    }
index 16d547cffbba06c77326b7c888149b3ad290c29a..e996dcf060e32b8ed50d3a0421ef67a5377d4c99 100644 (file)
@@ -308,6 +308,9 @@ build_minmax_path(PlannerInfo *root, RelOptInfo *rel, MinMaxAggInfo *info)
    ntest = makeNode(NullTest);
    ntest->nulltesttype = IS_NOT_NULL;
    ntest->arg = copyObject(info->target);
+   ntest->argisrow = type_is_rowtype(exprType((Node *) ntest->arg));
+   if (ntest->argisrow)
+       return false;           /* punt on composites */
    info->notnulltest = ntest;
 
    /*
index ba6154637c8cc8fcb7518bae80c3d070557a1985..929aade9a42c3e4635c0814eb4307efe50bb4aa4 100644 (file)
@@ -1295,7 +1295,7 @@ find_nonnullable_rels_walker(Node *node, bool top_level)
        /* IS NOT NULL can be considered strict, but only at top level */
        NullTest   *expr = (NullTest *) node;
 
-       if (top_level && expr->nulltesttype == IS_NOT_NULL)
+       if (top_level && expr->nulltesttype == IS_NOT_NULL && !expr->argisrow)
            result = find_nonnullable_rels_walker((Node *) expr->arg, false);
    }
    else if (IsA(node, BooleanTest))
@@ -1497,7 +1497,7 @@ find_nonnullable_vars_walker(Node *node, bool top_level)
        /* IS NOT NULL can be considered strict, but only at top level */
        NullTest   *expr = (NullTest *) node;
 
-       if (top_level && expr->nulltesttype == IS_NOT_NULL)
+       if (top_level && expr->nulltesttype == IS_NOT_NULL && !expr->argisrow)
            result = find_nonnullable_vars_walker((Node *) expr->arg, false);
    }
    else if (IsA(node, BooleanTest))
@@ -1601,7 +1601,7 @@ find_forced_null_var(Node *node)
        /* check for var IS NULL */
        NullTest   *expr = (NullTest *) node;
 
-       if (expr->nulltesttype == IS_NULL)
+       if (expr->nulltesttype == IS_NULL && !expr->argisrow)
        {
            Var        *var = (Var *) expr->arg;
 
@@ -2856,6 +2856,7 @@ eval_const_expressions_mutator(Node *node,
                newntest = makeNode(NullTest);
                newntest->arg = (Expr *) relem;
                newntest->nulltesttype = ntest->nulltesttype;
+               newntest->argisrow = ntest->argisrow;
                newargs = lappend(newargs, newntest);
            }
            /* If all the inputs were constants, result is TRUE */
@@ -2867,7 +2868,7 @@ eval_const_expressions_mutator(Node *node,
            /* Else we need an AND node */
            return (Node *) make_andclause(newargs);
        }
-       if (arg && IsA(arg, Const))
+       if (!ntest->argisrow && arg && IsA(arg, Const))
        {
            Const      *carg = (Const *) arg;
            bool        result;
@@ -2893,6 +2894,7 @@ eval_const_expressions_mutator(Node *node,
        newntest = makeNode(NullTest);
        newntest->arg = (Expr *) arg;
        newntest->nulltesttype = ntest->nulltesttype;
+       newntest->argisrow = ntest->argisrow;
        return (Node *) newntest;
    }
    if (IsA(node, BooleanTest))
index 941917851b36d9380be7223ecb4ca5a357fe5cd2..6684d38597409ea8e3a24968051ab7d56454554d 100644 (file)
@@ -541,6 +541,7 @@ get_relation_constraints(PlannerInfo *root,
                                                  att->atttypmod,
                                                  0);
                    ntest->nulltesttype = IS_NOT_NULL;
+                   ntest->argisrow = type_is_rowtype(att->atttypid);
                    result = lappend(result, ntest);
                }
            }
index 731155f9c06ac5780b414e639db631c7f5306b97..2cdcc44d94eb6b4d13d5ca21218f4404d6a27e2d 100644 (file)
@@ -1043,7 +1043,7 @@ predicate_implied_by_simple_clause(Expr *predicate, Node *clause)
        Expr       *nonnullarg = ((NullTest *) predicate)->arg;
 
        /* row IS NOT NULL does not act in the simple way we have in mind */
-       if (!type_is_rowtype(exprType((Node *) nonnullarg)))
+       if (!((NullTest *) predicate)->argisrow)
        {
            if (is_opclause(clause) &&
                list_member_strip(((OpExpr *) clause)->args, nonnullarg) &&
@@ -1102,7 +1102,7 @@ predicate_refuted_by_simple_clause(Expr *predicate, Node *clause)
        Expr       *isnullarg = ((NullTest *) predicate)->arg;
 
        /* row IS NULL does not act in the simple way we have in mind */
-       if (type_is_rowtype(exprType((Node *) isnullarg)))
+       if (((NullTest *) predicate)->argisrow)
            return false;
 
        /* Any strict op/func on foo refutes foo IS NULL */
@@ -1118,6 +1118,7 @@ predicate_refuted_by_simple_clause(Expr *predicate, Node *clause)
        /* foo IS NOT NULL refutes foo IS NULL */
        if (clause && IsA(clause, NullTest) &&
            ((NullTest *) clause)->nulltesttype == IS_NOT_NULL &&
+           !((NullTest *) clause)->argisrow &&
            equal(((NullTest *) clause)->arg, isnullarg))
            return true;
 
@@ -1131,12 +1132,13 @@ predicate_refuted_by_simple_clause(Expr *predicate, Node *clause)
        Expr       *isnullarg = ((NullTest *) clause)->arg;
 
        /* row IS NULL does not act in the simple way we have in mind */
-       if (type_is_rowtype(exprType((Node *) isnullarg)))
+       if (((NullTest *) clause)->argisrow)
            return false;
 
        /* foo IS NULL refutes foo IS NOT NULL */
        if (predicate && IsA(predicate, NullTest) &&
            ((NullTest *) predicate)->nulltesttype == IS_NOT_NULL &&
+           !((NullTest *) predicate)->argisrow &&
            equal(((NullTest *) predicate)->arg, isnullarg))
            return true;
 
index c8c15d6c64e6b9a5cd1dc907cf957aca869a0f4a..7202c1c485e58900dff92dbc15ac2b9f760b7af2 100644 (file)
@@ -276,6 +276,7 @@ transformExpr(ParseState *pstate, Node *expr)
 
                n->arg = (Expr *) transformExpr(pstate, (Node *) n->arg);
                /* the argument can be any type, so don't coerce it */
+               n->argisrow = type_is_rowtype(exprType((Node *) n->arg));
                result = expr;
                break;
            }
index 271b30ec8b2f6d458d2053960473ea3a77d3605c..c907d6c36bb816a50602046b4260fa2bc4d11083 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 200912291
+#define CATALOG_VERSION_NO 201001011
 
 #endif
index 7e4b7459ce47c8667bd116909266108f3585db8d..d8f85fdca1fe807a7cbd5ef5d208961b05d6dc8b 100644 (file)
@@ -886,8 +886,7 @@ typedef struct NullTestState
 {
    ExprState   xprstate;
    ExprState  *arg;            /* input expression */
-   bool        argisrow;       /* T if input is of a composite type */
-   /* used only if argisrow: */
+   /* used only if input is of composite type: */
    TupleDesc   argdesc;        /* tupdesc for most recent input */
 } NullTestState;
 
index b28c8f70b9c1fcaef7b8e543b5fc281a0b91d1bb..7b6fe76deebd5271ad96363e630ba92e3f715b4b 100644 (file)
@@ -936,9 +936,7 @@ typedef OpExpr NullIfExpr;
  * The appropriate test is performed and returned as a boolean Datum.
  *
  * NOTE: the semantics of this for rowtype inputs are noticeably different
- * from the scalar case.  It would probably be a good idea to include an
- * "argisrow" flag in the struct to reflect that, but for the moment,
- * we do not do so to avoid forcing an initdb during 8.2beta.
+ * from the scalar case.  We provide an "argisrow" flag to reflect that.
  * ----------------
  */
 
@@ -952,6 +950,7 @@ typedef struct NullTest
    Expr        xpr;
    Expr       *arg;            /* input expression */
    NullTestType nulltesttype;  /* IS NULL, IS NOT NULL */
+   bool        argisrow;       /* T if input is of a composite type */
 } NullTest;
 
 /*