public inbox for [email protected]
help / color / mirror / Atom feed[PATCH 01/10] Introduce RelOptInfo->notnullattrs attribute
52+ messages / 3 participants
[nested] [flat]
* [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 6da0dcd61c..484dab0a1a 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -1005,6 +1005,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1061,6 +1062,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index e978b491f6..95b1b14cd3 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -830,6 +830,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
false, below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 25545029d7..0b2f9d398a 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -463,6 +464,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 485d1b06c9..9e3ebd488a 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -709,6 +709,8 @@ typedef struct RelOptInfo
PlannerInfo *subroot; /* if subquery */
List *subplan_params; /* if subquery */
int rel_parallel_workers; /* wanted number of parallel workers */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.21.0
--op7mf2i72xk5yu7c
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v36-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 6da0dcd61c..484dab0a1a 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -1005,6 +1005,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1061,6 +1062,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index e978b491f6..95b1b14cd3 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -830,6 +830,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
false, below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 25545029d7..0b2f9d398a 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -463,6 +464,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 485d1b06c9..9e3ebd488a 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -709,6 +709,8 @@ typedef struct RelOptInfo
PlannerInfo *subroot; /* if subquery */
List *subplan_params; /* if subquery */
int rel_parallel_workers; /* wanted number of parallel workers */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.21.0
--op7mf2i72xk5yu7c
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v36-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index d73ac562eb..37b4223adb 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -998,6 +998,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1054,6 +1055,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 02f813cebd..d27167dc76 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -829,6 +829,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index c5947fa418..eebabcfccf 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -480,6 +481,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 86405a274e..0d61f04d27 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -718,6 +718,8 @@ typedef struct RelOptInfo
int rel_parallel_workers; /* wanted number of parallel workers */
uint32 amflags; /* Bitmask of optional features supported by
* the table AM */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.26.2
--yh7cw345mbttadjz
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v38-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index d73ac562eb..37b4223adb 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -998,6 +998,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1054,6 +1055,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 02f813cebd..d27167dc76 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -829,6 +829,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index c5947fa418..eebabcfccf 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -480,6 +481,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 86405a274e..0d61f04d27 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -718,6 +718,8 @@ typedef struct RelOptInfo
int rel_parallel_workers; /* wanted number of parallel workers */
uint32 amflags; /* Bitmask of optional features supported by
* the table AM */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.26.2
--yh7cw345mbttadjz
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v38-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index d73ac562eb..37b4223adb 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -998,6 +998,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1054,6 +1055,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 02f813cebd..d27167dc76 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -829,6 +829,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index c5947fa418..eebabcfccf 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -480,6 +481,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 86405a274e..0d61f04d27 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -718,6 +718,8 @@ typedef struct RelOptInfo
int rel_parallel_workers; /* wanted number of parallel workers */
uint32 amflags; /* Bitmask of optional features supported by
* the table AM */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.26.2
--yh7cw345mbttadjz
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v38-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 6da0dcd61c..484dab0a1a 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -1005,6 +1005,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1061,6 +1062,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index e978b491f6..95b1b14cd3 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -830,6 +830,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
false, below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 25545029d7..0b2f9d398a 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -463,6 +464,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 485d1b06c9..9e3ebd488a 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -709,6 +709,8 @@ typedef struct RelOptInfo
PlannerInfo *subroot; /* if subquery */
List *subplan_params; /* if subquery */
int rel_parallel_workers; /* wanted number of parallel workers */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.21.0
--op7mf2i72xk5yu7c
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v36-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 6da0dcd61c..484dab0a1a 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -1005,6 +1005,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1061,6 +1062,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index e978b491f6..95b1b14cd3 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -830,6 +830,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
false, below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 25545029d7..0b2f9d398a 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -463,6 +464,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 485d1b06c9..9e3ebd488a 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -709,6 +709,8 @@ typedef struct RelOptInfo
PlannerInfo *subroot; /* if subquery */
List *subplan_params; /* if subquery */
int rel_parallel_workers; /* wanted number of parallel workers */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.21.0
--op7mf2i72xk5yu7c
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v36-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 6da0dcd61c..484dab0a1a 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -1005,6 +1005,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1061,6 +1062,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index e978b491f6..95b1b14cd3 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -830,6 +830,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
false, below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 25545029d7..0b2f9d398a 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -463,6 +464,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 485d1b06c9..9e3ebd488a 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -709,6 +709,8 @@ typedef struct RelOptInfo
PlannerInfo *subroot; /* if subquery */
List *subplan_params; /* if subquery */
int rel_parallel_workers; /* wanted number of parallel workers */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.21.0
--op7mf2i72xk5yu7c
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v36-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index d73ac562eb..37b4223adb 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -998,6 +998,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1054,6 +1055,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 02f813cebd..d27167dc76 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -829,6 +829,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index c5947fa418..eebabcfccf 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -480,6 +481,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 86405a274e..0d61f04d27 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -718,6 +718,8 @@ typedef struct RelOptInfo
int rel_parallel_workers; /* wanted number of parallel workers */
uint32 amflags; /* Bitmask of optional features supported by
* the table AM */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.26.2
--yh7cw345mbttadjz
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v38-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index d73ac562eb..37b4223adb 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -998,6 +998,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1054,6 +1055,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 02f813cebd..d27167dc76 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -829,6 +829,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index c5947fa418..eebabcfccf 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -480,6 +481,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 86405a274e..0d61f04d27 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -718,6 +718,8 @@ typedef struct RelOptInfo
int rel_parallel_workers; /* wanted number of parallel workers */
uint32 amflags; /* Bitmask of optional features supported by
* the table AM */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.26.2
--yh7cw345mbttadjz
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v38-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index d73ac562eb..37b4223adb 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -998,6 +998,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1054,6 +1055,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 02f813cebd..d27167dc76 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -829,6 +829,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index c5947fa418..eebabcfccf 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -480,6 +481,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 86405a274e..0d61f04d27 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -718,6 +718,8 @@ typedef struct RelOptInfo
int rel_parallel_workers; /* wanted number of parallel workers */
uint32 amflags; /* Bitmask of optional features supported by
* the table AM */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.26.2
--yh7cw345mbttadjz
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v38-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index d73ac562eb..37b4223adb 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -998,6 +998,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1054,6 +1055,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 02f813cebd..d27167dc76 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -829,6 +829,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index c5947fa418..eebabcfccf 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -480,6 +481,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 86405a274e..0d61f04d27 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -718,6 +718,8 @@ typedef struct RelOptInfo
int rel_parallel_workers; /* wanted number of parallel workers */
uint32 amflags; /* Bitmask of optional features supported by
* the table AM */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.26.2
--yh7cw345mbttadjz
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v38-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 6da0dcd61c..484dab0a1a 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -1005,6 +1005,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1061,6 +1062,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index e978b491f6..95b1b14cd3 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -830,6 +830,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
false, below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 25545029d7..0b2f9d398a 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -463,6 +464,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 485d1b06c9..9e3ebd488a 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -709,6 +709,8 @@ typedef struct RelOptInfo
PlannerInfo *subroot; /* if subquery */
List *subplan_params; /* if subquery */
int rel_parallel_workers; /* wanted number of parallel workers */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.21.0
--op7mf2i72xk5yu7c
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v36-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index d73ac562eb..37b4223adb 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -998,6 +998,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1054,6 +1055,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 02f813cebd..d27167dc76 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -829,6 +829,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index c5947fa418..eebabcfccf 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -480,6 +481,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 86405a274e..0d61f04d27 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -718,6 +718,8 @@ typedef struct RelOptInfo
int rel_parallel_workers; /* wanted number of parallel workers */
uint32 amflags; /* Bitmask of optional features supported by
* the table AM */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.26.2
--yh7cw345mbttadjz
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v38-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 6da0dcd61c..484dab0a1a 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -1005,6 +1005,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1061,6 +1062,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index e978b491f6..95b1b14cd3 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -830,6 +830,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
false, below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 25545029d7..0b2f9d398a 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -463,6 +464,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 485d1b06c9..9e3ebd488a 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -709,6 +709,8 @@ typedef struct RelOptInfo
PlannerInfo *subroot; /* if subquery */
List *subplan_params; /* if subquery */
int rel_parallel_workers; /* wanted number of parallel workers */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.21.0
--op7mf2i72xk5yu7c
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v36-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH 01/10] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index d73ac562eb..37b4223adb 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -998,6 +998,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1054,6 +1055,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 02f813cebd..d27167dc76 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -829,6 +829,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index c5947fa418..eebabcfccf 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -480,6 +481,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 86405a274e..0d61f04d27 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -718,6 +718,8 @@ typedef struct RelOptInfo
int rel_parallel_workers; /* wanted number of parallel workers */
uint32 amflags; /* Bitmask of optional features supported by
* the table AM */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.30.2
--------------F495F6B18672582269F00FF9
Content-Type: text/x-patch; charset=UTF-8;
name="0002-review-20210317.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="0002-review-20210317.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH 01/10] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index d73ac562eb..37b4223adb 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -998,6 +998,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1054,6 +1055,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 02f813cebd..d27167dc76 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -829,6 +829,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index c5947fa418..eebabcfccf 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -480,6 +481,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 86405a274e..0d61f04d27 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -718,6 +718,8 @@ typedef struct RelOptInfo
int rel_parallel_workers; /* wanted number of parallel workers */
uint32 amflags; /* Bitmask of optional features supported by
* the table AM */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.30.2
--------------F495F6B18672582269F00FF9
Content-Type: text/x-patch; charset=UTF-8;
name="0002-review-20210317.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="0002-review-20210317.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index d73ac562eb..37b4223adb 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -998,6 +998,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1054,6 +1055,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 02f813cebd..d27167dc76 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -829,6 +829,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index c5947fa418..eebabcfccf 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -480,6 +481,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 86405a274e..0d61f04d27 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -718,6 +718,8 @@ typedef struct RelOptInfo
int rel_parallel_workers; /* wanted number of parallel workers */
uint32 amflags; /* Bitmask of optional features supported by
* the table AM */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.26.2
--yh7cw345mbttadjz
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v38-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 6da0dcd61c..484dab0a1a 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -1005,6 +1005,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1061,6 +1062,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index e978b491f6..95b1b14cd3 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -830,6 +830,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
false, below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 25545029d7..0b2f9d398a 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -463,6 +464,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 485d1b06c9..9e3ebd488a 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -709,6 +709,8 @@ typedef struct RelOptInfo
PlannerInfo *subroot; /* if subquery */
List *subplan_params; /* if subquery */
int rel_parallel_workers; /* wanted number of parallel workers */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.21.0
--op7mf2i72xk5yu7c
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v36-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 6da0dcd61c..484dab0a1a 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -1005,6 +1005,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1061,6 +1062,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index e978b491f6..95b1b14cd3 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -830,6 +830,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
false, below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 25545029d7..0b2f9d398a 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -463,6 +464,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 485d1b06c9..9e3ebd488a 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -709,6 +709,8 @@ typedef struct RelOptInfo
PlannerInfo *subroot; /* if subquery */
List *subplan_params; /* if subquery */
int rel_parallel_workers; /* wanted number of parallel workers */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.21.0
--op7mf2i72xk5yu7c
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v36-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 6da0dcd61c..484dab0a1a 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -1005,6 +1005,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1061,6 +1062,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index e978b491f6..95b1b14cd3 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -830,6 +830,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
false, below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 25545029d7..0b2f9d398a 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -463,6 +464,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 485d1b06c9..9e3ebd488a 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -709,6 +709,8 @@ typedef struct RelOptInfo
PlannerInfo *subroot; /* if subquery */
List *subplan_params; /* if subquery */
int rel_parallel_workers; /* wanted number of parallel workers */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.21.0
--op7mf2i72xk5yu7c
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v36-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index d73ac562eb..37b4223adb 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -998,6 +998,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1054,6 +1055,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 02f813cebd..d27167dc76 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -829,6 +829,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index c5947fa418..eebabcfccf 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -480,6 +481,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 86405a274e..0d61f04d27 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -718,6 +718,8 @@ typedef struct RelOptInfo
int rel_parallel_workers; /* wanted number of parallel workers */
uint32 amflags; /* Bitmask of optional features supported by
* the table AM */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.26.2
--yh7cw345mbttadjz
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v38-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 6da0dcd61c..484dab0a1a 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -1005,6 +1005,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1061,6 +1062,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index e978b491f6..95b1b14cd3 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -830,6 +830,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
false, below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 25545029d7..0b2f9d398a 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -463,6 +464,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 485d1b06c9..9e3ebd488a 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -709,6 +709,8 @@ typedef struct RelOptInfo
PlannerInfo *subroot; /* if subquery */
List *subplan_params; /* if subquery */
int rel_parallel_workers; /* wanted number of parallel workers */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.21.0
--op7mf2i72xk5yu7c
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v36-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 6da0dcd61c..484dab0a1a 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -1005,6 +1005,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1061,6 +1062,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index e978b491f6..95b1b14cd3 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -830,6 +830,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
false, below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 25545029d7..0b2f9d398a 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -463,6 +464,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 485d1b06c9..9e3ebd488a 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -709,6 +709,8 @@ typedef struct RelOptInfo
PlannerInfo *subroot; /* if subquery */
List *subplan_params; /* if subquery */
int rel_parallel_workers; /* wanted number of parallel workers */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.21.0
--op7mf2i72xk5yu7c
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v36-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index d73ac562eb..37b4223adb 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -998,6 +998,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1054,6 +1055,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 02f813cebd..d27167dc76 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -829,6 +829,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index c5947fa418..eebabcfccf 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -480,6 +481,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 86405a274e..0d61f04d27 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -718,6 +718,8 @@ typedef struct RelOptInfo
int rel_parallel_workers; /* wanted number of parallel workers */
uint32 amflags; /* Bitmask of optional features supported by
* the table AM */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.26.2
--yh7cw345mbttadjz
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v38-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index d73ac562eb..37b4223adb 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -998,6 +998,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1054,6 +1055,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 02f813cebd..d27167dc76 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -829,6 +829,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index c5947fa418..eebabcfccf 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -480,6 +481,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 86405a274e..0d61f04d27 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -718,6 +718,8 @@ typedef struct RelOptInfo
int rel_parallel_workers; /* wanted number of parallel workers */
uint32 amflags; /* Bitmask of optional features supported by
* the table AM */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.26.2
--yh7cw345mbttadjz
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v38-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index d73ac562eb..37b4223adb 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -998,6 +998,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1054,6 +1055,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 02f813cebd..d27167dc76 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -829,6 +829,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index c5947fa418..eebabcfccf 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -480,6 +481,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 86405a274e..0d61f04d27 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -718,6 +718,8 @@ typedef struct RelOptInfo
int rel_parallel_workers; /* wanted number of parallel workers */
uint32 amflags; /* Bitmask of optional features supported by
* the table AM */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.26.2
--yh7cw345mbttadjz
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v38-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index d73ac562eb..37b4223adb 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -998,6 +998,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1054,6 +1055,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 02f813cebd..d27167dc76 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -829,6 +829,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index c5947fa418..eebabcfccf 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -480,6 +481,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 86405a274e..0d61f04d27 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -718,6 +718,8 @@ typedef struct RelOptInfo
int rel_parallel_workers; /* wanted number of parallel workers */
uint32 amflags; /* Bitmask of optional features supported by
* the table AM */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.26.2
--yh7cw345mbttadjz
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v38-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index d73ac562eb..37b4223adb 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -998,6 +998,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1054,6 +1055,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 02f813cebd..d27167dc76 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -829,6 +829,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index c5947fa418..eebabcfccf 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -480,6 +481,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 86405a274e..0d61f04d27 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -718,6 +718,8 @@ typedef struct RelOptInfo
int rel_parallel_workers; /* wanted number of parallel workers */
uint32 amflags; /* Bitmask of optional features supported by
* the table AM */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.26.2
--yh7cw345mbttadjz
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v38-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 6da0dcd61c..484dab0a1a 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -1005,6 +1005,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1061,6 +1062,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index e978b491f6..95b1b14cd3 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -830,6 +830,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
false, below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 25545029d7..0b2f9d398a 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -463,6 +464,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 485d1b06c9..9e3ebd488a 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -709,6 +709,8 @@ typedef struct RelOptInfo
PlannerInfo *subroot; /* if subquery */
List *subplan_params; /* if subquery */
int rel_parallel_workers; /* wanted number of parallel workers */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.21.0
--op7mf2i72xk5yu7c
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v36-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v35 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
---
src/backend/optimizer/plan/initsplan.c | 10 ++++++++++
src/backend/optimizer/util/plancat.c | 10 ++++++++++
src/include/nodes/pathnodes.h | 2 ++
3 files changed, 22 insertions(+)
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index e978b491f6..95b1b14cd3 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -830,6 +830,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
false, below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 25545029d7..0b2f9d398a 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -463,6 +464,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 485d1b06c9..9e3ebd488a 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -709,6 +709,8 @@ typedef struct RelOptInfo
PlannerInfo *subroot; /* if subquery */
List *subplan_params; /* if subquery */
int rel_parallel_workers; /* wanted number of parallel workers */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.21.0
--tbesu4k6dthoevcy
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v8-0002-Introuduce-RelOptInfo.uniquekeys-attribute.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index d73ac562eb..37b4223adb 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -998,6 +998,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1054,6 +1055,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 02f813cebd..d27167dc76 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -829,6 +829,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index c5947fa418..eebabcfccf 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -480,6 +481,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 86405a274e..0d61f04d27 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -718,6 +718,8 @@ typedef struct RelOptInfo
int rel_parallel_workers; /* wanted number of parallel workers */
uint32 amflags; /* Bitmask of optional features supported by
* the table AM */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.26.2
--yh7cw345mbttadjz
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v38-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 6da0dcd61c..484dab0a1a 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -1005,6 +1005,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1061,6 +1062,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index e978b491f6..95b1b14cd3 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -830,6 +830,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
false, below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 25545029d7..0b2f9d398a 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -463,6 +464,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 485d1b06c9..9e3ebd488a 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -709,6 +709,8 @@ typedef struct RelOptInfo
PlannerInfo *subroot; /* if subquery */
List *subplan_params; /* if subquery */
int rel_parallel_workers; /* wanted number of parallel workers */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.21.0
--op7mf2i72xk5yu7c
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v36-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 6da0dcd61c..484dab0a1a 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -1005,6 +1005,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1061,6 +1062,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index e978b491f6..95b1b14cd3 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -830,6 +830,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
false, below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 25545029d7..0b2f9d398a 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -463,6 +464,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 485d1b06c9..9e3ebd488a 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -709,6 +709,8 @@ typedef struct RelOptInfo
PlannerInfo *subroot; /* if subquery */
List *subplan_params; /* if subquery */
int rel_parallel_workers; /* wanted number of parallel workers */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.21.0
--op7mf2i72xk5yu7c
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v36-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index d73ac562eb..37b4223adb 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -998,6 +998,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1054,6 +1055,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 02f813cebd..d27167dc76 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -829,6 +829,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index c5947fa418..eebabcfccf 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -480,6 +481,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 86405a274e..0d61f04d27 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -718,6 +718,8 @@ typedef struct RelOptInfo
int rel_parallel_workers; /* wanted number of parallel workers */
uint32 amflags; /* Bitmask of optional features supported by
* the table AM */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.26.2
--yh7cw345mbttadjz
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v38-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index d73ac562eb..37b4223adb 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -998,6 +998,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1054,6 +1055,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 02f813cebd..d27167dc76 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -829,6 +829,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index c5947fa418..eebabcfccf 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -480,6 +481,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 86405a274e..0d61f04d27 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -718,6 +718,8 @@ typedef struct RelOptInfo
int rel_parallel_workers; /* wanted number of parallel workers */
uint32 amflags; /* Bitmask of optional features supported by
* the table AM */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.26.2
--yh7cw345mbttadjz
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v38-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index d73ac562eb..37b4223adb 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -998,6 +998,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1054,6 +1055,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 02f813cebd..d27167dc76 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -829,6 +829,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index c5947fa418..eebabcfccf 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -480,6 +481,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 86405a274e..0d61f04d27 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -718,6 +718,8 @@ typedef struct RelOptInfo
int rel_parallel_workers; /* wanted number of parallel workers */
uint32 amflags; /* Bitmask of optional features supported by
* the table AM */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.26.2
--yh7cw345mbttadjz
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v38-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index d73ac562eb..37b4223adb 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -998,6 +998,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1054,6 +1055,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 02f813cebd..d27167dc76 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -829,6 +829,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index c5947fa418..eebabcfccf 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -480,6 +481,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 86405a274e..0d61f04d27 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -718,6 +718,8 @@ typedef struct RelOptInfo
int rel_parallel_workers; /* wanted number of parallel workers */
uint32 amflags; /* Bitmask of optional features supported by
* the table AM */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.26.2
--yh7cw345mbttadjz
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v38-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v37 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index b399592ff8..754f6d64f6 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -1009,6 +1009,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1065,6 +1066,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index e978b491f6..95b1b14cd3 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -830,6 +830,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
false, below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index f9d0d67aa7..bdd4876a84 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -463,6 +464,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 3dd16b9ad5..925f2eac3f 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -708,6 +708,8 @@ typedef struct RelOptInfo
PlannerInfo *subroot; /* if subquery */
List *subplan_params; /* if subquery */
int rel_parallel_workers; /* wanted number of parallel workers */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.21.0
--snesplnlompos6d4
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v37-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 6da0dcd61c..484dab0a1a 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -1005,6 +1005,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1061,6 +1062,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index e978b491f6..95b1b14cd3 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -830,6 +830,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
false, below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 25545029d7..0b2f9d398a 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -463,6 +464,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 485d1b06c9..9e3ebd488a 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -709,6 +709,8 @@ typedef struct RelOptInfo
PlannerInfo *subroot; /* if subquery */
List *subplan_params; /* if subquery */
int rel_parallel_workers; /* wanted number of parallel workers */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.21.0
--op7mf2i72xk5yu7c
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v36-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index d73ac562eb..37b4223adb 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -998,6 +998,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1054,6 +1055,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 02f813cebd..d27167dc76 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -829,6 +829,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index c5947fa418..eebabcfccf 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -480,6 +481,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 86405a274e..0d61f04d27 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -718,6 +718,8 @@ typedef struct RelOptInfo
int rel_parallel_workers; /* wanted number of parallel workers */
uint32 amflags; /* Bitmask of optional features supported by
* the table AM */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.26.2
--yh7cw345mbttadjz
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v38-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 6da0dcd61c..484dab0a1a 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -1005,6 +1005,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1061,6 +1062,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index e978b491f6..95b1b14cd3 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -830,6 +830,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
false, below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 25545029d7..0b2f9d398a 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -463,6 +464,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 485d1b06c9..9e3ebd488a 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -709,6 +709,8 @@ typedef struct RelOptInfo
PlannerInfo *subroot; /* if subquery */
List *subplan_params; /* if subquery */
int rel_parallel_workers; /* wanted number of parallel workers */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.21.0
--op7mf2i72xk5yu7c
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v36-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 6da0dcd61c..484dab0a1a 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -1005,6 +1005,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1061,6 +1062,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index e978b491f6..95b1b14cd3 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -830,6 +830,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
false, below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 25545029d7..0b2f9d398a 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -463,6 +464,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 485d1b06c9..9e3ebd488a 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -709,6 +709,8 @@ typedef struct RelOptInfo
PlannerInfo *subroot; /* if subquery */
List *subplan_params; /* if subquery */
int rel_parallel_workers; /* wanted number of parallel workers */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.21.0
--op7mf2i72xk5yu7c
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v36-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index d73ac562eb..37b4223adb 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -998,6 +998,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1054,6 +1055,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 02f813cebd..d27167dc76 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -829,6 +829,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index c5947fa418..eebabcfccf 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -480,6 +481,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 86405a274e..0d61f04d27 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -718,6 +718,8 @@ typedef struct RelOptInfo
int rel_parallel_workers; /* wanted number of parallel workers */
uint32 amflags; /* Bitmask of optional features supported by
* the table AM */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.26.2
--yh7cw345mbttadjz
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v38-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 6da0dcd61c..484dab0a1a 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -1005,6 +1005,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1061,6 +1062,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index e978b491f6..95b1b14cd3 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -830,6 +830,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
false, below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 25545029d7..0b2f9d398a 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -463,6 +464,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 485d1b06c9..9e3ebd488a 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -709,6 +709,8 @@ typedef struct RelOptInfo
PlannerInfo *subroot; /* if subquery */
List *subplan_params; /* if subquery */
int rel_parallel_workers; /* wanted number of parallel workers */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.21.0
--op7mf2i72xk5yu7c
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v36-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index d73ac562eb..37b4223adb 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -998,6 +998,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1054,6 +1055,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 02f813cebd..d27167dc76 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -829,6 +829,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index c5947fa418..eebabcfccf 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -480,6 +481,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 86405a274e..0d61f04d27 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -718,6 +718,8 @@ typedef struct RelOptInfo
int rel_parallel_workers; /* wanted number of parallel workers */
uint32 amflags; /* Bitmask of optional features supported by
* the table AM */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.26.2
--yh7cw345mbttadjz
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v38-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute
@ 2020-05-03 14:37 一挃 <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: 一挃 @ 2020-05-03 14:37 UTC (permalink / raw)
The notnullattrs is calculated from catalog and run-time query. That
infomation is translated to child relation as well for partitioned
table.
---
src/backend/optimizer/path/allpaths.c | 31 ++++++++++++++++++++++++++
src/backend/optimizer/plan/initsplan.c | 10 +++++++++
src/backend/optimizer/util/plancat.c | 10 +++++++++
src/include/nodes/pathnodes.h | 2 ++
4 files changed, 53 insertions(+)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index d73ac562eb..37b4223adb 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -998,6 +998,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
RelOptInfo *childrel;
ListCell *parentvars;
ListCell *childvars;
+ int i = -1;
/* append_rel_list contains all append rels; ignore others */
if (appinfo->parent_relid != parentRTindex)
@@ -1054,6 +1055,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
(Node *) rel->reltarget->exprs,
1, &appinfo);
+ /* Copy notnullattrs. */
+ while ((i = bms_next_member(rel->notnullattrs, i)) > 0)
+ {
+ AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
+ AttrNumber child_attno;
+ if (attno == 0)
+ {
+ /* Whole row is not null, so must be same for child */
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ break;
+ }
+ if (attno < 0 )
+ /* no need to translate system column */
+ child_attno = attno;
+ else
+ {
+ Node * node = list_nth(appinfo->translated_vars, attno - 1);
+ if (!IsA(node, Var))
+ /* This may happens at UNION case, like (SELECT a FROM t1 UNION SELECT a + 3
+ * FROM t2) t and we know t.a is not null
+ */
+ continue;
+ child_attno = castNode(Var, node)->varattno;
+ }
+
+ childrel->notnullattrs = bms_add_member(childrel->notnullattrs,
+ child_attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 02f813cebd..d27167dc76 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -829,6 +829,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
+ /* Set the not null info now */
+ ListCell *lc;
+ List *non_nullable_vars = find_nonnullable_vars(qual);
+ foreach(lc, non_nullable_vars)
+ {
+ Var *var = lfirst_node(Var, lc);
+ RelOptInfo *rel = root->simple_rel_array[var->varno];
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
distribute_qual_to_rels(root, qual,
below_outer_join, JOIN_INNER,
root->qual_security_level,
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index c5947fa418..eebabcfccf 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -117,6 +117,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Relation relation;
bool hasindex;
List *indexinfos = NIL;
+ int i;
/*
* We need not lock the relation since it was already locked, either by
@@ -480,6 +481,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
set_relation_partition_info(root, rel, relation);
+ Assert(rel->notnullattrs == NULL);
+ for(i = 0; i < relation->rd_att->natts; i++)
+ {
+ FormData_pg_attribute attr = relation->rd_att->attrs[i];
+ if (attr.attnotnull)
+ rel->notnullattrs = bms_add_member(rel->notnullattrs,
+ attr.attnum - FirstLowInvalidHeapAttributeNumber);
+ }
+
table_close(relation, NoLock);
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 86405a274e..0d61f04d27 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -718,6 +718,8 @@ typedef struct RelOptInfo
int rel_parallel_workers; /* wanted number of parallel workers */
uint32 amflags; /* Bitmask of optional features supported by
* the table AM */
+ /* Not null attrs, start from -FirstLowInvalidHeapAttributeNumber */
+ Bitmapset *notnullattrs;
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
--
2.26.2
--yh7cw345mbttadjz
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment;
filename="v38-0002-Introduce-UniqueKey-attributes-on-RelOptInfo-str.patch"
^ permalink raw reply [nested|flat] 52+ messages in thread
* Fix incorrect start up costs for WindowAgg paths (bug #17862)
@ 2023-04-12 09:03 David Rowley <[email protected]>
2023-04-12 14:28 ` Re: Fix incorrect start up costs for WindowAgg paths (bug #17862) Andy Fan <[email protected]>
2023-05-31 00:59 ` Re: Fix incorrect start up costs for WindowAgg paths (bug #17862) David Rowley <[email protected]>
0 siblings, 2 replies; 52+ messages in thread
From: David Rowley @ 2023-04-12 09:03 UTC (permalink / raw)
To: PostgreSQL Developers <[email protected]>
Over on [1], Tim reported that the planner is making some bad choices
when the plan contains a WindowFunc which requires reading all of, or
a large portion of the WindowAgg subnode in order to produce the first
WindowAgg row.
For example:
EXPLAIN (ANALYZE, TIMING OFF)
SELECT COUNT(*) OVER ()
FROM tenk1 t1 INNER JOIN tenk1 t2 ON t1.unique1 = t2.tenthous
LIMIT 1;
With master, we get the following plan:
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=0.29..0.67 rows=1 width=8) (actual time=47.491..47.492
rows=1 loops=1)
-> WindowAgg (cost=0.29..3815.00 rows=10000 width=8) (actual
time=47.489..47.490 rows=1 loops=1)
-> Nested Loop (cost=0.29..3690.00 rows=10000 width=0)
(actual time=0.026..42.972 rows=10000 loops=1)
-> Seq Scan on tenk1 t2 (cost=0.00..445.00 rows=10000
width=4) (actual time=0.009..1.734 rows=10000 loops=1)
-> Index Only Scan using tenk1_unique1 on tenk1 t1
(cost=0.29..0.31 rows=1 width=4) (actual time=0.003..0.004 rows=1
loops=10000)
Index Cond: (unique1 = t2.tenthous)
Heap Fetches: 0
Planning Time: 0.420 ms
Execution Time: 48.107 ms
You can see that the time to get the first WindowAgg row (47.489 ms)
is not well aligned to the startup cost (0.29). This effectively
causes the planner to choose a Nested Loop plan as it thinks it'll
read just 1 row from the join. Due to the OVER (), we'll read all
rows! Not good.
It's not hard to imagine that a slightly different schema could yield
a *far* worse plan if it opted to use a non-parameterised nested loop
plan and proceed to read all rows from it.
With the attached patch, that turns into:
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=928.02..928.02 rows=1 width=8) (actual
time=29.308..29.310 rows=1 loops=1)
-> WindowAgg (cost=928.02..928.07 rows=10000 width=8) (actual
time=29.306..29.308 rows=1 loops=1)
-> Hash Join (cost=395.57..803.07 rows=10000 width=0)
(actual time=10.674..22.032 rows=10000 loops=1)
Hash Cond: (t1.unique1 = t2.tenthous)
-> Index Only Scan using tenk1_unique1 on tenk1 t1
(cost=0.29..270.29 rows=10000 width=4) (actual time=0.036..4.961
rows=10000 loops=1)
Heap Fetches: 0
-> Hash (cost=270.29..270.29 rows=10000 width=4)
(actual time=10.581..10.582 rows=10000 loops=1)
Buckets: 16384 Batches: 1 Memory Usage: 480kB
-> Index Only Scan using tenk1_thous_tenthous on
tenk1 t2 (cost=0.29..270.29 rows=10000 width=4) (actual
time=0.055..5.437 rows=10000 loops=1)
Heap Fetches: 0
Planning Time: 2.415 ms
Execution Time: 30.554 ms
I'm not sure if we should consider backpatching a fix for this bug.
We tend not to commit stuff that would destabilise plans in the back
branches. On the other hand, it's fairly hard to imagine how we
could make this much worse even given bad estimates.
I do think we should fix this in v16, however.
I'll add this to the "Older bugs affecting stable branches" section of
the PG 16 open items list
David
[1] https://postgr.es/m/[email protected]
Attachments:
[application/octet-stream] fix_bug_17862.patch (11.6K, ../../CAApHDvrB0S5BMv+0-wTTqWFE-BJ0noWqTnDu9QQfjZ2VSpLv_g@mail.gmail.com/2-fix_bug_17862.patch)
download | inline diff:
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index 0a2562c149..00f80e4f34 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -2809,6 +2809,96 @@ cost_agg(Path *path, PlannerInfo *root,
path->total_cost = total_cost;
}
+/*
+ * get_windowclause_startup_tuples
+ * Determine how many tuples we'll need to fetch from a WindowAgg's
+ * subnode before we can output the first WindowAgg tuple.
+ */
+static double
+get_windowclause_startup_tuples(PlannerInfo *root, WindowClause *wc,
+ double input_tuples)
+{
+ double partition_tuples;
+
+ /* Figure out how many partitions there are likely to be */
+ if (wc->partitionClause != NIL)
+ {
+ double num_partitions;
+ List *partexprs = get_sortgrouplist_exprs(wc->partitionClause,
+ root->parse->targetList);
+
+ num_partitions = estimate_num_groups(root, partexprs, input_tuples,
+ NULL, NULL);
+ list_free(partexprs);
+
+ partition_tuples = input_tuples / num_partitions;
+ }
+ else
+ {
+ /* all tuples belong to the same partition */
+ partition_tuples = input_tuples;
+ }
+
+ /*
+ * An empty ORDER BY means all rows are peers and WindowAgg will process
+ * the entire partition for the first tuple.
+ */
+ if (wc->orderClause == NIL)
+ return clamp_row_est(partition_tuples);
+
+ /*
+ * BETWEEN ... AND CURRENT ROW means the executor only needs to read at
+ * most 1 row from the subnode before outputting the first tuple.
+ */
+ if (wc->frameOptions & FRAMEOPTION_END_CURRENT_ROW)
+ return 1.0;
+
+ /*
+ * BETWEEN ... AND UNBOUNDED FOLLOWING means we need to read the entire
+ * partition before outputting the first tuple.
+ */
+ if (wc->frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING)
+ return clamp_row_est(partition_tuples);
+
+ /*
+ * BETWEEN ... AND N PRECEDING does not need to read from the subnode for
+ * the first N tuples. To be safe, we return 1.0. The endOffset could be
+ * 0.
+ */
+ if (wc->frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING)
+ return 1.0;
+
+ /*
+ * BETWEEN ... AND N FOLLOWING is more complex. We need to try to
+ * determine the value of endOffset.
+ */
+ if (wc->frameOptions & FRAMEOPTION_END_OFFSET_FOLLOWING &&
+ IsA(wc->endOffset, Const))
+ {
+ Const *endOffset = (Const *) wc->endOffset;
+
+ if (endOffset->constisnull)
+ {
+ /*
+ * This should raise an ERROR during execution, but we'd better do
+ * something sane here.
+ */
+ return 1.0;
+ }
+
+ /* XXX do we expect any other type of Const? */
+ else if (endOffset->consttype == INT4OID)
+ return clamp_row_est(Min(partition_tuples,
+ (double) DatumGetInt32(endOffset->constvalue)));
+ else if (endOffset->consttype == INT8OID)
+ return clamp_row_est(Min(partition_tuples,
+ (double) DatumGetInt64(endOffset->constvalue)));
+ }
+
+ /* Just assume we'll need DEFAULT_INEQ_SEL of the partition's tuples */
+ return clamp_row_est(partition_tuples * DEFAULT_INEQ_SEL);
+}
+
/*
* cost_windowagg
* Determines and returns the cost of performing a WindowAgg plan node,
@@ -2818,17 +2908,34 @@ cost_agg(Path *path, PlannerInfo *root,
*/
void
cost_windowagg(Path *path, PlannerInfo *root,
- List *windowFuncs, int numPartCols, int numOrderCols,
+ List *windowFuncs, WindowClause *winclause,
Cost input_startup_cost, Cost input_total_cost,
double input_tuples)
{
Cost startup_cost;
Cost total_cost;
+ double startup_tuples;
+ int numPartCols;
+ int numOrderCols;
ListCell *lc;
+ numPartCols = list_length(winclause->partitionClause);
+ numOrderCols = list_length(winclause->orderClause);
+
startup_cost = input_startup_cost;
total_cost = input_total_cost;
+ /*
+ * Estimate how many tuples we'll need to read from the subnode before we
+ * can output the first WindowAgg row.
+ *
+ * XXX is it worth caching this value in the WindowClause to prevent
+ * having to calculate it for each path we generate? The number of
+ * input_tuples could vary from path to path, however.
+ */
+ startup_tuples = get_windowclause_startup_tuples(root, winclause,
+ input_tuples);
+
/*
* Window functions are assumed to cost their stated execution cost, plus
* the cost of evaluating their input expressions, per tuple. Since they
@@ -2880,6 +2987,18 @@ cost_windowagg(Path *path, PlannerInfo *root,
path->rows = input_tuples;
path->startup_cost = startup_cost;
path->total_cost = total_cost;
+
+ /*
+ * Also take into account how many tuples we need to read from the subnode
+ * in order to produce the first tuple from the WindowAgg. To do this we
+ * proportion the run cost (total cost not including startup costs) over
+ * the estimated startup tuples. We already included the startup cost of
+ * the subnode, so we only need to do this when the estimated startup
+ * tuples is above 1.0.
+ */
+ if (startup_tuples > 1.0)
+ path->startup_cost += (total_cost - startup_cost) / input_tuples *
+ (startup_tuples - 1.0);
}
/*
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 65a191ebfd..8c4dbff00a 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -3445,8 +3445,7 @@ create_windowagg_path(PlannerInfo *root,
*/
cost_windowagg(&pathnode->path, root,
windowFuncs,
- list_length(winclause->partitionClause),
- list_length(winclause->orderClause),
+ winclause,
subpath->startup_cost,
subpath->total_cost,
subpath->rows);
diff --git a/src/include/optimizer/cost.h b/src/include/optimizer/cost.h
index 6cf49705d3..bee090ffc2 100644
--- a/src/include/optimizer/cost.h
+++ b/src/include/optimizer/cost.h
@@ -131,7 +131,7 @@ extern void cost_agg(Path *path, PlannerInfo *root,
Cost input_startup_cost, Cost input_total_cost,
double input_tuples, double input_width);
extern void cost_windowagg(Path *path, PlannerInfo *root,
- List *windowFuncs, int numPartCols, int numOrderCols,
+ List *windowFuncs, WindowClause *winclause,
Cost input_startup_cost, Cost input_total_cost,
double input_tuples);
extern void cost_group(Path *path, PlannerInfo *root,
diff --git a/src/test/regress/expected/window.out b/src/test/regress/expected/window.out
index 1d4b78b9b2..2628033327 100644
--- a/src/test/regress/expected/window.out
+++ b/src/test/regress/expected/window.out
@@ -4808,6 +4808,80 @@ SELECT i, b, bool_and(b) OVER w, bool_or(b) OVER w
5 | t | t | t
(5 rows)
+--
+-- Test WindowAgg costing takes into account the number of rows that need to
+-- be fetched before the first row can be output.
+--
+-- Ensure we get a cheap start up plan as the WindowAgg can output the first
+-- row after reading 1 row from the join.
+EXPLAIN (COSTS OFF)
+SELECT COUNT(*) OVER (ORDER BY t1.unique1)
+FROM tenk1 t1 INNER JOIN tenk1 t2 ON t1.unique1 = t2.tenthous
+LIMIT 1;
+ QUERY PLAN
+--------------------------------------------------------------------------
+ Limit
+ -> WindowAgg
+ -> Nested Loop
+ -> Index Only Scan using tenk1_unique1 on tenk1 t1
+ -> Index Only Scan using tenk1_thous_tenthous on tenk1 t2
+ Index Cond: (tenthous = t1.unique1)
+(6 rows)
+
+-- Ensure we get a cheap total plan. Lack of ORDER BY in the WindowClause
+-- means that all rows must be read from the join, so a cheap startup plan
+-- isn't a good choice.
+EXPLAIN (COSTS OFF)
+SELECT COUNT(*) OVER ()
+FROM tenk1 t1 INNER JOIN tenk1 t2 ON t1.unique1 = t2.tenthous
+LIMIT 1;
+ QUERY PLAN
+--------------------------------------------------------------------------------
+ Limit
+ -> WindowAgg
+ -> Hash Join
+ Hash Cond: (t1.unique1 = t2.tenthous)
+ -> Index Only Scan using tenk1_unique1 on tenk1 t1
+ -> Hash
+ -> Index Only Scan using tenk1_thous_tenthous on tenk1 t2
+(7 rows)
+
+-- Ensure we get a cheap total plan. This time use UNBOUNDED FOLLOWING, which
+-- needs to read all join rows to output the first WindowAgg row.
+EXPLAIN (COSTS OFF)
+SELECT COUNT(*) OVER (ORDER BY t1.unique1 ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
+FROM tenk1 t1 INNER JOIN tenk1 t2 ON t1.unique1 = t2.tenthous
+LIMIT 1;
+ QUERY PLAN
+--------------------------------------------------------------------------------
+ Limit
+ -> WindowAgg
+ -> Merge Join
+ Merge Cond: (t1.unique1 = t2.tenthous)
+ -> Index Only Scan using tenk1_unique1 on tenk1 t1
+ -> Sort
+ Sort Key: t2.tenthous
+ -> Index Only Scan using tenk1_thous_tenthous on tenk1 t2
+(8 rows)
+
+-- Ensure we get a cheap total plan. This time use 10000 FOLLOWING so we need
+-- to read all join rows.
+EXPLAIN (COSTS OFF)
+SELECT COUNT(*) OVER (ORDER BY t1.unique1 ROWS BETWEEN UNBOUNDED PRECEDING AND 10000 FOLLOWING)
+FROM tenk1 t1 INNER JOIN tenk1 t2 ON t1.unique1 = t2.tenthous
+LIMIT 1;
+ QUERY PLAN
+--------------------------------------------------------------------------------
+ Limit
+ -> WindowAgg
+ -> Merge Join
+ Merge Cond: (t1.unique1 = t2.tenthous)
+ -> Index Only Scan using tenk1_unique1 on tenk1 t1
+ -> Sort
+ Sort Key: t2.tenthous
+ -> Index Only Scan using tenk1_thous_tenthous on tenk1 t2
+(8 rows)
+
-- Tests for problems with failure to walk or mutate expressions
-- within window frame clauses.
-- test walker (fails with collation error if expressions are not walked)
diff --git a/src/test/regress/sql/window.sql b/src/test/regress/sql/window.sql
index 3ab6ac715d..4789de0937 100644
--- a/src/test/regress/sql/window.sql
+++ b/src/test/regress/sql/window.sql
@@ -1716,6 +1716,40 @@ SELECT i, b, bool_and(b) OVER w, bool_or(b) OVER w
FROM (VALUES (1,true), (2,true), (3,false), (4,false), (5,true)) v(i,b)
WINDOW w AS (ORDER BY i ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING);
+--
+-- Test WindowAgg costing takes into account the number of rows that need to
+-- be fetched before the first row can be output.
+--
+
+-- Ensure we get a cheap start up plan as the WindowAgg can output the first
+-- row after reading 1 row from the join.
+EXPLAIN (COSTS OFF)
+SELECT COUNT(*) OVER (ORDER BY t1.unique1)
+FROM tenk1 t1 INNER JOIN tenk1 t2 ON t1.unique1 = t2.tenthous
+LIMIT 1;
+
+-- Ensure we get a cheap total plan. Lack of ORDER BY in the WindowClause
+-- means that all rows must be read from the join, so a cheap startup plan
+-- isn't a good choice.
+EXPLAIN (COSTS OFF)
+SELECT COUNT(*) OVER ()
+FROM tenk1 t1 INNER JOIN tenk1 t2 ON t1.unique1 = t2.tenthous
+LIMIT 1;
+
+-- Ensure we get a cheap total plan. This time use UNBOUNDED FOLLOWING, which
+-- needs to read all join rows to output the first WindowAgg row.
+EXPLAIN (COSTS OFF)
+SELECT COUNT(*) OVER (ORDER BY t1.unique1 ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
+FROM tenk1 t1 INNER JOIN tenk1 t2 ON t1.unique1 = t2.tenthous
+LIMIT 1;
+
+-- Ensure we get a cheap total plan. This time use 10000 FOLLOWING so we need
+-- to read all join rows.
+EXPLAIN (COSTS OFF)
+SELECT COUNT(*) OVER (ORDER BY t1.unique1 ROWS BETWEEN UNBOUNDED PRECEDING AND 10000 FOLLOWING)
+FROM tenk1 t1 INNER JOIN tenk1 t2 ON t1.unique1 = t2.tenthous
+LIMIT 1;
+
-- Tests for problems with failure to walk or mutate expressions
-- within window frame clauses.
^ permalink raw reply [nested|flat] 52+ messages in thread
* Re: Fix incorrect start up costs for WindowAgg paths (bug #17862)
2023-04-12 09:03 Fix incorrect start up costs for WindowAgg paths (bug #17862) David Rowley <[email protected]>
@ 2023-04-12 14:28 ` Andy Fan <[email protected]>
1 sibling, 0 replies; 52+ messages in thread
From: Andy Fan @ 2023-04-12 14:28 UTC (permalink / raw)
To: David Rowley <[email protected]>; +Cc: PostgreSQL Developers <[email protected]>
On Wed, Apr 12, 2023 at 5:04 PM David Rowley <[email protected]> wrote:
>
> With the attached patch, that turns into:
>
The concept of startup_tuples for a WindowAgg looks good to me, but I
can't follow up with the below line:
+ return clamp_row_est(partition_tuples * DEFAULT_INEQ_SEL);
# select count(*) over() from tenk1 limit 1;
count
-------
10000 --> We need to scan all the tuples.
Should we just return clamp_row_est(partition_tuples)?
--
Best Regards
Andy Fan
^ permalink raw reply [nested|flat] 52+ messages in thread
* Re: Fix incorrect start up costs for WindowAgg paths (bug #17862)
2023-04-12 09:03 Fix incorrect start up costs for WindowAgg paths (bug #17862) David Rowley <[email protected]>
@ 2023-05-31 00:59 ` David Rowley <[email protected]>
2023-08-03 04:50 ` Re: Fix incorrect start up costs for WindowAgg paths (bug #17862) David Rowley <[email protected]>
1 sibling, 1 reply; 52+ messages in thread
From: David Rowley @ 2023-05-31 00:59 UTC (permalink / raw)
To: PostgreSQL Developers <[email protected]>
On Wed, 12 Apr 2023 at 21:03, David Rowley <[email protected]> wrote:
> I'm not sure if we should consider backpatching a fix for this bug.
> We tend not to commit stuff that would destabilise plans in the back
> branches. On the other hand, it's fairly hard to imagine how we
> could make this much worse even given bad estimates.
>
> I do think we should fix this in v16, however.
>
> I'll add this to the "Older bugs affecting stable branches" section of
> the PG 16 open items list
When I wrote the above, it was very soon after the feature freeze for
PG16. I wondered, since we tend not to do cost changes as part of bug
fixes due to not wanting to destabilise plans between minor versions
if we could instead just fix it in PG16 given the freeze had *just*
started. That's no longer the case, so I'm just going to move this
out from where I added it in the PG16 Open items "Live issues" section
and just add a July CF entry for it instead.
David
^ permalink raw reply [nested|flat] 52+ messages in thread
* Re: Fix incorrect start up costs for WindowAgg paths (bug #17862)
2023-04-12 09:03 Fix incorrect start up costs for WindowAgg paths (bug #17862) David Rowley <[email protected]>
2023-05-31 00:59 ` Re: Fix incorrect start up costs for WindowAgg paths (bug #17862) David Rowley <[email protected]>
@ 2023-08-03 04:50 ` David Rowley <[email protected]>
2023-08-03 06:49 ` Re: Fix incorrect start up costs for WindowAgg paths (bug #17862) Andy Fan <[email protected]>
0 siblings, 1 reply; 52+ messages in thread
From: David Rowley @ 2023-08-03 04:50 UTC (permalink / raw)
To: PostgreSQL Developers <[email protected]>; Tim Palmer <[email protected]>
On Wed, 31 May 2023 at 12:59, David Rowley <[email protected]> wrote:
>
> On Wed, 12 Apr 2023 at 21:03, David Rowley <[email protected]> wrote:
> > I'll add this to the "Older bugs affecting stable branches" section of
> > the PG 16 open items list
>
> When I wrote the above, it was very soon after the feature freeze for
> PG16. I wondered, since we tend not to do cost changes as part of bug
> fixes due to not wanting to destabilise plans between minor versions
> if we could instead just fix it in PG16 given the freeze had *just*
> started. That's no longer the case, so I'm just going to move this
> out from where I added it in the PG16 Open items "Live issues" section
> and just add a July CF entry for it instead.
I'm keen to move this patch along. It's not a particularly
interesting patch and don't expect much interest in it, but I feel
it's pretty important to have the planner not accidentally choose a
cheap startup plan when a WindowAgg is going to fetch the entire
subplan's tuples.
I've made another pass over the patch and made a bunch of cosmetic
changes. As far as mechanical changes, I only changed the EXCLUDE
TIES and EXCLUDE GROUP behaviour when there is no ORDER BY clause in
the WindowClause. If there's no ORDER BY then subtracting 1.0 rows
seems like the right thing to do rather than what the previous patch
did.
I (temporarily) left the DEBUG1 elog in there if anyone wants to test
for themselves (saves debugger use). In the absence of that, I'm
planning on just pushing it to master only tomorrow. It seems fairly
low risk and unlikely to attract too much interest since it only
affects startup costs of WindowAgg nodes. I'm currently thinking it's
a bad idea to backpatch this but I'd consider it more if someone else
thought it was a good idea or if more people came along complaining
about poor plan choice in plans containing WindowAggs. Currently, it
seems better not to destabilise plans in the back branches. (CC'd Tim,
who reported #17862, as he may have an opinion on this)
The only thought I had while looking at this again aside from what I
changed was if get_windowclause_startup_tuples() should go in
selfuncs.c. I wondered if it would be neater to use
convert_numeric_to_scalar() instead of the code I had to add to
convert the (SMALL|BIG)INT Consts in <Const> FOLLOWING to double.
Aside from that reason, it seems we don't have many usages of
DEFAULT_INEQ_SEL outside of selfuncs.c. I didn't feel strongly enough
about this to actually move the function.
The updated patch is attached.
Here are the results of my testing (note the DEBUG message matches the
COUNT(*) result in all cases apart from one case where COUNT(*)
returns 0 and the estimated tuples is 1.0).
create table ab (a int, b int);
insert into ab select a,b from generate_series(1,100) a,
generate_series(1,100) b;
analyze ab;
set client_min_messages=debug1;
# select count(*) over () from ab limit 1;
DEBUG: startup_tuples = 10000
count
-------
10000
(1 row)
# select count(*) over (partition by a) from ab limit 1;
DEBUG: startup_tuples = 100
count
-------
100
(1 row)
# select count(*) over (partition by a order by b) from ab limit 1;
DEBUG: startup_tuples = 1
count
-------
1
(1 row)
# select count(*) over (partition by a order by b rows between current
row and unbounded following) from ab limit 1;
DEBUG: startup_tuples = 100
count
-------
100
(1 row)
# select count(*) over (partition by a order by b rows between current
row and 10 following) from ab limit 1;
DEBUG: startup_tuples = 11
count
-------
11
(1 row)
# select count(*) over (partition by a order by b rows between current
row and 10 following exclude current row) from ab limit 1;
DEBUG: startup_tuples = 10
count
-------
10
(1 row)
# select count(*) over (partition by a order by b rows between current
row and 10 following exclude ties) from ab limit 1;
DEBUG: startup_tuples = 11
count
-------
11
(1 row)
# select count(*) over (partition by a order by b range between
current row and 10 following exclude ties) from ab limit 1;
DEBUG: startup_tuples = 11
count
-------
11
(1 row)
# select count(*) over (partition by a order by b range between
current row and unbounded following exclude ties) from ab limit 1;
DEBUG: startup_tuples = 100
count
-------
100
(1 row)
# select count(*) over (partition by a order by b range between
current row and unbounded following exclude group) from ab limit 1;
DEBUG: startup_tuples = 99
count
-------
99
(1 row)
# select count(*) over (partition by a order by b groups between
current row and unbounded following exclude group) from ab limit 1;
DEBUG: startup_tuples = 99
count
-------
99
(1 row)
# select count(*) over (partition by a rows between current row and
unbounded following exclude group) from ab limit 1;
DEBUG: startup_tuples = 1
count
-------
0
(1 row)
# select count(*) over (partition by a rows between current row and
unbounded following exclude ties) from ab limit 1;
DEBUG: startup_tuples = 1
count
-------
1
(1 row)
# select count(*) over (partition by a order by b rows between current
row and unbounded following exclude ties) from ab limit 1;
DEBUG: startup_tuples = 100
count
-------
100
(1 row)
# select count(*) over (partition by a order by b rows between current
row and unbounded following exclude current row) from ab limit 1;
DEBUG: startup_tuples = 99
count
-------
99
(1 row)
# select count(*) over (partition by a order by b range between
current row and 9223372036854775807 following exclude ties) from ab
limit 1;
DEBUG: startup_tuples = 100
count
-------
100
(1 row)
David
Attachments:
[application/octet-stream] fix_bug_17862_v3.patch (14.9K, ../../CAApHDvpQaO8mGGqGiOdKpbYgwEzJR--5-s1Wxsaww2bXGOwPKA@mail.gmail.com/2-fix_bug_17862_v3.patch)
download | inline diff:
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index ef475d95a1..c39eff3f70 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -2809,6 +2809,227 @@ cost_agg(Path *path, PlannerInfo *root,
path->total_cost = total_cost;
}
+/*
+ * get_windowclause_startup_tuples
+ * Estimate how many tuples we'll need to fetch from a WindowAgg's
+ * subnode before we can output the first WindowAgg tuple.
+ *
+ * How many tuples need to be read depends on the WindowClause. For example,
+ * a WindowClause with no PARTITION BY and no ORDER BY requires that all
+ * subnode tuples are read and aggregated before the WindowAgg can output
+ * anything. If there's a PARTITION BY, then we only need to look at tuples
+ * in the first partition. Here we attempt to estimate just how many
+ * 'input_tuples' the WindowAgg will need to read for the given WindowClause
+ * before the first tuple can be output.
+ */
+static double
+get_windowclause_startup_tuples(PlannerInfo *root, WindowClause *wc,
+ double input_tuples)
+{
+ int frameOptions = wc->frameOptions;
+ double partition_tuples;
+ double return_tuples;
+ double peer_tuples;
+
+ /*
+ * First, figure out how many partitions there are likely to be and set
+ * partition_tuples according to that estimate.
+ */
+ if (wc->partitionClause != NIL)
+ {
+ double num_partitions;
+ List *partexprs = get_sortgrouplist_exprs(wc->partitionClause,
+ root->parse->targetList);
+
+ num_partitions = estimate_num_groups(root, partexprs, input_tuples,
+ NULL, NULL);
+ list_free(partexprs);
+
+ partition_tuples = input_tuples / num_partitions;
+ }
+ else
+ {
+ /* all tuples belong to the same partition */
+ partition_tuples = input_tuples;
+ }
+
+ /* estimate the number of tuples in each peer group */
+ if (wc->orderClause != NIL)
+ {
+ double num_groups;
+ List *orderexprs;
+
+ orderexprs = get_sortgrouplist_exprs(wc->orderClause,
+ root->parse->targetList);
+
+ /* estimate out how many peer groups there are in the partition */
+ num_groups = estimate_num_groups(root, orderexprs,
+ partition_tuples, NULL,
+ NULL);
+ list_free(orderexprs);
+ peer_tuples = partition_tuples / num_groups;
+ }
+ else
+ {
+ /* no ORDER BY so only 1 tuple belongs in each peer group */
+ peer_tuples = 1.0;
+ }
+
+ if (frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING)
+ {
+ /* include all partition rows */
+ return_tuples = partition_tuples;
+ }
+ else if (frameOptions & FRAMEOPTION_END_CURRENT_ROW)
+ {
+ if (frameOptions & FRAMEOPTION_ROWS)
+ {
+ /* just count the current row */
+ return_tuples = 1.0;
+ }
+ else if (frameOptions & (FRAMEOPTION_RANGE | FRAMEOPTION_GROUPS))
+ {
+ /*
+ * When in RANGE/GROUPS mode, it's more complex. If there's no
+ * ORDER BY, then all rows in the partition are peers, otherwise
+ * we'll need to read the first group of peers.
+ */
+ if (wc->orderClause == NIL)
+ return_tuples = partition_tuples;
+ else
+ return_tuples = peer_tuples;
+ }
+ else
+ {
+ /*
+ * Something new we don't support yet? This needs attention. We'll just
+ * return 1.0 in the meantime.
+ */
+ Assert(false);
+ return_tuples = 1.0;
+ }
+ }
+ else if (frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING)
+ {
+ /*
+ * BETWEEN ... AND N PRECEDING will only need to read the WindowAgg's
+ * subnode after N ROWS/RANGES/GROUPS. N can be 0, but not negative,
+ * so we'll just assume only the current row needs to be read to fetch
+ * the first WindowAgg row.
+ */
+ return_tuples = 1.0;
+ }
+ else if (frameOptions & FRAMEOPTION_END_OFFSET_FOLLOWING)
+ {
+ Const *endOffset = (Const *) wc->endOffset;
+ double end_offset_value;
+
+ /* try and figure out the value specified in the endOffset. */
+ if (IsA(endOffset, Const))
+ {
+ if (endOffset->constisnull)
+ {
+ /*
+ * NULLs are not allowed, but currently, there's no code to
+ * error out if there's a NULL Const. We'll only discover
+ * this during execution. For now, just pretend everything is
+ * fine and assume that just the current row/range/group will
+ * be needed.
+ */
+ end_offset_value = 1.0;
+ }
+ else
+ {
+ switch (endOffset->consttype)
+ {
+ case INT2OID:
+ end_offset_value =
+ (double) DatumGetInt16(endOffset->constvalue);
+ break;
+ case INT4OID:
+ end_offset_value =
+ (double) DatumGetInt32(endOffset->constvalue);
+ break;
+ case INT8OID:
+ end_offset_value =
+ (double) DatumGetInt64(endOffset->constvalue);
+ break;
+ default:
+ end_offset_value =
+ partition_tuples / peer_tuples *
+ DEFAULT_INEQ_SEL;
+ break;
+ }
+ }
+ }
+ else
+ {
+ /*
+ * When the end bound is not a Const, we'll just need to guess. We
+ * just make use of DEFAULT_INEQ_SEL.
+ */
+ end_offset_value =
+ partition_tuples / peer_tuples * DEFAULT_INEQ_SEL;
+ }
+
+ if (frameOptions & FRAMEOPTION_ROWS)
+ {
+ /* include the N FOLLOWING and the current row */
+ return_tuples = end_offset_value + 1.0;
+ }
+ else if (frameOptions & (FRAMEOPTION_RANGE | FRAMEOPTION_GROUPS))
+ {
+ /* include N FOLLOWING ranges/group and the initial range/group */
+ return_tuples = peer_tuples * (end_offset_value + 1.0);
+ }
+ else
+ {
+ /*
+ * Something new we don't support yet? This needs attention.
+ * We'll just return 1.0 in the meantime.
+ */
+ Assert(false);
+ return_tuples = 1.0;
+ }
+ }
+ else
+ {
+ /*
+ * Something new we don't support yet? This needs attention. We'll
+ * just return 1.0 in the meantime.
+ */
+ Assert(false);
+ return_tuples = 1.0;
+ }
+
+ /*
+ * Cap the return value so it's never higher than the expected tuples in
+ * the partition. This must be done before processing the exclusions as
+ * the exclusions are eliminated from the start of the frame, not the end.
+ */
+ return_tuples = Min(return_tuples, partition_tuples);
+
+ /* process any exclusions */
+ if (frameOptions & FRAMEOPTION_EXCLUDE_CURRENT_ROW)
+ return_tuples -= 1.0;
+ else if (frameOptions & FRAMEOPTION_EXCLUDE_GROUP)
+ {
+ if (wc->orderClause != NIL)
+ return_tuples -= peer_tuples;
+ else
+ return_tuples = 1.0;
+ }
+ else if (frameOptions & FRAMEOPTION_EXCLUDE_TIES)
+ {
+ if (wc->orderClause != NIL)
+ return_tuples -= (peer_tuples - 1.0);
+ else
+ return_tuples = 1.0;
+ }
+
+ return clamp_row_est(return_tuples);
+}
+
/*
* cost_windowagg
* Determines and returns the cost of performing a WindowAgg plan node,
@@ -2818,17 +3039,32 @@ cost_agg(Path *path, PlannerInfo *root,
*/
void
cost_windowagg(Path *path, PlannerInfo *root,
- List *windowFuncs, int numPartCols, int numOrderCols,
+ List *windowFuncs, WindowClause *winclause,
Cost input_startup_cost, Cost input_total_cost,
double input_tuples)
{
Cost startup_cost;
Cost total_cost;
+ double startup_tuples;
+ int numPartCols;
+ int numOrderCols;
ListCell *lc;
+ numPartCols = list_length(winclause->partitionClause);
+ numOrderCols = list_length(winclause->orderClause);
+
startup_cost = input_startup_cost;
total_cost = input_total_cost;
+ /*
+ * Estimate how many tuples we'll need to read from the subnode before we
+ * can output the first WindowAgg row.
+ */
+ startup_tuples = get_windowclause_startup_tuples(root, winclause,
+ input_tuples);
+
+ elog(DEBUG1, "startup_tuples = %g", startup_tuples); /* XXX not for commit */
+
/*
* Window functions are assumed to cost their stated execution cost, plus
* the cost of evaluating their input expressions, per tuple. Since they
@@ -2880,6 +3116,18 @@ cost_windowagg(Path *path, PlannerInfo *root,
path->rows = input_tuples;
path->startup_cost = startup_cost;
path->total_cost = total_cost;
+
+ /*
+ * Also, take into account how many tuples we need to read from the
+ * subnode in order to produce the first tuple from the WindowAgg. To do
+ * this we proportion the run cost (total cost not including startup cost)
+ * over the estimated startup tuples. We already included the startup
+ * cost of the subnode, so we only need to do this when the estimated
+ * startup tuples is above 1.0.
+ */
+ if (startup_tuples > 1.0)
+ path->startup_cost += (total_cost - startup_cost) / input_tuples *
+ (startup_tuples - 1.0);
}
/*
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index f123fcb41e..754f0b9f34 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -3457,8 +3457,7 @@ create_windowagg_path(PlannerInfo *root,
*/
cost_windowagg(&pathnode->path, root,
windowFuncs,
- list_length(winclause->partitionClause),
- list_length(winclause->orderClause),
+ winclause,
subpath->startup_cost,
subpath->total_cost,
subpath->rows);
diff --git a/src/include/optimizer/cost.h b/src/include/optimizer/cost.h
index 6cf49705d3..bee090ffc2 100644
--- a/src/include/optimizer/cost.h
+++ b/src/include/optimizer/cost.h
@@ -131,7 +131,7 @@ extern void cost_agg(Path *path, PlannerInfo *root,
Cost input_startup_cost, Cost input_total_cost,
double input_tuples, double input_width);
extern void cost_windowagg(Path *path, PlannerInfo *root,
- List *windowFuncs, int numPartCols, int numOrderCols,
+ List *windowFuncs, WindowClause *winclause,
Cost input_startup_cost, Cost input_total_cost,
double input_tuples);
extern void cost_group(Path *path, PlannerInfo *root,
diff --git a/src/test/regress/expected/window.out b/src/test/regress/expected/window.out
index 1d4b78b9b2..2628033327 100644
--- a/src/test/regress/expected/window.out
+++ b/src/test/regress/expected/window.out
@@ -4808,6 +4808,80 @@ SELECT i, b, bool_and(b) OVER w, bool_or(b) OVER w
5 | t | t | t
(5 rows)
+--
+-- Test WindowAgg costing takes into account the number of rows that need to
+-- be fetched before the first row can be output.
+--
+-- Ensure we get a cheap start up plan as the WindowAgg can output the first
+-- row after reading 1 row from the join.
+EXPLAIN (COSTS OFF)
+SELECT COUNT(*) OVER (ORDER BY t1.unique1)
+FROM tenk1 t1 INNER JOIN tenk1 t2 ON t1.unique1 = t2.tenthous
+LIMIT 1;
+ QUERY PLAN
+--------------------------------------------------------------------------
+ Limit
+ -> WindowAgg
+ -> Nested Loop
+ -> Index Only Scan using tenk1_unique1 on tenk1 t1
+ -> Index Only Scan using tenk1_thous_tenthous on tenk1 t2
+ Index Cond: (tenthous = t1.unique1)
+(6 rows)
+
+-- Ensure we get a cheap total plan. Lack of ORDER BY in the WindowClause
+-- means that all rows must be read from the join, so a cheap startup plan
+-- isn't a good choice.
+EXPLAIN (COSTS OFF)
+SELECT COUNT(*) OVER ()
+FROM tenk1 t1 INNER JOIN tenk1 t2 ON t1.unique1 = t2.tenthous
+LIMIT 1;
+ QUERY PLAN
+--------------------------------------------------------------------------------
+ Limit
+ -> WindowAgg
+ -> Hash Join
+ Hash Cond: (t1.unique1 = t2.tenthous)
+ -> Index Only Scan using tenk1_unique1 on tenk1 t1
+ -> Hash
+ -> Index Only Scan using tenk1_thous_tenthous on tenk1 t2
+(7 rows)
+
+-- Ensure we get a cheap total plan. This time use UNBOUNDED FOLLOWING, which
+-- needs to read all join rows to output the first WindowAgg row.
+EXPLAIN (COSTS OFF)
+SELECT COUNT(*) OVER (ORDER BY t1.unique1 ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
+FROM tenk1 t1 INNER JOIN tenk1 t2 ON t1.unique1 = t2.tenthous
+LIMIT 1;
+ QUERY PLAN
+--------------------------------------------------------------------------------
+ Limit
+ -> WindowAgg
+ -> Merge Join
+ Merge Cond: (t1.unique1 = t2.tenthous)
+ -> Index Only Scan using tenk1_unique1 on tenk1 t1
+ -> Sort
+ Sort Key: t2.tenthous
+ -> Index Only Scan using tenk1_thous_tenthous on tenk1 t2
+(8 rows)
+
+-- Ensure we get a cheap total plan. This time use 10000 FOLLOWING so we need
+-- to read all join rows.
+EXPLAIN (COSTS OFF)
+SELECT COUNT(*) OVER (ORDER BY t1.unique1 ROWS BETWEEN UNBOUNDED PRECEDING AND 10000 FOLLOWING)
+FROM tenk1 t1 INNER JOIN tenk1 t2 ON t1.unique1 = t2.tenthous
+LIMIT 1;
+ QUERY PLAN
+--------------------------------------------------------------------------------
+ Limit
+ -> WindowAgg
+ -> Merge Join
+ Merge Cond: (t1.unique1 = t2.tenthous)
+ -> Index Only Scan using tenk1_unique1 on tenk1 t1
+ -> Sort
+ Sort Key: t2.tenthous
+ -> Index Only Scan using tenk1_thous_tenthous on tenk1 t2
+(8 rows)
+
-- Tests for problems with failure to walk or mutate expressions
-- within window frame clauses.
-- test walker (fails with collation error if expressions are not walked)
diff --git a/src/test/regress/sql/window.sql b/src/test/regress/sql/window.sql
index 3ab6ac715d..4789de0937 100644
--- a/src/test/regress/sql/window.sql
+++ b/src/test/regress/sql/window.sql
@@ -1716,6 +1716,40 @@ SELECT i, b, bool_and(b) OVER w, bool_or(b) OVER w
FROM (VALUES (1,true), (2,true), (3,false), (4,false), (5,true)) v(i,b)
WINDOW w AS (ORDER BY i ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING);
+--
+-- Test WindowAgg costing takes into account the number of rows that need to
+-- be fetched before the first row can be output.
+--
+
+-- Ensure we get a cheap start up plan as the WindowAgg can output the first
+-- row after reading 1 row from the join.
+EXPLAIN (COSTS OFF)
+SELECT COUNT(*) OVER (ORDER BY t1.unique1)
+FROM tenk1 t1 INNER JOIN tenk1 t2 ON t1.unique1 = t2.tenthous
+LIMIT 1;
+
+-- Ensure we get a cheap total plan. Lack of ORDER BY in the WindowClause
+-- means that all rows must be read from the join, so a cheap startup plan
+-- isn't a good choice.
+EXPLAIN (COSTS OFF)
+SELECT COUNT(*) OVER ()
+FROM tenk1 t1 INNER JOIN tenk1 t2 ON t1.unique1 = t2.tenthous
+LIMIT 1;
+
+-- Ensure we get a cheap total plan. This time use UNBOUNDED FOLLOWING, which
+-- needs to read all join rows to output the first WindowAgg row.
+EXPLAIN (COSTS OFF)
+SELECT COUNT(*) OVER (ORDER BY t1.unique1 ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
+FROM tenk1 t1 INNER JOIN tenk1 t2 ON t1.unique1 = t2.tenthous
+LIMIT 1;
+
+-- Ensure we get a cheap total plan. This time use 10000 FOLLOWING so we need
+-- to read all join rows.
+EXPLAIN (COSTS OFF)
+SELECT COUNT(*) OVER (ORDER BY t1.unique1 ROWS BETWEEN UNBOUNDED PRECEDING AND 10000 FOLLOWING)
+FROM tenk1 t1 INNER JOIN tenk1 t2 ON t1.unique1 = t2.tenthous
+LIMIT 1;
+
-- Tests for problems with failure to walk or mutate expressions
-- within window frame clauses.
^ permalink raw reply [nested|flat] 52+ messages in thread
* Re: Fix incorrect start up costs for WindowAgg paths (bug #17862)
2023-04-12 09:03 Fix incorrect start up costs for WindowAgg paths (bug #17862) David Rowley <[email protected]>
2023-05-31 00:59 ` Re: Fix incorrect start up costs for WindowAgg paths (bug #17862) David Rowley <[email protected]>
2023-08-03 04:50 ` Re: Fix incorrect start up costs for WindowAgg paths (bug #17862) David Rowley <[email protected]>
@ 2023-08-03 06:49 ` Andy Fan <[email protected]>
0 siblings, 0 replies; 52+ messages in thread
From: Andy Fan @ 2023-08-03 06:49 UTC (permalink / raw)
To: David Rowley <[email protected]>; +Cc: PostgreSQL Developers <[email protected]>; Tim Palmer <[email protected]>
Hi David:
Sorry for feedback at the last minute! I study the patch and find the
following cases.
1. ORDER BY or PARTITION BY
select *, count(two) over (order by unique1) from tenk1 limit 1;
DEBUG: startup_tuples = 1
DEBUG: startup_tuples = 1
select *, count(two) over (partition by unique1) from tenk1 limit 1;
DEBUG: startup_tuples = 1
DEBUG: startup_tuples = 1
Due to the Executor of nodeWindowAgg, we have to fetch the next tuple
until it mismatches with the current one, then we can calculate the
WindowAgg function. In the current patch, we didn't count the
mismatched tuple. I verified my thought with 'break at IndexNext'
function and see IndexNext is called twice, so in the above case the
startup_tuples should be 2?
2. ORDER BY and PARTITION BY
select two, hundred,
count(two) over (partition by ten order by hundred)
from tenk1 limit 1;
DEBUG: startup_tuples = 10
two | hundred | count
-----+---------+-------
0 | 0 | 100
If we consider the mismatched tuples, it should be 101?
3. As we can see the log for startup_tuples is logged twice sometimes,
the reason is because it is used in cost_windowagg, so it is calculated
for every create_one_window_path. I think the startup_tuples should be
independent with the physical path, maybe we can cache it somewhere to
save some planning cycles?
Thanks for the patch!
--
Best Regards
Andy Fan
^ permalink raw reply [nested|flat] 52+ messages in thread
end of thread, other threads:[~2023-08-03 06:49 UTC | newest]
Thread overview: 52+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2020-05-03 14:37 [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH 01/10] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH 01/10] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v35 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v37 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v36 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2020-05-03 14:37 [PATCH v38 1/6] Introduce RelOptInfo->notnullattrs attribute 一挃 <[email protected]>
2023-04-12 09:03 Fix incorrect start up costs for WindowAgg paths (bug #17862) David Rowley <[email protected]>
2023-04-12 14:28 ` Re: Fix incorrect start up costs for WindowAgg paths (bug #17862) Andy Fan <[email protected]>
2023-05-31 00:59 ` Re: Fix incorrect start up costs for WindowAgg paths (bug #17862) David Rowley <[email protected]>
2023-08-03 04:50 ` Re: Fix incorrect start up costs for WindowAgg paths (bug #17862) David Rowley <[email protected]>
2023-08-03 06:49 ` Re: Fix incorrect start up costs for WindowAgg paths (bug #17862) Andy Fan <[email protected]>
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox