ignore_is_not_null_base_quals_on_not_null_columns.patch
text/plain
Filename: ignore_is_not_null_base_quals_on_not_null_columns.patch
Type: text/plain
Part: 0
Patch
Format: unified
| File | + | − |
|---|---|---|
| src/backend/optimizer/plan/initsplan.c | 72 | 46 |
| src/backend/optimizer/util/plancat.c | 9 | 0 |
| src/include/nodes/pathnodes.h | 2 | 0 |
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index b31d892121..277314c8cb 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -2618,6 +2618,50 @@ check_redundant_nullability_qual(PlannerInfo *root, Node *clause)
return false;
}
+/*
+ * add_baserestrictinfo_to_rel
+ * Add 'restrictinfo' as a baserestrictinfo to the base relation denoted by
+ * 'relid' with some prechecks to try to determine if the qual is always
+ * true, in which case we ignore it rather than add it.
+ */
+static void
+add_baserestrictinfo_to_rel(PlannerInfo *root, Index relid,
+ RestrictInfo *restrictinfo)
+{
+ RelOptInfo *rel = find_base_rel(root, relid);
+
+ Assert(bms_membership(restrictinfo->required_relids) == BMS_SINGLETON);
+
+ /* Any IS NOT NULL qual on a NOT NULL column is always true */
+ if (IsA(restrictinfo->clause, NullTest))
+ {
+ NullTest *nulltest = (NullTest *) restrictinfo->clause;
+
+ if (nulltest->nulltesttype == IS_NOT_NULL && IsA(nulltest->arg, Var))
+ {
+ Var *var = (Var *) nulltest->arg;
+
+ Assert(var->varno == rel->relid);
+
+ /* don't add the qual as system columns cannot be NULL */
+ if (var->varattno < 0)
+ return;
+
+ /* don't add the IS NOT NULL when the column is defined NOT NULL */
+ if (var->varattno > 0 &&
+ bms_is_member(var->varattno, rel->notnullattnums))
+ return;
+ }
+ }
+
+ /* Add clause to rel's restriction list */
+ rel->baserestrictinfo = lappend(rel->baserestrictinfo, restrictinfo);
+
+ /* Update security level info */
+ rel->baserestrict_min_security = Min(rel->baserestrict_min_security,
+ restrictinfo->security_level);
+}
+
/*
* distribute_restrictinfo_to_rels
* Push a completed RestrictInfo into the proper restriction or join
@@ -2633,57 +2677,39 @@ distribute_restrictinfo_to_rels(PlannerInfo *root,
{
Relids relids = restrictinfo->required_relids;
RelOptInfo *rel;
+ int relid;
- switch (bms_membership(relids))
+ if (relids == NULL)
{
- case BMS_SINGLETON:
-
- /*
- * There is only one relation participating in the clause, so it
- * is a restriction clause for that relation.
- */
- rel = find_base_rel(root, bms_singleton_member(relids));
-
- /* Add clause to rel's restriction list */
- rel->baserestrictinfo = lappend(rel->baserestrictinfo,
- restrictinfo);
- /* Update security level info */
- rel->baserestrict_min_security = Min(rel->baserestrict_min_security,
- restrictinfo->security_level);
- break;
- case BMS_MULTIPLE:
-
- /*
- * The clause is a join clause, since there is more than one rel
- * in its relid set.
- */
-
- /*
- * Check for hashjoinable operators. (We don't bother setting the
- * hashjoin info except in true join clauses.)
- */
- check_hashjoinable(restrictinfo);
+ /*
+ * clause references no rels, and therefore we have no place to
+ * attach it. Shouldn't get here if callers are working properly.
+ */
+ elog(ERROR, "cannot cope with variable-free clause");
+ }
+ else if (bms_get_singleton_member(relids, &relid))
+ add_baserestrictinfo_to_rel(root, relid, restrictinfo);
+ else
+ {
+ /*
+ * The clause is a join clause, since there is more than one rel in
+ * its relid set.
+ */
- /*
- * Likewise, check if the clause is suitable to be used with a
- * Memoize node to cache inner tuples during a parameterized
- * nested loop.
- */
- check_memoizable(restrictinfo);
+ /*
+ * Check for hashjoinable operators. (We don't bother setting the
+ * hashjoin info except in true join clauses.)
+ */
+ check_hashjoinable(restrictinfo);
- /*
- * Add clause to the join lists of all the relevant relations.
- */
- add_join_clause_to_rels(root, restrictinfo, relids);
- break;
- default:
+ /*
+ * Likewise, check if the clause is suitable to be used with a Memoize
+ * node to cache inner tuples during a parameterized nested loop.
+ */
+ check_memoizable(restrictinfo);
- /*
- * clause references no rels, and therefore we have no place to
- * attach it. Shouldn't get here if callers are working properly.
- */
- elog(ERROR, "cannot cope with variable-free clause");
- break;
+ /* Add clause to the join lists of all the relevant relations. */
+ add_join_clause_to_rels(root, restrictinfo, relids);
}
}
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 39932d3c2d..d810ad8127 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -163,6 +163,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
rel->attr_widths = (int32 *)
palloc0((rel->max_attr - rel->min_attr + 1) * sizeof(int32));
+ /* record which columns are defined as NOT NULL */
+ for (int i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute *attr = &relation->rd_att->attrs[i];
+
+ if (attr->attnotnull)
+ rel->notnullattnums = bms_add_member(rel->notnullattnums, attr->attnum);
+ }
+
/*
* Estimate relation size --- unless it's an inheritance parent, in which
* case the size we want is not the rel's own size but the size of its
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index c17b53f7ad..851a4513a9 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -913,6 +913,8 @@ typedef struct RelOptInfo
Relids *attr_needed pg_node_attr(read_write_ignore);
/* array indexed [min_attr .. max_attr] */
int32 *attr_widths pg_node_attr(read_write_ignore);
+ /* zero-based set containing attnums of NOT NULL columns */
+ Bitmapset *notnullattnums;
/* relids of outer joins that can null this baserel */
Relids nulling_relids;
/* LATERAL Vars and PHVs referenced by rel */