pg.ddx.io pgsql-hackers@postgresql.org mailing list archive
help / color / mirror / Atom feedPartitioned tables and relfilenode
96+ messages / 10 participants
[nested] [flat]
* Partitioned tables and relfilenode
@ 2017-02-10 06:19 Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-10 06:58 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-15 07:14 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-27 18:54 ` Re: Partitioned tables and relfilenode Bruce Momjian <bruce@momjian.us>
0 siblings, 4 replies; 96+ messages in thread
From: Amit Langote @ 2017-02-10 06:19 UTC (permalink / raw)
To: pgsql-hackers
The new partitioned tables do not contain any data by themselves. Any
data inserted into a partitioned table is routed to and stored in one of
its partitions. In fact, it is impossible to insert *any* data before a
partition (to be precise, a leaf partition) is created. It seems wasteful
then to allocate physical storage (files) for partitioned tables. If we
do not allocate the storage, then we must make sure that the right thing
happens when a command that is intended to manipulate a table's storage
encounters a partitioned table, the "right thing" here being that the
command's code either throws an error or warning (in some cases) if the
specified table is a partitioned table or ignores any partitioned tables
when it reads the list of relations to process from pg_class. Commands
that need to be taught about this are vacuum, analyze, truncate, and alter
table. Specifically:
- In case of vacuum, specifying a partitioned table causes a warning
- In case of analyze, we do not throw an error or warning but simply
avoid calling do_analyze_rel() *non-recursively*. Further in
acquire_inherited_sample_rows(), any partitioned tables in the list
returned by find_all_inheritors() are skipped.
- In case of truncate, only the part which manipulates table's physical
storage is skipped for partitioned tables.
- ATRewriteTables() skips on the AlteredTableInfo entries for partitioned
tables, because there is nothing to be done.
- Since we cannot create indexes on partitioned tables anyway, there is
no need to handle cluster and reindex (they throw a meaningful error
already due to the lack of indexes.)
Patches 0001 and 0002 of the attached implement the above part. 0001
teaches the above mentioned commands to do the "right thing" as described
above and 0002 teaches heap_create() and heap_create_with_catalog() to not
create any physical storage (none of the forks) for partitioned tables.
Then comes 0003, which concerns inheritance planning. In a regular
inheritance set (ie, the inheritance set corresponding to an inheritance
hierarchy whose root is a regular table), the inheritance parents are
included in their role as child members, because they might contribute
rows to the final result. So AppendRelInfo's are created for each such
table by the planner prep phase, which the later planning steps use to
create a scan plan for those tables as the Append's child plans.
Currently, the partitioned tables are also processed by the optimizer as
inheritance sets. Partitioned table inheritance parents do not own any
storage, so we *must* not create scan plans for them. So we do not need
to process them as child members of the inheritance set. 0003 teaches
expand_inherited_rtentry() to not add partitioned tables as child members.
Also, since the root partitioned table RTE is no longer added to the
Append list as the 1st child member, inheritance_planner() cannot assume
that it can install the 1st child RTE as the nominalRelation of a given
ModifyTable node, instead the original root parent table RTE is installed
as the nominalRelation.
Together the above patches implement the first item listed in "Some
notes:" part of an email [1] on the original declarative partitioning
thread, which says:
"We should try to teach the executor never to scan the parent. That's
never necessary with this system, and it might add significant overhead.
We should also try to get rid of the idea of the parent having storage
(i.e. a relfilenode)."
Thoughts, comments?
Thanks,
Amit
[1]
https://postgr.es/m/CA%2BTgmob6DJEQBd%3DqH2wZG1onYZ9R1Sji3q%2BGqCRUqQi%2Bug28Rw%40mail.gmail.com
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Attachments:
[text/x-diff] 0001-Partitioned-tables-are-empty-themselves.patch (6.4K, ../../2b0d42f2-3a53-763b-c9c2-47139e4b1c2e@lab.ntt.co.jp/2-0001-Partitioned-tables-are-empty-themselves.patch)
download | inline diff:
From 1cc123a2f01066ababdc971a3ac9aafe1028be74 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Mon, 6 Feb 2017 18:03:28 +0900
Subject: [PATCH 1/3] Partitioned tables are empty themselves
So, there is not much point in trying to do things to them that need
accessing files (a later commit will make it so that there is no file
at all to access.) Things that needed attention are: vacuum, analyze,
truncate, ATRewriteTables.
---
src/backend/commands/analyze.c | 39 +++++++++++++++++++++++++++------------
src/backend/commands/tablecmds.c | 15 ++++++++++++---
src/backend/commands/vacuum.c | 14 +++++++++-----
3 files changed, 48 insertions(+), 20 deletions(-)
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index ed3acb1673..4dc5bd48f8 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -201,8 +201,7 @@ analyze_rel(Oid relid, RangeVar *relation, int options,
* locked the relation.
*/
if (onerel->rd_rel->relkind == RELKIND_RELATION ||
- onerel->rd_rel->relkind == RELKIND_MATVIEW ||
- onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ onerel->rd_rel->relkind == RELKIND_MATVIEW)
{
/* Regular table, so we'll use the regular row acquisition function */
acquirefunc = acquire_sample_rows;
@@ -234,7 +233,11 @@ analyze_rel(Oid relid, RangeVar *relation, int options,
return;
}
}
- else
+ /*
+ * Although we cannot analyze partitioned tables themselves, we are
+ * still be able to do the recursive ANALYZE.
+ */
+ else if (onerel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
{
/* No need for a WARNING if we already complained during VACUUM */
if (!(options & VACOPT_VACUUM))
@@ -255,8 +258,9 @@ analyze_rel(Oid relid, RangeVar *relation, int options,
/*
* Do the normal non-recursive ANALYZE.
*/
- do_analyze_rel(onerel, options, params, va_cols, acquirefunc, relpages,
- false, in_outer_xact, elevel);
+ if (onerel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
+ do_analyze_rel(onerel, options, params, va_cols, acquirefunc,
+ relpages, false, in_outer_xact, elevel);
/*
* If there are child tables, do recursive ANALYZE.
@@ -1318,8 +1322,7 @@ acquire_inherited_sample_rows(Relation onerel, int elevel,
/* Check table type (MATVIEW can't happen, but might as well allow) */
if (childrel->rd_rel->relkind == RELKIND_RELATION ||
- childrel->rd_rel->relkind == RELKIND_MATVIEW ||
- childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ childrel->rd_rel->relkind == RELKIND_MATVIEW)
{
/* Regular table, so use the regular row acquisition function */
acquirefunc = acquire_sample_rows;
@@ -1351,9 +1354,18 @@ acquire_inherited_sample_rows(Relation onerel, int elevel,
}
else
{
- /* ignore, but release the lock on it */
- Assert(childrel != onerel);
- heap_close(childrel, AccessShareLock);
+ /*
+ * Ignore, but release the lock on it. Partitioned tables are
+ * ignored here.
+ */
+ Assert(childrel != onerel ||
+ childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
+
+ /* Do not try to unlock the passed in rel */
+ if (childrel == onerel)
+ heap_close(childrel, NoLock);
+ else
+ heap_close(childrel, AccessShareLock);
continue;
}
@@ -1366,9 +1378,12 @@ acquire_inherited_sample_rows(Relation onerel, int elevel,
}
/*
- * If we don't have at least two tables to consider, fail.
+ * If we don't have at least two tables to consider, fail. In case the
+ * passed in relation is a partitioned table, we could have just one
+ * leaf partition and that'd be fine.
*/
- if (nrels < 2)
+ if ((onerel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE && nrels < 2) ||
+ nrels < 1)
{
ereport(elevel,
(errmsg("skipping analyze of \"%s.%s\" inheritance tree --- this inheritance tree contains no analyzable child tables",
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 37a4c4a3d6..92dfb46b45 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -1354,6 +1354,10 @@ ExecuteTruncate(TruncateStmt *stmt)
{
Relation rel = (Relation) lfirst(cell);
+ /* Skip partitioned tables as there is nothing to do */
+ if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ continue;
+
/*
* Normally, we need a transaction-safe truncation here. However, if
* the table was either created in the current (sub)transaction or has
@@ -1464,7 +1468,11 @@ truncate_check_rel(Relation rel)
{
AclResult aclresult;
- /* Only allow truncate on regular tables */
+ /*
+ * Only allow truncate on regular tables and partitioned tables (although,
+ * the latter are only being included here for the following checks; no
+ * physical truncation will occur in their case.)
+ */
if (rel->rd_rel->relkind != RELKIND_RELATION &&
rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
ereport(ERROR,
@@ -4011,8 +4019,9 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode)
{
AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
- /* Foreign tables have no storage. */
- if (tab->relkind == RELKIND_FOREIGN_TABLE)
+ /* Foreign tables have no storage, nor do partitioned tables. */
+ if (tab->relkind == RELKIND_FOREIGN_TABLE ||
+ tab->relkind == RELKIND_PARTITIONED_TABLE)
continue;
/*
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 812fb4a48f..cc09effa29 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -1322,12 +1322,16 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params)
*/
if (onerel->rd_rel->relkind != RELKIND_RELATION &&
onerel->rd_rel->relkind != RELKIND_MATVIEW &&
- onerel->rd_rel->relkind != RELKIND_TOASTVALUE &&
- onerel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
+ onerel->rd_rel->relkind != RELKIND_TOASTVALUE)
{
- ereport(WARNING,
- (errmsg("skipping \"%s\" --- cannot vacuum non-tables or special system tables",
- RelationGetRelationName(onerel))));
+ if (onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ ereport(WARNING,
+ (errmsg("skipping \"%s\" --- cannot vacuum partitioned tables",
+ RelationGetRelationName(onerel))));
+ else
+ ereport(WARNING,
+ (errmsg("skipping \"%s\" --- cannot vacuum non-tables or special system tables",
+ RelationGetRelationName(onerel))));
relation_close(onerel, lmode);
PopActiveSnapshot();
CommitTransactionCommand();
--
2.11.0
[text/x-diff] 0002-Do-not-allocate-storage-for-partitioned-tables.patch (1.2K, ../../2b0d42f2-3a53-763b-c9c2-47139e4b1c2e@lab.ntt.co.jp/3-0002-Do-not-allocate-storage-for-partitioned-tables.patch)
download | inline diff:
From cdd6776f5bf846933d18e48de1c16bb5545bbfaa Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Tue, 24 Jan 2017 14:22:34 +0900
Subject: [PATCH 2/3] Do not allocate storage for partitioned tables.
Currently, it is not possible to insert any data into a partitioned
table. So, they're empty at all times, which means it is wasteful to
allocate relfilenode and related storage objects.
---
src/backend/catalog/heap.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 41c0056556..b08af1205d 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -291,6 +291,7 @@ heap_create(const char *relname,
case RELKIND_VIEW:
case RELKIND_COMPOSITE_TYPE:
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
create_storage = false;
/*
@@ -1351,7 +1352,12 @@ heap_create_with_catalog(const char *relname,
relkind == RELKIND_TOASTVALUE ||
relkind == RELKIND_PARTITIONED_TABLE);
- heap_create_init_fork(new_rel_desc);
+ /*
+ * We do not want to create any storage objects for a partitioned
+ * table.
+ */
+ if (relkind != RELKIND_PARTITIONED_TABLE)
+ heap_create_init_fork(new_rel_desc);
}
/*
--
2.11.0
[text/x-diff] 0003-Always-plan-partitioned-tables-as-inheritance-sets.patch (14.6K, ../../2b0d42f2-3a53-763b-c9c2-47139e4b1c2e@lab.ntt.co.jp/4-0003-Always-plan-partitioned-tables-as-inheritance-sets.patch)
download | inline diff:
From 72569808dce0e584e6138ff0086a6dddc7957cae Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Mon, 6 Feb 2017 17:26:48 +0900
Subject: [PATCH 3/3] Always plan partitioned tables as inheritance sets
...even if empty. Currently, we create scan plans for inheritance
parents in their role as an inheritance set member. Partitioned tables
do not contain any data, so it's not right to create scan plans for them.
So we need not create AppendRelInfo's for them in the planner prep phase.
That means the Append set for a partitioned table may contain zero members
if it does not have leaf partitions Currently, such a case is treated by
the current code as a non-inheritance situation and a scan plan is created
for just the parent. It is done by turning off the inh flag of the parent
RTE so that later planner phases create a simple scan plan for it. Since
we cannot create scan plans for partitioned tables, don't turn off its inh
flag even if we found that there are no Append members. Let this empty
Append member list cause later code create a constant-false Result plan.
Also, inheritance_planner() must not always assume that the 1st child
member of an inheritance set is the nominal relation. For partitioned
tables, we use the original parent RTE as the nominal relation in that
case, because we no longer create the duplicate RTE representing a
partitioned table as a child member of the inheritance set.
---
src/backend/optimizer/plan/planner.c | 15 +++++
src/backend/optimizer/prep/prepunion.c | 34 +++++++++--
src/test/regress/expected/inherit.out | 108 +++++++--------------------------
3 files changed, 66 insertions(+), 91 deletions(-)
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 881742f46b..271d73acca 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -996,10 +996,20 @@ inheritance_planner(PlannerInfo *root)
RelOptInfo *final_rel;
ListCell *lc;
Index rti;
+ RangeTblEntry *parent_rte;
Assert(parse->commandType != CMD_INSERT);
/*
+ * If the parent RTE is a partitioned table, we should use that as the
+ * nominal relation, because we do not have the duplicate parent RTE,
+ * unlike in the case of a non-partitioned inheritance parent.
+ */
+ parent_rte = rt_fetch(parentRTindex, root->parse->rtable);
+ if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
+ nominalRelation = parentRTindex;
+
+ /*
* We generate a modified instance of the original Query for each target
* relation, plan that, and put all the plans into a list that will be
* controlled by a single ModifyTable node. All the instances share the
@@ -1214,6 +1224,11 @@ inheritance_planner(PlannerInfo *root)
* will not be otherwise referenced in the plan, doing so would give
* rise to confusing use of multiple aliases in EXPLAIN output for
* what the user will think is the "same" table.)
+ *
+ * If the parent is a partitioned table, we do not have a separate RTE
+ * representing it as a member of the inheritance set, because we do
+ * not create a scan plan for it. As mentioned at the top of this
+ * function, we make the parent RTE itself the nominal relation.
*/
if (nominalRelation < 0)
nominalRelation = appinfo->child_relid;
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 06e843dff0..781bf149a7 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -1374,9 +1374,16 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
Assert(rte->rtekind == RTE_SUBQUERY);
return;
}
- /* Fast path for common case of childless table */
+ /*
+ * Fast path for common case of childless table. However, a partitioned
+ * table RTE should *always* be processed by the later code as an
+ * inheritance set, possibly an empty one in the absence of any leaf
+ * partitions. It is wrong to try to create a scan plan for a partitioned
+ * table, since it does not own storage.
+ */
parentOID = rte->relid;
- if (!has_subclass(parentOID))
+ if (rte->relkind != RELKIND_PARTITIONED_TABLE &&
+ !has_subclass(parentOID))
{
/* Clear flag before returning */
rte->inh = false;
@@ -1410,9 +1417,11 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
/*
* Check that there's at least one descendant, else treat as no-child
* case. This could happen despite above has_subclass() check, if table
- * once had a child but no longer does.
+ * once had a child but no longer does. Again, do not disable inheritance
+ * for a partitioned table as described above.
*/
- if (list_length(inhOIDs) < 2)
+ if (rte->relkind != RELKIND_PARTITIONED_TABLE &&
+ list_length(inhOIDs) < 2)
{
/* Clear flag before returning */
rte->inh = false;
@@ -1450,6 +1459,17 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
newrelation = oldrelation;
/*
+ * Do not add partitioned tables as Append members, because we should
+ * not create scan plans for partitioned tables.
+ */
+ if (newrelation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ if (newrelation != oldrelation)
+ heap_close(newrelation, lockmode);
+ continue;
+ }
+
+ /*
* It is possible that the parent table has children that are temp
* tables of other backends. We cannot safely access such tables
* (because of buffering issues), and the best thing to do seems to be
@@ -1548,9 +1568,11 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
* If all the children were temp tables, pretend it's a non-inheritance
* situation. The duplicate RTE we added for the parent table is
* harmless, so we don't bother to get rid of it; ditto for the useless
- * PlanRowMark node.
+ * PlanRowMark node. Do not pretend non-inheritance for partitioned
+ * tables as described above.
*/
- if (list_length(appinfos) < 2)
+ if (rte->relkind != RELKIND_PARTITIONED_TABLE &&
+ list_length(appinfos) < 2)
{
/* Clear flag before returning */
rte->inh = false;
diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out
index a8c8b28a75..ef4e049047 100644
--- a/src/test/regress/expected/inherit.out
+++ b/src/test/regress/expected/inherit.out
@@ -1605,71 +1605,60 @@ explain (costs off) select * from list_parted;
QUERY PLAN
--------------------------------
Append
- -> Seq Scan on list_parted
-> Seq Scan on part_ab_cd
-> Seq Scan on part_ef_gh
-> Seq Scan on part_null_xy
-(5 rows)
+(4 rows)
explain (costs off) select * from list_parted where a is null;
QUERY PLAN
--------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (a IS NULL)
-> Seq Scan on part_null_xy
Filter: (a IS NULL)
-(5 rows)
+(3 rows)
explain (costs off) select * from list_parted where a is not null;
QUERY PLAN
---------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (a IS NOT NULL)
-> Seq Scan on part_ab_cd
Filter: (a IS NOT NULL)
-> Seq Scan on part_ef_gh
Filter: (a IS NOT NULL)
-> Seq Scan on part_null_xy
Filter: (a IS NOT NULL)
-(9 rows)
+(7 rows)
explain (costs off) select * from list_parted where a in ('ab', 'cd', 'ef');
QUERY PLAN
----------------------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-> Seq Scan on part_ab_cd
Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-> Seq Scan on part_ef_gh
Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-(7 rows)
+(5 rows)
explain (costs off) select * from list_parted where a = 'ab' or a in (null, 'cd');
QUERY PLAN
---------------------------------------------------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_ab_cd
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_ef_gh
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_null_xy
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-(9 rows)
+(7 rows)
explain (costs off) select * from list_parted where a = 'ab';
QUERY PLAN
------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: ((a)::text = 'ab'::text)
-> Seq Scan on part_ab_cd
Filter: ((a)::text = 'ab'::text)
-(5 rows)
+(3 rows)
create table range_list_parted (
a int,
@@ -1689,14 +1678,9 @@ create table part_40_inf_ab partition of part_40_inf for values in ('ab');
create table part_40_inf_cd partition of part_40_inf for values in ('cd');
create table part_40_inf_null partition of part_40_inf for values in (null);
explain (costs off) select * from range_list_parted;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- -> Seq Scan on part_1_10
- -> Seq Scan on part_10_20
- -> Seq Scan on part_21_30
- -> Seq Scan on part_40_inf
-> Seq Scan on part_1_10_ab
-> Seq Scan on part_1_10_cd
-> Seq Scan on part_10_20_ab
@@ -1706,36 +1690,22 @@ explain (costs off) select * from range_list_parted;
-> Seq Scan on part_40_inf_ab
-> Seq Scan on part_40_inf_cd
-> Seq Scan on part_40_inf_null
-(15 rows)
+(10 rows)
explain (costs off) select * from range_list_parted where a = 5;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+--------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (a = 5)
- -> Seq Scan on part_1_10
- Filter: (a = 5)
-> Seq Scan on part_1_10_ab
Filter: (a = 5)
-> Seq Scan on part_1_10_cd
Filter: (a = 5)
-(9 rows)
+(5 rows)
explain (costs off) select * from range_list_parted where b = 'ab';
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_1_10
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_10_20
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_21_30
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_40_inf
- Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_1_10_ab
Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_10_20_ab
@@ -1744,27 +1714,19 @@ explain (costs off) select * from range_list_parted where b = 'ab';
Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_40_inf_ab
Filter: (b = 'ab'::bpchar)
-(19 rows)
+(9 rows)
explain (costs off) select * from range_list_parted where a between 3 and 23 and b in ('ab');
QUERY PLAN
-----------------------------------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_1_10
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_10_20
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_21_30
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_1_10_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_10_20_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_21_30_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-(15 rows)
+(7 rows)
/* Should select no rows because range partition key cannot be null */
explain (costs off) select * from range_list_parted where a is null;
@@ -1776,37 +1738,17 @@ explain (costs off) select * from range_list_parted where a is null;
/* Should only select rows from the null-accepting partition */
explain (costs off) select * from range_list_parted where b is null;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (b IS NULL)
- -> Seq Scan on part_1_10
- Filter: (b IS NULL)
- -> Seq Scan on part_10_20
- Filter: (b IS NULL)
- -> Seq Scan on part_21_30
- Filter: (b IS NULL)
- -> Seq Scan on part_40_inf
- Filter: (b IS NULL)
-> Seq Scan on part_40_inf_null
Filter: (b IS NULL)
-(13 rows)
+(3 rows)
explain (costs off) select * from range_list_parted where a is not null and a < 67;
QUERY PLAN
------------------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_1_10
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_10_20
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_21_30
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_40_inf
- Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_1_10_ab
Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_1_10_cd
@@ -1825,23 +1767,19 @@ explain (costs off) select * from range_list_parted where a is not null and a <
Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_40_inf_null
Filter: ((a IS NOT NULL) AND (a < 67))
-(29 rows)
+(19 rows)
explain (costs off) select * from range_list_parted where a >= 30;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (a >= 30)
- -> Seq Scan on part_40_inf
- Filter: (a >= 30)
-> Seq Scan on part_40_inf_ab
Filter: (a >= 30)
-> Seq Scan on part_40_inf_cd
Filter: (a >= 30)
-> Seq Scan on part_40_inf_null
Filter: (a >= 30)
-(11 rows)
+(7 rows)
drop table list_parted cascade;
NOTICE: drop cascades to 3 other objects
--
2.11.0
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-02-10 06:58 ` Simon Riggs <simon@2ndquadrant.com>
2017-02-10 07:15 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
3 siblings, 1 reply; 96+ messages in thread
From: Simon Riggs @ 2017-02-10 06:58 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: pgsql-hackers
On 10 February 2017 at 06:19, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
> The new partitioned tables do not contain any data by themselves. Any
> data inserted into a partitioned table is routed to and stored in one of
> its partitions. In fact, it is impossible to insert *any* data before a
> partition (to be precise, a leaf partition) is created.
Where is all of this documented? All I see at the moment is old docs.
--
Simon Riggs http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-10 06:58 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
@ 2017-02-10 07:15 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
0 siblings, 0 replies; 96+ messages in thread
From: Amit Langote @ 2017-02-10 07:15 UTC (permalink / raw)
To: Simon Riggs <simon@2ndquadrant.com>; +Cc: pgsql-hackers
On 2017/02/10 15:58, Simon Riggs wrote:
> On 10 February 2017 at 06:19, Amit Langote
> <Langote_Amit_f8@lab.ntt.co.jp> wrote:
>> The new partitioned tables do not contain any data by themselves. Any
>> data inserted into a partitioned table is routed to and stored in one of
>> its partitions. In fact, it is impossible to insert *any* data before a
>> partition (to be precise, a leaf partition) is created.
>
> Where is all of this documented? All I see at the moment is old docs.
Last week I sent documentation patches in a separate message titled
"Documentation improvements for partitioning" [1]. One of the patches
adds a separate section in the DDL chapter describing partitioned tables.
Thanks,
Amit
[1]
https://www.postgresql.org/message-id/bf9ebbb3-fb1e-3206-b67c-e7a803a747d9%40lab.ntt.co.jp
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-02-15 07:14 ` Michael Paquier <michael.paquier@gmail.com>
2017-02-15 16:14 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 02:34 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
3 siblings, 2 replies; 96+ messages in thread
From: Michael Paquier @ 2017-02-15 07:14 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: pgsql-hackers
On Fri, Feb 10, 2017 at 3:19 PM, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
> The new partitioned tables do not contain any data by themselves. Any
> data inserted into a partitioned table is routed to and stored in one of
> its partitions. In fact, it is impossible to insert *any* data before a
> partition (to be precise, a leaf partition) is created. It seems wasteful
> then to allocate physical storage (files) for partitioned tables. If we
> do not allocate the storage, then we must make sure that the right thing
> happens when a command that is intended to manipulate a table's storage
> encounters a partitioned table, the "right thing" here being that the
> command's code either throws an error or warning (in some cases) if the
> specified table is a partitioned table or ignores any partitioned tables
> when it reads the list of relations to process from pg_class. Commands
> that need to be taught about this are vacuum, analyze, truncate, and alter
> table. Specifically:
Thanks. I have been looking a bit at this set of patches.
> - In case of vacuum, specifying a partitioned table causes a warning
> - In case of analyze, we do not throw an error or warning but simply
> avoid calling do_analyze_rel() *non-recursively*. Further in
> acquire_inherited_sample_rows(), any partitioned tables in the list
> returned by find_all_inheritors() are skipped.
> - In case of truncate, only the part which manipulates table's physical
> storage is skipped for partitioned tables.
I am wondering if instead those should not just be errors saying that
such operations are just not support. This could be relaxed in the
future to mean that a vacuum, truncate or analyze on the partitioned
table triggers an operator in cascade.
> - ATRewriteTables() skips on the AlteredTableInfo entries for partitioned
> tables, because there is nothing to be done.
Perhaps that makes sense, foreign tables do that.
> - Since we cannot create indexes on partitioned tables anyway, there is
> no need to handle cluster and reindex (they throw a meaningful error
> already due to the lack of indexes.)
Yep.
> Patches 0001 and 0002 of the attached implement the above part. 0001
> teaches the above mentioned commands to do the "right thing" as described
> above and 0002 teaches heap_create() and heap_create_with_catalog() to not
> create any physical storage (none of the forks) for partitioned tables.
- else
+ /*
+ * Although we cannot analyze partitioned tables themselves, we are
+ * still be able to do the recursive ANALYZE.
+ */
+ else if (onerel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
{
/* No need for a WARNING if we already complained during VACUUM */
if (!(options & VACOPT_VACUUM))
It seems to me that it is better style to use an empty else if with
only the comment. Comments related to a condition that are outside
this condition should be conditional in their formulations. Comments
within a condition can be affirmations when they refer to a decided
state of things.
From patch 2:
@@ -1351,7 +1352,12 @@ heap_create_with_catalog(const char *relname,
relkind == RELKIND_TOASTVALUE ||
relkind == RELKIND_PARTITIONED_TABLE);
- heap_create_init_fork(new_rel_desc);
+ /*
+ * We do not want to create any storage objects for a partitioned
+ * table.
+ */
+ if (relkind != RELKIND_PARTITIONED_TABLE)
+ heap_create_init_fork(new_rel_desc);
}
This does not make much sense with an assertion telling exactly the
contrary a couple of lines before. I think that it would make more
sense to move the assertion on relkind directly in
heap_create_init_fork().
> Then comes 0003, which concerns inheritance planning. In a regular
> inheritance set (ie, the inheritance set corresponding to an inheritance
> hierarchy whose root is a regular table), the inheritance parents are
> included in their role as child members, because they might contribute
> rows to the final result. So AppendRelInfo's are created for each such
> table by the planner prep phase, which the later planning steps use to
> create a scan plan for those tables as the Append's child plans.
> Currently, the partitioned tables are also processed by the optimizer as
> inheritance sets. Partitioned table inheritance parents do not own any
> storage, so we *must* not create scan plans for them. So we do not need
> to process them as child members of the inheritance set. 0003 teaches
> expand_inherited_rtentry() to not add partitioned tables as child members.
> Also, since the root partitioned table RTE is no longer added to the
> Append list as the 1st child member, inheritance_planner() cannot assume
> that it can install the 1st child RTE as the nominalRelation of a given
> ModifyTable node, instead the original root parent table RTE is installed
> as the nominalRelation.
This is a collection of checks on relkind == RELKIND_PARTITIONED_TABLE
to avoid interactions with partition tables. Did you consider doing
something in the executor instead?
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-15 07:14 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
@ 2017-02-15 16:14 ` Robert Haas <robertmhaas@gmail.com>
1 sibling, 0 replies; 96+ messages in thread
From: Robert Haas @ 2017-02-15 16:14 UTC (permalink / raw)
To: Michael Paquier <michael.paquier@gmail.com>; +Cc: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; pgsql-hackers
On Wed, Feb 15, 2017 at 2:14 AM, Michael Paquier
<michael.paquier@gmail.com> wrote:
> This is a collection of checks on relkind == RELKIND_PARTITIONED_TABLE
> to avoid interactions with partition tables. Did you consider doing
> something in the executor instead?
That seems inferior, because the planner really ought to know that the
partitioning root doesn't need to be scanned. That way, it can do a
better job getting the cost and selectivity estimates right.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-15 07:14 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
@ 2017-02-17 02:34 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
1 sibling, 0 replies; 96+ messages in thread
From: Amit Langote @ 2017-02-17 02:34 UTC (permalink / raw)
To: Michael Paquier <michael.paquier@gmail.com>; +Cc: pgsql-hackers
On 2017/02/15 16:14, Michael Paquier wrote:
> On Fri, Feb 10, 2017 at 3:19 PM, Amit Langote
> <Langote_Amit_f8@lab.ntt.co.jp> wrote:
>> The new partitioned tables do not contain any data by themselves. Any
>> data inserted into a partitioned table is routed to and stored in one of
>> its partitions. In fact, it is impossible to insert *any* data before a
>> partition (to be precise, a leaf partition) is created. It seems wasteful
>> then to allocate physical storage (files) for partitioned tables. If we
>> do not allocate the storage, then we must make sure that the right thing
>> happens when a command that is intended to manipulate a table's storage
>> encounters a partitioned table, the "right thing" here being that the
>> command's code either throws an error or warning (in some cases) if the
>> specified table is a partitioned table or ignores any partitioned tables
>> when it reads the list of relations to process from pg_class. Commands
>> that need to be taught about this are vacuum, analyze, truncate, and alter
>> table. Specifically:
>
> Thanks. I have been looking a bit at this set of patches.
Thanks for reviewing!
>> - In case of vacuum, specifying a partitioned table causes a warning
>> - In case of analyze, we do not throw an error or warning but simply
>> avoid calling do_analyze_rel() *non-recursively*. Further in
>> acquire_inherited_sample_rows(), any partitioned tables in the list
>> returned by find_all_inheritors() are skipped.
>> - In case of truncate, only the part which manipulates table's physical
>> storage is skipped for partitioned tables.
>
> I am wondering if instead those should not just be errors saying that
> such operations are just not support. This could be relaxed in the
> future to mean that a vacuum, truncate or analyze on the partitioned
> table triggers an operator in cascade.
As the discussion down-thread suggests, that might be a path worth
considering. That is, vacuum or analyze on a partitioned table causes all
the (leaf) partitions to be vacuumed or analyzed.
Truncate already does that (that is, recurse to leaf partitions). This
patch simply prevents ExecuteTruncate() from trying to manipulate the
partitioned table's relfilenode.
>> - Since we cannot create indexes on partitioned tables anyway, there is
>> no need to handle cluster and reindex (they throw a meaningful error
>> already due to the lack of indexes.)
>
> Yep.
This one is still under discussion.
>> Patches 0001 and 0002 of the attached implement the above part. 0001
>> teaches the above mentioned commands to do the "right thing" as described
>> above and 0002 teaches heap_create() and heap_create_with_catalog() to not
>> create any physical storage (none of the forks) for partitioned tables.
>
> - else
> + /*
> + * Although we cannot analyze partitioned tables themselves, we are
> + * still be able to do the recursive ANALYZE.
> + */
> + else if (onerel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
> {
> /* No need for a WARNING if we already complained during VACUUM */
> if (!(options & VACOPT_VACUUM))
> It seems to me that it is better style to use an empty else if with
> only the comment. Comments related to a condition that are outside
> this condition should be conditional in their formulations. Comments
> within a condition can be affirmations when they refer to a decided
> state of things.
Not sure if this will survive based on the decisions on what to do about
vacuum and analyze, but how about the following rewrite of the above:
else if (onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
{
/*
* Although we cannot analyze partitioned tables themselves, we are
* still be able to do the recursive ANALYZE, which we do below.
*/
}
else
{
>>From patch 2:
> @@ -1351,7 +1352,12 @@ heap_create_with_catalog(const char *relname,
> relkind == RELKIND_TOASTVALUE ||
> relkind == RELKIND_PARTITIONED_TABLE);
>
> - heap_create_init_fork(new_rel_desc);
> + /*
> + * We do not want to create any storage objects for a partitioned
> + * table.
> + */
> + if (relkind != RELKIND_PARTITIONED_TABLE)
> + heap_create_init_fork(new_rel_desc);
> }
> This does not make much sense with an assertion telling exactly the
> contrary a couple of lines before. I think that it would make more
> sense to move the assertion on relkind directly in
> heap_create_init_fork().
Hmm, perhaps the below is saner, with the Assert moved to the start of
heap_create_init_fork() as shown below:
/*
* We do not want to create any storage objects for a partitioned
* table, including the init fork.
*/
if (relpersistence == RELPERSISTENCE_UNLOGGED &&
relkind != RELKIND_PARTITIONED_TABLE)
heap_create_init_fork(new_rel_desc);
@@ -1382,6 +1376,8 @@ heap_create_with_catalog(const char *relname,
void
heap_create_init_fork(Relation rel)
{
+ Assert(relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW ||
+ relkind == RELKIND_TOASTVALUE);
>> Then comes 0003, which concerns inheritance planning. In a regular
>> inheritance set (ie, the inheritance set corresponding to an inheritance
>> hierarchy whose root is a regular table), the inheritance parents are
>> included in their role as child members, because they might contribute
>> rows to the final result. So AppendRelInfo's are created for each such
>> table by the planner prep phase, which the later planning steps use to
>> create a scan plan for those tables as the Append's child plans.
>> Currently, the partitioned tables are also processed by the optimizer as
>> inheritance sets. Partitioned table inheritance parents do not own any
>> storage, so we *must* not create scan plans for them. So we do not need
>> to process them as child members of the inheritance set. 0003 teaches
>> expand_inherited_rtentry() to not add partitioned tables as child members.
>> Also, since the root partitioned table RTE is no longer added to the
>> Append list as the 1st child member, inheritance_planner() cannot assume
>> that it can install the 1st child RTE as the nominalRelation of a given
>> ModifyTable node, instead the original root parent table RTE is installed
>> as the nominalRelation.
>
> This is a collection of checks on relkind == RELKIND_PARTITIONED_TABLE
> to avoid interactions with partition tables. Did you consider doing
> something in the executor instead?
Getting rid of the parent relation (of which there could be many if a
given partition tree is multi-level) well within the optimizer means that
the optimizer makes a plan that does not have redundant Scan nodes for
partitioned tables (and if the 2nd patch is worthy of consideration, we
absolutely cannot create Scan nodes for them at all). And Robert's point
about optimizer's cost and selectivity estimations.
I will post the updated patches after addressing other comments in the thread.
Thanks,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-02-16 11:32 ` Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-19 20:31 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
3 siblings, 2 replies; 96+ messages in thread
From: Simon Riggs @ 2017-02-16 11:32 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: pgsql-hackers
On 10 February 2017 at 06:19, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
> the "right thing" here being that the
> command's code either throws an error or warning (in some cases) if the
> specified table is a partitioned table or ignores any partitioned tables
> when it reads the list of relations to process from pg_class.
This is a massive assumption and deserves major discussion.
My expectation is that "partitioned tables" are "tables". Anything
else seems to fly in the face of both the SQL Standard and the POLA
principle for users coming from other database systems.
IMHO all the main actions should all "just work" not throw errors.
> Commands
> that need to be taught about this are vacuum, analyze, truncate, and alter
> table. Specifically:
>
> - In case of vacuum, specifying a partitioned table causes a warning
Why not vacuum all partitions?
> - In case of analyze, we do not throw an error or warning but simply
> avoid calling do_analyze_rel() *non-recursively*. Further in
> acquire_inherited_sample_rows(), any partitioned tables in the list
> returned by find_all_inheritors() are skipped.
Why not analyze all partitions?
> - In case of truncate, only the part which manipulates table's physical
> storage is skipped for partitioned tables.
Truncate all partitions
> - ATRewriteTables() skips on the AlteredTableInfo entries for partitioned
> tables, because there is nothing to be done.
>
> - Since we cannot create indexes on partitioned tables anyway, there is
> no need to handle cluster and reindex (they throw a meaningful error
> already due to the lack of indexes.)
Create index on all partitions
> Thoughts, comments?
We already have Inheritance. Anybody that likes that behaviour can use it.
Most people don't like that behaviour and wish to see change. They
want the same behaviour as they get from other database products where
a partitioned table is a table and you can do stuff to it just like
other tables. We have the opportunity to change things here and we
should do so.
(It also seems like wasted effort to try to remove the overhead caused
by a parent table for partitioning. Why introduce a special case to
save a few bytes? Premature optimization, surely?)
--
Simon Riggs http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
@ 2017-02-16 14:40 ` Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
1 sibling, 1 reply; 96+ messages in thread
From: Robert Haas @ 2017-02-16 14:40 UTC (permalink / raw)
To: Simon Riggs <simon@2ndquadrant.com>; +Cc: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; pgsql-hackers
On Thu, Feb 16, 2017 at 6:32 AM, Simon Riggs <simon@2ndquadrant.com> wrote:
> Why not vacuum all partitions?
> Why not analyze all partitions?
> Truncate all partitions
I agree. But, we need to be careful that a database-wide VACUUM or
ANALYZE doesn't hit the partitions multiple times, once for the parent
and again for each child. Actually, a database-wide VACUUM should hit
each partition individually and do nothing for the parents, but a
database-wide ANALYZE should process the parents and do nothing for
the children, so that the inheritance statistics get updated.
>> - ATRewriteTables() skips on the AlteredTableInfo entries for partitioned
>> tables, because there is nothing to be done.
>>
>> - Since we cannot create indexes on partitioned tables anyway, there is
>> no need to handle cluster and reindex (they throw a meaningful error
>> already due to the lack of indexes.)
>
> Create index on all partitions
That one's more complicated, per what I wrote in
https://www.postgresql.org/message-id/CA+TgmoZUwj=QYnaK+F7xEf4w_e2g3XxdMnSNZMZjuinHRcOB8A@mail.gmail...
> (It also seems like wasted effort to try to remove the overhead caused
> by a parent table for partitioning. Why introduce a special case to
> save a few bytes? Premature optimization, surely?)
I don't think it's wasted effort, actually. My concern isn't so much
the empty file on disk (which is stupid, but maybe harmless) as
eliminating the dummy scan from the query plan. I believe the
do-nothing scan can actually be a noticeable drag on performance in
some cases - e.g. if the scan of the partitioned table is on the
inside of a nested loop, so that instead of repeatedly doing an index
scan on each of 4 partitions, you repeatedly do an index scan on each
of 4 partitions and a sequential scan of an empty table. A zero-page
sequential scan is pretty fast, but not free. An even bigger problem
is that the planner may think that always-empty parent can contain
some rows, throwing planner estimates off and messing up the whole
plan. We've been living with that problem for a long time, but now
that we have an opportunity to fix it, it would be good to do so.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
@ 2017-02-17 07:42 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
0 siblings, 1 reply; 96+ messages in thread
From: Amit Langote @ 2017-02-17 07:42 UTC (permalink / raw)
To: Robert Haas <robertmhaas@gmail.com>; Simon Riggs <simon@2ndquadrant.com>; +Cc: pgsql-hackers
On 2017/02/16 23:40, Robert Haas wrote:
> On Thu, Feb 16, 2017 at 6:32 AM, Simon Riggs <simon@2ndquadrant.com> wrote:
>> Why not vacuum all partitions?
>> Why not analyze all partitions?
>> Truncate all partitions
>
> I agree. But, we need to be careful that a database-wide VACUUM or
> ANALYZE doesn't hit the partitions multiple times, once for the parent
> and again for each child. Actually, a database-wide VACUUM should hit
> each partition individually and do nothing for the parents, but a
This is what would happen even without the patch. Patch only modifies
what happens when a partitioned table is specified in the vacuum command.
It emits a warning:
WARNING: skipping "%s" --- cannot vacuum partitioned tables
It seems both you and Simon agree that instead of this warning, we should
recurse to process the leaf partitions (ignoring any partitioned tables in
the hierarchy for which there is nothing to do). If that's right, I will
modify the patch to do that.
> database-wide ANALYZE should process the parents and do nothing for
> the children, so that the inheritance statistics get updated.
Currently vacuum() processes the following relations:
/*
* Process all plain relations and materialized views listed in
* pg_class
*/
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
if (classForm->relkind != RELKIND_RELATION &&
classForm->relkind != RELKIND_MATVIEW)
continue;
Do you mean that if database-wide analyze is to be run, we should also
exclude those RELKIND_RELATION relations that are partitions?
So the only way to update a partition's statistics is to directly specify
it in the command or by autovacuum.
Truncate already recurses to partitions by way of inheritance recursion
that's already in place. The patch simply teaches ExecuteTruncate() to
ignore partitioned tables when we get to the part where relfilenodes are
manipulated.
>>> - ATRewriteTables() skips on the AlteredTableInfo entries for partitioned
>>> tables, because there is nothing to be done.
>>>
>>> - Since we cannot create indexes on partitioned tables anyway, there is
>>> no need to handle cluster and reindex (they throw a meaningful error
>>> already due to the lack of indexes.)
>>
>> Create index on all partitions
>
> That one's more complicated, per what I wrote in
> https://www.postgresql.org/message-id/CA+TgmoZUwj=QYnaK+F7xEf4w_e2g3XxdMnSNZMZjuinHRcOB8A@mail.gmail...
I agree that it would be nice to fix this usability issue. But, it's also
important as you say in the quoted email that we should not underestimate
the amount of work that might be required to properly implement it.
>> (It also seems like wasted effort to try to remove the overhead caused
>> by a parent table for partitioning. Why introduce a special case to
>> save a few bytes? Premature optimization, surely?)
>
> I don't think it's wasted effort, actually. My concern isn't so much
> the empty file on disk (which is stupid, but maybe harmless) as
> eliminating the dummy scan from the query plan. I believe the
> do-nothing scan can actually be a noticeable drag on performance in
> some cases - e.g. if the scan of the partitioned table is on the
> inside of a nested loop, so that instead of repeatedly doing an index
> scan on each of 4 partitions, you repeatedly do an index scan on each
> of 4 partitions and a sequential scan of an empty table. A zero-page
> sequential scan is pretty fast, but not free. An even bigger problem
> is that the planner may think that always-empty parent can contain
> some rows, throwing planner estimates off and messing up the whole
> plan. We've been living with that problem for a long time, but now
> that we have an opportunity to fix it, it would be good to do so.
Agreed. I would have reconsidered if it were a more invasive patch.
Thanks,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-02-19 09:53 ` Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
0 siblings, 1 reply; 96+ messages in thread
From: Robert Haas @ 2017-02-19 09:53 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On Fri, Feb 17, 2017 at 1:12 PM, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
>> I agree. But, we need to be careful that a database-wide VACUUM or
>> ANALYZE doesn't hit the partitions multiple times, once for the parent
>> and again for each child. Actually, a database-wide VACUUM should hit
>> each partition individually and do nothing for the parents, but a
>
> This is what would happen even without the patch. Patch only modifies
> what happens when a partitioned table is specified in the vacuum command.
> It emits a warning:
>
> WARNING: skipping "%s" --- cannot vacuum partitioned tables
>
> It seems both you and Simon agree that instead of this warning, we should
> recurse to process the leaf partitions (ignoring any partitioned tables in
> the hierarchy for which there is nothing to do). If that's right, I will
> modify the patch to do that.
Yeah, that sounds fine.
>> database-wide ANALYZE should process the parents and do nothing for
>> the children, so that the inheritance statistics get updated.
>
> Currently vacuum() processes the following relations:
>
> /*
> * Process all plain relations and materialized views listed in
> * pg_class
> */
>
> while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
> {
> Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
>
> if (classForm->relkind != RELKIND_RELATION &&
> classForm->relkind != RELKIND_MATVIEW)
> continue;
>
> Do you mean that if database-wide analyze is to be run, we should also
> exclude those RELKIND_RELATION relations that are partitions?
>
> So the only way to update a partition's statistics is to directly specify
> it in the command or by autovacuum.
I think if you type:
ANALYZE;
...that should process all partitioned tables and all tables that are
not themselves partitions. If you type:
ANALYZE name;
...that should ANALYZE that relation, whatever it is. If it's a
partitioned table, it should recurse.
> Truncate already recurses to partitions by way of inheritance recursion
> that's already in place. The patch simply teaches ExecuteTruncate() to
> ignore partitioned tables when we get to the part where relfilenodes are
> manipulated.
Oh, OK. That seems fine.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
@ 2017-02-20 10:30 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
0 siblings, 1 reply; 96+ messages in thread
From: Amit Langote @ 2017-02-20 10:30 UTC (permalink / raw)
To: Robert Haas <robertmhaas@gmail.com>; +Cc: Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On 2017/02/19 18:53, Robert Haas wrote:
> On Fri, Feb 17, 2017 at 1:12 PM, Amit Langote wrote:
>> Do you mean that if database-wide analyze is to be run, we should also
>> exclude those RELKIND_RELATION relations that are partitions?
>>
>> So the only way to update a partition's statistics is to directly specify
>> it in the command or by autovacuum.
>
> I think if you type:
>
> ANALYZE;
>
> ...that should process all partitioned tables and all tables that are
> not themselves partitions.
OK.
> If you type:
>
> ANALYZE name;
>
> ...that should ANALYZE that relation, whatever it is. If it's a
> partitioned table, it should recurse.
To be clear, by "recurse" I assume you mean to perform ANALYZE on
individual partitions, not just collect the inheritance statistics. So
ANALYZE partitioned_table would both a) collect the inheritance statistics
for the specified table and other partitioned tables in the hierarchy, b)
ANALYZE every leaf partitions updating their statistics in pg_class.
While working on this, I noticed that autovacuum.c does not collect
RELKIND_PARTITIONED_TABLE relations, which I think is not right. It
should match what get_rel_oids() does, which in the database-wide
VACUUM/ANALYZE case collects them.
Attached updated patches:
Updated 0001 addresses the following comments:
- should recurse when vacuum/analyze is performed on a partitioned table
- database-wide vacuum should ignore partitioned tables
- database-wide analyze should ignore partitions; only the inheritance
statistics of the partitioned tables must be collected in this case
Thanks,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Attachments:
[text/x-diff] 0001-Partitioned-tables-are-empty-themselves.patch (12.4K, ../../a3aef18d-ce05-2163-30e3-d1f9154cc076@lab.ntt.co.jp/2-0001-Partitioned-tables-are-empty-themselves.patch)
download | inline diff:
From 982366eb019585438513b0c7b6e86acc74e459d1 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Mon, 6 Feb 2017 18:03:28 +0900
Subject: [PATCH 1/3] Partitioned tables are empty themselves
So, there is not much point in trying to do things to them that need
accessing files (a later commit will make it so that there is no file
at all to access.) Things that needed attention are: vacuum, analyze,
truncate, ATRewriteTables.
---
src/backend/commands/analyze.c | 39 ++++++++++++++------
src/backend/commands/tablecmds.c | 15 ++++++--
src/backend/commands/vacuum.c | 71 +++++++++++++++++++++++++++++++++----
src/backend/postmaster/autovacuum.c | 20 +++++++----
4 files changed, 118 insertions(+), 27 deletions(-)
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index ed3acb1673..12cd0110b0 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -201,8 +201,7 @@ analyze_rel(Oid relid, RangeVar *relation, int options,
* locked the relation.
*/
if (onerel->rd_rel->relkind == RELKIND_RELATION ||
- onerel->rd_rel->relkind == RELKIND_MATVIEW ||
- onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ onerel->rd_rel->relkind == RELKIND_MATVIEW)
{
/* Regular table, so we'll use the regular row acquisition function */
acquirefunc = acquire_sample_rows;
@@ -234,6 +233,12 @@ analyze_rel(Oid relid, RangeVar *relation, int options,
return;
}
}
+ else if (onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ /*
+ * For partitioned tables, we want to do the recursive ANALYZE below.
+ */
+ }
else
{
/* No need for a WARNING if we already complained during VACUUM */
@@ -253,13 +258,15 @@ analyze_rel(Oid relid, RangeVar *relation, int options,
LWLockRelease(ProcArrayLock);
/*
- * Do the normal non-recursive ANALYZE.
+ * Do the normal non-recursive ANALYZE, non-partitioned relations.
*/
- do_analyze_rel(onerel, options, params, va_cols, acquirefunc, relpages,
- false, in_outer_xact, elevel);
+ if (onerel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
+ do_analyze_rel(onerel, options, params, va_cols, acquirefunc,
+ relpages, false, in_outer_xact, elevel);
/*
- * If there are child tables, do recursive ANALYZE.
+ * If there are child tables, do recursive ANALYZE. This includes
+ * partitioned tables.
*/
if (onerel->rd_rel->relhassubclass)
do_analyze_rel(onerel, options, params, va_cols, acquirefunc, relpages,
@@ -1316,10 +1323,20 @@ acquire_inherited_sample_rows(Relation onerel, int elevel,
continue;
}
+ /* Ignore partitioned tables as there are no tuples to collect */
+ if (childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ /* Don't try to unlock the passed-in root table. */
+ if (childrel == onerel)
+ heap_close(childrel, NoLock);
+ else
+ heap_close(childrel, AccessShareLock);
+ continue;
+ }
+
/* Check table type (MATVIEW can't happen, but might as well allow) */
if (childrel->rd_rel->relkind == RELKIND_RELATION ||
- childrel->rd_rel->relkind == RELKIND_MATVIEW ||
- childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ childrel->rd_rel->relkind == RELKIND_MATVIEW)
{
/* Regular table, so use the regular row acquisition function */
acquirefunc = acquire_sample_rows;
@@ -1366,9 +1383,11 @@ acquire_inherited_sample_rows(Relation onerel, int elevel,
}
/*
- * If we don't have at least two tables to consider, fail.
+ * If we don't have at least one child table to consider, fail. If the
+ * relation is a partitioned table, it's not counted as a child table.
*/
- if (nrels < 2)
+ if ((onerel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE && nrels < 2) ||
+ nrels < 1)
{
ereport(elevel,
(errmsg("skipping analyze of \"%s.%s\" inheritance tree --- this inheritance tree contains no analyzable child tables",
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 3cea220421..317012068b 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -1349,6 +1349,10 @@ ExecuteTruncate(TruncateStmt *stmt)
{
Relation rel = (Relation) lfirst(cell);
+ /* Skip partitioned tables as there is nothing to do */
+ if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ continue;
+
/*
* Normally, we need a transaction-safe truncation here. However, if
* the table was either created in the current (sub)transaction or has
@@ -1459,7 +1463,11 @@ truncate_check_rel(Relation rel)
{
AclResult aclresult;
- /* Only allow truncate on regular tables */
+ /*
+ * Only allow truncate on regular tables and partitioned tables (although,
+ * the latter are only being included here for the following checks; no
+ * physical truncation will occur in their case.)
+ */
if (rel->rd_rel->relkind != RELKIND_RELATION &&
rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
ereport(ERROR,
@@ -4006,8 +4014,9 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode)
{
AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
- /* Foreign tables have no storage. */
- if (tab->relkind == RELKIND_FOREIGN_TABLE)
+ /* Foreign tables have no storage, nor do partitioned tables. */
+ if (tab->relkind == RELKIND_FOREIGN_TABLE ||
+ tab->relkind == RELKIND_PARTITIONED_TABLE)
continue;
/*
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 812fb4a48f..856673fb58 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -32,6 +32,7 @@
#include "access/xact.h"
#include "catalog/namespace.h"
#include "catalog/pg_database.h"
+#include "catalog/pg_inherits_fn.h"
#include "catalog/pg_namespace.h"
#include "commands/cluster.h"
#include "commands/vacuum.h"
@@ -66,7 +67,7 @@ static BufferAccessStrategy vac_strategy;
/* non-export function prototypes */
-static List *get_rel_oids(Oid relid, const RangeVar *vacrel);
+static List *get_rel_oids(Oid relid, const RangeVar *vacrel, bool is_vacuum);
static void vac_truncate_clog(TransactionId frozenXID,
MultiXactId minMulti,
TransactionId lastSaneFrozenXid,
@@ -226,9 +227,12 @@ vacuum(int options, RangeVar *relation, Oid relid, VacuumParams *params,
/*
* Build list of relations to process, unless caller gave us one. (If we
- * build one, we put it in vac_context for safekeeping.)
+ * build one, we put it in vac_context for safekeeping.) Also pass
+ * whether we are going to be doing VACUUM, in which case we must include
+ * partitions in the list (considered only in the case of a database-wide
+ * invocation).
*/
- relations = get_rel_oids(relid, relation);
+ relations = get_rel_oids(relid, relation, options & VACOPT_VACUUM);
/*
* Decide whether we need to start/commit our own transactions.
@@ -378,7 +382,7 @@ vacuum(int options, RangeVar *relation, Oid relid, VacuumParams *params,
* per-relation transactions.
*/
static List *
-get_rel_oids(Oid relid, const RangeVar *vacrel)
+get_rel_oids(Oid relid, const RangeVar *vacrel, bool is_vacuum)
{
List *oid_list = NIL;
MemoryContext oldcontext;
@@ -394,6 +398,9 @@ get_rel_oids(Oid relid, const RangeVar *vacrel)
{
/* Process a specific relation */
Oid relid;
+ HeapTuple tuple;
+ Form_pg_class classForm;
+ bool include_parts;
/*
* Since we don't take a lock here, the relation might be gone, or the
@@ -406,9 +413,29 @@ get_rel_oids(Oid relid, const RangeVar *vacrel)
*/
relid = RangeVarGetRelid(vacrel, NoLock, false);
- /* Make a relation list entry for this guy */
+ /*
+ * To check whether the relation is a partitioned table, fetch its
+ * syscache entry.
+ */
+ tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for relation %u", relid);
+ classForm = (Form_pg_class) GETSTRUCT(tuple);
+ include_parts = (classForm->relkind == RELKIND_PARTITIONED_TABLE);
+ ReleaseSysCache(tuple);
+
+ /*
+ * Make relation list entries for this guy and its partitions, if any.
+ * Note that the list returned by find_all_inheritors() include the
+ * passed-in OID at its head. Also note that we did not request a
+ * lock to be taken to match what would be done otherwise.
+ */
oldcontext = MemoryContextSwitchTo(vac_context);
- oid_list = lappend_oid(oid_list, relid);
+ if (include_parts)
+ oid_list = list_concat(oid_list,
+ find_all_inheritors(relid, NoLock, NULL));
+ else
+ oid_list = lappend_oid(oid_list, relid);
MemoryContextSwitchTo(oldcontext);
}
else
@@ -429,8 +456,23 @@ get_rel_oids(Oid relid, const RangeVar *vacrel)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
+ /*
+ * We include partitioned tables here; depending on which
+ * operation is to be performed, caller will decide whether to
+ * process or ignore them.
+ */
if (classForm->relkind != RELKIND_RELATION &&
- classForm->relkind != RELKIND_MATVIEW)
+ classForm->relkind != RELKIND_MATVIEW &&
+ classForm->relkind != RELKIND_PARTITIONED_TABLE)
+ continue;
+
+ /*
+ * If only ANALYZE is to be performed, there is no need to include
+ * partitions in the list. In a database-wide ANALYZE, we only
+ * update the inheritance statistics of partitioned tables, not
+ * the statistics of individual partitions.
+ */
+ if (!is_vacuum && classForm->relispartition)
continue;
/* Make a relation list entry for this guy */
@@ -1350,6 +1392,21 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params)
}
/*
+ * Ignore partitioned tables as there is no work to be done. Since we
+ * release the lock here, it's possible that any partitions added from
+ * this point on will not get processed, but that seems harmless.
+ */
+ if (onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ relation_close(onerel, lmode);
+ PopActiveSnapshot();
+ CommitTransactionCommand();
+
+ /* It's OK for other commands to look at this table */
+ return true;
+ }
+
+ /*
* Get a session-level lock too. This will protect our access to the
* relation across multiple transactions, so that we can vacuum the
* relation's TOAST table (if any) secure in the knowledge that no one is
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 0c5ffa086c..d7d1f5ea6f 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -1986,11 +1986,11 @@ do_autovacuum(void)
* Scan pg_class to determine which tables to vacuum.
*
* We do this in two passes: on the first one we collect the list of plain
- * relations and materialized views, and on the second one we collect
- * TOAST tables. The reason for doing the second pass is that during it we
- * want to use the main relation's pg_class.reloptions entry if the TOAST
- * table does not have any, and we cannot obtain it unless we know
- * beforehand what's the main table OID.
+ * relations, partitioned tables, and materialized views, and on the
+ * second one we collect TOAST tables. The reason for doing the second
+ * pass is that during it we want to use the main relation's
+ * pg_class.reloptions entry if the TOAST table does not have any, and we
+ * cannot obtain it unless we know beforehand what's the main table OID.
*
* We need to check TOAST tables separately because in cases with short,
* wide tables there might be proportionally much more activity in the
@@ -2013,7 +2013,8 @@ do_autovacuum(void)
bool wraparound;
if (classForm->relkind != RELKIND_RELATION &&
- classForm->relkind != RELKIND_MATVIEW)
+ classForm->relkind != RELKIND_MATVIEW &&
+ classForm->relkind != RELKIND_PARTITIONED_TABLE)
continue;
relid = HeapTupleGetOid(tuple);
@@ -2195,7 +2196,8 @@ do_autovacuum(void)
* completely unrelated to the one we saw before.
*/
if (!((classForm->relkind == RELKIND_RELATION ||
- classForm->relkind == RELKIND_MATVIEW) &&
+ classForm->relkind == RELKIND_MATVIEW ||
+ classForm->relkind == RELKIND_PARTITIONED_TABLE) &&
classForm->relpersistence == RELPERSISTENCE_TEMP))
{
UnlockRelationOid(relid, AccessExclusiveLock);
@@ -2614,6 +2616,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
if (classForm->relkind == RELKIND_TOASTVALUE)
doanalyze = false;
+ /* ignore VACUUM for partitioned tables */
+ if (classForm->relkind == RELKIND_PARTITIONED_TABLE)
+ dovacuum = false;
+
/* OK, it needs something done */
if (doanalyze || dovacuum)
{
--
2.11.0
[text/x-diff] 0002-Do-not-allocate-storage-for-partitioned-tables.patch (3.1K, ../../a3aef18d-ce05-2163-30e3-d1f9154cc076@lab.ntt.co.jp/3-0002-Do-not-allocate-storage-for-partitioned-tables.patch)
download | inline diff:
From 0ee8319aa374879bc8ad3ea5a5ef8887ad926e80 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Tue, 24 Jan 2017 14:22:34 +0900
Subject: [PATCH 2/3] Do not allocate storage for partitioned tables.
Currently, it is not possible to insert any data into a partitioned
table. So, they're empty at all times, which means it is wasteful to
allocate relfilenode and related storage objects.
---
src/backend/access/common/reloptions.c | 3 +--
src/backend/catalog/heap.c | 17 ++++++++++-------
2 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 816483ef8b..ec90d2b625 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -930,7 +930,6 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
case RELKIND_RELATION:
case RELKIND_TOASTVALUE:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
options = heap_reloptions(classForm->relkind, datum, false);
break;
case RELKIND_VIEW:
@@ -940,6 +939,7 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
options = index_reloptions(amoptions, datum, false);
break;
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
options = NULL;
break;
default:
@@ -1382,7 +1382,6 @@ heap_reloptions(char relkind, Datum reloptions, bool validate)
return (bytea *) rdopts;
case RELKIND_RELATION:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
default:
/* other relkinds are not supported */
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 41c0056556..2f5090b183 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -291,6 +291,7 @@ heap_create(const char *relname,
case RELKIND_VIEW:
case RELKIND_COMPOSITE_TYPE:
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
create_storage = false;
/*
@@ -1345,14 +1346,13 @@ heap_create_with_catalog(const char *relname,
if (oncommit != ONCOMMIT_NOOP)
register_on_commit_action(relid, oncommit);
- if (relpersistence == RELPERSISTENCE_UNLOGGED)
- {
- Assert(relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW ||
- relkind == RELKIND_TOASTVALUE ||
- relkind == RELKIND_PARTITIONED_TABLE);
-
+ /*
+ * We do not want to create any storage objects for a partitioned
+ * table, including the init fork.
+ */
+ if (relpersistence == RELPERSISTENCE_UNLOGGED &&
+ relkind != RELKIND_PARTITIONED_TABLE)
heap_create_init_fork(new_rel_desc);
- }
/*
* ok, the relation has been cataloged, so close our relations and return
@@ -1376,6 +1376,9 @@ heap_create_with_catalog(const char *relname,
void
heap_create_init_fork(Relation rel)
{
+ Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
+ rel->rd_rel->relkind == RELKIND_MATVIEW ||
+ rel->rd_rel->relkind == RELKIND_TOASTVALUE);
RelationOpenSmgr(rel);
smgrcreate(rel->rd_smgr, INIT_FORKNUM, false);
log_smgrcreate(&rel->rd_smgr->smgr_rnode.node, INIT_FORKNUM);
--
2.11.0
[text/x-diff] 0003-Always-plan-partitioned-tables-as-inheritance-sets.patch (14.6K, ../../a3aef18d-ce05-2163-30e3-d1f9154cc076@lab.ntt.co.jp/4-0003-Always-plan-partitioned-tables-as-inheritance-sets.patch)
download | inline diff:
From 965a6eb7e1f260a83dc713b2d23f4e6c6701d178 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Mon, 6 Feb 2017 17:26:48 +0900
Subject: [PATCH 3/3] Always plan partitioned tables as inheritance sets
...even if empty. Currently, we create scan plans for inheritance
parents in their role as an inheritance set member. Partitioned tables
do not contain any data, so it's not right to create scan plans for them.
So we need not create AppendRelInfo's for them in the planner prep phase.
That means the Append set for a partitioned table may contain zero members
if it does not have leaf partitions Currently, such a case is treated by
the current code as a non-inheritance situation and a scan plan is created
for just the parent. It is done by turning off the inh flag of the parent
RTE so that later planner phases create a simple scan plan for it. Since
we cannot create scan plans for partitioned tables, don't turn off its inh
flag even if we found that there are no Append members. Let this empty
Append member list cause later code create a constant-false Result plan.
Also, inheritance_planner() must not always assume that the 1st child
member of an inheritance set is the nominal relation. For partitioned
tables, we use the original parent RTE as the nominal relation in that
case, because we no longer create the duplicate RTE representing a
partitioned table as a child member of the inheritance set.
---
src/backend/optimizer/plan/planner.c | 15 +++++
src/backend/optimizer/prep/prepunion.c | 36 +++++++++--
src/test/regress/expected/inherit.out | 108 +++++++--------------------------
3 files changed, 68 insertions(+), 91 deletions(-)
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 3d33d46971..c18c92d0a8 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -996,10 +996,20 @@ inheritance_planner(PlannerInfo *root)
RelOptInfo *final_rel;
ListCell *lc;
Index rti;
+ RangeTblEntry *parent_rte;
Assert(parse->commandType != CMD_INSERT);
/*
+ * If the parent RTE is a partitioned table, we should use that as the
+ * nominal relation, because we do not have the duplicate parent RTE,
+ * unlike in the case of a non-partitioned inheritance parent.
+ */
+ parent_rte = rt_fetch(parentRTindex, root->parse->rtable);
+ if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
+ nominalRelation = parentRTindex;
+
+ /*
* We generate a modified instance of the original Query for each target
* relation, plan that, and put all the plans into a list that will be
* controlled by a single ModifyTable node. All the instances share the
@@ -1214,6 +1224,11 @@ inheritance_planner(PlannerInfo *root)
* will not be otherwise referenced in the plan, doing so would give
* rise to confusing use of multiple aliases in EXPLAIN output for
* what the user will think is the "same" table.)
+ *
+ * If the parent is a partitioned table, we do not have a separate RTE
+ * representing it as a member of the inheritance set, because we do
+ * not create a scan plan for it. As mentioned at the top of this
+ * function, we make the parent RTE itself the nominal relation.
*/
if (nominalRelation < 0)
nominalRelation = appinfo->child_relid;
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 06e843dff0..10f7494215 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -1374,9 +1374,17 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
Assert(rte->rtekind == RTE_SUBQUERY);
return;
}
- /* Fast path for common case of childless table */
+ /*
+ * Fast path for common case of childless table. However, a partitioned
+ * table RTE should *always* be processed by the later code as an
+ * inheritance set, possibly an empty one in the absence of any leaf
+ * partitions. It is wrong for the later phases to try to create a scan
+ * plan for a partitioned table, which would be the case if we turn off
+ * the inh flag here.
+ */
parentOID = rte->relid;
- if (!has_subclass(parentOID))
+ if (rte->relkind != RELKIND_PARTITIONED_TABLE &&
+ !has_subclass(parentOID))
{
/* Clear flag before returning */
rte->inh = false;
@@ -1410,9 +1418,11 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
/*
* Check that there's at least one descendant, else treat as no-child
* case. This could happen despite above has_subclass() check, if table
- * once had a child but no longer does.
+ * once had a child but no longer does. Again, do not disable inheritance
+ * for a partitioned table as described above.
*/
- if (list_length(inhOIDs) < 2)
+ if (rte->relkind != RELKIND_PARTITIONED_TABLE &&
+ list_length(inhOIDs) < 2)
{
/* Clear flag before returning */
rte->inh = false;
@@ -1450,6 +1460,18 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
newrelation = oldrelation;
/*
+ * Ignore partitioned tables here, because we do not want them to
+ * be considered as child tables in the inheritance set. No scan
+ * plans will be created for them.
+ */
+ if (newrelation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ if (newrelation != oldrelation)
+ heap_close(newrelation, lockmode);
+ continue;
+ }
+
+ /*
* It is possible that the parent table has children that are temp
* tables of other backends. We cannot safely access such tables
* (because of buffering issues), and the best thing to do seems to be
@@ -1548,9 +1570,11 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
* If all the children were temp tables, pretend it's a non-inheritance
* situation. The duplicate RTE we added for the parent table is
* harmless, so we don't bother to get rid of it; ditto for the useless
- * PlanRowMark node.
+ * PlanRowMark node. Do not disable inheritance for partitioned tables
+ * as described above.
*/
- if (list_length(appinfos) < 2)
+ if (rte->relkind != RELKIND_PARTITIONED_TABLE &&
+ list_length(appinfos) < 2)
{
/* Clear flag before returning */
rte->inh = false;
diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out
index a8c8b28a75..ef4e049047 100644
--- a/src/test/regress/expected/inherit.out
+++ b/src/test/regress/expected/inherit.out
@@ -1605,71 +1605,60 @@ explain (costs off) select * from list_parted;
QUERY PLAN
--------------------------------
Append
- -> Seq Scan on list_parted
-> Seq Scan on part_ab_cd
-> Seq Scan on part_ef_gh
-> Seq Scan on part_null_xy
-(5 rows)
+(4 rows)
explain (costs off) select * from list_parted where a is null;
QUERY PLAN
--------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (a IS NULL)
-> Seq Scan on part_null_xy
Filter: (a IS NULL)
-(5 rows)
+(3 rows)
explain (costs off) select * from list_parted where a is not null;
QUERY PLAN
---------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (a IS NOT NULL)
-> Seq Scan on part_ab_cd
Filter: (a IS NOT NULL)
-> Seq Scan on part_ef_gh
Filter: (a IS NOT NULL)
-> Seq Scan on part_null_xy
Filter: (a IS NOT NULL)
-(9 rows)
+(7 rows)
explain (costs off) select * from list_parted where a in ('ab', 'cd', 'ef');
QUERY PLAN
----------------------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-> Seq Scan on part_ab_cd
Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-> Seq Scan on part_ef_gh
Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-(7 rows)
+(5 rows)
explain (costs off) select * from list_parted where a = 'ab' or a in (null, 'cd');
QUERY PLAN
---------------------------------------------------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_ab_cd
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_ef_gh
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_null_xy
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-(9 rows)
+(7 rows)
explain (costs off) select * from list_parted where a = 'ab';
QUERY PLAN
------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: ((a)::text = 'ab'::text)
-> Seq Scan on part_ab_cd
Filter: ((a)::text = 'ab'::text)
-(5 rows)
+(3 rows)
create table range_list_parted (
a int,
@@ -1689,14 +1678,9 @@ create table part_40_inf_ab partition of part_40_inf for values in ('ab');
create table part_40_inf_cd partition of part_40_inf for values in ('cd');
create table part_40_inf_null partition of part_40_inf for values in (null);
explain (costs off) select * from range_list_parted;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- -> Seq Scan on part_1_10
- -> Seq Scan on part_10_20
- -> Seq Scan on part_21_30
- -> Seq Scan on part_40_inf
-> Seq Scan on part_1_10_ab
-> Seq Scan on part_1_10_cd
-> Seq Scan on part_10_20_ab
@@ -1706,36 +1690,22 @@ explain (costs off) select * from range_list_parted;
-> Seq Scan on part_40_inf_ab
-> Seq Scan on part_40_inf_cd
-> Seq Scan on part_40_inf_null
-(15 rows)
+(10 rows)
explain (costs off) select * from range_list_parted where a = 5;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+--------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (a = 5)
- -> Seq Scan on part_1_10
- Filter: (a = 5)
-> Seq Scan on part_1_10_ab
Filter: (a = 5)
-> Seq Scan on part_1_10_cd
Filter: (a = 5)
-(9 rows)
+(5 rows)
explain (costs off) select * from range_list_parted where b = 'ab';
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_1_10
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_10_20
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_21_30
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_40_inf
- Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_1_10_ab
Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_10_20_ab
@@ -1744,27 +1714,19 @@ explain (costs off) select * from range_list_parted where b = 'ab';
Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_40_inf_ab
Filter: (b = 'ab'::bpchar)
-(19 rows)
+(9 rows)
explain (costs off) select * from range_list_parted where a between 3 and 23 and b in ('ab');
QUERY PLAN
-----------------------------------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_1_10
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_10_20
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_21_30
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_1_10_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_10_20_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_21_30_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-(15 rows)
+(7 rows)
/* Should select no rows because range partition key cannot be null */
explain (costs off) select * from range_list_parted where a is null;
@@ -1776,37 +1738,17 @@ explain (costs off) select * from range_list_parted where a is null;
/* Should only select rows from the null-accepting partition */
explain (costs off) select * from range_list_parted where b is null;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (b IS NULL)
- -> Seq Scan on part_1_10
- Filter: (b IS NULL)
- -> Seq Scan on part_10_20
- Filter: (b IS NULL)
- -> Seq Scan on part_21_30
- Filter: (b IS NULL)
- -> Seq Scan on part_40_inf
- Filter: (b IS NULL)
-> Seq Scan on part_40_inf_null
Filter: (b IS NULL)
-(13 rows)
+(3 rows)
explain (costs off) select * from range_list_parted where a is not null and a < 67;
QUERY PLAN
------------------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_1_10
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_10_20
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_21_30
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_40_inf
- Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_1_10_ab
Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_1_10_cd
@@ -1825,23 +1767,19 @@ explain (costs off) select * from range_list_parted where a is not null and a <
Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_40_inf_null
Filter: ((a IS NOT NULL) AND (a < 67))
-(29 rows)
+(19 rows)
explain (costs off) select * from range_list_parted where a >= 30;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (a >= 30)
- -> Seq Scan on part_40_inf
- Filter: (a >= 30)
-> Seq Scan on part_40_inf_ab
Filter: (a >= 30)
-> Seq Scan on part_40_inf_cd
Filter: (a >= 30)
-> Seq Scan on part_40_inf_null
Filter: (a >= 30)
-(11 rows)
+(7 rows)
drop table list_parted cascade;
NOTICE: drop cascades to 3 other objects
--
2.11.0
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-02-21 13:21 ` Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
0 siblings, 1 reply; 96+ messages in thread
From: Ashutosh Bapat @ 2017-02-21 13:21 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: Robert Haas <robertmhaas@gmail.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
Some comments about 0003 patch.
@@ -996,10 +996,20 @@ inheritance_planner(PlannerInfo *root)
Index rti;
+ RangeTblEntry *parent_rte;
There's already another variable declared in that function within a loop
foreach(lc, root->append_rel_list)
{
...
RangeTblEntry *parent_rte;
RangeTblEntry *child_rte;
You might want to choose a different name or delete the one within the loop.
I am wondering whether we should deal with inh flat reset in a
slightly different way. Let expand_inherited_rtentry() mark inh =
false for the partitioned tables without any partitions and deal with
those at the time of estimating size by marking those as dummy. That
might be better than multiple changes here. I will try to cook up a
patch soon for that.
Also we should add tests to make sure the scans on partitioned tables
without any partitions do not get into problems. PFA patch which adds
those tests.
--
Best Wishes,
Ashutosh Bapat
EnterpriseDB Corporation
The Postgres Database Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Attachments:
[application/octet-stream] 0003-Always-plan-partitioned-tables-as-inheritance-sets_v2.patch (15.3K, ../../CAFjFpRdMvMD3hMYw67pC23_ncD=ONLX1LRi8MEdvsco+=09-3A@mail.gmail.com/2-0003-Always-plan-partitioned-tables-as-inheritance-sets_v2.patch)
download | inline diff:
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 3d33d46..c18c92d 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -996,10 +996,20 @@ inheritance_planner(PlannerInfo *root)
RelOptInfo *final_rel;
ListCell *lc;
Index rti;
+ RangeTblEntry *parent_rte;
Assert(parse->commandType != CMD_INSERT);
/*
+ * If the parent RTE is a partitioned table, we should use that as the
+ * nominal relation, because we do not have the duplicate parent RTE,
+ * unlike in the case of a non-partitioned inheritance parent.
+ */
+ parent_rte = rt_fetch(parentRTindex, root->parse->rtable);
+ if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
+ nominalRelation = parentRTindex;
+
+ /*
* We generate a modified instance of the original Query for each target
* relation, plan that, and put all the plans into a list that will be
* controlled by a single ModifyTable node. All the instances share the
@@ -1214,6 +1224,11 @@ inheritance_planner(PlannerInfo *root)
* will not be otherwise referenced in the plan, doing so would give
* rise to confusing use of multiple aliases in EXPLAIN output for
* what the user will think is the "same" table.)
+ *
+ * If the parent is a partitioned table, we do not have a separate RTE
+ * representing it as a member of the inheritance set, because we do
+ * not create a scan plan for it. As mentioned at the top of this
+ * function, we make the parent RTE itself the nominal relation.
*/
if (nominalRelation < 0)
nominalRelation = appinfo->child_relid;
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 06e843d..10f7494 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -1374,9 +1374,17 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
Assert(rte->rtekind == RTE_SUBQUERY);
return;
}
- /* Fast path for common case of childless table */
+ /*
+ * Fast path for common case of childless table. However, a partitioned
+ * table RTE should *always* be processed by the later code as an
+ * inheritance set, possibly an empty one in the absence of any leaf
+ * partitions. It is wrong for the later phases to try to create a scan
+ * plan for a partitioned table, which would be the case if we turn off
+ * the inh flag here.
+ */
parentOID = rte->relid;
- if (!has_subclass(parentOID))
+ if (rte->relkind != RELKIND_PARTITIONED_TABLE &&
+ !has_subclass(parentOID))
{
/* Clear flag before returning */
rte->inh = false;
@@ -1410,9 +1418,11 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
/*
* Check that there's at least one descendant, else treat as no-child
* case. This could happen despite above has_subclass() check, if table
- * once had a child but no longer does.
+ * once had a child but no longer does. Again, do not disable inheritance
+ * for a partitioned table as described above.
*/
- if (list_length(inhOIDs) < 2)
+ if (rte->relkind != RELKIND_PARTITIONED_TABLE &&
+ list_length(inhOIDs) < 2)
{
/* Clear flag before returning */
rte->inh = false;
@@ -1450,6 +1460,18 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
newrelation = oldrelation;
/*
+ * Ignore partitioned tables here, because we do not want them to
+ * be considered as child tables in the inheritance set. No scan
+ * plans will be created for them.
+ */
+ if (newrelation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ if (newrelation != oldrelation)
+ heap_close(newrelation, lockmode);
+ continue;
+ }
+
+ /*
* It is possible that the parent table has children that are temp
* tables of other backends. We cannot safely access such tables
* (because of buffering issues), and the best thing to do seems to be
@@ -1548,9 +1570,11 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
* If all the children were temp tables, pretend it's a non-inheritance
* situation. The duplicate RTE we added for the parent table is
* harmless, so we don't bother to get rid of it; ditto for the useless
- * PlanRowMark node.
+ * PlanRowMark node. Do not disable inheritance for partitioned tables
+ * as described above.
*/
- if (list_length(appinfos) < 2)
+ if (rte->relkind != RELKIND_PARTITIONED_TABLE &&
+ list_length(appinfos) < 2)
{
/* Clear flag before returning */
rte->inh = false;
diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out
index a8c8b28..7215f03 100644
--- a/src/test/regress/expected/inherit.out
+++ b/src/test/regress/expected/inherit.out
@@ -1598,6 +1598,14 @@ reset enable_bitmapscan;
create table list_parted (
a varchar
) partition by list (a);
+-- test scanning partitioned table without any partitions
+explain (costs off) select * from list_parted;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
create table part_ab_cd partition of list_parted for values in ('ab', 'cd');
create table part_ef_gh partition of list_parted for values in ('ef', 'gh');
create table part_null_xy partition of list_parted for values in (null, 'xy');
@@ -1605,77 +1613,74 @@ explain (costs off) select * from list_parted;
QUERY PLAN
--------------------------------
Append
- -> Seq Scan on list_parted
-> Seq Scan on part_ab_cd
-> Seq Scan on part_ef_gh
-> Seq Scan on part_null_xy
-(5 rows)
+(4 rows)
explain (costs off) select * from list_parted where a is null;
QUERY PLAN
--------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (a IS NULL)
-> Seq Scan on part_null_xy
Filter: (a IS NULL)
-(5 rows)
+(3 rows)
explain (costs off) select * from list_parted where a is not null;
QUERY PLAN
---------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (a IS NOT NULL)
-> Seq Scan on part_ab_cd
Filter: (a IS NOT NULL)
-> Seq Scan on part_ef_gh
Filter: (a IS NOT NULL)
-> Seq Scan on part_null_xy
Filter: (a IS NOT NULL)
-(9 rows)
+(7 rows)
explain (costs off) select * from list_parted where a in ('ab', 'cd', 'ef');
QUERY PLAN
----------------------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-> Seq Scan on part_ab_cd
Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-> Seq Scan on part_ef_gh
Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-(7 rows)
+(5 rows)
explain (costs off) select * from list_parted where a = 'ab' or a in (null, 'cd');
QUERY PLAN
---------------------------------------------------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_ab_cd
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_ef_gh
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_null_xy
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-(9 rows)
+(7 rows)
explain (costs off) select * from list_parted where a = 'ab';
QUERY PLAN
------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: ((a)::text = 'ab'::text)
-> Seq Scan on part_ab_cd
Filter: ((a)::text = 'ab'::text)
-(5 rows)
+(3 rows)
create table range_list_parted (
a int,
b char(2)
) partition by range (a);
create table part_1_10 partition of range_list_parted for values from (1) to (10) partition by list (b);
+-- test scanning partitioned table without any partitions
+explain (costs off) select * from range_list_parted;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
create table part_1_10_ab partition of part_1_10 for values in ('ab');
create table part_1_10_cd partition of part_1_10 for values in ('cd');
create table part_10_20 partition of range_list_parted for values from (10) to (20) partition by list (b);
@@ -1689,14 +1694,9 @@ create table part_40_inf_ab partition of part_40_inf for values in ('ab');
create table part_40_inf_cd partition of part_40_inf for values in ('cd');
create table part_40_inf_null partition of part_40_inf for values in (null);
explain (costs off) select * from range_list_parted;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- -> Seq Scan on part_1_10
- -> Seq Scan on part_10_20
- -> Seq Scan on part_21_30
- -> Seq Scan on part_40_inf
-> Seq Scan on part_1_10_ab
-> Seq Scan on part_1_10_cd
-> Seq Scan on part_10_20_ab
@@ -1706,36 +1706,22 @@ explain (costs off) select * from range_list_parted;
-> Seq Scan on part_40_inf_ab
-> Seq Scan on part_40_inf_cd
-> Seq Scan on part_40_inf_null
-(15 rows)
+(10 rows)
explain (costs off) select * from range_list_parted where a = 5;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+--------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (a = 5)
- -> Seq Scan on part_1_10
- Filter: (a = 5)
-> Seq Scan on part_1_10_ab
Filter: (a = 5)
-> Seq Scan on part_1_10_cd
Filter: (a = 5)
-(9 rows)
+(5 rows)
explain (costs off) select * from range_list_parted where b = 'ab';
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_1_10
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_10_20
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_21_30
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_40_inf
- Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_1_10_ab
Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_10_20_ab
@@ -1744,27 +1730,19 @@ explain (costs off) select * from range_list_parted where b = 'ab';
Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_40_inf_ab
Filter: (b = 'ab'::bpchar)
-(19 rows)
+(9 rows)
explain (costs off) select * from range_list_parted where a between 3 and 23 and b in ('ab');
QUERY PLAN
-----------------------------------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_1_10
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_10_20
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_21_30
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_1_10_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_10_20_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_21_30_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-(15 rows)
+(7 rows)
/* Should select no rows because range partition key cannot be null */
explain (costs off) select * from range_list_parted where a is null;
@@ -1776,37 +1754,17 @@ explain (costs off) select * from range_list_parted where a is null;
/* Should only select rows from the null-accepting partition */
explain (costs off) select * from range_list_parted where b is null;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (b IS NULL)
- -> Seq Scan on part_1_10
- Filter: (b IS NULL)
- -> Seq Scan on part_10_20
- Filter: (b IS NULL)
- -> Seq Scan on part_21_30
- Filter: (b IS NULL)
- -> Seq Scan on part_40_inf
- Filter: (b IS NULL)
-> Seq Scan on part_40_inf_null
Filter: (b IS NULL)
-(13 rows)
+(3 rows)
explain (costs off) select * from range_list_parted where a is not null and a < 67;
QUERY PLAN
------------------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_1_10
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_10_20
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_21_30
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_40_inf
- Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_1_10_ab
Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_1_10_cd
@@ -1825,23 +1783,19 @@ explain (costs off) select * from range_list_parted where a is not null and a <
Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_40_inf_null
Filter: ((a IS NOT NULL) AND (a < 67))
-(29 rows)
+(19 rows)
explain (costs off) select * from range_list_parted where a >= 30;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (a >= 30)
- -> Seq Scan on part_40_inf
- Filter: (a >= 30)
-> Seq Scan on part_40_inf_ab
Filter: (a >= 30)
-> Seq Scan on part_40_inf_cd
Filter: (a >= 30)
-> Seq Scan on part_40_inf_null
Filter: (a >= 30)
-(11 rows)
+(7 rows)
drop table list_parted cascade;
NOTICE: drop cascades to 3 other objects
diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql
index a8b7eb1..fa0bb47 100644
--- a/src/test/regress/sql/inherit.sql
+++ b/src/test/regress/sql/inherit.sql
@@ -570,6 +570,10 @@ reset enable_bitmapscan;
create table list_parted (
a varchar
) partition by list (a);
+
+-- test scanning partitioned table without any partitions
+explain (costs off) select * from list_parted;
+
create table part_ab_cd partition of list_parted for values in ('ab', 'cd');
create table part_ef_gh partition of list_parted for values in ('ef', 'gh');
create table part_null_xy partition of list_parted for values in (null, 'xy');
@@ -586,6 +590,10 @@ create table range_list_parted (
b char(2)
) partition by range (a);
create table part_1_10 partition of range_list_parted for values from (1) to (10) partition by list (b);
+
+-- test scanning partitioned table without any partitions
+explain (costs off) select * from range_list_parted;
+
create table part_1_10_ab partition of part_1_10 for values in ('ab');
create table part_1_10_cd partition of part_1_10 for values in ('cd');
create table part_10_20 partition of range_list_parted for values from (10) to (20) partition by list (b);
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
@ 2017-02-22 08:20 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
0 siblings, 1 reply; 96+ messages in thread
From: Amit Langote @ 2017-02-22 08:20 UTC (permalink / raw)
To: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; +Cc: Robert Haas <robertmhaas@gmail.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On 2017/02/21 22:21, Ashutosh Bapat wrote:
> Some comments about 0003 patch.
>
> @@ -996,10 +996,20 @@ inheritance_planner(PlannerInfo *root)
> Index rti;
> + RangeTblEntry *parent_rte;
> There's already another variable declared in that function within a loop
> foreach(lc, root->append_rel_list)
> {
> ...
> RangeTblEntry *parent_rte;
> RangeTblEntry *child_rte;
>
> You might want to choose a different name or delete the one within the loop.
Deleted the one within the loop.
> I am wondering whether we should deal with inh flat reset in a
> slightly different way. Let expand_inherited_rtentry() mark inh =
> false for the partitioned tables without any partitions and deal with
> those at the time of estimating size by marking those as dummy. That
> might be better than multiple changes here. I will try to cook up a
> patch soon for that.
Are thinking something along the lines of the attached rewritten patch
0003? I also tend to think that's probably a cleaner patch. Thanks for
the idea.
> Also we should add tests to make sure the scans on partitioned tables
> without any partitions do not get into problems. PFA patch which adds
> those tests.
I added the test case you suggest, but kept just the first one.
I am including the patches 0001 and 0002 to keep all patches being
discussed on this thread together.
Thanks,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Attachments:
[text/x-diff] 0001-Partitioned-tables-are-empty-themselves.patch (12.9K, ../../9be09bd2-6cda-f68a-5992-8e8e53a56f51@lab.ntt.co.jp/2-0001-Partitioned-tables-are-empty-themselves.patch)
download | inline diff:
From 79d7234743a5414f2b7f2df4ebdde472f2328209 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Mon, 6 Feb 2017 18:03:28 +0900
Subject: [PATCH 1/3] Partitioned tables are empty themselves
So, there is not much point in trying to do things to them that need
accessing files (a later commit will make it so that there is no file
at all to access.) Things that needed attention are: vacuum, analyze,
truncate, ATRewriteTables.
---
doc/src/sgml/ddl.sgml | 7 ++--
src/backend/commands/analyze.c | 39 ++++++++++++++------
src/backend/commands/tablecmds.c | 15 ++++++--
src/backend/commands/vacuum.c | 71 +++++++++++++++++++++++++++++++++----
src/backend/postmaster/autovacuum.c | 20 +++++++----
5 files changed, 123 insertions(+), 29 deletions(-)
diff --git a/doc/src/sgml/ddl.sgml b/doc/src/sgml/ddl.sgml
index 5779eac43d..358bf956d0 100644
--- a/doc/src/sgml/ddl.sgml
+++ b/doc/src/sgml/ddl.sgml
@@ -3840,8 +3840,11 @@ UNION ALL SELECT * FROM measurement_y2008m01;
<programlisting>
ANALYZE measurement;
</programlisting>
- will only process the master table. This is true even for partitioned
- tables.
+ will only process the master table.
+ </para>
+
+ <para>
+ This does not apply to partitioned tables though.
</para>
</listitem>
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index ed3acb1673..12cd0110b0 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -201,8 +201,7 @@ analyze_rel(Oid relid, RangeVar *relation, int options,
* locked the relation.
*/
if (onerel->rd_rel->relkind == RELKIND_RELATION ||
- onerel->rd_rel->relkind == RELKIND_MATVIEW ||
- onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ onerel->rd_rel->relkind == RELKIND_MATVIEW)
{
/* Regular table, so we'll use the regular row acquisition function */
acquirefunc = acquire_sample_rows;
@@ -234,6 +233,12 @@ analyze_rel(Oid relid, RangeVar *relation, int options,
return;
}
}
+ else if (onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ /*
+ * For partitioned tables, we want to do the recursive ANALYZE below.
+ */
+ }
else
{
/* No need for a WARNING if we already complained during VACUUM */
@@ -253,13 +258,15 @@ analyze_rel(Oid relid, RangeVar *relation, int options,
LWLockRelease(ProcArrayLock);
/*
- * Do the normal non-recursive ANALYZE.
+ * Do the normal non-recursive ANALYZE, non-partitioned relations.
*/
- do_analyze_rel(onerel, options, params, va_cols, acquirefunc, relpages,
- false, in_outer_xact, elevel);
+ if (onerel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
+ do_analyze_rel(onerel, options, params, va_cols, acquirefunc,
+ relpages, false, in_outer_xact, elevel);
/*
- * If there are child tables, do recursive ANALYZE.
+ * If there are child tables, do recursive ANALYZE. This includes
+ * partitioned tables.
*/
if (onerel->rd_rel->relhassubclass)
do_analyze_rel(onerel, options, params, va_cols, acquirefunc, relpages,
@@ -1316,10 +1323,20 @@ acquire_inherited_sample_rows(Relation onerel, int elevel,
continue;
}
+ /* Ignore partitioned tables as there are no tuples to collect */
+ if (childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ /* Don't try to unlock the passed-in root table. */
+ if (childrel == onerel)
+ heap_close(childrel, NoLock);
+ else
+ heap_close(childrel, AccessShareLock);
+ continue;
+ }
+
/* Check table type (MATVIEW can't happen, but might as well allow) */
if (childrel->rd_rel->relkind == RELKIND_RELATION ||
- childrel->rd_rel->relkind == RELKIND_MATVIEW ||
- childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ childrel->rd_rel->relkind == RELKIND_MATVIEW)
{
/* Regular table, so use the regular row acquisition function */
acquirefunc = acquire_sample_rows;
@@ -1366,9 +1383,11 @@ acquire_inherited_sample_rows(Relation onerel, int elevel,
}
/*
- * If we don't have at least two tables to consider, fail.
+ * If we don't have at least one child table to consider, fail. If the
+ * relation is a partitioned table, it's not counted as a child table.
*/
- if (nrels < 2)
+ if ((onerel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE && nrels < 2) ||
+ nrels < 1)
{
ereport(elevel,
(errmsg("skipping analyze of \"%s.%s\" inheritance tree --- this inheritance tree contains no analyzable child tables",
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 3cea220421..317012068b 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -1349,6 +1349,10 @@ ExecuteTruncate(TruncateStmt *stmt)
{
Relation rel = (Relation) lfirst(cell);
+ /* Skip partitioned tables as there is nothing to do */
+ if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ continue;
+
/*
* Normally, we need a transaction-safe truncation here. However, if
* the table was either created in the current (sub)transaction or has
@@ -1459,7 +1463,11 @@ truncate_check_rel(Relation rel)
{
AclResult aclresult;
- /* Only allow truncate on regular tables */
+ /*
+ * Only allow truncate on regular tables and partitioned tables (although,
+ * the latter are only being included here for the following checks; no
+ * physical truncation will occur in their case.)
+ */
if (rel->rd_rel->relkind != RELKIND_RELATION &&
rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
ereport(ERROR,
@@ -4006,8 +4014,9 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode)
{
AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
- /* Foreign tables have no storage. */
- if (tab->relkind == RELKIND_FOREIGN_TABLE)
+ /* Foreign tables have no storage, nor do partitioned tables. */
+ if (tab->relkind == RELKIND_FOREIGN_TABLE ||
+ tab->relkind == RELKIND_PARTITIONED_TABLE)
continue;
/*
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 812fb4a48f..856673fb58 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -32,6 +32,7 @@
#include "access/xact.h"
#include "catalog/namespace.h"
#include "catalog/pg_database.h"
+#include "catalog/pg_inherits_fn.h"
#include "catalog/pg_namespace.h"
#include "commands/cluster.h"
#include "commands/vacuum.h"
@@ -66,7 +67,7 @@ static BufferAccessStrategy vac_strategy;
/* non-export function prototypes */
-static List *get_rel_oids(Oid relid, const RangeVar *vacrel);
+static List *get_rel_oids(Oid relid, const RangeVar *vacrel, bool is_vacuum);
static void vac_truncate_clog(TransactionId frozenXID,
MultiXactId minMulti,
TransactionId lastSaneFrozenXid,
@@ -226,9 +227,12 @@ vacuum(int options, RangeVar *relation, Oid relid, VacuumParams *params,
/*
* Build list of relations to process, unless caller gave us one. (If we
- * build one, we put it in vac_context for safekeeping.)
+ * build one, we put it in vac_context for safekeeping.) Also pass
+ * whether we are going to be doing VACUUM, in which case we must include
+ * partitions in the list (considered only in the case of a database-wide
+ * invocation).
*/
- relations = get_rel_oids(relid, relation);
+ relations = get_rel_oids(relid, relation, options & VACOPT_VACUUM);
/*
* Decide whether we need to start/commit our own transactions.
@@ -378,7 +382,7 @@ vacuum(int options, RangeVar *relation, Oid relid, VacuumParams *params,
* per-relation transactions.
*/
static List *
-get_rel_oids(Oid relid, const RangeVar *vacrel)
+get_rel_oids(Oid relid, const RangeVar *vacrel, bool is_vacuum)
{
List *oid_list = NIL;
MemoryContext oldcontext;
@@ -394,6 +398,9 @@ get_rel_oids(Oid relid, const RangeVar *vacrel)
{
/* Process a specific relation */
Oid relid;
+ HeapTuple tuple;
+ Form_pg_class classForm;
+ bool include_parts;
/*
* Since we don't take a lock here, the relation might be gone, or the
@@ -406,9 +413,29 @@ get_rel_oids(Oid relid, const RangeVar *vacrel)
*/
relid = RangeVarGetRelid(vacrel, NoLock, false);
- /* Make a relation list entry for this guy */
+ /*
+ * To check whether the relation is a partitioned table, fetch its
+ * syscache entry.
+ */
+ tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for relation %u", relid);
+ classForm = (Form_pg_class) GETSTRUCT(tuple);
+ include_parts = (classForm->relkind == RELKIND_PARTITIONED_TABLE);
+ ReleaseSysCache(tuple);
+
+ /*
+ * Make relation list entries for this guy and its partitions, if any.
+ * Note that the list returned by find_all_inheritors() include the
+ * passed-in OID at its head. Also note that we did not request a
+ * lock to be taken to match what would be done otherwise.
+ */
oldcontext = MemoryContextSwitchTo(vac_context);
- oid_list = lappend_oid(oid_list, relid);
+ if (include_parts)
+ oid_list = list_concat(oid_list,
+ find_all_inheritors(relid, NoLock, NULL));
+ else
+ oid_list = lappend_oid(oid_list, relid);
MemoryContextSwitchTo(oldcontext);
}
else
@@ -429,8 +456,23 @@ get_rel_oids(Oid relid, const RangeVar *vacrel)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
+ /*
+ * We include partitioned tables here; depending on which
+ * operation is to be performed, caller will decide whether to
+ * process or ignore them.
+ */
if (classForm->relkind != RELKIND_RELATION &&
- classForm->relkind != RELKIND_MATVIEW)
+ classForm->relkind != RELKIND_MATVIEW &&
+ classForm->relkind != RELKIND_PARTITIONED_TABLE)
+ continue;
+
+ /*
+ * If only ANALYZE is to be performed, there is no need to include
+ * partitions in the list. In a database-wide ANALYZE, we only
+ * update the inheritance statistics of partitioned tables, not
+ * the statistics of individual partitions.
+ */
+ if (!is_vacuum && classForm->relispartition)
continue;
/* Make a relation list entry for this guy */
@@ -1350,6 +1392,21 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params)
}
/*
+ * Ignore partitioned tables as there is no work to be done. Since we
+ * release the lock here, it's possible that any partitions added from
+ * this point on will not get processed, but that seems harmless.
+ */
+ if (onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ relation_close(onerel, lmode);
+ PopActiveSnapshot();
+ CommitTransactionCommand();
+
+ /* It's OK for other commands to look at this table */
+ return true;
+ }
+
+ /*
* Get a session-level lock too. This will protect our access to the
* relation across multiple transactions, so that we can vacuum the
* relation's TOAST table (if any) secure in the knowledge that no one is
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 0c5ffa086c..d7d1f5ea6f 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -1986,11 +1986,11 @@ do_autovacuum(void)
* Scan pg_class to determine which tables to vacuum.
*
* We do this in two passes: on the first one we collect the list of plain
- * relations and materialized views, and on the second one we collect
- * TOAST tables. The reason for doing the second pass is that during it we
- * want to use the main relation's pg_class.reloptions entry if the TOAST
- * table does not have any, and we cannot obtain it unless we know
- * beforehand what's the main table OID.
+ * relations, partitioned tables, and materialized views, and on the
+ * second one we collect TOAST tables. The reason for doing the second
+ * pass is that during it we want to use the main relation's
+ * pg_class.reloptions entry if the TOAST table does not have any, and we
+ * cannot obtain it unless we know beforehand what's the main table OID.
*
* We need to check TOAST tables separately because in cases with short,
* wide tables there might be proportionally much more activity in the
@@ -2013,7 +2013,8 @@ do_autovacuum(void)
bool wraparound;
if (classForm->relkind != RELKIND_RELATION &&
- classForm->relkind != RELKIND_MATVIEW)
+ classForm->relkind != RELKIND_MATVIEW &&
+ classForm->relkind != RELKIND_PARTITIONED_TABLE)
continue;
relid = HeapTupleGetOid(tuple);
@@ -2195,7 +2196,8 @@ do_autovacuum(void)
* completely unrelated to the one we saw before.
*/
if (!((classForm->relkind == RELKIND_RELATION ||
- classForm->relkind == RELKIND_MATVIEW) &&
+ classForm->relkind == RELKIND_MATVIEW ||
+ classForm->relkind == RELKIND_PARTITIONED_TABLE) &&
classForm->relpersistence == RELPERSISTENCE_TEMP))
{
UnlockRelationOid(relid, AccessExclusiveLock);
@@ -2614,6 +2616,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
if (classForm->relkind == RELKIND_TOASTVALUE)
doanalyze = false;
+ /* ignore VACUUM for partitioned tables */
+ if (classForm->relkind == RELKIND_PARTITIONED_TABLE)
+ dovacuum = false;
+
/* OK, it needs something done */
if (doanalyze || dovacuum)
{
--
2.11.0
[text/x-diff] 0002-Do-not-allocate-storage-for-partitioned-tables.patch (3.1K, ../../9be09bd2-6cda-f68a-5992-8e8e53a56f51@lab.ntt.co.jp/3-0002-Do-not-allocate-storage-for-partitioned-tables.patch)
download | inline diff:
From 61e2c64b9626c4b98a4346bdbbca49d6e3ed3c45 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Tue, 24 Jan 2017 14:22:34 +0900
Subject: [PATCH 2/3] Do not allocate storage for partitioned tables.
Currently, it is not possible to insert any data into a partitioned
table. So, they're empty at all times, which means it is wasteful to
allocate relfilenode and related storage objects.
---
src/backend/access/common/reloptions.c | 3 +--
src/backend/catalog/heap.c | 17 ++++++++++-------
2 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 816483ef8b..ec90d2b625 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -930,7 +930,6 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
case RELKIND_RELATION:
case RELKIND_TOASTVALUE:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
options = heap_reloptions(classForm->relkind, datum, false);
break;
case RELKIND_VIEW:
@@ -940,6 +939,7 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
options = index_reloptions(amoptions, datum, false);
break;
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
options = NULL;
break;
default:
@@ -1382,7 +1382,6 @@ heap_reloptions(char relkind, Datum reloptions, bool validate)
return (bytea *) rdopts;
case RELKIND_RELATION:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
default:
/* other relkinds are not supported */
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 41c0056556..2f5090b183 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -291,6 +291,7 @@ heap_create(const char *relname,
case RELKIND_VIEW:
case RELKIND_COMPOSITE_TYPE:
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
create_storage = false;
/*
@@ -1345,14 +1346,13 @@ heap_create_with_catalog(const char *relname,
if (oncommit != ONCOMMIT_NOOP)
register_on_commit_action(relid, oncommit);
- if (relpersistence == RELPERSISTENCE_UNLOGGED)
- {
- Assert(relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW ||
- relkind == RELKIND_TOASTVALUE ||
- relkind == RELKIND_PARTITIONED_TABLE);
-
+ /*
+ * We do not want to create any storage objects for a partitioned
+ * table, including the init fork.
+ */
+ if (relpersistence == RELPERSISTENCE_UNLOGGED &&
+ relkind != RELKIND_PARTITIONED_TABLE)
heap_create_init_fork(new_rel_desc);
- }
/*
* ok, the relation has been cataloged, so close our relations and return
@@ -1376,6 +1376,9 @@ heap_create_with_catalog(const char *relname,
void
heap_create_init_fork(Relation rel)
{
+ Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
+ rel->rd_rel->relkind == RELKIND_MATVIEW ||
+ rel->rd_rel->relkind == RELKIND_TOASTVALUE);
RelationOpenSmgr(rel);
smgrcreate(rel->rd_smgr, INIT_FORKNUM, false);
log_smgrcreate(&rel->rd_smgr->smgr_rnode.node, INIT_FORKNUM);
--
2.11.0
[text/x-diff] 0003-Avoid-creating-scan-nodes-for-partitioned-tables.patch (15.4K, ../../9be09bd2-6cda-f68a-5992-8e8e53a56f51@lab.ntt.co.jp/4-0003-Avoid-creating-scan-nodes-for-partitioned-tables.patch)
download | inline diff:
From 254f96967188123851f4324d46d30c36e6637edd Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Mon, 6 Feb 2017 17:26:48 +0900
Subject: [PATCH 3/3] Avoid creating scan nodes for partitioned tables
Currently, we create scan nodes for inheritance parents in their role
as an inheritance set member. Partitioned tables do not contain any
data, so it's useless to create scan nodes for them. So we need not
create AppendRelInfo's for them in the planner prep phase.
Further, the planner prep phase turns off inheritance on the parent RTE
if there isn't at least one child member (other than the parent itself
which in normal cases is also a child member), which means the latter
phases will not consider creating an Append plan and instead create a
scan node. Avoid this if the RTE is a partitioned table, by noticing
such cases in set_rel_size(). Per suggestion from Ashutosh Bapat.
Next, since we do not add the RTE corresponding to the root partitioned
table as the 1st child member of the inheritance set, inheritance_planner()
must not assume the same when assigning nominalRelation to a ModifyTable
node.
---
src/backend/optimizer/path/allpaths.c | 9 +++
src/backend/optimizer/plan/planner.c | 16 ++++-
src/backend/optimizer/prep/prepunion.c | 19 +++++-
src/test/regress/expected/inherit.out | 116 +++++++++------------------------
src/test/regress/sql/inherit.sql | 4 ++
5 files changed, 76 insertions(+), 88 deletions(-)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 633b5c1608..759e14d5fe 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -342,6 +342,15 @@ set_rel_size(PlannerInfo *root, RelOptInfo *rel,
/* Foreign table */
set_foreign_size(root, rel, rte);
}
+ else if (rte->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ /*
+ * An empty partitioned table, i.e., one without any leaf
+ * partitions, as signaled by rte->inh being set to false
+ * by the prep phase (see expand_inherited_rtentry).
+ */
+ set_dummy_rel_pathlist(rel);
+ }
else if (rte->tablesample != NULL)
{
/* Sampled relation */
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index ca0ae7883e..9918d2ba8c 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -996,10 +996,20 @@ inheritance_planner(PlannerInfo *root)
RelOptInfo *final_rel;
ListCell *lc;
Index rti;
+ RangeTblEntry *parent_rte;
Assert(parse->commandType != CMD_INSERT);
/*
+ * If the parent RTE is a partitioned table, we should use that as the
+ * nominal relation, because we do not have the duplicate parent RTE,
+ * unlike in the case of a non-partitioned inheritance parent.
+ */
+ parent_rte = rt_fetch(parentRTindex, root->parse->rtable);
+ if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
+ nominalRelation = parentRTindex;
+
+ /*
* We generate a modified instance of the original Query for each target
* relation, plan that, and put all the plans into a list that will be
* controlled by a single ModifyTable node. All the instances share the
@@ -1060,7 +1070,6 @@ inheritance_planner(PlannerInfo *root)
{
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
PlannerInfo *subroot;
- RangeTblEntry *parent_rte;
RangeTblEntry *child_rte;
RelOptInfo *sub_final_rel;
Path *subpath;
@@ -1214,6 +1223,11 @@ inheritance_planner(PlannerInfo *root)
* will not be otherwise referenced in the plan, doing so would give
* rise to confusing use of multiple aliases in EXPLAIN output for
* what the user will think is the "same" table.)
+ *
+ * If the parent is a partitioned table, we do not have a separate RTE
+ * representing it as a member of the inheritance set, because we do
+ * not create a scan plan for it. As mentioned at the top of this
+ * function, we make the parent RTE itself the nominal relation.
*/
if (nominalRelation < 0)
nominalRelation = appinfo->child_relid;
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 1389db18ba..78f51c762b 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -1450,6 +1450,18 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
newrelation = oldrelation;
/*
+ * Ignore partitioned tables here, because we do not want them to
+ * be considered as child tables in the inheritance set. No scan
+ * plans will be created for them.
+ */
+ if (newrelation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ if (newrelation != oldrelation)
+ heap_close(newrelation, lockmode);
+ continue;
+ }
+
+ /*
* It is possible that the parent table has children that are temp
* tables of other backends. We cannot safely access such tables
* (because of buffering issues), and the best thing to do seems to be
@@ -1548,9 +1560,12 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
* If all the children were temp tables, pretend it's a non-inheritance
* situation. The duplicate RTE we added for the parent table is
* harmless, so we don't bother to get rid of it; ditto for the useless
- * PlanRowMark node.
+ * PlanRowMark node. Since we do not create appinfos for partitioned
+ * tables above, we may end up with just one appinfo corresponding to
+ * the only leaf partition, which is fine.
*/
- if (list_length(appinfos) < 2)
+ if ((rte->relkind != RELKIND_PARTITIONED_TABLE &&
+ list_length(appinfos) < 2) || list_length(appinfos) < 1)
{
/* Clear flag before returning */
rte->inh = false;
diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out
index a8c8b28a75..cd33a1a7ec 100644
--- a/src/test/regress/expected/inherit.out
+++ b/src/test/regress/expected/inherit.out
@@ -1598,6 +1598,14 @@ reset enable_bitmapscan;
create table list_parted (
a varchar
) partition by list (a);
+-- test scanning partitioned table without any partitions
+explain (costs off) select * from list_parted;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
create table part_ab_cd partition of list_parted for values in ('ab', 'cd');
create table part_ef_gh partition of list_parted for values in ('ef', 'gh');
create table part_null_xy partition of list_parted for values in (null, 'xy');
@@ -1605,71 +1613,60 @@ explain (costs off) select * from list_parted;
QUERY PLAN
--------------------------------
Append
- -> Seq Scan on list_parted
-> Seq Scan on part_ab_cd
-> Seq Scan on part_ef_gh
-> Seq Scan on part_null_xy
-(5 rows)
+(4 rows)
explain (costs off) select * from list_parted where a is null;
QUERY PLAN
--------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (a IS NULL)
-> Seq Scan on part_null_xy
Filter: (a IS NULL)
-(5 rows)
+(3 rows)
explain (costs off) select * from list_parted where a is not null;
QUERY PLAN
---------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (a IS NOT NULL)
-> Seq Scan on part_ab_cd
Filter: (a IS NOT NULL)
-> Seq Scan on part_ef_gh
Filter: (a IS NOT NULL)
-> Seq Scan on part_null_xy
Filter: (a IS NOT NULL)
-(9 rows)
+(7 rows)
explain (costs off) select * from list_parted where a in ('ab', 'cd', 'ef');
QUERY PLAN
----------------------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-> Seq Scan on part_ab_cd
Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-> Seq Scan on part_ef_gh
Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-(7 rows)
+(5 rows)
explain (costs off) select * from list_parted where a = 'ab' or a in (null, 'cd');
QUERY PLAN
---------------------------------------------------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_ab_cd
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_ef_gh
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_null_xy
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-(9 rows)
+(7 rows)
explain (costs off) select * from list_parted where a = 'ab';
QUERY PLAN
------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: ((a)::text = 'ab'::text)
-> Seq Scan on part_ab_cd
Filter: ((a)::text = 'ab'::text)
-(5 rows)
+(3 rows)
create table range_list_parted (
a int,
@@ -1689,14 +1686,9 @@ create table part_40_inf_ab partition of part_40_inf for values in ('ab');
create table part_40_inf_cd partition of part_40_inf for values in ('cd');
create table part_40_inf_null partition of part_40_inf for values in (null);
explain (costs off) select * from range_list_parted;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- -> Seq Scan on part_1_10
- -> Seq Scan on part_10_20
- -> Seq Scan on part_21_30
- -> Seq Scan on part_40_inf
-> Seq Scan on part_1_10_ab
-> Seq Scan on part_1_10_cd
-> Seq Scan on part_10_20_ab
@@ -1706,36 +1698,22 @@ explain (costs off) select * from range_list_parted;
-> Seq Scan on part_40_inf_ab
-> Seq Scan on part_40_inf_cd
-> Seq Scan on part_40_inf_null
-(15 rows)
+(10 rows)
explain (costs off) select * from range_list_parted where a = 5;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+--------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (a = 5)
- -> Seq Scan on part_1_10
- Filter: (a = 5)
-> Seq Scan on part_1_10_ab
Filter: (a = 5)
-> Seq Scan on part_1_10_cd
Filter: (a = 5)
-(9 rows)
+(5 rows)
explain (costs off) select * from range_list_parted where b = 'ab';
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_1_10
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_10_20
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_21_30
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_40_inf
- Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_1_10_ab
Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_10_20_ab
@@ -1744,27 +1722,19 @@ explain (costs off) select * from range_list_parted where b = 'ab';
Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_40_inf_ab
Filter: (b = 'ab'::bpchar)
-(19 rows)
+(9 rows)
explain (costs off) select * from range_list_parted where a between 3 and 23 and b in ('ab');
QUERY PLAN
-----------------------------------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_1_10
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_10_20
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_21_30
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_1_10_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_10_20_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_21_30_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-(15 rows)
+(7 rows)
/* Should select no rows because range partition key cannot be null */
explain (costs off) select * from range_list_parted where a is null;
@@ -1776,37 +1746,17 @@ explain (costs off) select * from range_list_parted where a is null;
/* Should only select rows from the null-accepting partition */
explain (costs off) select * from range_list_parted where b is null;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (b IS NULL)
- -> Seq Scan on part_1_10
- Filter: (b IS NULL)
- -> Seq Scan on part_10_20
- Filter: (b IS NULL)
- -> Seq Scan on part_21_30
- Filter: (b IS NULL)
- -> Seq Scan on part_40_inf
- Filter: (b IS NULL)
-> Seq Scan on part_40_inf_null
Filter: (b IS NULL)
-(13 rows)
+(3 rows)
explain (costs off) select * from range_list_parted where a is not null and a < 67;
QUERY PLAN
------------------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_1_10
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_10_20
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_21_30
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_40_inf
- Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_1_10_ab
Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_1_10_cd
@@ -1825,23 +1775,19 @@ explain (costs off) select * from range_list_parted where a is not null and a <
Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_40_inf_null
Filter: ((a IS NOT NULL) AND (a < 67))
-(29 rows)
+(19 rows)
explain (costs off) select * from range_list_parted where a >= 30;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (a >= 30)
- -> Seq Scan on part_40_inf
- Filter: (a >= 30)
-> Seq Scan on part_40_inf_ab
Filter: (a >= 30)
-> Seq Scan on part_40_inf_cd
Filter: (a >= 30)
-> Seq Scan on part_40_inf_null
Filter: (a >= 30)
-(11 rows)
+(7 rows)
drop table list_parted cascade;
NOTICE: drop cascades to 3 other objects
diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql
index a8b7eb1c8d..34274746d3 100644
--- a/src/test/regress/sql/inherit.sql
+++ b/src/test/regress/sql/inherit.sql
@@ -570,6 +570,10 @@ reset enable_bitmapscan;
create table list_parted (
a varchar
) partition by list (a);
+
+-- test scanning partitioned table without any partitions
+explain (costs off) select * from list_parted;
+
create table part_ab_cd partition of list_parted for values in ('ab', 'cd');
create table part_ef_gh partition of list_parted for values in ('ef', 'gh');
create table part_null_xy partition of list_parted for values in (null, 'xy');
--
2.11.0
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-02-22 12:58 ` Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
0 siblings, 1 reply; 96+ messages in thread
From: Ashutosh Bapat @ 2017-02-22 12:58 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: Robert Haas <robertmhaas@gmail.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
>
>> I am wondering whether we should deal with inh flat reset in a
>> slightly different way. Let expand_inherited_rtentry() mark inh =
>> false for the partitioned tables without any partitions and deal with
>> those at the time of estimating size by marking those as dummy. That
>> might be better than multiple changes here. I will try to cook up a
>> patch soon for that.
>
> Are thinking something along the lines of the attached rewritten patch
> 0003? I also tend to think that's probably a cleaner patch. Thanks for
> the idea.
Yes. Thanks for working on it.
>
>> Also we should add tests to make sure the scans on partitioned tables
>> without any partitions do not get into problems. PFA patch which adds
>> those tests.
>
> I added the test case you suggest, but kept just the first one.
The second one was testing multi-level partitioning case, which
deserves a testcase by its own.
Some more comments
The comment below seems too verbose. All it can say is "A partitioned table
without any partitions results in a dummy relation." I don't think we need to
be explicit about rte->inh. But it's more of personal preference. We will leave
it to the committer, if you don't agree.
+ /*
+ * An empty partitioned table, i.e., one without any leaf
+ * partitions, as signaled by rte->inh being set to false
+ * by the prep phase (see expand_inherited_rtentry).
+ */
We don't need this comment as well. Rather than repeating what's been said at
the top of the function, it should just refer to it like "nominal relation has
been set above for partitioned tables. For other parent relations, we'll use
the first child ...".
+ *
+ * If the parent is a partitioned table, we do not have a separate RTE
+ * representing it as a member of the inheritance set, because we do
+ * not create a scan plan for it. As mentioned at the top of this
+ * function, we make the parent RTE itself the nominal relation.
*/
Following condition is not very readable. It's not evident that it's of the
form (A && B) || C, at a glance it looks like it's A && (B || C).
+ if ((rte->relkind != RELKIND_PARTITIONED_TABLE &&
+ list_length(appinfos) < 2) || list_length(appinfos) < 1)
Instead you may rearrage it as
min_child_rels = (rte->relkind == RELKIND_PARTITIONED_TABLE ? 1 : 2);
if (list_length(appinfos) < min_child_rels)
--
Best Wishes,
Ashutosh Bapat
EnterpriseDB Corporation
The Postgres Database Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
@ 2017-02-23 05:49 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-23 06:44 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
0 siblings, 2 replies; 96+ messages in thread
From: Amit Langote @ 2017-02-23 05:49 UTC (permalink / raw)
To: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; +Cc: Robert Haas <robertmhaas@gmail.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
Thanks for the review.
On 2017/02/22 21:58, Ashutosh Bapat wrote:
>>> Also we should add tests to make sure the scans on partitioned tables
>>> without any partitions do not get into problems. PFA patch which adds
>>> those tests.
>>
>> I added the test case you suggest, but kept just the first one.
>
> The second one was testing multi-level partitioning case, which
> deserves a testcase by its own.
Ah, okay. Added it back.
> Some more comments
>
> The comment below seems too verbose. All it can say is "A partitioned table
> without any partitions results in a dummy relation." I don't think we need to
> be explicit about rte->inh. But it's more of personal preference. We will leave
> it to the committer, if you don't agree.
> + /*
> + * An empty partitioned table, i.e., one without any leaf
> + * partitions, as signaled by rte->inh being set to false
> + * by the prep phase (see expand_inherited_rtentry).
> + */
It does seem poorly worded. How about:
/*
* A partitioned table without leaf partitions is marked
* as a dummy rel.
*/
> We don't need this comment as well. Rather than repeating what's been said at
> the top of the function, it should just refer to it like "nominal relation has
> been set above for partitioned tables. For other parent relations, we'll use
> the first child ...".
> + *
> + * If the parent is a partitioned table, we do not have a separate RTE
> + * representing it as a member of the inheritance set, because we do
> + * not create a scan plan for it. As mentioned at the top of this
> + * function, we make the parent RTE itself the nominal relation.
> */
Rewrote that comment block as:
*
* If the parent is a partitioned table, we already set the nominal
* relation.
*/
> Following condition is not very readable. It's not evident that it's of the
> form (A && B) || C, at a glance it looks like it's A && (B || C).
> + if ((rte->relkind != RELKIND_PARTITIONED_TABLE &&
> + list_length(appinfos) < 2) || list_length(appinfos) < 1)
>
> Instead you may rearrage it as
> min_child_rels = (rte->relkind == RELKIND_PARTITIONED_TABLE ? 1 : 2);
> if (list_length(appinfos) < min_child_rels)
OK, done that way.
Thanks,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Attachments:
[text/x-diff] 0001-Partitioned-tables-are-empty-themselves.patch (12.9K, ../../a34313a6-6a50-4690-79f6-0691bb87db83@lab.ntt.co.jp/2-0001-Partitioned-tables-are-empty-themselves.patch)
download | inline diff:
From ed28c10fa4c4ae30beb1dbc621b4d38d31f718e1 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Mon, 6 Feb 2017 18:03:28 +0900
Subject: [PATCH 1/3] Partitioned tables are empty themselves
So, there is not much point in trying to do things to them that need
accessing files (a later commit will make it so that there is no file
at all to access.) Things that needed attention are: vacuum, analyze,
truncate, ATRewriteTables.
---
doc/src/sgml/ddl.sgml | 7 ++--
src/backend/commands/analyze.c | 39 ++++++++++++++------
src/backend/commands/tablecmds.c | 15 ++++++--
src/backend/commands/vacuum.c | 71 +++++++++++++++++++++++++++++++++----
src/backend/postmaster/autovacuum.c | 20 +++++++----
5 files changed, 123 insertions(+), 29 deletions(-)
diff --git a/doc/src/sgml/ddl.sgml b/doc/src/sgml/ddl.sgml
index ef0f7cf727..c10d312139 100644
--- a/doc/src/sgml/ddl.sgml
+++ b/doc/src/sgml/ddl.sgml
@@ -3840,8 +3840,11 @@ UNION ALL SELECT * FROM measurement_y2008m01;
<programlisting>
ANALYZE measurement;
</programlisting>
- will only process the master table. This is true even for partitioned
- tables.
+ will only process the master table.
+ </para>
+
+ <para>
+ This does not apply to partitioned tables though.
</para>
</listitem>
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index ed3acb1673..12cd0110b0 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -201,8 +201,7 @@ analyze_rel(Oid relid, RangeVar *relation, int options,
* locked the relation.
*/
if (onerel->rd_rel->relkind == RELKIND_RELATION ||
- onerel->rd_rel->relkind == RELKIND_MATVIEW ||
- onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ onerel->rd_rel->relkind == RELKIND_MATVIEW)
{
/* Regular table, so we'll use the regular row acquisition function */
acquirefunc = acquire_sample_rows;
@@ -234,6 +233,12 @@ analyze_rel(Oid relid, RangeVar *relation, int options,
return;
}
}
+ else if (onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ /*
+ * For partitioned tables, we want to do the recursive ANALYZE below.
+ */
+ }
else
{
/* No need for a WARNING if we already complained during VACUUM */
@@ -253,13 +258,15 @@ analyze_rel(Oid relid, RangeVar *relation, int options,
LWLockRelease(ProcArrayLock);
/*
- * Do the normal non-recursive ANALYZE.
+ * Do the normal non-recursive ANALYZE, non-partitioned relations.
*/
- do_analyze_rel(onerel, options, params, va_cols, acquirefunc, relpages,
- false, in_outer_xact, elevel);
+ if (onerel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
+ do_analyze_rel(onerel, options, params, va_cols, acquirefunc,
+ relpages, false, in_outer_xact, elevel);
/*
- * If there are child tables, do recursive ANALYZE.
+ * If there are child tables, do recursive ANALYZE. This includes
+ * partitioned tables.
*/
if (onerel->rd_rel->relhassubclass)
do_analyze_rel(onerel, options, params, va_cols, acquirefunc, relpages,
@@ -1316,10 +1323,20 @@ acquire_inherited_sample_rows(Relation onerel, int elevel,
continue;
}
+ /* Ignore partitioned tables as there are no tuples to collect */
+ if (childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ /* Don't try to unlock the passed-in root table. */
+ if (childrel == onerel)
+ heap_close(childrel, NoLock);
+ else
+ heap_close(childrel, AccessShareLock);
+ continue;
+ }
+
/* Check table type (MATVIEW can't happen, but might as well allow) */
if (childrel->rd_rel->relkind == RELKIND_RELATION ||
- childrel->rd_rel->relkind == RELKIND_MATVIEW ||
- childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ childrel->rd_rel->relkind == RELKIND_MATVIEW)
{
/* Regular table, so use the regular row acquisition function */
acquirefunc = acquire_sample_rows;
@@ -1366,9 +1383,11 @@ acquire_inherited_sample_rows(Relation onerel, int elevel,
}
/*
- * If we don't have at least two tables to consider, fail.
+ * If we don't have at least one child table to consider, fail. If the
+ * relation is a partitioned table, it's not counted as a child table.
*/
- if (nrels < 2)
+ if ((onerel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE && nrels < 2) ||
+ nrels < 1)
{
ereport(elevel,
(errmsg("skipping analyze of \"%s.%s\" inheritance tree --- this inheritance tree contains no analyzable child tables",
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 3cea220421..317012068b 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -1349,6 +1349,10 @@ ExecuteTruncate(TruncateStmt *stmt)
{
Relation rel = (Relation) lfirst(cell);
+ /* Skip partitioned tables as there is nothing to do */
+ if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ continue;
+
/*
* Normally, we need a transaction-safe truncation here. However, if
* the table was either created in the current (sub)transaction or has
@@ -1459,7 +1463,11 @@ truncate_check_rel(Relation rel)
{
AclResult aclresult;
- /* Only allow truncate on regular tables */
+ /*
+ * Only allow truncate on regular tables and partitioned tables (although,
+ * the latter are only being included here for the following checks; no
+ * physical truncation will occur in their case.)
+ */
if (rel->rd_rel->relkind != RELKIND_RELATION &&
rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
ereport(ERROR,
@@ -4006,8 +4014,9 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode)
{
AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
- /* Foreign tables have no storage. */
- if (tab->relkind == RELKIND_FOREIGN_TABLE)
+ /* Foreign tables have no storage, nor do partitioned tables. */
+ if (tab->relkind == RELKIND_FOREIGN_TABLE ||
+ tab->relkind == RELKIND_PARTITIONED_TABLE)
continue;
/*
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 812fb4a48f..856673fb58 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -32,6 +32,7 @@
#include "access/xact.h"
#include "catalog/namespace.h"
#include "catalog/pg_database.h"
+#include "catalog/pg_inherits_fn.h"
#include "catalog/pg_namespace.h"
#include "commands/cluster.h"
#include "commands/vacuum.h"
@@ -66,7 +67,7 @@ static BufferAccessStrategy vac_strategy;
/* non-export function prototypes */
-static List *get_rel_oids(Oid relid, const RangeVar *vacrel);
+static List *get_rel_oids(Oid relid, const RangeVar *vacrel, bool is_vacuum);
static void vac_truncate_clog(TransactionId frozenXID,
MultiXactId minMulti,
TransactionId lastSaneFrozenXid,
@@ -226,9 +227,12 @@ vacuum(int options, RangeVar *relation, Oid relid, VacuumParams *params,
/*
* Build list of relations to process, unless caller gave us one. (If we
- * build one, we put it in vac_context for safekeeping.)
+ * build one, we put it in vac_context for safekeeping.) Also pass
+ * whether we are going to be doing VACUUM, in which case we must include
+ * partitions in the list (considered only in the case of a database-wide
+ * invocation).
*/
- relations = get_rel_oids(relid, relation);
+ relations = get_rel_oids(relid, relation, options & VACOPT_VACUUM);
/*
* Decide whether we need to start/commit our own transactions.
@@ -378,7 +382,7 @@ vacuum(int options, RangeVar *relation, Oid relid, VacuumParams *params,
* per-relation transactions.
*/
static List *
-get_rel_oids(Oid relid, const RangeVar *vacrel)
+get_rel_oids(Oid relid, const RangeVar *vacrel, bool is_vacuum)
{
List *oid_list = NIL;
MemoryContext oldcontext;
@@ -394,6 +398,9 @@ get_rel_oids(Oid relid, const RangeVar *vacrel)
{
/* Process a specific relation */
Oid relid;
+ HeapTuple tuple;
+ Form_pg_class classForm;
+ bool include_parts;
/*
* Since we don't take a lock here, the relation might be gone, or the
@@ -406,9 +413,29 @@ get_rel_oids(Oid relid, const RangeVar *vacrel)
*/
relid = RangeVarGetRelid(vacrel, NoLock, false);
- /* Make a relation list entry for this guy */
+ /*
+ * To check whether the relation is a partitioned table, fetch its
+ * syscache entry.
+ */
+ tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for relation %u", relid);
+ classForm = (Form_pg_class) GETSTRUCT(tuple);
+ include_parts = (classForm->relkind == RELKIND_PARTITIONED_TABLE);
+ ReleaseSysCache(tuple);
+
+ /*
+ * Make relation list entries for this guy and its partitions, if any.
+ * Note that the list returned by find_all_inheritors() include the
+ * passed-in OID at its head. Also note that we did not request a
+ * lock to be taken to match what would be done otherwise.
+ */
oldcontext = MemoryContextSwitchTo(vac_context);
- oid_list = lappend_oid(oid_list, relid);
+ if (include_parts)
+ oid_list = list_concat(oid_list,
+ find_all_inheritors(relid, NoLock, NULL));
+ else
+ oid_list = lappend_oid(oid_list, relid);
MemoryContextSwitchTo(oldcontext);
}
else
@@ -429,8 +456,23 @@ get_rel_oids(Oid relid, const RangeVar *vacrel)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
+ /*
+ * We include partitioned tables here; depending on which
+ * operation is to be performed, caller will decide whether to
+ * process or ignore them.
+ */
if (classForm->relkind != RELKIND_RELATION &&
- classForm->relkind != RELKIND_MATVIEW)
+ classForm->relkind != RELKIND_MATVIEW &&
+ classForm->relkind != RELKIND_PARTITIONED_TABLE)
+ continue;
+
+ /*
+ * If only ANALYZE is to be performed, there is no need to include
+ * partitions in the list. In a database-wide ANALYZE, we only
+ * update the inheritance statistics of partitioned tables, not
+ * the statistics of individual partitions.
+ */
+ if (!is_vacuum && classForm->relispartition)
continue;
/* Make a relation list entry for this guy */
@@ -1350,6 +1392,21 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params)
}
/*
+ * Ignore partitioned tables as there is no work to be done. Since we
+ * release the lock here, it's possible that any partitions added from
+ * this point on will not get processed, but that seems harmless.
+ */
+ if (onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ relation_close(onerel, lmode);
+ PopActiveSnapshot();
+ CommitTransactionCommand();
+
+ /* It's OK for other commands to look at this table */
+ return true;
+ }
+
+ /*
* Get a session-level lock too. This will protect our access to the
* relation across multiple transactions, so that we can vacuum the
* relation's TOAST table (if any) secure in the knowledge that no one is
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 0c5ffa086c..d7d1f5ea6f 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -1986,11 +1986,11 @@ do_autovacuum(void)
* Scan pg_class to determine which tables to vacuum.
*
* We do this in two passes: on the first one we collect the list of plain
- * relations and materialized views, and on the second one we collect
- * TOAST tables. The reason for doing the second pass is that during it we
- * want to use the main relation's pg_class.reloptions entry if the TOAST
- * table does not have any, and we cannot obtain it unless we know
- * beforehand what's the main table OID.
+ * relations, partitioned tables, and materialized views, and on the
+ * second one we collect TOAST tables. The reason for doing the second
+ * pass is that during it we want to use the main relation's
+ * pg_class.reloptions entry if the TOAST table does not have any, and we
+ * cannot obtain it unless we know beforehand what's the main table OID.
*
* We need to check TOAST tables separately because in cases with short,
* wide tables there might be proportionally much more activity in the
@@ -2013,7 +2013,8 @@ do_autovacuum(void)
bool wraparound;
if (classForm->relkind != RELKIND_RELATION &&
- classForm->relkind != RELKIND_MATVIEW)
+ classForm->relkind != RELKIND_MATVIEW &&
+ classForm->relkind != RELKIND_PARTITIONED_TABLE)
continue;
relid = HeapTupleGetOid(tuple);
@@ -2195,7 +2196,8 @@ do_autovacuum(void)
* completely unrelated to the one we saw before.
*/
if (!((classForm->relkind == RELKIND_RELATION ||
- classForm->relkind == RELKIND_MATVIEW) &&
+ classForm->relkind == RELKIND_MATVIEW ||
+ classForm->relkind == RELKIND_PARTITIONED_TABLE) &&
classForm->relpersistence == RELPERSISTENCE_TEMP))
{
UnlockRelationOid(relid, AccessExclusiveLock);
@@ -2614,6 +2616,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
if (classForm->relkind == RELKIND_TOASTVALUE)
doanalyze = false;
+ /* ignore VACUUM for partitioned tables */
+ if (classForm->relkind == RELKIND_PARTITIONED_TABLE)
+ dovacuum = false;
+
/* OK, it needs something done */
if (doanalyze || dovacuum)
{
--
2.11.0
[text/x-diff] 0002-Do-not-allocate-storage-for-partitioned-tables.patch (3.1K, ../../a34313a6-6a50-4690-79f6-0691bb87db83@lab.ntt.co.jp/3-0002-Do-not-allocate-storage-for-partitioned-tables.patch)
download | inline diff:
From 1242d605b771f6a4da0f478f2824669ab3e73092 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Tue, 24 Jan 2017 14:22:34 +0900
Subject: [PATCH 2/3] Do not allocate storage for partitioned tables.
Currently, it is not possible to insert any data into a partitioned
table. So, they're empty at all times, which means it is wasteful to
allocate relfilenode and related storage objects.
---
src/backend/access/common/reloptions.c | 3 +--
src/backend/catalog/heap.c | 17 ++++++++++-------
2 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 816483ef8b..ec90d2b625 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -930,7 +930,6 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
case RELKIND_RELATION:
case RELKIND_TOASTVALUE:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
options = heap_reloptions(classForm->relkind, datum, false);
break;
case RELKIND_VIEW:
@@ -940,6 +939,7 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
options = index_reloptions(amoptions, datum, false);
break;
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
options = NULL;
break;
default:
@@ -1382,7 +1382,6 @@ heap_reloptions(char relkind, Datum reloptions, bool validate)
return (bytea *) rdopts;
case RELKIND_RELATION:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
default:
/* other relkinds are not supported */
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 41c0056556..2f5090b183 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -291,6 +291,7 @@ heap_create(const char *relname,
case RELKIND_VIEW:
case RELKIND_COMPOSITE_TYPE:
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
create_storage = false;
/*
@@ -1345,14 +1346,13 @@ heap_create_with_catalog(const char *relname,
if (oncommit != ONCOMMIT_NOOP)
register_on_commit_action(relid, oncommit);
- if (relpersistence == RELPERSISTENCE_UNLOGGED)
- {
- Assert(relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW ||
- relkind == RELKIND_TOASTVALUE ||
- relkind == RELKIND_PARTITIONED_TABLE);
-
+ /*
+ * We do not want to create any storage objects for a partitioned
+ * table, including the init fork.
+ */
+ if (relpersistence == RELPERSISTENCE_UNLOGGED &&
+ relkind != RELKIND_PARTITIONED_TABLE)
heap_create_init_fork(new_rel_desc);
- }
/*
* ok, the relation has been cataloged, so close our relations and return
@@ -1376,6 +1376,9 @@ heap_create_with_catalog(const char *relname,
void
heap_create_init_fork(Relation rel)
{
+ Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
+ rel->rd_rel->relkind == RELKIND_MATVIEW ||
+ rel->rd_rel->relkind == RELKIND_TOASTVALUE);
RelationOpenSmgr(rel);
smgrcreate(rel->rd_smgr, INIT_FORKNUM, false);
log_smgrcreate(&rel->rd_smgr->smgr_rnode.node, INIT_FORKNUM);
--
2.11.0
[text/x-diff] 0003-Avoid-creating-scan-nodes-for-partitioned-tables.patch (16.6K, ../../a34313a6-6a50-4690-79f6-0691bb87db83@lab.ntt.co.jp/4-0003-Avoid-creating-scan-nodes-for-partitioned-tables.patch)
download | inline diff:
From 45f10bd34077c17aaa8ea18a62d03a237ab1ac14 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Mon, 6 Feb 2017 17:26:48 +0900
Subject: [PATCH 3/3] Avoid creating scan nodes for partitioned tables
Currently, we create scan nodes for inheritance parents in their role
as an inheritance set member. Partitioned tables do not contain any
data, so it's useless to create scan nodes for them. So we need not
create AppendRelInfo's for them in the planner prep phase.
Further, the planner prep phase turns off inheritance on the parent RTE
if there isn't at least one child member (other than the parent itself
which in normal cases is also a child member), which means the latter
phases will not consider creating an Append plan and instead create a
scan node. Avoid this if the RTE is a partitioned table, by noticing
such cases in set_rel_size(). Per suggestion from Ashutosh Bapat.
Next, since we do not add the RTE corresponding to the root partitioned
table as the 1st child member of the inheritance set, inheritance_planner()
must not assume the same when assigning nominalRelation to a ModifyTable
node.
---
src/backend/optimizer/path/allpaths.c | 8 +++
src/backend/optimizer/plan/planner.c | 14 +++-
src/backend/optimizer/prep/prepunion.c | 24 ++++++-
src/test/regress/expected/inherit.out | 124 +++++++++++----------------------
src/test/regress/sql/inherit.sql | 8 +++
5 files changed, 90 insertions(+), 88 deletions(-)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 633b5c1608..f2c8d27193 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -342,6 +342,14 @@ set_rel_size(PlannerInfo *root, RelOptInfo *rel,
/* Foreign table */
set_foreign_size(root, rel, rte);
}
+ else if (rte->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ /*
+ * A partitioned table without leaf partitions is marked
+ * as a dummy rel.
+ */
+ set_dummy_rel_pathlist(rel);
+ }
else if (rte->tablesample != NULL)
{
/* Sampled relation */
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index ca0ae7883e..b5698f0ce7 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -996,10 +996,20 @@ inheritance_planner(PlannerInfo *root)
RelOptInfo *final_rel;
ListCell *lc;
Index rti;
+ RangeTblEntry *parent_rte;
Assert(parse->commandType != CMD_INSERT);
/*
+ * If the parent RTE is a partitioned table, we should use that as the
+ * nominal relation, because we do not have the duplicate parent RTE,
+ * unlike in the case of a non-partitioned inheritance parent.
+ */
+ parent_rte = rt_fetch(parentRTindex, root->parse->rtable);
+ if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
+ nominalRelation = parentRTindex;
+
+ /*
* We generate a modified instance of the original Query for each target
* relation, plan that, and put all the plans into a list that will be
* controlled by a single ModifyTable node. All the instances share the
@@ -1060,7 +1070,6 @@ inheritance_planner(PlannerInfo *root)
{
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
PlannerInfo *subroot;
- RangeTblEntry *parent_rte;
RangeTblEntry *child_rte;
RelOptInfo *sub_final_rel;
Path *subpath;
@@ -1214,6 +1223,9 @@ inheritance_planner(PlannerInfo *root)
* will not be otherwise referenced in the plan, doing so would give
* rise to confusing use of multiple aliases in EXPLAIN output for
* what the user will think is the "same" table.)
+ *
+ * If the parent is a partitioned table, we already set the nominal
+ * relation.
*/
if (nominalRelation < 0)
nominalRelation = appinfo->child_relid;
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 1389db18ba..e31daf737b 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -1364,6 +1364,7 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
List *inhOIDs;
List *appinfos;
ListCell *l;
+ int min_child_rels;
/* Does RT entry allow inheritance? */
if (!rte->inh)
@@ -1450,6 +1451,22 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
newrelation = oldrelation;
/*
+ * Ignore partitioned tables here, because we do not want them to
+ * be considered as child tables in the inheritance set. No scan
+ * plans will be created for them.
+ */
+ if (newrelation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ /*
+ * Don't lose the lock taken for us by find_all_inheritors()
+ * lest its partitions change under us.
+ */
+ if (newrelation != oldrelation)
+ heap_close(newrelation, NoLock);
+ continue;
+ }
+
+ /*
* It is possible that the parent table has children that are temp
* tables of other backends. We cannot safely access such tables
* (because of buffering issues), and the best thing to do seems to be
@@ -1548,9 +1565,12 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
* If all the children were temp tables, pretend it's a non-inheritance
* situation. The duplicate RTE we added for the parent table is
* harmless, so we don't bother to get rid of it; ditto for the useless
- * PlanRowMark node.
+ * PlanRowMark node. Since we do not create appinfos for partitioned
+ * tables above, we may end up with just one appinfo corresponding to
+ * the only leaf partition, which is fine.
*/
- if (list_length(appinfos) < 2)
+ min_child_rels = (rte->relkind == RELKIND_PARTITIONED_TABLE ? 1 : 2);
+ if (list_length(appinfos) < min_child_rels)
{
/* Clear flag before returning */
rte->inh = false;
diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out
index a8c8b28a75..55b147432f 100644
--- a/src/test/regress/expected/inherit.out
+++ b/src/test/regress/expected/inherit.out
@@ -1598,6 +1598,14 @@ reset enable_bitmapscan;
create table list_parted (
a varchar
) partition by list (a);
+-- test scanning partitioned table without any partitions
+explain (costs off) select * from list_parted;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
create table part_ab_cd partition of list_parted for values in ('ab', 'cd');
create table part_ef_gh partition of list_parted for values in ('ef', 'gh');
create table part_null_xy partition of list_parted for values in (null, 'xy');
@@ -1605,77 +1613,74 @@ explain (costs off) select * from list_parted;
QUERY PLAN
--------------------------------
Append
- -> Seq Scan on list_parted
-> Seq Scan on part_ab_cd
-> Seq Scan on part_ef_gh
-> Seq Scan on part_null_xy
-(5 rows)
+(4 rows)
explain (costs off) select * from list_parted where a is null;
QUERY PLAN
--------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (a IS NULL)
-> Seq Scan on part_null_xy
Filter: (a IS NULL)
-(5 rows)
+(3 rows)
explain (costs off) select * from list_parted where a is not null;
QUERY PLAN
---------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (a IS NOT NULL)
-> Seq Scan on part_ab_cd
Filter: (a IS NOT NULL)
-> Seq Scan on part_ef_gh
Filter: (a IS NOT NULL)
-> Seq Scan on part_null_xy
Filter: (a IS NOT NULL)
-(9 rows)
+(7 rows)
explain (costs off) select * from list_parted where a in ('ab', 'cd', 'ef');
QUERY PLAN
----------------------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-> Seq Scan on part_ab_cd
Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-> Seq Scan on part_ef_gh
Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-(7 rows)
+(5 rows)
explain (costs off) select * from list_parted where a = 'ab' or a in (null, 'cd');
QUERY PLAN
---------------------------------------------------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_ab_cd
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_ef_gh
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_null_xy
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-(9 rows)
+(7 rows)
explain (costs off) select * from list_parted where a = 'ab';
QUERY PLAN
------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: ((a)::text = 'ab'::text)
-> Seq Scan on part_ab_cd
Filter: ((a)::text = 'ab'::text)
-(5 rows)
+(3 rows)
create table range_list_parted (
a int,
b char(2)
) partition by range (a);
create table part_1_10 partition of range_list_parted for values from (1) to (10) partition by list (b);
+-- test scanning partitioned table without any leaf partitions
+explain (costs off) select * from range_list_parted;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
create table part_1_10_ab partition of part_1_10 for values in ('ab');
create table part_1_10_cd partition of part_1_10 for values in ('cd');
create table part_10_20 partition of range_list_parted for values from (10) to (20) partition by list (b);
@@ -1689,14 +1694,9 @@ create table part_40_inf_ab partition of part_40_inf for values in ('ab');
create table part_40_inf_cd partition of part_40_inf for values in ('cd');
create table part_40_inf_null partition of part_40_inf for values in (null);
explain (costs off) select * from range_list_parted;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- -> Seq Scan on part_1_10
- -> Seq Scan on part_10_20
- -> Seq Scan on part_21_30
- -> Seq Scan on part_40_inf
-> Seq Scan on part_1_10_ab
-> Seq Scan on part_1_10_cd
-> Seq Scan on part_10_20_ab
@@ -1706,36 +1706,22 @@ explain (costs off) select * from range_list_parted;
-> Seq Scan on part_40_inf_ab
-> Seq Scan on part_40_inf_cd
-> Seq Scan on part_40_inf_null
-(15 rows)
+(10 rows)
explain (costs off) select * from range_list_parted where a = 5;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+--------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (a = 5)
- -> Seq Scan on part_1_10
- Filter: (a = 5)
-> Seq Scan on part_1_10_ab
Filter: (a = 5)
-> Seq Scan on part_1_10_cd
Filter: (a = 5)
-(9 rows)
+(5 rows)
explain (costs off) select * from range_list_parted where b = 'ab';
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_1_10
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_10_20
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_21_30
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_40_inf
- Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_1_10_ab
Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_10_20_ab
@@ -1744,27 +1730,19 @@ explain (costs off) select * from range_list_parted where b = 'ab';
Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_40_inf_ab
Filter: (b = 'ab'::bpchar)
-(19 rows)
+(9 rows)
explain (costs off) select * from range_list_parted where a between 3 and 23 and b in ('ab');
QUERY PLAN
-----------------------------------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_1_10
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_10_20
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_21_30
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_1_10_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_10_20_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_21_30_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-(15 rows)
+(7 rows)
/* Should select no rows because range partition key cannot be null */
explain (costs off) select * from range_list_parted where a is null;
@@ -1776,37 +1754,17 @@ explain (costs off) select * from range_list_parted where a is null;
/* Should only select rows from the null-accepting partition */
explain (costs off) select * from range_list_parted where b is null;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (b IS NULL)
- -> Seq Scan on part_1_10
- Filter: (b IS NULL)
- -> Seq Scan on part_10_20
- Filter: (b IS NULL)
- -> Seq Scan on part_21_30
- Filter: (b IS NULL)
- -> Seq Scan on part_40_inf
- Filter: (b IS NULL)
-> Seq Scan on part_40_inf_null
Filter: (b IS NULL)
-(13 rows)
+(3 rows)
explain (costs off) select * from range_list_parted where a is not null and a < 67;
QUERY PLAN
------------------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_1_10
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_10_20
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_21_30
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_40_inf
- Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_1_10_ab
Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_1_10_cd
@@ -1825,23 +1783,19 @@ explain (costs off) select * from range_list_parted where a is not null and a <
Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_40_inf_null
Filter: ((a IS NOT NULL) AND (a < 67))
-(29 rows)
+(19 rows)
explain (costs off) select * from range_list_parted where a >= 30;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (a >= 30)
- -> Seq Scan on part_40_inf
- Filter: (a >= 30)
-> Seq Scan on part_40_inf_ab
Filter: (a >= 30)
-> Seq Scan on part_40_inf_cd
Filter: (a >= 30)
-> Seq Scan on part_40_inf_null
Filter: (a >= 30)
-(11 rows)
+(7 rows)
drop table list_parted cascade;
NOTICE: drop cascades to 3 other objects
diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql
index a8b7eb1c8d..04cc4ffa23 100644
--- a/src/test/regress/sql/inherit.sql
+++ b/src/test/regress/sql/inherit.sql
@@ -570,6 +570,10 @@ reset enable_bitmapscan;
create table list_parted (
a varchar
) partition by list (a);
+
+-- test scanning partitioned table without any partitions
+explain (costs off) select * from list_parted;
+
create table part_ab_cd partition of list_parted for values in ('ab', 'cd');
create table part_ef_gh partition of list_parted for values in ('ef', 'gh');
create table part_null_xy partition of list_parted for values in (null, 'xy');
@@ -586,6 +590,10 @@ create table range_list_parted (
b char(2)
) partition by range (a);
create table part_1_10 partition of range_list_parted for values from (1) to (10) partition by list (b);
+
+-- test scanning partitioned table without any leaf partitions
+explain (costs off) select * from range_list_parted;
+
create table part_1_10_ab partition of part_1_10 for values in ('ab');
create table part_1_10_cd partition of part_1_10 for values in ('cd');
create table part_10_20 partition of range_list_parted for values from (10) to (20) partition by list (b);
--
2.11.0
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-02-23 06:44 ` Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 07:38 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
1 sibling, 1 reply; 96+ messages in thread
From: Ashutosh Bapat @ 2017-02-23 06:44 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: Robert Haas <robertmhaas@gmail.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On Thu, Feb 23, 2017 at 11:19 AM, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
> Thanks for the review.
>
> On 2017/02/22 21:58, Ashutosh Bapat wrote:
>>>> Also we should add tests to make sure the scans on partitioned tables
>>>> without any partitions do not get into problems. PFA patch which adds
>>>> those tests.
>>>
>>> I added the test case you suggest, but kept just the first one.
>>
>> The second one was testing multi-level partitioning case, which
>> deserves a testcase by its own.
>
> Ah, okay. Added it back.
Thanks.
>
>> Some more comments
>>
>> The comment below seems too verbose. All it can say is "A partitioned table
>> without any partitions results in a dummy relation." I don't think we need to
>> be explicit about rte->inh. But it's more of personal preference. We will leave
>> it to the committer, if you don't agree.
>> + /*
>> + * An empty partitioned table, i.e., one without any leaf
>> + * partitions, as signaled by rte->inh being set to false
>> + * by the prep phase (see expand_inherited_rtentry).
>> + */
>
> It does seem poorly worded. How about:
>
> /*
> * A partitioned table without leaf partitions is marked
> * as a dummy rel.
> */
>
>> We don't need this comment as well. Rather than repeating what's been said at
>> the top of the function, it should just refer to it like "nominal relation has
>> been set above for partitioned tables. For other parent relations, we'll use
>> the first child ...".
>> + *
>> + * If the parent is a partitioned table, we do not have a separate RTE
>> + * representing it as a member of the inheritance set, because we do
>> + * not create a scan plan for it. As mentioned at the top of this
>> + * function, we make the parent RTE itself the nominal relation.
>> */
>
> Rewrote that comment block as:
>
> *
> * If the parent is a partitioned table, we already set the nominal
> * relation.
> */
>
I reworded those comments a bit and corrected grammar. Please check in
the attached patch.
>
>> Following condition is not very readable. It's not evident that it's of the
>> form (A && B) || C, at a glance it looks like it's A && (B || C).
>> + if ((rte->relkind != RELKIND_PARTITIONED_TABLE &&
>> + list_length(appinfos) < 2) || list_length(appinfos) < 1)
>>
>> Instead you may rearrage it as
>> min_child_rels = (rte->relkind == RELKIND_PARTITIONED_TABLE ? 1 : 2);
>> if (list_length(appinfos) < min_child_rels)
>
> OK, done that way.
On a second thought, I added a boolean to check if there were any
children created and then reset rte->inh based on that value. That's
better than relying on appinfos length now.
Let me know what you think.
--
Best Wishes,
Ashutosh Bapat
EnterpriseDB Corporation
The Postgres Database Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Attachments:
[application/octet-stream] 0003-Avoid-creating-scan-nodes-for-partitioned-tables_v2.patch (17.1K, ../../CAFjFpRd0Pa2y_KJ1CPQ4V4vw8_dXo4h53aL7P1CkGj5Toa0M1A@mail.gmail.com/2-0003-Avoid-creating-scan-nodes-for-partitioned-tables_v2.patch)
download | inline diff:
From 66ac1388addfc0d4b7521937fd00141394df6f52 Mon Sep 17 00:00:00 2001
From: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
Date: Thu, 23 Feb 2017 12:06:46 +0530
Subject: [PATCH] Avoid creating scan nodes for partitioned tables.
Currently, we create scan nodes for inheritance parents in their role
as an inheritance set member. Partitioned tables do not contain any
data, so it's useless to create scan nodes for them. So we need not
create AppendRelInfo's for them in the planner prep phase.
Further, the planner prep phase turns off inheritance on the parent RTE
if there isn't at least one child member (other than the parent itself
which in normal cases is also a child member), which means the latter
phases will not consider creating an Append plan and instead create a
scan node. Avoid this if the RTE is a partitioned table, by noticing
such cases in set_rel_size(). Per suggestion from Ashutosh Bapat.
Next, since we do not add the RTE corresponding to the root partitioned
table as the 1st child member of the inheritance set, inheritance_planner()
must not assume the same when assigning nominalRelation to a ModifyTable
node.
---
src/backend/optimizer/path/allpaths.c | 8 +++
src/backend/optimizer/plan/planner.c | 14 +++-
src/backend/optimizer/prep/prepunion.c | 32 +++++++--
src/test/regress/expected/inherit.out | 124 ++++++++++----------------------
src/test/regress/sql/inherit.sql | 8 +++
5 files changed, 96 insertions(+), 90 deletions(-)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index eeacf81..ac3ec92 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -342,6 +342,14 @@ set_rel_size(PlannerInfo *root, RelOptInfo *rel,
/* Foreign table */
set_foreign_size(root, rel, rte);
}
+ else if (rte->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ /*
+ * A partitioned table without leaf partitions does not
+ * have any data, hence mark it as dummy.
+ */
+ set_dummy_rel_pathlist(rel);
+ }
else if (rte->tablesample != NULL)
{
/* Sampled relation */
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 3d33d46..5e84a82 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -996,10 +996,20 @@ inheritance_planner(PlannerInfo *root)
RelOptInfo *final_rel;
ListCell *lc;
Index rti;
+ RangeTblEntry *parent_rte;
Assert(parse->commandType != CMD_INSERT);
/*
+ * Partitioned tables do not have storage for themselves and should not be
+ * scanned. So, we do not create a child RTE and a child relation for the
+ * parent partitioned table. Hence use parent relation as nominal relation.
+ */
+ parent_rte = rt_fetch(parentRTindex, root->parse->rtable);
+ if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
+ nominalRelation = parentRTindex;
+
+ /*
* We generate a modified instance of the original Query for each target
* relation, plan that, and put all the plans into a list that will be
* controlled by a single ModifyTable node. All the instances share the
@@ -1060,7 +1070,6 @@ inheritance_planner(PlannerInfo *root)
{
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
PlannerInfo *subroot;
- RangeTblEntry *parent_rte;
RangeTblEntry *child_rte;
RelOptInfo *sub_final_rel;
Path *subpath;
@@ -1214,6 +1223,9 @@ inheritance_planner(PlannerInfo *root)
* will not be otherwise referenced in the plan, doing so would give
* rise to confusing use of multiple aliases in EXPLAIN output for
* what the user will think is the "same" table.)
+ *
+ * If the parent is a partitioned table, we have already set the
+ * nominal relation.
*/
if (nominalRelation < 0)
nominalRelation = appinfo->child_relid;
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 06e843d..1ae3b35 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -1364,6 +1364,7 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
List *inhOIDs;
List *appinfos;
ListCell *l;
+ bool has_real_child = false;
/* Does RT entry allow inheritance? */
if (!rte->inh)
@@ -1450,6 +1451,21 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
newrelation = oldrelation;
/*
+ * Partitioned tables themselves do not have any storage and should not
+ * be scanned. So, do not create child relations for those.
+ */
+ if (newrelation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ /*
+ * Don't lose the lock taken for us by find_all_inheritors()
+ * lest its partitions change under us.
+ */
+ if (newrelation != oldrelation)
+ heap_close(newrelation, NoLock);
+ continue;
+ }
+
+ /*
* It is possible that the parent table has children that are temp
* tables of other backends. We cannot safely access such tables
* (because of buffering issues), and the best thing to do seems to be
@@ -1512,6 +1528,12 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
appinfo->translated_vars);
childrte->updatedCols = translate_col_privs(rte->updatedCols,
appinfo->translated_vars);
+
+ /*
+ * We have a child which represents scan on a table different from
+ * the parent table.
+ */
+ has_real_child = true;
}
/*
@@ -1546,11 +1568,13 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
/*
* If all the children were temp tables, pretend it's a non-inheritance
- * situation. The duplicate RTE we added for the parent table is
- * harmless, so we don't bother to get rid of it; ditto for the useless
- * PlanRowMark node.
+ * situation. Similarly, if the partitioned table does not have any leaf
+ * partitions, pretend it's a non-inheritance. The planner will treat such
+ * a partitioned relation as dummy. The duplicate RTE we added for the
+ * parent table is harmless, so we don't bother to get rid of it; ditto for
+ * the useless PlanRowMark node.
*/
- if (list_length(appinfos) < 2)
+ if (!has_real_child)
{
/* Clear flag before returning */
rte->inh = false;
diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out
index a8c8b28..55b1474 100644
--- a/src/test/regress/expected/inherit.out
+++ b/src/test/regress/expected/inherit.out
@@ -1598,6 +1598,14 @@ reset enable_bitmapscan;
create table list_parted (
a varchar
) partition by list (a);
+-- test scanning partitioned table without any partitions
+explain (costs off) select * from list_parted;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
create table part_ab_cd partition of list_parted for values in ('ab', 'cd');
create table part_ef_gh partition of list_parted for values in ('ef', 'gh');
create table part_null_xy partition of list_parted for values in (null, 'xy');
@@ -1605,77 +1613,74 @@ explain (costs off) select * from list_parted;
QUERY PLAN
--------------------------------
Append
- -> Seq Scan on list_parted
-> Seq Scan on part_ab_cd
-> Seq Scan on part_ef_gh
-> Seq Scan on part_null_xy
-(5 rows)
+(4 rows)
explain (costs off) select * from list_parted where a is null;
QUERY PLAN
--------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (a IS NULL)
-> Seq Scan on part_null_xy
Filter: (a IS NULL)
-(5 rows)
+(3 rows)
explain (costs off) select * from list_parted where a is not null;
QUERY PLAN
---------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (a IS NOT NULL)
-> Seq Scan on part_ab_cd
Filter: (a IS NOT NULL)
-> Seq Scan on part_ef_gh
Filter: (a IS NOT NULL)
-> Seq Scan on part_null_xy
Filter: (a IS NOT NULL)
-(9 rows)
+(7 rows)
explain (costs off) select * from list_parted where a in ('ab', 'cd', 'ef');
QUERY PLAN
----------------------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-> Seq Scan on part_ab_cd
Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-> Seq Scan on part_ef_gh
Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-(7 rows)
+(5 rows)
explain (costs off) select * from list_parted where a = 'ab' or a in (null, 'cd');
QUERY PLAN
---------------------------------------------------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_ab_cd
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_ef_gh
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_null_xy
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-(9 rows)
+(7 rows)
explain (costs off) select * from list_parted where a = 'ab';
QUERY PLAN
------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: ((a)::text = 'ab'::text)
-> Seq Scan on part_ab_cd
Filter: ((a)::text = 'ab'::text)
-(5 rows)
+(3 rows)
create table range_list_parted (
a int,
b char(2)
) partition by range (a);
create table part_1_10 partition of range_list_parted for values from (1) to (10) partition by list (b);
+-- test scanning partitioned table without any leaf partitions
+explain (costs off) select * from range_list_parted;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
create table part_1_10_ab partition of part_1_10 for values in ('ab');
create table part_1_10_cd partition of part_1_10 for values in ('cd');
create table part_10_20 partition of range_list_parted for values from (10) to (20) partition by list (b);
@@ -1689,14 +1694,9 @@ create table part_40_inf_ab partition of part_40_inf for values in ('ab');
create table part_40_inf_cd partition of part_40_inf for values in ('cd');
create table part_40_inf_null partition of part_40_inf for values in (null);
explain (costs off) select * from range_list_parted;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- -> Seq Scan on part_1_10
- -> Seq Scan on part_10_20
- -> Seq Scan on part_21_30
- -> Seq Scan on part_40_inf
-> Seq Scan on part_1_10_ab
-> Seq Scan on part_1_10_cd
-> Seq Scan on part_10_20_ab
@@ -1706,36 +1706,22 @@ explain (costs off) select * from range_list_parted;
-> Seq Scan on part_40_inf_ab
-> Seq Scan on part_40_inf_cd
-> Seq Scan on part_40_inf_null
-(15 rows)
+(10 rows)
explain (costs off) select * from range_list_parted where a = 5;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+--------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (a = 5)
- -> Seq Scan on part_1_10
- Filter: (a = 5)
-> Seq Scan on part_1_10_ab
Filter: (a = 5)
-> Seq Scan on part_1_10_cd
Filter: (a = 5)
-(9 rows)
+(5 rows)
explain (costs off) select * from range_list_parted where b = 'ab';
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_1_10
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_10_20
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_21_30
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_40_inf
- Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_1_10_ab
Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_10_20_ab
@@ -1744,27 +1730,19 @@ explain (costs off) select * from range_list_parted where b = 'ab';
Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_40_inf_ab
Filter: (b = 'ab'::bpchar)
-(19 rows)
+(9 rows)
explain (costs off) select * from range_list_parted where a between 3 and 23 and b in ('ab');
QUERY PLAN
-----------------------------------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_1_10
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_10_20
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_21_30
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_1_10_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_10_20_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_21_30_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-(15 rows)
+(7 rows)
/* Should select no rows because range partition key cannot be null */
explain (costs off) select * from range_list_parted where a is null;
@@ -1776,37 +1754,17 @@ explain (costs off) select * from range_list_parted where a is null;
/* Should only select rows from the null-accepting partition */
explain (costs off) select * from range_list_parted where b is null;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (b IS NULL)
- -> Seq Scan on part_1_10
- Filter: (b IS NULL)
- -> Seq Scan on part_10_20
- Filter: (b IS NULL)
- -> Seq Scan on part_21_30
- Filter: (b IS NULL)
- -> Seq Scan on part_40_inf
- Filter: (b IS NULL)
-> Seq Scan on part_40_inf_null
Filter: (b IS NULL)
-(13 rows)
+(3 rows)
explain (costs off) select * from range_list_parted where a is not null and a < 67;
QUERY PLAN
------------------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_1_10
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_10_20
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_21_30
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_40_inf
- Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_1_10_ab
Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_1_10_cd
@@ -1825,23 +1783,19 @@ explain (costs off) select * from range_list_parted where a is not null and a <
Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_40_inf_null
Filter: ((a IS NOT NULL) AND (a < 67))
-(29 rows)
+(19 rows)
explain (costs off) select * from range_list_parted where a >= 30;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (a >= 30)
- -> Seq Scan on part_40_inf
- Filter: (a >= 30)
-> Seq Scan on part_40_inf_ab
Filter: (a >= 30)
-> Seq Scan on part_40_inf_cd
Filter: (a >= 30)
-> Seq Scan on part_40_inf_null
Filter: (a >= 30)
-(11 rows)
+(7 rows)
drop table list_parted cascade;
NOTICE: drop cascades to 3 other objects
diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql
index a8b7eb1..04cc4ff 100644
--- a/src/test/regress/sql/inherit.sql
+++ b/src/test/regress/sql/inherit.sql
@@ -570,6 +570,10 @@ reset enable_bitmapscan;
create table list_parted (
a varchar
) partition by list (a);
+
+-- test scanning partitioned table without any partitions
+explain (costs off) select * from list_parted;
+
create table part_ab_cd partition of list_parted for values in ('ab', 'cd');
create table part_ef_gh partition of list_parted for values in ('ef', 'gh');
create table part_null_xy partition of list_parted for values in (null, 'xy');
@@ -586,6 +590,10 @@ create table range_list_parted (
b char(2)
) partition by range (a);
create table part_1_10 partition of range_list_parted for values from (1) to (10) partition by list (b);
+
+-- test scanning partitioned table without any leaf partitions
+explain (costs off) select * from range_list_parted;
+
create table part_1_10_ab partition of part_1_10 for values in ('ab');
create table part_1_10_cd partition of part_1_10 for values in ('cd');
create table part_10_20 partition of range_list_parted for values from (10) to (20) partition by list (b);
--
1.7.9.5
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-23 06:44 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
@ 2017-02-23 07:38 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-23 07:48 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
0 siblings, 1 reply; 96+ messages in thread
From: Amit Langote @ 2017-02-23 07:38 UTC (permalink / raw)
To: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; +Cc: Robert Haas <robertmhaas@gmail.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
Thanks for the review.
On 2017/02/23 15:44, Ashutosh Bapat wrote:
> On Thu, Feb 23, 2017 at 11:19 AM, Amit Langote wrote:
>> Rewrote that comment block as:
>>
>> *
>> * If the parent is a partitioned table, we already set the nominal
>> * relation.
>> */
>>
>
> I reworded those comments a bit and corrected grammar. Please check in
> the attached patch.
What was there sounds grammatically correct to me, but fine.
>>> Following condition is not very readable. It's not evident that it's of the
>>> form (A && B) || C, at a glance it looks like it's A && (B || C).
>>> + if ((rte->relkind != RELKIND_PARTITIONED_TABLE &&
>>> + list_length(appinfos) < 2) || list_length(appinfos) < 1)
>>>
>>> Instead you may rearrage it as
>>> min_child_rels = (rte->relkind == RELKIND_PARTITIONED_TABLE ? 1 : 2);
>>> if (list_length(appinfos) < min_child_rels)
>>
>> OK, done that way.
>
> On a second thought, I added a boolean to check if there were any
> children created and then reset rte->inh based on that value. That's
> better than relying on appinfos length now.
@@ -996,10 +996,20 @@ inheritance_planner(PlannerInfo *root)
/*
+ * Partitioned tables do not have storage for themselves and should not be
+ * scanned.
@@ -1450,6 +1451,21 @@ expand_inherited_rtentry(PlannerInfo *root,
RangeTblEntry *rte, Index rti)
/*
+ * Partitioned tables themselves do not have any storage and should not
+ * be scanned. So, do not create child relations for those.
+ */
I guess we should not have to repeat "partitioned tables do not have
storage" in all these places.
+ * a partitioned relation as dummy. The duplicate RTE we added for the
+ * parent table is harmless, so we don't bother to get rid of it; ditto for
+ * the useless PlanRowMark node.
There is no duplicate RTE in the partitioned table case, which even my
original comment failed to consider. Can you, maybe?
Thanks,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-23 06:44 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 07:38 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-02-23 07:48 ` Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 08:08 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
0 siblings, 1 reply; 96+ messages in thread
From: Ashutosh Bapat @ 2017-02-23 07:48 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: Robert Haas <robertmhaas@gmail.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On Thu, Feb 23, 2017 at 1:08 PM, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
> Thanks for the review.
>
> On 2017/02/23 15:44, Ashutosh Bapat wrote:
>> On Thu, Feb 23, 2017 at 11:19 AM, Amit Langote wrote:
>>> Rewrote that comment block as:
>>>
>>> *
>>> * If the parent is a partitioned table, we already set the nominal
>>> * relation.
>>> */
>>>
>>
>> I reworded those comments a bit and corrected grammar. Please check in
>> the attached patch.
>
> What was there sounds grammatically correct to me, but fine.
>
>>>> Following condition is not very readable. It's not evident that it's of the
>>>> form (A && B) || C, at a glance it looks like it's A && (B || C).
>>>> + if ((rte->relkind != RELKIND_PARTITIONED_TABLE &&
>>>> + list_length(appinfos) < 2) || list_length(appinfos) < 1)
>>>>
>>>> Instead you may rearrage it as
>>>> min_child_rels = (rte->relkind == RELKIND_PARTITIONED_TABLE ? 1 : 2);
>>>> if (list_length(appinfos) < min_child_rels)
>>>
>>> OK, done that way.
>>
>> On a second thought, I added a boolean to check if there were any
>> children created and then reset rte->inh based on that value. That's
>> better than relying on appinfos length now.
>
> @@ -996,10 +996,20 @@ inheritance_planner(PlannerInfo *root)
> /*
> + * Partitioned tables do not have storage for themselves and should not be
> + * scanned.
>
> @@ -1450,6 +1451,21 @@ expand_inherited_rtentry(PlannerInfo *root,
> RangeTblEntry *rte, Index rti)
> /*
> + * Partitioned tables themselves do not have any storage and should not
> + * be scanned. So, do not create child relations for those.
> + */
>
> I guess we should not have to repeat "partitioned tables do not have
> storage" in all these places.
Hmm, you are right. But they are two different functions and the code
blocks are located away from each other. So, I thought it would be
better to have complete comment there, instead of pointing to other
places. I am fine, if we can reword it without compromising
readability.
>
> + * a partitioned relation as dummy. The duplicate RTE we added for the
> + * parent table is harmless, so we don't bother to get rid of it; ditto for
> + * the useless PlanRowMark node.
>
> There is no duplicate RTE in the partitioned table case, which even my
> original comment failed to consider. Can you, maybe?
May be we could says "If we have added duplicate RTE for the parent
table, it is harmless ...". Does that sound good?
--
Best Wishes,
Ashutosh Bapat
EnterpriseDB Corporation
The Postgres Database Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-23 06:44 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 07:38 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-23 07:48 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
@ 2017-02-23 08:08 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-23 08:49 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
0 siblings, 1 reply; 96+ messages in thread
From: Amit Langote @ 2017-02-23 08:08 UTC (permalink / raw)
To: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; +Cc: Robert Haas <robertmhaas@gmail.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On 2017/02/23 16:48, Ashutosh Bapat wrote:
> On Thu, Feb 23, 2017 at 1:08 PM, Amit Langote wrote:
>> @@ -996,10 +996,20 @@ inheritance_planner(PlannerInfo *root)
>> /*
>> + * Partitioned tables do not have storage for themselves and should not be
>> + * scanned.
>>
>> @@ -1450,6 +1451,21 @@ expand_inherited_rtentry(PlannerInfo *root,
>> RangeTblEntry *rte, Index rti)
>> /*
>> + * Partitioned tables themselves do not have any storage and should not
>> + * be scanned. So, do not create child relations for those.
>> + */
>>
>> I guess we should not have to repeat "partitioned tables do not have
>> storage" in all these places.
>
> Hmm, you are right. But they are two different functions and the code
> blocks are located away from each other. So, I thought it would be
> better to have complete comment there, instead of pointing to other
> places. I am fine, if we can reword it without compromising
> readability.
I was saying in general. I agree that different sites in the optimizer
may have different considerations for why partitioned tables are to be
handled specially, common theme being that we do not have to scan the
parent relation. If the implementation changes someday such that we don't
manipulate child tables (especially, partitions) through most planning
phases anymore, then maybe we will start using some different terminology
where we don't have to stress this fact too much. We're not there yet though.
>> + * a partitioned relation as dummy. The duplicate RTE we added for the
>> + * parent table is harmless, so we don't bother to get rid of it; ditto for
>> + * the useless PlanRowMark node.
>>
>> There is no duplicate RTE in the partitioned table case, which even my
>> original comment failed to consider. Can you, maybe?
>
> May be we could says "If we have added duplicate RTE for the parent
> table, it is harmless ...". Does that sound good?
Duplicate RTE added in the non-partitioned table case is harmless, so we
don't bother to get rid of it; ditto for the useless PlanRowMark node.
Thanks,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-23 06:44 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 07:38 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-23 07:48 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 08:08 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-02-23 08:49 ` Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
0 siblings, 0 replies; 96+ messages in thread
From: Ashutosh Bapat @ 2017-02-23 08:49 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: Robert Haas <robertmhaas@gmail.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On Thu, Feb 23, 2017 at 1:38 PM, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
> On 2017/02/23 16:48, Ashutosh Bapat wrote:
>> On Thu, Feb 23, 2017 at 1:08 PM, Amit Langote wrote:
>>> @@ -996,10 +996,20 @@ inheritance_planner(PlannerInfo *root)
>>> /*
>>> + * Partitioned tables do not have storage for themselves and should not be
>>> + * scanned.
>>>
>>> @@ -1450,6 +1451,21 @@ expand_inherited_rtentry(PlannerInfo *root,
>>> RangeTblEntry *rte, Index rti)
>>> /*
>>> + * Partitioned tables themselves do not have any storage and should not
>>> + * be scanned. So, do not create child relations for those.
>>> + */
>>>
>>> I guess we should not have to repeat "partitioned tables do not have
>>> storage" in all these places.
>>
>> Hmm, you are right. But they are two different functions and the code
>> blocks are located away from each other. So, I thought it would be
>> better to have complete comment there, instead of pointing to other
>> places. I am fine, if we can reword it without compromising
>> readability.
>
> I was saying in general. I agree that different sites in the optimizer
> may have different considerations for why partitioned tables are to be
> handled specially, common theme being that we do not have to scan the
> parent relation. If the implementation changes someday such that we don't
> manipulate child tables (especially, partitions) through most planning
> phases anymore, then maybe we will start using some different terminology
> where we don't have to stress this fact too much. We're not there yet though.
I agree.
>
>>> + * a partitioned relation as dummy. The duplicate RTE we added for the
>>> + * parent table is harmless, so we don't bother to get rid of it; ditto for
>>> + * the useless PlanRowMark node.
>>>
>>> There is no duplicate RTE in the partitioned table case, which even my
>>> original comment failed to consider. Can you, maybe?
>>
>> May be we could says "If we have added duplicate RTE for the parent
>> table, it is harmless ...". Does that sound good?
>
> Duplicate RTE added in the non-partitioned table case is harmless, so we
> don't bother to get rid of it; ditto for the useless PlanRowMark node.
Fine with me.
--
Best Wishes,
Ashutosh Bapat
EnterpriseDB Corporation
The Postgres Database Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-02-28 03:20 ` Robert Haas <robertmhaas@gmail.com>
2017-02-28 04:52 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
1 sibling, 2 replies; 96+ messages in thread
From: Robert Haas @ 2017-02-28 03:20 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On Thu, Feb 23, 2017 at 11:19 AM, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
> Thanks for the review.
In 0001, the documentation which you are patching has a section for
limitations that apply only to both partitioning and constraint
exclusion, and another for limitations that apply only to constraint
exclusion. Surely the patch should be moving a limitation that will
no longer apply to partitioning from the first section to the second
section, rather than leaving it in the section for limitations that
apply to both systems and just adding a note that say "this doesn't
apply to partitioning any more".
In acquire_inherited_sample_rows(), instead of inserting a whole
stanza of logic just above the existing dispatch on relkind, I think
we can get by with a very slightly update to what's already there.
You can't use the result of a & b as a bool. You need to write (a &
b) != 0, because the bool should always use 1 for true and 0 for
false; it should not set some higher-numbered bit.
The changes to autovacuum.c look useless, because
relation_needs_vacanalyze() will presumably never fire for a table
with no tuples of its own.
Updated patch with those changes and a few cosmetic tweaks attached.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Attachments:
[application/octet-stream] avoid-useless-partition-ops.patch (10.3K, ../../CA+TgmoY4q_oGaPqaFSb5ZDPCpaisU=+F0BzqAgy0e4aTxvT0og@mail.gmail.com/2-avoid-useless-partition-ops.patch)
download | inline diff:
diff --git a/doc/src/sgml/ddl.sgml b/doc/src/sgml/ddl.sgml
index ef0f7cf..62861fa 100644
--- a/doc/src/sgml/ddl.sgml
+++ b/doc/src/sgml/ddl.sgml
@@ -3834,19 +3834,6 @@ UNION ALL SELECT * FROM measurement_y2008m01;
<listitem>
<para>
- If you are using manual <command>VACUUM</command> or
- <command>ANALYZE</command> commands, don't forget that
- you need to run them on each partition individually. A command like:
-<programlisting>
-ANALYZE measurement;
-</programlisting>
- will only process the master table. This is true even for partitioned
- tables.
- </para>
- </listitem>
-
- <listitem>
- <para>
<command>INSERT</command> statements with <literal>ON CONFLICT</>
clauses are unlikely to work as expected, as the <literal>ON CONFLICT</>
action is only taken in case of unique violations on the specified
@@ -3903,6 +3890,17 @@ ANALYZE measurement;
</para>
</listitem>
+ <listitem>
+ <para>
+ If you are using manual <command>VACUUM</command> or
+ <command>ANALYZE</command> commands, you must run them on each partition
+ individually.
+<programlisting>
+ANALYZE measurement;
+</programlisting>
+ will only process the master table.
+ </para>
+ </listitem>
</itemizedlist>
</para>
</sect2>
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index ed3acb1..b6f2543 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -201,8 +201,7 @@ analyze_rel(Oid relid, RangeVar *relation, int options,
* locked the relation.
*/
if (onerel->rd_rel->relkind == RELKIND_RELATION ||
- onerel->rd_rel->relkind == RELKIND_MATVIEW ||
- onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ onerel->rd_rel->relkind == RELKIND_MATVIEW)
{
/* Regular table, so we'll use the regular row acquisition function */
acquirefunc = acquire_sample_rows;
@@ -234,6 +233,12 @@ analyze_rel(Oid relid, RangeVar *relation, int options,
return;
}
}
+ else if (onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ /*
+ * For partitioned tables, we want to do the recursive ANALYZE below.
+ */
+ }
else
{
/* No need for a WARNING if we already complained during VACUUM */
@@ -253,10 +258,12 @@ analyze_rel(Oid relid, RangeVar *relation, int options,
LWLockRelease(ProcArrayLock);
/*
- * Do the normal non-recursive ANALYZE.
+ * Do the normal non-recursive ANALYZE. We can skip this for partitioned
+ * tables, which don't contain any rows.
*/
- do_analyze_rel(onerel, options, params, va_cols, acquirefunc, relpages,
- false, in_outer_xact, elevel);
+ if (onerel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
+ do_analyze_rel(onerel, options, params, va_cols, acquirefunc,
+ relpages, false, in_outer_xact, elevel);
/*
* If there are child tables, do recursive ANALYZE.
@@ -1318,8 +1325,7 @@ acquire_inherited_sample_rows(Relation onerel, int elevel,
/* Check table type (MATVIEW can't happen, but might as well allow) */
if (childrel->rd_rel->relkind == RELKIND_RELATION ||
- childrel->rd_rel->relkind == RELKIND_MATVIEW ||
- childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ childrel->rd_rel->relkind == RELKIND_MATVIEW)
{
/* Regular table, so use the regular row acquisition function */
acquirefunc = acquire_sample_rows;
@@ -1351,9 +1357,12 @@ acquire_inherited_sample_rows(Relation onerel, int elevel,
}
else
{
- /* ignore, but release the lock on it */
- Assert(childrel != onerel);
- heap_close(childrel, AccessShareLock);
+ /*
+ * ignore, but release the lock on it. could be a partitioned
+ * table.
+ */
+ if (childrel != onerel)
+ heap_close(childrel, AccessShareLock);
continue;
}
@@ -1366,9 +1375,11 @@ acquire_inherited_sample_rows(Relation onerel, int elevel,
}
/*
- * If we don't have at least two tables to consider, fail.
+ * If we don't have at least one child table to consider, fail. If the
+ * relation is a partitioned table, it's not counted as a child table.
*/
- if (nrels < 2)
+ if ((onerel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE && nrels < 2) ||
+ nrels < 1)
{
ereport(elevel,
(errmsg("skipping analyze of \"%s.%s\" inheritance tree --- this inheritance tree contains no analyzable child tables",
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 3cea220..3170120 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -1349,6 +1349,10 @@ ExecuteTruncate(TruncateStmt *stmt)
{
Relation rel = (Relation) lfirst(cell);
+ /* Skip partitioned tables as there is nothing to do */
+ if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ continue;
+
/*
* Normally, we need a transaction-safe truncation here. However, if
* the table was either created in the current (sub)transaction or has
@@ -1459,7 +1463,11 @@ truncate_check_rel(Relation rel)
{
AclResult aclresult;
- /* Only allow truncate on regular tables */
+ /*
+ * Only allow truncate on regular tables and partitioned tables (although,
+ * the latter are only being included here for the following checks; no
+ * physical truncation will occur in their case.)
+ */
if (rel->rd_rel->relkind != RELKIND_RELATION &&
rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
ereport(ERROR,
@@ -4006,8 +4014,9 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode)
{
AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
- /* Foreign tables have no storage. */
- if (tab->relkind == RELKIND_FOREIGN_TABLE)
+ /* Foreign tables have no storage, nor do partitioned tables. */
+ if (tab->relkind == RELKIND_FOREIGN_TABLE ||
+ tab->relkind == RELKIND_PARTITIONED_TABLE)
continue;
/*
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 812fb4a..763ffc5 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -32,6 +32,7 @@
#include "access/xact.h"
#include "catalog/namespace.h"
#include "catalog/pg_database.h"
+#include "catalog/pg_inherits_fn.h"
#include "catalog/pg_namespace.h"
#include "commands/cluster.h"
#include "commands/vacuum.h"
@@ -66,7 +67,7 @@ static BufferAccessStrategy vac_strategy;
/* non-export function prototypes */
-static List *get_rel_oids(Oid relid, const RangeVar *vacrel);
+static List *get_rel_oids(Oid relid, const RangeVar *vacrel, bool is_vacuum);
static void vac_truncate_clog(TransactionId frozenXID,
MultiXactId minMulti,
TransactionId lastSaneFrozenXid,
@@ -228,7 +229,7 @@ vacuum(int options, RangeVar *relation, Oid relid, VacuumParams *params,
* Build list of relations to process, unless caller gave us one. (If we
* build one, we put it in vac_context for safekeeping.)
*/
- relations = get_rel_oids(relid, relation);
+ relations = get_rel_oids(relid, relation, (options & VACOPT_VACUUM) != 0);
/*
* Decide whether we need to start/commit our own transactions.
@@ -378,7 +379,7 @@ vacuum(int options, RangeVar *relation, Oid relid, VacuumParams *params,
* per-relation transactions.
*/
static List *
-get_rel_oids(Oid relid, const RangeVar *vacrel)
+get_rel_oids(Oid relid, const RangeVar *vacrel, bool is_vacuum)
{
List *oid_list = NIL;
MemoryContext oldcontext;
@@ -394,6 +395,9 @@ get_rel_oids(Oid relid, const RangeVar *vacrel)
{
/* Process a specific relation */
Oid relid;
+ HeapTuple tuple;
+ Form_pg_class classForm;
+ bool include_parts;
/*
* Since we don't take a lock here, the relation might be gone, or the
@@ -406,9 +410,29 @@ get_rel_oids(Oid relid, const RangeVar *vacrel)
*/
relid = RangeVarGetRelid(vacrel, NoLock, false);
- /* Make a relation list entry for this guy */
+ /*
+ * To check whether the relation is a partitioned table, fetch its
+ * syscache entry.
+ */
+ tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for relation %u", relid);
+ classForm = (Form_pg_class) GETSTRUCT(tuple);
+ include_parts = (classForm->relkind == RELKIND_PARTITIONED_TABLE);
+ ReleaseSysCache(tuple);
+
+ /*
+ * Make relation list entries for this guy and its partitions, if any.
+ * Note that the list returned by find_all_inheritors() include the
+ * passed-in OID at its head. Also note that we did not request a
+ * lock to be taken to match what would be done otherwise.
+ */
oldcontext = MemoryContextSwitchTo(vac_context);
- oid_list = lappend_oid(oid_list, relid);
+ if (include_parts)
+ oid_list = list_concat(oid_list,
+ find_all_inheritors(relid, NoLock, NULL));
+ else
+ oid_list = lappend_oid(oid_list, relid);
MemoryContextSwitchTo(oldcontext);
}
else
@@ -429,8 +453,23 @@ get_rel_oids(Oid relid, const RangeVar *vacrel)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
+ /*
+ * We include partitioned tables here; depending on which
+ * operation is to be performed, caller will decide whether to
+ * process or ignore them.
+ */
if (classForm->relkind != RELKIND_RELATION &&
- classForm->relkind != RELKIND_MATVIEW)
+ classForm->relkind != RELKIND_MATVIEW &&
+ classForm->relkind != RELKIND_PARTITIONED_TABLE)
+ continue;
+
+ /*
+ * If only ANALYZE is to be performed, there is no need to include
+ * partitions in the list. In a database-wide ANALYZE, we only
+ * update the inheritance statistics of partitioned tables, not
+ * the statistics of individual partitions.
+ */
+ if (!is_vacuum && classForm->relispartition)
continue;
/* Make a relation list entry for this guy */
@@ -1350,6 +1389,21 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params)
}
/*
+ * Ignore partitioned tables as there is no work to be done. Since we
+ * release the lock here, it's possible that any partitions added from
+ * this point on will not get processed, but that seems harmless.
+ */
+ if (onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ relation_close(onerel, lmode);
+ PopActiveSnapshot();
+ CommitTransactionCommand();
+
+ /* It's OK for other commands to look at this table */
+ return true;
+ }
+
+ /*
* Get a session-level lock too. This will protect our access to the
* relation across multiple transactions, so that we can vacuum the
* relation's TOAST table (if any) secure in the knowledge that no one is
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
@ 2017-02-28 04:52 ` Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-28 05:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
1 sibling, 1 reply; 96+ messages in thread
From: Ashutosh Bapat @ 2017-02-28 04:52 UTC (permalink / raw)
To: Robert Haas <robertmhaas@gmail.com>; +Cc: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
Amit's original patch had an assertion failure in
extract_autovac_opts(). His patch adds partitioned tables in the list
of tables to be auto-analyzed. But there's an assertion in
extract_autovac_opts(), which did not consider partitioned tables.
When a partitioned table is created, the assertion trips in autovacuum
worker and resets the cluster, restarting all the backends. I have
updated Robert's patch with the assertion fixed.
On Tue, Feb 28, 2017 at 8:50 AM, Robert Haas <robertmhaas@gmail.com> wrote:
> On Thu, Feb 23, 2017 at 11:19 AM, Amit Langote
> <Langote_Amit_f8@lab.ntt.co.jp> wrote:
>> Thanks for the review.
>
> In 0001, the documentation which you are patching has a section for
> limitations that apply only to both partitioning and constraint
> exclusion, and another for limitations that apply only to constraint
> exclusion. Surely the patch should be moving a limitation that will
> no longer apply to partitioning from the first section to the second
> section, rather than leaving it in the section for limitations that
> apply to both systems and just adding a note that say "this doesn't
> apply to partitioning any more".
>
> In acquire_inherited_sample_rows(), instead of inserting a whole
> stanza of logic just above the existing dispatch on relkind, I think
> we can get by with a very slightly update to what's already there.
>
> You can't use the result of a & b as a bool. You need to write (a &
> b) != 0, because the bool should always use 1 for true and 0 for
> false; it should not set some higher-numbered bit.
>
> The changes to autovacuum.c look useless, because
> relation_needs_vacanalyze() will presumably never fire for a table
> with no tuples of its own.
>
> Updated patch with those changes and a few cosmetic tweaks attached.
>
> --
> Robert Haas
> EnterpriseDB: http://www.enterprisedb.com
> The Enterprise PostgreSQL Company
--
Best Wishes,
Ashutosh Bapat
EnterpriseDB Corporation
The Postgres Database Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Attachments:
[application/octet-stream] avoid-useless-partition-ops_v2.patch (11.0K, ../../CAFjFpRd3WJGa0ZRcMWaw4Mt1oak1MzWkN-T=+VkxQeRKVUvjLA@mail.gmail.com/2-avoid-useless-partition-ops_v2.patch)
download | inline diff:
diff --git a/doc/src/sgml/ddl.sgml b/doc/src/sgml/ddl.sgml
index ef0f7cf..62861fa 100644
--- a/doc/src/sgml/ddl.sgml
+++ b/doc/src/sgml/ddl.sgml
@@ -3834,19 +3834,6 @@ UNION ALL SELECT * FROM measurement_y2008m01;
<listitem>
<para>
- If you are using manual <command>VACUUM</command> or
- <command>ANALYZE</command> commands, don't forget that
- you need to run them on each partition individually. A command like:
-<programlisting>
-ANALYZE measurement;
-</programlisting>
- will only process the master table. This is true even for partitioned
- tables.
- </para>
- </listitem>
-
- <listitem>
- <para>
<command>INSERT</command> statements with <literal>ON CONFLICT</>
clauses are unlikely to work as expected, as the <literal>ON CONFLICT</>
action is only taken in case of unique violations on the specified
@@ -3903,6 +3890,17 @@ ANALYZE measurement;
</para>
</listitem>
+ <listitem>
+ <para>
+ If you are using manual <command>VACUUM</command> or
+ <command>ANALYZE</command> commands, you must run them on each partition
+ individually.
+<programlisting>
+ANALYZE measurement;
+</programlisting>
+ will only process the master table.
+ </para>
+ </listitem>
</itemizedlist>
</para>
</sect2>
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index ed3acb1..b6f2543 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -201,8 +201,7 @@ analyze_rel(Oid relid, RangeVar *relation, int options,
* locked the relation.
*/
if (onerel->rd_rel->relkind == RELKIND_RELATION ||
- onerel->rd_rel->relkind == RELKIND_MATVIEW ||
- onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ onerel->rd_rel->relkind == RELKIND_MATVIEW)
{
/* Regular table, so we'll use the regular row acquisition function */
acquirefunc = acquire_sample_rows;
@@ -234,6 +233,12 @@ analyze_rel(Oid relid, RangeVar *relation, int options,
return;
}
}
+ else if (onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ /*
+ * For partitioned tables, we want to do the recursive ANALYZE below.
+ */
+ }
else
{
/* No need for a WARNING if we already complained during VACUUM */
@@ -253,10 +258,12 @@ analyze_rel(Oid relid, RangeVar *relation, int options,
LWLockRelease(ProcArrayLock);
/*
- * Do the normal non-recursive ANALYZE.
+ * Do the normal non-recursive ANALYZE. We can skip this for partitioned
+ * tables, which don't contain any rows.
*/
- do_analyze_rel(onerel, options, params, va_cols, acquirefunc, relpages,
- false, in_outer_xact, elevel);
+ if (onerel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
+ do_analyze_rel(onerel, options, params, va_cols, acquirefunc,
+ relpages, false, in_outer_xact, elevel);
/*
* If there are child tables, do recursive ANALYZE.
@@ -1318,8 +1325,7 @@ acquire_inherited_sample_rows(Relation onerel, int elevel,
/* Check table type (MATVIEW can't happen, but might as well allow) */
if (childrel->rd_rel->relkind == RELKIND_RELATION ||
- childrel->rd_rel->relkind == RELKIND_MATVIEW ||
- childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ childrel->rd_rel->relkind == RELKIND_MATVIEW)
{
/* Regular table, so use the regular row acquisition function */
acquirefunc = acquire_sample_rows;
@@ -1351,9 +1357,12 @@ acquire_inherited_sample_rows(Relation onerel, int elevel,
}
else
{
- /* ignore, but release the lock on it */
- Assert(childrel != onerel);
- heap_close(childrel, AccessShareLock);
+ /*
+ * ignore, but release the lock on it. could be a partitioned
+ * table.
+ */
+ if (childrel != onerel)
+ heap_close(childrel, AccessShareLock);
continue;
}
@@ -1366,9 +1375,11 @@ acquire_inherited_sample_rows(Relation onerel, int elevel,
}
/*
- * If we don't have at least two tables to consider, fail.
+ * If we don't have at least one child table to consider, fail. If the
+ * relation is a partitioned table, it's not counted as a child table.
*/
- if (nrels < 2)
+ if ((onerel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE && nrels < 2) ||
+ nrels < 1)
{
ereport(elevel,
(errmsg("skipping analyze of \"%s.%s\" inheritance tree --- this inheritance tree contains no analyzable child tables",
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 3cea220..3170120 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -1349,6 +1349,10 @@ ExecuteTruncate(TruncateStmt *stmt)
{
Relation rel = (Relation) lfirst(cell);
+ /* Skip partitioned tables as there is nothing to do */
+ if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ continue;
+
/*
* Normally, we need a transaction-safe truncation here. However, if
* the table was either created in the current (sub)transaction or has
@@ -1459,7 +1463,11 @@ truncate_check_rel(Relation rel)
{
AclResult aclresult;
- /* Only allow truncate on regular tables */
+ /*
+ * Only allow truncate on regular tables and partitioned tables (although,
+ * the latter are only being included here for the following checks; no
+ * physical truncation will occur in their case.)
+ */
if (rel->rd_rel->relkind != RELKIND_RELATION &&
rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
ereport(ERROR,
@@ -4006,8 +4014,9 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode)
{
AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
- /* Foreign tables have no storage. */
- if (tab->relkind == RELKIND_FOREIGN_TABLE)
+ /* Foreign tables have no storage, nor do partitioned tables. */
+ if (tab->relkind == RELKIND_FOREIGN_TABLE ||
+ tab->relkind == RELKIND_PARTITIONED_TABLE)
continue;
/*
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 812fb4a..763ffc5 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -32,6 +32,7 @@
#include "access/xact.h"
#include "catalog/namespace.h"
#include "catalog/pg_database.h"
+#include "catalog/pg_inherits_fn.h"
#include "catalog/pg_namespace.h"
#include "commands/cluster.h"
#include "commands/vacuum.h"
@@ -66,7 +67,7 @@ static BufferAccessStrategy vac_strategy;
/* non-export function prototypes */
-static List *get_rel_oids(Oid relid, const RangeVar *vacrel);
+static List *get_rel_oids(Oid relid, const RangeVar *vacrel, bool is_vacuum);
static void vac_truncate_clog(TransactionId frozenXID,
MultiXactId minMulti,
TransactionId lastSaneFrozenXid,
@@ -228,7 +229,7 @@ vacuum(int options, RangeVar *relation, Oid relid, VacuumParams *params,
* Build list of relations to process, unless caller gave us one. (If we
* build one, we put it in vac_context for safekeeping.)
*/
- relations = get_rel_oids(relid, relation);
+ relations = get_rel_oids(relid, relation, (options & VACOPT_VACUUM) != 0);
/*
* Decide whether we need to start/commit our own transactions.
@@ -378,7 +379,7 @@ vacuum(int options, RangeVar *relation, Oid relid, VacuumParams *params,
* per-relation transactions.
*/
static List *
-get_rel_oids(Oid relid, const RangeVar *vacrel)
+get_rel_oids(Oid relid, const RangeVar *vacrel, bool is_vacuum)
{
List *oid_list = NIL;
MemoryContext oldcontext;
@@ -394,6 +395,9 @@ get_rel_oids(Oid relid, const RangeVar *vacrel)
{
/* Process a specific relation */
Oid relid;
+ HeapTuple tuple;
+ Form_pg_class classForm;
+ bool include_parts;
/*
* Since we don't take a lock here, the relation might be gone, or the
@@ -406,9 +410,29 @@ get_rel_oids(Oid relid, const RangeVar *vacrel)
*/
relid = RangeVarGetRelid(vacrel, NoLock, false);
- /* Make a relation list entry for this guy */
+ /*
+ * To check whether the relation is a partitioned table, fetch its
+ * syscache entry.
+ */
+ tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for relation %u", relid);
+ classForm = (Form_pg_class) GETSTRUCT(tuple);
+ include_parts = (classForm->relkind == RELKIND_PARTITIONED_TABLE);
+ ReleaseSysCache(tuple);
+
+ /*
+ * Make relation list entries for this guy and its partitions, if any.
+ * Note that the list returned by find_all_inheritors() include the
+ * passed-in OID at its head. Also note that we did not request a
+ * lock to be taken to match what would be done otherwise.
+ */
oldcontext = MemoryContextSwitchTo(vac_context);
- oid_list = lappend_oid(oid_list, relid);
+ if (include_parts)
+ oid_list = list_concat(oid_list,
+ find_all_inheritors(relid, NoLock, NULL));
+ else
+ oid_list = lappend_oid(oid_list, relid);
MemoryContextSwitchTo(oldcontext);
}
else
@@ -429,8 +453,23 @@ get_rel_oids(Oid relid, const RangeVar *vacrel)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
+ /*
+ * We include partitioned tables here; depending on which
+ * operation is to be performed, caller will decide whether to
+ * process or ignore them.
+ */
if (classForm->relkind != RELKIND_RELATION &&
- classForm->relkind != RELKIND_MATVIEW)
+ classForm->relkind != RELKIND_MATVIEW &&
+ classForm->relkind != RELKIND_PARTITIONED_TABLE)
+ continue;
+
+ /*
+ * If only ANALYZE is to be performed, there is no need to include
+ * partitions in the list. In a database-wide ANALYZE, we only
+ * update the inheritance statistics of partitioned tables, not
+ * the statistics of individual partitions.
+ */
+ if (!is_vacuum && classForm->relispartition)
continue;
/* Make a relation list entry for this guy */
@@ -1350,6 +1389,21 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params)
}
/*
+ * Ignore partitioned tables as there is no work to be done. Since we
+ * release the lock here, it's possible that any partitions added from
+ * this point on will not get processed, but that seems harmless.
+ */
+ if (onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ relation_close(onerel, lmode);
+ PopActiveSnapshot();
+ CommitTransactionCommand();
+
+ /* It's OK for other commands to look at this table */
+ return true;
+ }
+
+ /*
* Get a session-level lock too. This will protect our access to the
* relation across multiple transactions, so that we can vacuum the
* relation's TOAST table (if any) secure in the knowledge that no one is
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 0c5ffa0..4f3bb2d 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -2513,7 +2513,8 @@ extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
- ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
+ ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE ||
+ ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_PARTITIONED_TABLE);
relopts = extractRelOptions(tup, pg_class_desc, NULL);
if (relopts == NULL)
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 04:52 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
@ 2017-02-28 05:03 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
0 siblings, 0 replies; 96+ messages in thread
From: Amit Langote @ 2017-02-28 05:03 UTC (permalink / raw)
To: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; Robert Haas <robertmhaas@gmail.com>; +Cc: Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On 2017/02/28 13:52, Ashutosh Bapat wrote:
> Amit's original patch had an assertion failure in
> extract_autovac_opts(). His patch adds partitioned tables in the list
> of tables to be auto-analyzed. But there's an assertion in
> extract_autovac_opts(), which did not consider partitioned tables.
> When a partitioned table is created, the assertion trips in autovacuum
> worker and resets the cluster, restarting all the backends. I have
> updated Robert's patch with the assertion fixed.
Since Robert's patch backed out all autovacuum.c changes, partitioned
tables case would no longer be able to reach that Assert.
Thanks,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
@ 2017-02-28 06:05 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
1 sibling, 1 reply; 96+ messages in thread
From: Amit Langote @ 2017-02-28 06:05 UTC (permalink / raw)
To: Robert Haas <robertmhaas@gmail.com>; +Cc: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
Thanks for the review. I was just about to send a new version of the patches.
On 2017/02/28 12:20, Robert Haas wrote:
> On Thu, Feb 23, 2017 at 11:19 AM, Amit Langote
> <Langote_Amit_f8@lab.ntt.co.jp> wrote:
>> Thanks for the review.
>
> In 0001, the documentation which you are patching has a section for
> limitations that apply only to both partitioning and constraint
> exclusion, and another for limitations that apply only to constraint
> exclusion. Surely the patch should be moving a limitation that will
> no longer apply to partitioning from the first section to the second
> section, rather than leaving it in the section for limitations that
> apply to both systems and just adding a note that say "this doesn't
> apply to partitioning any more".
So we have the following headings under 5.11.6 Caveats:
"The following caveats apply to partitioned tables implemented using
either method (unless noted otherwise)"
and,
"The following caveats apply to constraint exclusion"
The latter lists only the caveats about the planner capability (constraint
exclusion) for partitioning - that it cannot be performed against volatile
WHERE conditions, only works with comparisons using btree operators, does
not scale beyond hundred partitions, etc. These limitations are common to
both systems (inheritance and declarative partitioned tables), because
both rely on constraint exclusion.
How about separating the limitations listed under the first heading into:
"Limitations of using inheritance for partitioning"
and,
"Limitations of using partitioned tables"
This particular patch gets rid of the restriction that vacuum/analyze do
not recurse to child tables (partitions) only for the second of the above.
How about the documentation changes in the attached updated 0001? I know
that this page needs a much larger rewrite as we are discussing in the
other thread.
> In acquire_inherited_sample_rows(), instead of inserting a whole
> stanza of logic just above the existing dispatch on relkind, I think
> we can get by with a very slightly update to what's already there.
>
> You can't use the result of a & b as a bool. You need to write (a &
> b) != 0, because the bool should always use 1 for true and 0 for
> false; it should not set some higher-numbered bit.
Oops, thanks for fixing that. I suppose you are referring to this hunk in
the original patch:
- relations = get_rel_oids(relid, relation);
+ relations = get_rel_oids(relid, relation, options & VACOPT_VACUUM);
And we need to do it this way in *this* case, because we're passing it as
a bool argument. I see that it's OK to do this:
stmttype = (options & VACOPT_VACUUM) ? "VACUUM" : "ANALYZE";
Or this:
if (options & VACOPT_VACUUM)
{
PreventTransactionChain(isTopLevel, stmttype);
> The changes to autovacuum.c look useless, because
> relation_needs_vacanalyze() will presumably never fire for a table
> with no tuples of its own.
Hmm, I guess that makes sense. Inheritance statistics are never collected
by autovacuum (at least in the partitioning setups and especially with the
partitioned tables now). I recall that you mentioned [1] this as one of
the limitations of the system currently.
> Updated patch with those changes and a few cosmetic tweaks attached.
I have incorporated the changes in your patch in the attached updated
0001, with documentation tweaks as mentioned above.
Other than that, in acquire_inherited_sample_rows() I've used a method
suggested by Ashutosh Bapat to track if we encountered a child table,
which is much less ugly than below:
- if (nrels < 2)
+ if ((onerel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE && nrels <
2) ||
+ nrels < 1)
I keep updated 0002 and 0003 here, but I've changed their order. Don't
scan partitioned tables thing is now 0002 and don't allocate file for
partitioned tables is 0003. Sorry about the confusion.
Thanks,
Amit
[1]
https://postgr.es/m/CA%2BTgmobTxn2%2B0x96h5Le%2BGOK5kw3J37SRveNfzEdx9s5-Yd8vA%40mail.gmail.com
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Attachments:
[text/x-diff] 0001-Avoid-useless-partitioned-table-ops.patch (13.8K, ../../2afbddc5-7be9-6a7d-d499-c0a49fe2f663@lab.ntt.co.jp/2-0001-Avoid-useless-partitioned-table-ops.patch)
download | inline diff:
From 5e3a88765b87d872083700f3d6dc1ddd86b64ae6 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Tue, 28 Feb 2017 13:43:59 +0900
Subject: [PATCH 1/3] Avoid useless partitioned table ops
Also, recursively perform VACUUM and ANALYZE on partitions when the
command is applied to a partitioned table.
---
doc/src/sgml/ddl.sgml | 47 ++++++++++++++--------------
src/backend/commands/analyze.c | 37 ++++++++++++++--------
src/backend/commands/tablecmds.c | 15 +++++++--
src/backend/commands/vacuum.c | 66 ++++++++++++++++++++++++++++++++++++----
4 files changed, 120 insertions(+), 45 deletions(-)
diff --git a/doc/src/sgml/ddl.sgml b/doc/src/sgml/ddl.sgml
index ef0f7cf727..09b5b3ff70 100644
--- a/doc/src/sgml/ddl.sgml
+++ b/doc/src/sgml/ddl.sgml
@@ -3792,8 +3792,7 @@ UNION ALL SELECT * FROM measurement_y2008m01;
<title>Caveats</title>
<para>
- The following caveats apply to partitioned tables implemented using either
- method (unless noted otherwise):
+ The following caveats apply to using inheritance to implement partitioning:
<itemizedlist>
<listitem>
<para>
@@ -3803,13 +3802,6 @@ UNION ALL SELECT * FROM measurement_y2008m01;
partitions and creates and/or modifies associated objects than
to write each by hand.
</para>
-
- <para>
- This is not a problem with partitioned tables though, as trying to
- create a partition that overlaps with one of the existing partitions
- results in an error, so it is impossible to end up with partitions
- that overlap one another.
- </para>
</listitem>
<listitem>
@@ -3822,14 +3814,6 @@ UNION ALL SELECT * FROM measurement_y2008m01;
on the partition tables, but it makes management of the structure
much more complicated.
</para>
-
- <para>
- This problem exists even for partitioned tables. An <command>UPDATE</>
- that causes a row to move from one partition to another fails, because
- the new value of the row fails to satisfy the implicit partition
- constraint of the original partition. This might change in future
- releases.
- </para>
</listitem>
<listitem>
@@ -3840,8 +3824,7 @@ UNION ALL SELECT * FROM measurement_y2008m01;
<programlisting>
ANALYZE measurement;
</programlisting>
- will only process the master table. This is true even for partitioned
- tables.
+ will only process the master table.
</para>
</listitem>
@@ -3852,11 +3835,27 @@ ANALYZE measurement;
action is only taken in case of unique violations on the specified
target relation, not its child relations.
</para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ The following caveats apply to partitioned tables created with the
+ explicit syntax:
+ <itemizedlist>
+ <listitem>
+ <para>
+ An <command>UPDATE</> that causes a row to move from one partition to
+ another fails, because the new value of the row fails to satisfy the
+ implicit partition constraint of the original partition. This might
+ change in future releases.
+ </para>
+ </listitem>
+
+ <listitem>
<para>
<command>INSERT</command> statements with <literal>ON CONFLICT</>
- clause are currently not allowed on partitioned tables, that is,
- cause error when specified.
+ clause are currently not allowed on partitioned tables.
</para>
</listitem>
@@ -3864,7 +3863,8 @@ ANALYZE measurement;
</para>
<para>
- The following caveats apply to constraint exclusion:
+ The following caveats apply to constraint exclusion, which is currently
+ used by both inheritance and partitioned tables:
<itemizedlist>
<listitem>
@@ -3898,8 +3898,7 @@ ANALYZE measurement;
during constraint exclusion, so large numbers of partitions are likely
to increase query planning time considerably. Partitioning using
these techniques will work well with up to perhaps a hundred partitions;
- don't try to use many thousands of partitions. This restriction applies
- both to inheritance and explicit partitioning syntax.
+ don't try to use many thousands of partitions.
</para>
</listitem>
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index ed3acb1673..a70c760341 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -201,8 +201,7 @@ analyze_rel(Oid relid, RangeVar *relation, int options,
* locked the relation.
*/
if (onerel->rd_rel->relkind == RELKIND_RELATION ||
- onerel->rd_rel->relkind == RELKIND_MATVIEW ||
- onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ onerel->rd_rel->relkind == RELKIND_MATVIEW)
{
/* Regular table, so we'll use the regular row acquisition function */
acquirefunc = acquire_sample_rows;
@@ -234,6 +233,12 @@ analyze_rel(Oid relid, RangeVar *relation, int options,
return;
}
}
+ else if (onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ /*
+ * For partitioned tables, we want to do the recursive ANALYZE below.
+ */
+ }
else
{
/* No need for a WARNING if we already complained during VACUUM */
@@ -253,10 +258,12 @@ analyze_rel(Oid relid, RangeVar *relation, int options,
LWLockRelease(ProcArrayLock);
/*
- * Do the normal non-recursive ANALYZE.
+ * Do the normal non-recursive ANALYZE. We can skip this for partitioned
+ * tables, which don't contain any rows.
*/
- do_analyze_rel(onerel, options, params, va_cols, acquirefunc, relpages,
- false, in_outer_xact, elevel);
+ if (onerel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
+ do_analyze_rel(onerel, options, params, va_cols, acquirefunc,
+ relpages, false, in_outer_xact, elevel);
/*
* If there are child tables, do recursive ANALYZE.
@@ -1260,6 +1267,7 @@ acquire_inherited_sample_rows(Relation onerel, int elevel,
nrels,
i;
ListCell *lc;
+ bool has_child;
/*
* Find all members of inheritance set. We only need AccessShareLock on
@@ -1297,6 +1305,7 @@ acquire_inherited_sample_rows(Relation onerel, int elevel,
relblocks = (double *) palloc(list_length(tableOIDs) * sizeof(double));
totalblocks = 0;
nrels = 0;
+ has_child = false;
foreach(lc, tableOIDs)
{
Oid childOID = lfirst_oid(lc);
@@ -1318,8 +1327,7 @@ acquire_inherited_sample_rows(Relation onerel, int elevel,
/* Check table type (MATVIEW can't happen, but might as well allow) */
if (childrel->rd_rel->relkind == RELKIND_RELATION ||
- childrel->rd_rel->relkind == RELKIND_MATVIEW ||
- childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ childrel->rd_rel->relkind == RELKIND_MATVIEW)
{
/* Regular table, so use the regular row acquisition function */
acquirefunc = acquire_sample_rows;
@@ -1351,13 +1359,17 @@ acquire_inherited_sample_rows(Relation onerel, int elevel,
}
else
{
- /* ignore, but release the lock on it */
- Assert(childrel != onerel);
- heap_close(childrel, AccessShareLock);
+ /*
+ * ignore, but release the lock on it. could be a partitioned
+ * table.
+ */
+ if (childrel != onerel)
+ heap_close(childrel, AccessShareLock);
continue;
}
/* OK, we'll process this child */
+ has_child = true;
rels[nrels] = childrel;
acquirefuncs[nrels] = acquirefunc;
relblocks[nrels] = (double) relpages;
@@ -1366,9 +1378,10 @@ acquire_inherited_sample_rows(Relation onerel, int elevel,
}
/*
- * If we don't have at least two tables to consider, fail.
+ * If we don't have at least one child table to consider, fail. If the
+ * relation is a partitioned table, it's not counted as a child table.
*/
- if (nrels < 2)
+ if (!has_child)
{
ereport(elevel,
(errmsg("skipping analyze of \"%s.%s\" inheritance tree --- this inheritance tree contains no analyzable child tables",
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 3cea220421..317012068b 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -1349,6 +1349,10 @@ ExecuteTruncate(TruncateStmt *stmt)
{
Relation rel = (Relation) lfirst(cell);
+ /* Skip partitioned tables as there is nothing to do */
+ if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ continue;
+
/*
* Normally, we need a transaction-safe truncation here. However, if
* the table was either created in the current (sub)transaction or has
@@ -1459,7 +1463,11 @@ truncate_check_rel(Relation rel)
{
AclResult aclresult;
- /* Only allow truncate on regular tables */
+ /*
+ * Only allow truncate on regular tables and partitioned tables (although,
+ * the latter are only being included here for the following checks; no
+ * physical truncation will occur in their case.)
+ */
if (rel->rd_rel->relkind != RELKIND_RELATION &&
rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
ereport(ERROR,
@@ -4006,8 +4014,9 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode)
{
AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
- /* Foreign tables have no storage. */
- if (tab->relkind == RELKIND_FOREIGN_TABLE)
+ /* Foreign tables have no storage, nor do partitioned tables. */
+ if (tab->relkind == RELKIND_FOREIGN_TABLE ||
+ tab->relkind == RELKIND_PARTITIONED_TABLE)
continue;
/*
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 812fb4a48f..763ffc5363 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -32,6 +32,7 @@
#include "access/xact.h"
#include "catalog/namespace.h"
#include "catalog/pg_database.h"
+#include "catalog/pg_inherits_fn.h"
#include "catalog/pg_namespace.h"
#include "commands/cluster.h"
#include "commands/vacuum.h"
@@ -66,7 +67,7 @@ static BufferAccessStrategy vac_strategy;
/* non-export function prototypes */
-static List *get_rel_oids(Oid relid, const RangeVar *vacrel);
+static List *get_rel_oids(Oid relid, const RangeVar *vacrel, bool is_vacuum);
static void vac_truncate_clog(TransactionId frozenXID,
MultiXactId minMulti,
TransactionId lastSaneFrozenXid,
@@ -228,7 +229,7 @@ vacuum(int options, RangeVar *relation, Oid relid, VacuumParams *params,
* Build list of relations to process, unless caller gave us one. (If we
* build one, we put it in vac_context for safekeeping.)
*/
- relations = get_rel_oids(relid, relation);
+ relations = get_rel_oids(relid, relation, (options & VACOPT_VACUUM) != 0);
/*
* Decide whether we need to start/commit our own transactions.
@@ -378,7 +379,7 @@ vacuum(int options, RangeVar *relation, Oid relid, VacuumParams *params,
* per-relation transactions.
*/
static List *
-get_rel_oids(Oid relid, const RangeVar *vacrel)
+get_rel_oids(Oid relid, const RangeVar *vacrel, bool is_vacuum)
{
List *oid_list = NIL;
MemoryContext oldcontext;
@@ -394,6 +395,9 @@ get_rel_oids(Oid relid, const RangeVar *vacrel)
{
/* Process a specific relation */
Oid relid;
+ HeapTuple tuple;
+ Form_pg_class classForm;
+ bool include_parts;
/*
* Since we don't take a lock here, the relation might be gone, or the
@@ -406,9 +410,29 @@ get_rel_oids(Oid relid, const RangeVar *vacrel)
*/
relid = RangeVarGetRelid(vacrel, NoLock, false);
- /* Make a relation list entry for this guy */
+ /*
+ * To check whether the relation is a partitioned table, fetch its
+ * syscache entry.
+ */
+ tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for relation %u", relid);
+ classForm = (Form_pg_class) GETSTRUCT(tuple);
+ include_parts = (classForm->relkind == RELKIND_PARTITIONED_TABLE);
+ ReleaseSysCache(tuple);
+
+ /*
+ * Make relation list entries for this guy and its partitions, if any.
+ * Note that the list returned by find_all_inheritors() include the
+ * passed-in OID at its head. Also note that we did not request a
+ * lock to be taken to match what would be done otherwise.
+ */
oldcontext = MemoryContextSwitchTo(vac_context);
- oid_list = lappend_oid(oid_list, relid);
+ if (include_parts)
+ oid_list = list_concat(oid_list,
+ find_all_inheritors(relid, NoLock, NULL));
+ else
+ oid_list = lappend_oid(oid_list, relid);
MemoryContextSwitchTo(oldcontext);
}
else
@@ -429,8 +453,23 @@ get_rel_oids(Oid relid, const RangeVar *vacrel)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
+ /*
+ * We include partitioned tables here; depending on which
+ * operation is to be performed, caller will decide whether to
+ * process or ignore them.
+ */
if (classForm->relkind != RELKIND_RELATION &&
- classForm->relkind != RELKIND_MATVIEW)
+ classForm->relkind != RELKIND_MATVIEW &&
+ classForm->relkind != RELKIND_PARTITIONED_TABLE)
+ continue;
+
+ /*
+ * If only ANALYZE is to be performed, there is no need to include
+ * partitions in the list. In a database-wide ANALYZE, we only
+ * update the inheritance statistics of partitioned tables, not
+ * the statistics of individual partitions.
+ */
+ if (!is_vacuum && classForm->relispartition)
continue;
/* Make a relation list entry for this guy */
@@ -1350,6 +1389,21 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params)
}
/*
+ * Ignore partitioned tables as there is no work to be done. Since we
+ * release the lock here, it's possible that any partitions added from
+ * this point on will not get processed, but that seems harmless.
+ */
+ if (onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ relation_close(onerel, lmode);
+ PopActiveSnapshot();
+ CommitTransactionCommand();
+
+ /* It's OK for other commands to look at this table */
+ return true;
+ }
+
+ /*
* Get a session-level lock too. This will protect our access to the
* relation across multiple transactions, so that we can vacuum the
* relation's TOAST table (if any) secure in the knowledge that no one is
--
2.11.0
[text/x-diff] 0002-Avoid-creating-scan-nodes-for-partitioned-tables.patch (21.1K, ../../2afbddc5-7be9-6a7d-d499-c0a49fe2f663@lab.ntt.co.jp/3-0002-Avoid-creating-scan-nodes-for-partitioned-tables.patch)
download | inline diff:
From c1a8b4240d8a13d9ba6c7b665d770db7e1e737f2 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Mon, 6 Feb 2017 17:26:48 +0900
Subject: [PATCH 2/3] Avoid creating scan nodes for partitioned tables
* Currently, we create scan nodes for inheritance parents in their role
as an inheritance set member. Partitioned tables do not contain any
data, so it's useless to create scan nodes for them. So we need not
create AppendRelInfo's for them in the planner prep phase.
* The planner prep phase turns off inheritance on the parent RTE if
there isn't at least one child member (other than the parent itself
which in normal cases is also a child member), which means the latter
phases will not consider creating an Append plan and instead create a
scan node. Avoid this if the RTE is a partitioned table, by noticing
such cases in set_rel_size(). Per suggestion from Ashutosh Bapat.
* Since we do not add the RTE corresponding to the root partitioned
table as the 1st child member of the inheritance set,
inheritance_planner() must not assume the same when assigning
nominalRelation to a ModifyTable node.
* In ExecInitModifyTable(), use nominalRelation to initialize tuple
routing information, instead of the first resultRelInfo. We set
ModifyTable.nominalRelation to the root parent RTE in the
partitioned table case (implicitly in the INSERT case, whereas
explicitly in the UPDATE/DELETE cases).
---
src/backend/executor/nodeModifyTable.c | 18 +++--
src/backend/optimizer/path/allpaths.c | 8 ++
src/backend/optimizer/plan/planner.c | 14 +++-
src/backend/optimizer/prep/prepunion.c | 32 ++++++--
src/test/regress/expected/inherit.out | 124 ++++++++++--------------------
src/test/regress/expected/tablesample.out | 4 +-
src/test/regress/sql/inherit.sql | 8 ++
7 files changed, 108 insertions(+), 100 deletions(-)
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 95e158970c..188ce8f8d4 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -45,6 +45,7 @@
#include "foreign/fdwapi.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
+#include "parser/parsetree.h"
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
#include "utils/builtins.h"
@@ -1634,7 +1635,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
Plan *subplan;
ListCell *l;
int i;
- Relation rel;
+ Relation nominalRel;
+ RangeTblEntry *nominalRTE;
/* check for unsupported flags */
Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
@@ -1726,9 +1728,10 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
estate->es_result_relation_info = saved_resultRelInfo;
/* Build state for INSERT tuple routing */
- rel = mtstate->resultRelInfo->ri_RelationDesc;
+ nominalRTE = rt_fetch(node->nominalRelation, estate->es_range_table);
+ nominalRel = heap_open(nominalRTE->relid, NoLock);
if (operation == CMD_INSERT &&
- rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ nominalRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
{
PartitionDispatch *partition_dispatch_info;
ResultRelInfo *partitions;
@@ -1737,7 +1740,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
int num_parted,
num_partitions;
- ExecSetupPartitionTupleRouting(rel,
+ ExecSetupPartitionTupleRouting(nominalRel,
&partition_dispatch_info,
&partitions,
&partition_tupconv_maps,
@@ -1801,7 +1804,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
/* varno = node->nominalRelation */
mapped_wcoList = map_partition_varattnos(wcoList,
node->nominalRelation,
- partrel, rel);
+ partrel, nominalRel);
foreach(ll, mapped_wcoList)
{
WithCheckOption *wco = (WithCheckOption *) lfirst(ll);
@@ -1876,7 +1879,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
/* varno = node->nominalRelation */
rlist = map_partition_varattnos(returningList,
node->nominalRelation,
- partrel, rel);
+ partrel, nominalRel);
rliststate = (List *) ExecInitExpr((Expr *) rlist, &mtstate->ps);
resultRelInfo->ri_projectReturning =
ExecBuildProjectionInfo(rliststate, econtext, slot,
@@ -1897,6 +1900,9 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
mtstate->ps.ps_ExprContext = NULL;
}
+ /* We're done using it. */
+ heap_close(nominalRel, NoLock);
+
/*
* If needed, Initialize target list, projection and qual for ON CONFLICT
* DO UPDATE.
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 633b5c1608..f2c8d27193 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -342,6 +342,14 @@ set_rel_size(PlannerInfo *root, RelOptInfo *rel,
/* Foreign table */
set_foreign_size(root, rel, rte);
}
+ else if (rte->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ /*
+ * A partitioned table without leaf partitions is marked
+ * as a dummy rel.
+ */
+ set_dummy_rel_pathlist(rel);
+ }
else if (rte->tablesample != NULL)
{
/* Sampled relation */
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index ca0ae7883e..b5698f0ce7 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -996,10 +996,20 @@ inheritance_planner(PlannerInfo *root)
RelOptInfo *final_rel;
ListCell *lc;
Index rti;
+ RangeTblEntry *parent_rte;
Assert(parse->commandType != CMD_INSERT);
/*
+ * If the parent RTE is a partitioned table, we should use that as the
+ * nominal relation, because we do not have the duplicate parent RTE,
+ * unlike in the case of a non-partitioned inheritance parent.
+ */
+ parent_rte = rt_fetch(parentRTindex, root->parse->rtable);
+ if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
+ nominalRelation = parentRTindex;
+
+ /*
* We generate a modified instance of the original Query for each target
* relation, plan that, and put all the plans into a list that will be
* controlled by a single ModifyTable node. All the instances share the
@@ -1060,7 +1070,6 @@ inheritance_planner(PlannerInfo *root)
{
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
PlannerInfo *subroot;
- RangeTblEntry *parent_rte;
RangeTblEntry *child_rte;
RelOptInfo *sub_final_rel;
Path *subpath;
@@ -1214,6 +1223,9 @@ inheritance_planner(PlannerInfo *root)
* will not be otherwise referenced in the plan, doing so would give
* rise to confusing use of multiple aliases in EXPLAIN output for
* what the user will think is the "same" table.)
+ *
+ * If the parent is a partitioned table, we already set the nominal
+ * relation.
*/
if (nominalRelation < 0)
nominalRelation = appinfo->child_relid;
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 1389db18ba..b4c65c4a90 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -1364,6 +1364,7 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
List *inhOIDs;
List *appinfos;
ListCell *l;
+ bool has_child;
/* Does RT entry allow inheritance? */
if (!rte->inh)
@@ -1435,6 +1436,7 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
/* Scan the inheritance set and expand it */
appinfos = NIL;
+ has_child = false;
foreach(l, inhOIDs)
{
Oid childOID = lfirst_oid(l);
@@ -1450,6 +1452,22 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
newrelation = oldrelation;
/*
+ * Since partitioned tables themselves do not contain data, later
+ * planning steps should not create scan nodes for them. So do not
+ * create the child RTE and AppendRelInfo.
+ */
+ if (newrelation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ /*
+ * Don't lose the lock taken for us by find_all_inheritors()
+ * lest its partitions change under us.
+ */
+ if (newrelation != oldrelation)
+ heap_close(newrelation, NoLock);
+ continue;
+ }
+
+ /*
* It is possible that the parent table has children that are temp
* tables of other backends. We cannot safely access such tables
* (because of buffering issues), and the best thing to do seems to be
@@ -1461,6 +1479,9 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
continue;
}
+ /* We have a child table. */
+ has_child = true;
+
/*
* Build an RTE for the child, and attach to query's rangetable list.
* We copy most fields of the parent's RTE, but replace relation OID
@@ -1545,12 +1566,13 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
heap_close(oldrelation, NoLock);
/*
- * If all the children were temp tables, pretend it's a non-inheritance
- * situation. The duplicate RTE we added for the parent table is
- * harmless, so we don't bother to get rid of it; ditto for the useless
- * PlanRowMark node.
+ * If all the children were temp tables or if the parent is a partitioned
+ * table without any leaf partitions, pretend it's a non-inheritance
+ * situation. The duplicate RTE for the parent table we added in the
+ * non-partitioned table case is harmless, so we don't bother to get rid
+ * of it; ditto for the useless PlanRowMark node.
*/
- if (list_length(appinfos) < 2)
+ if (!has_child)
{
/* Clear flag before returning */
rte->inh = false;
diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out
index a8c8b28a75..55b147432f 100644
--- a/src/test/regress/expected/inherit.out
+++ b/src/test/regress/expected/inherit.out
@@ -1598,6 +1598,14 @@ reset enable_bitmapscan;
create table list_parted (
a varchar
) partition by list (a);
+-- test scanning partitioned table without any partitions
+explain (costs off) select * from list_parted;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
create table part_ab_cd partition of list_parted for values in ('ab', 'cd');
create table part_ef_gh partition of list_parted for values in ('ef', 'gh');
create table part_null_xy partition of list_parted for values in (null, 'xy');
@@ -1605,77 +1613,74 @@ explain (costs off) select * from list_parted;
QUERY PLAN
--------------------------------
Append
- -> Seq Scan on list_parted
-> Seq Scan on part_ab_cd
-> Seq Scan on part_ef_gh
-> Seq Scan on part_null_xy
-(5 rows)
+(4 rows)
explain (costs off) select * from list_parted where a is null;
QUERY PLAN
--------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (a IS NULL)
-> Seq Scan on part_null_xy
Filter: (a IS NULL)
-(5 rows)
+(3 rows)
explain (costs off) select * from list_parted where a is not null;
QUERY PLAN
---------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (a IS NOT NULL)
-> Seq Scan on part_ab_cd
Filter: (a IS NOT NULL)
-> Seq Scan on part_ef_gh
Filter: (a IS NOT NULL)
-> Seq Scan on part_null_xy
Filter: (a IS NOT NULL)
-(9 rows)
+(7 rows)
explain (costs off) select * from list_parted where a in ('ab', 'cd', 'ef');
QUERY PLAN
----------------------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-> Seq Scan on part_ab_cd
Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-> Seq Scan on part_ef_gh
Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-(7 rows)
+(5 rows)
explain (costs off) select * from list_parted where a = 'ab' or a in (null, 'cd');
QUERY PLAN
---------------------------------------------------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_ab_cd
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_ef_gh
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_null_xy
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-(9 rows)
+(7 rows)
explain (costs off) select * from list_parted where a = 'ab';
QUERY PLAN
------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: ((a)::text = 'ab'::text)
-> Seq Scan on part_ab_cd
Filter: ((a)::text = 'ab'::text)
-(5 rows)
+(3 rows)
create table range_list_parted (
a int,
b char(2)
) partition by range (a);
create table part_1_10 partition of range_list_parted for values from (1) to (10) partition by list (b);
+-- test scanning partitioned table without any leaf partitions
+explain (costs off) select * from range_list_parted;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
create table part_1_10_ab partition of part_1_10 for values in ('ab');
create table part_1_10_cd partition of part_1_10 for values in ('cd');
create table part_10_20 partition of range_list_parted for values from (10) to (20) partition by list (b);
@@ -1689,14 +1694,9 @@ create table part_40_inf_ab partition of part_40_inf for values in ('ab');
create table part_40_inf_cd partition of part_40_inf for values in ('cd');
create table part_40_inf_null partition of part_40_inf for values in (null);
explain (costs off) select * from range_list_parted;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- -> Seq Scan on part_1_10
- -> Seq Scan on part_10_20
- -> Seq Scan on part_21_30
- -> Seq Scan on part_40_inf
-> Seq Scan on part_1_10_ab
-> Seq Scan on part_1_10_cd
-> Seq Scan on part_10_20_ab
@@ -1706,36 +1706,22 @@ explain (costs off) select * from range_list_parted;
-> Seq Scan on part_40_inf_ab
-> Seq Scan on part_40_inf_cd
-> Seq Scan on part_40_inf_null
-(15 rows)
+(10 rows)
explain (costs off) select * from range_list_parted where a = 5;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+--------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (a = 5)
- -> Seq Scan on part_1_10
- Filter: (a = 5)
-> Seq Scan on part_1_10_ab
Filter: (a = 5)
-> Seq Scan on part_1_10_cd
Filter: (a = 5)
-(9 rows)
+(5 rows)
explain (costs off) select * from range_list_parted where b = 'ab';
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_1_10
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_10_20
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_21_30
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_40_inf
- Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_1_10_ab
Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_10_20_ab
@@ -1744,27 +1730,19 @@ explain (costs off) select * from range_list_parted where b = 'ab';
Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_40_inf_ab
Filter: (b = 'ab'::bpchar)
-(19 rows)
+(9 rows)
explain (costs off) select * from range_list_parted where a between 3 and 23 and b in ('ab');
QUERY PLAN
-----------------------------------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_1_10
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_10_20
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_21_30
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_1_10_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_10_20_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_21_30_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-(15 rows)
+(7 rows)
/* Should select no rows because range partition key cannot be null */
explain (costs off) select * from range_list_parted where a is null;
@@ -1776,37 +1754,17 @@ explain (costs off) select * from range_list_parted where a is null;
/* Should only select rows from the null-accepting partition */
explain (costs off) select * from range_list_parted where b is null;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (b IS NULL)
- -> Seq Scan on part_1_10
- Filter: (b IS NULL)
- -> Seq Scan on part_10_20
- Filter: (b IS NULL)
- -> Seq Scan on part_21_30
- Filter: (b IS NULL)
- -> Seq Scan on part_40_inf
- Filter: (b IS NULL)
-> Seq Scan on part_40_inf_null
Filter: (b IS NULL)
-(13 rows)
+(3 rows)
explain (costs off) select * from range_list_parted where a is not null and a < 67;
QUERY PLAN
------------------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_1_10
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_10_20
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_21_30
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_40_inf
- Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_1_10_ab
Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_1_10_cd
@@ -1825,23 +1783,19 @@ explain (costs off) select * from range_list_parted where a is not null and a <
Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_40_inf_null
Filter: ((a IS NOT NULL) AND (a < 67))
-(29 rows)
+(19 rows)
explain (costs off) select * from range_list_parted where a >= 30;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (a >= 30)
- -> Seq Scan on part_40_inf
- Filter: (a >= 30)
-> Seq Scan on part_40_inf_ab
Filter: (a >= 30)
-> Seq Scan on part_40_inf_cd
Filter: (a >= 30)
-> Seq Scan on part_40_inf_null
Filter: (a >= 30)
-(11 rows)
+(7 rows)
drop table list_parted cascade;
NOTICE: drop cascades to 3 other objects
diff --git a/src/test/regress/expected/tablesample.out b/src/test/regress/expected/tablesample.out
index b18e420e9b..d3794140fb 100644
--- a/src/test/regress/expected/tablesample.out
+++ b/src/test/regress/expected/tablesample.out
@@ -322,12 +322,10 @@ explain (costs off)
QUERY PLAN
-------------------------------------------
Append
- -> Sample Scan on parted_sample
- Sampling: bernoulli ('100'::real)
-> Sample Scan on parted_sample_1
Sampling: bernoulli ('100'::real)
-> Sample Scan on parted_sample_2
Sampling: bernoulli ('100'::real)
-(7 rows)
+(5 rows)
drop table parted_sample, parted_sample_1, parted_sample_2;
diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql
index a8b7eb1c8d..04cc4ffa23 100644
--- a/src/test/regress/sql/inherit.sql
+++ b/src/test/regress/sql/inherit.sql
@@ -570,6 +570,10 @@ reset enable_bitmapscan;
create table list_parted (
a varchar
) partition by list (a);
+
+-- test scanning partitioned table without any partitions
+explain (costs off) select * from list_parted;
+
create table part_ab_cd partition of list_parted for values in ('ab', 'cd');
create table part_ef_gh partition of list_parted for values in ('ef', 'gh');
create table part_null_xy partition of list_parted for values in (null, 'xy');
@@ -586,6 +590,10 @@ create table range_list_parted (
b char(2)
) partition by range (a);
create table part_1_10 partition of range_list_parted for values from (1) to (10) partition by list (b);
+
+-- test scanning partitioned table without any leaf partitions
+explain (costs off) select * from range_list_parted;
+
create table part_1_10_ab partition of part_1_10 for values in ('ab');
create table part_1_10_cd partition of part_1_10 for values in ('cd');
create table part_10_20 partition of range_list_parted for values from (10) to (20) partition by list (b);
--
2.11.0
[text/x-diff] 0003-Do-not-allocate-storage-for-partitioned-tables.patch (3.1K, ../../2afbddc5-7be9-6a7d-d499-c0a49fe2f663@lab.ntt.co.jp/4-0003-Do-not-allocate-storage-for-partitioned-tables.patch)
download | inline diff:
From 5ac0d8e676984e15d51908f2377770ec82f07c42 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Tue, 24 Jan 2017 14:22:34 +0900
Subject: [PATCH 3/3] Do not allocate storage for partitioned tables.
Currently, it is not possible to insert any data into a partitioned
table. So, they're empty at all times, which means it is wasteful to
allocate relfilenode and related storage objects.
---
src/backend/access/common/reloptions.c | 3 +--
src/backend/catalog/heap.c | 17 ++++++++++-------
2 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 42b4ea410f..79a75152f0 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -932,7 +932,6 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
case RELKIND_RELATION:
case RELKIND_TOASTVALUE:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
options = heap_reloptions(classForm->relkind, datum, false);
break;
case RELKIND_VIEW:
@@ -942,6 +941,7 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
options = index_reloptions(amoptions, datum, false);
break;
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
options = NULL;
break;
default:
@@ -1384,7 +1384,6 @@ heap_reloptions(char relkind, Datum reloptions, bool validate)
return (bytea *) rdopts;
case RELKIND_RELATION:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
default:
/* other relkinds are not supported */
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 41c0056556..2f5090b183 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -291,6 +291,7 @@ heap_create(const char *relname,
case RELKIND_VIEW:
case RELKIND_COMPOSITE_TYPE:
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
create_storage = false;
/*
@@ -1345,14 +1346,13 @@ heap_create_with_catalog(const char *relname,
if (oncommit != ONCOMMIT_NOOP)
register_on_commit_action(relid, oncommit);
- if (relpersistence == RELPERSISTENCE_UNLOGGED)
- {
- Assert(relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW ||
- relkind == RELKIND_TOASTVALUE ||
- relkind == RELKIND_PARTITIONED_TABLE);
-
+ /*
+ * We do not want to create any storage objects for a partitioned
+ * table, including the init fork.
+ */
+ if (relpersistence == RELPERSISTENCE_UNLOGGED &&
+ relkind != RELKIND_PARTITIONED_TABLE)
heap_create_init_fork(new_rel_desc);
- }
/*
* ok, the relation has been cataloged, so close our relations and return
@@ -1376,6 +1376,9 @@ heap_create_with_catalog(const char *relname,
void
heap_create_init_fork(Relation rel)
{
+ Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
+ rel->rd_rel->relkind == RELKIND_MATVIEW ||
+ rel->rd_rel->relkind == RELKIND_TOASTVALUE);
RelationOpenSmgr(rel);
smgrcreate(rel->rd_smgr, INIT_FORKNUM, false);
log_smgrcreate(&rel->rd_smgr->smgr_rnode.node, INIT_FORKNUM);
--
2.11.0
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-03-02 09:36 ` Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
0 siblings, 1 reply; 96+ messages in thread
From: Robert Haas @ 2017-03-02 09:36 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On Tue, Feb 28, 2017 at 11:35 AM, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
> How about the documentation changes in the attached updated 0001? I know
> that this page needs a much larger rewrite as we are discussing in the
> other thread.
Looks good.
>> In acquire_inherited_sample_rows(), instead of inserting a whole
>> stanza of logic just above the existing dispatch on relkind, I think
>> we can get by with a very slightly update to what's already there.
>>
>> You can't use the result of a & b as a bool. You need to write (a &
>> b) != 0, because the bool should always use 1 for true and 0 for
>> false; it should not set some higher-numbered bit.
>
> Oops, thanks for fixing that. I suppose you are referring to this hunk in
> the original patch:
>
> - relations = get_rel_oids(relid, relation);
> + relations = get_rel_oids(relid, relation, options & VACOPT_VACUUM);
>
> And we need to do it this way in *this* case, because we're passing it as
> a bool argument. I see that it's OK to do this:
>
> stmttype = (options & VACOPT_VACUUM) ? "VACUUM" : "ANALYZE";
>
> Or this:
>
> if (options & VACOPT_VACUUM)
> {
> PreventTransactionChain(isTopLevel, stmttype);
In those cases it's still clearer, IMHO, to use != 0, but it's not
necessary. However, when you're explicitly creating a value of type
"bool", then it's necessary.
Actually, looking at this again, I now think this part is wrong:
+ /*
+ * If only ANALYZE is to be performed, there is no need to include
+ * partitions in the list. In a database-wide ANALYZE, we only
+ * update the inheritance statistics of partitioned tables, not
+ * the statistics of individual partitions.
+ */
+ if (!is_vacuum && classForm->relispartition)
continue;
I was thinking earlier that an ANALYZE on the parent would also update
the statistics for each child, but now I see that's not so. So now I
think we should omit this logic (and change the documentation to
match). That is, a database-wide ANALYZE should update the statistics
for each child as well as for the parent. Otherwise direct queries
against the children (and partitionwise joins, once we have that) are
going to go haywire.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
@ 2017-03-02 10:22 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
0 siblings, 1 reply; 96+ messages in thread
From: Amit Langote @ 2017-03-02 10:22 UTC (permalink / raw)
To: Robert Haas <robertmhaas@gmail.com>; +Cc: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On 2017/03/02 18:36, Robert Haas wrote:
> On Tue, Feb 28, 2017 at 11:35 AM, Amit Langote wrote:
>>> In acquire_inherited_sample_rows(), instead of inserting a whole
>>> stanza of logic just above the existing dispatch on relkind, I think
>>> we can get by with a very slightly update to what's already there.
>>>
>>> You can't use the result of a & b as a bool. You need to write (a &
>>> b) != 0, because the bool should always use 1 for true and 0 for
>>> false; it should not set some higher-numbered bit.
>>
>> Oops, thanks for fixing that. I suppose you are referring to this hunk in
>> the original patch:
>>
>> - relations = get_rel_oids(relid, relation);
>> + relations = get_rel_oids(relid, relation, options & VACOPT_VACUUM);
>>
>> And we need to do it this way in *this* case, because we're passing it as
>> a bool argument. I see that it's OK to do this:
>>
>> stmttype = (options & VACOPT_VACUUM) ? "VACUUM" : "ANALYZE";
>>
>> Or this:
>>
>> if (options & VACOPT_VACUUM)
>> {
>> PreventTransactionChain(isTopLevel, stmttype);
>
> In those cases it's still clearer, IMHO, to use != 0, but it's not
> necessary. However, when you're explicitly creating a value of type
> "bool", then it's necessary.
Agreed.
> Actually, looking at this again, I now think this part is wrong:
>
> + /*
> + * If only ANALYZE is to be performed, there is no need to include
> + * partitions in the list. In a database-wide ANALYZE, we only
> + * update the inheritance statistics of partitioned tables, not
> + * the statistics of individual partitions.
> + */
> + if (!is_vacuum && classForm->relispartition)
> continue;
>
> I was thinking earlier that an ANALYZE on the parent would also update
> the statistics for each child, but now I see that's not so. So now I
Yep, the patch enables ANALYZE to be propagated to partitions when the
parent table is specified in the command. The above logic in the patch
made the database-wide ANALYZE to ignore partitions, in which case, only
the inheritance statistics would be updated. I can also see why that'd be
undesirable.
> think we should omit this logic (and change the documentation to
> match). That is, a database-wide ANALYZE should update the statistics
> for each child as well as for the parent. Otherwise direct queries
> against the children (and partitionwise joins, once we have that) are
> going to go haywire.
OK, done. I updated both analyze.sgml and vacuum.sgml to be more up to
date. Both pages previously omitted materialized views.
Attached updated patches.
Thanks,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Attachments:
[text/x-diff] 0001-Avoid-useless-partitioned-table-ops.patch (14.1K, ../../47288cf1-f72c-dfc2-5ff0-4af962ae5c1b@lab.ntt.co.jp/2-0001-Avoid-useless-partitioned-table-ops.patch)
download | inline diff:
From 32447566c1c3bf5201e36141590f4654d144f777 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Tue, 28 Feb 2017 13:43:59 +0900
Subject: [PATCH 1/3] Avoid useless partitioned table ops
Also, recursively perform VACUUM and ANALYZE on partitions when the
command is applied to a partitioned table.
---
doc/src/sgml/ddl.sgml | 47 ++++++++++++++++++------------------
doc/src/sgml/ref/analyze.sgml | 7 ++++--
doc/src/sgml/ref/vacuum.sgml | 4 +++-
src/backend/commands/analyze.c | 37 +++++++++++++++++++----------
src/backend/commands/tablecmds.c | 15 +++++++++---
src/backend/commands/vacuum.c | 51 +++++++++++++++++++++++++++++++++++++---
6 files changed, 116 insertions(+), 45 deletions(-)
diff --git a/doc/src/sgml/ddl.sgml b/doc/src/sgml/ddl.sgml
index ef0f7cf727..09b5b3ff70 100644
--- a/doc/src/sgml/ddl.sgml
+++ b/doc/src/sgml/ddl.sgml
@@ -3792,8 +3792,7 @@ UNION ALL SELECT * FROM measurement_y2008m01;
<title>Caveats</title>
<para>
- The following caveats apply to partitioned tables implemented using either
- method (unless noted otherwise):
+ The following caveats apply to using inheritance to implement partitioning:
<itemizedlist>
<listitem>
<para>
@@ -3803,13 +3802,6 @@ UNION ALL SELECT * FROM measurement_y2008m01;
partitions and creates and/or modifies associated objects than
to write each by hand.
</para>
-
- <para>
- This is not a problem with partitioned tables though, as trying to
- create a partition that overlaps with one of the existing partitions
- results in an error, so it is impossible to end up with partitions
- that overlap one another.
- </para>
</listitem>
<listitem>
@@ -3822,14 +3814,6 @@ UNION ALL SELECT * FROM measurement_y2008m01;
on the partition tables, but it makes management of the structure
much more complicated.
</para>
-
- <para>
- This problem exists even for partitioned tables. An <command>UPDATE</>
- that causes a row to move from one partition to another fails, because
- the new value of the row fails to satisfy the implicit partition
- constraint of the original partition. This might change in future
- releases.
- </para>
</listitem>
<listitem>
@@ -3840,8 +3824,7 @@ UNION ALL SELECT * FROM measurement_y2008m01;
<programlisting>
ANALYZE measurement;
</programlisting>
- will only process the master table. This is true even for partitioned
- tables.
+ will only process the master table.
</para>
</listitem>
@@ -3852,11 +3835,27 @@ ANALYZE measurement;
action is only taken in case of unique violations on the specified
target relation, not its child relations.
</para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ The following caveats apply to partitioned tables created with the
+ explicit syntax:
+ <itemizedlist>
+ <listitem>
+ <para>
+ An <command>UPDATE</> that causes a row to move from one partition to
+ another fails, because the new value of the row fails to satisfy the
+ implicit partition constraint of the original partition. This might
+ change in future releases.
+ </para>
+ </listitem>
+
+ <listitem>
<para>
<command>INSERT</command> statements with <literal>ON CONFLICT</>
- clause are currently not allowed on partitioned tables, that is,
- cause error when specified.
+ clause are currently not allowed on partitioned tables.
</para>
</listitem>
@@ -3864,7 +3863,8 @@ ANALYZE measurement;
</para>
<para>
- The following caveats apply to constraint exclusion:
+ The following caveats apply to constraint exclusion, which is currently
+ used by both inheritance and partitioned tables:
<itemizedlist>
<listitem>
@@ -3898,8 +3898,7 @@ ANALYZE measurement;
during constraint exclusion, so large numbers of partitions are likely
to increase query planning time considerably. Partitioning using
these techniques will work well with up to perhaps a hundred partitions;
- don't try to use many thousands of partitions. This restriction applies
- both to inheritance and explicit partitioning syntax.
+ don't try to use many thousands of partitions.
</para>
</listitem>
diff --git a/doc/src/sgml/ref/analyze.sgml b/doc/src/sgml/ref/analyze.sgml
index 27ab4fca42..620d2e43ff 100644
--- a/doc/src/sgml/ref/analyze.sgml
+++ b/doc/src/sgml/ref/analyze.sgml
@@ -63,8 +63,11 @@ ANALYZE [ VERBOSE ] [ <replaceable class="PARAMETER">table_name</replaceable> [
<listitem>
<para>
The name (possibly schema-qualified) of a specific table to
- analyze. If omitted, all regular tables (but not foreign tables)
- in the current database are analyzed.
+ analyze. If omitted, all regular tables, partitioned tables (but not
+ foreign tables), and materialized views in the current database are
+ analyzed. If the specified table is a partitioned table, both the
+ inheritance statistics of the partitioned table as a whole and
+ statistics of the individual partitions are updated.
</para>
</listitem>
</varlistentry>
diff --git a/doc/src/sgml/ref/vacuum.sgml b/doc/src/sgml/ref/vacuum.sgml
index f18180a2fa..543ebcf649 100644
--- a/doc/src/sgml/ref/vacuum.sgml
+++ b/doc/src/sgml/ref/vacuum.sgml
@@ -153,7 +153,9 @@ VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] ANALYZE [ <replaceable class="PARAMETER">
<listitem>
<para>
The name (optionally schema-qualified) of a specific table to
- vacuum. Defaults to all tables in the current database.
+ vacuum. If omitted, all regular tables and materialized views in the
+ current database are vacuumed. If the specified table is a partitioned
+ table, all of its leaf partitions are vacuumed.
</para>
</listitem>
</varlistentry>
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index ed3acb1673..a70c760341 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -201,8 +201,7 @@ analyze_rel(Oid relid, RangeVar *relation, int options,
* locked the relation.
*/
if (onerel->rd_rel->relkind == RELKIND_RELATION ||
- onerel->rd_rel->relkind == RELKIND_MATVIEW ||
- onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ onerel->rd_rel->relkind == RELKIND_MATVIEW)
{
/* Regular table, so we'll use the regular row acquisition function */
acquirefunc = acquire_sample_rows;
@@ -234,6 +233,12 @@ analyze_rel(Oid relid, RangeVar *relation, int options,
return;
}
}
+ else if (onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ /*
+ * For partitioned tables, we want to do the recursive ANALYZE below.
+ */
+ }
else
{
/* No need for a WARNING if we already complained during VACUUM */
@@ -253,10 +258,12 @@ analyze_rel(Oid relid, RangeVar *relation, int options,
LWLockRelease(ProcArrayLock);
/*
- * Do the normal non-recursive ANALYZE.
+ * Do the normal non-recursive ANALYZE. We can skip this for partitioned
+ * tables, which don't contain any rows.
*/
- do_analyze_rel(onerel, options, params, va_cols, acquirefunc, relpages,
- false, in_outer_xact, elevel);
+ if (onerel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
+ do_analyze_rel(onerel, options, params, va_cols, acquirefunc,
+ relpages, false, in_outer_xact, elevel);
/*
* If there are child tables, do recursive ANALYZE.
@@ -1260,6 +1267,7 @@ acquire_inherited_sample_rows(Relation onerel, int elevel,
nrels,
i;
ListCell *lc;
+ bool has_child;
/*
* Find all members of inheritance set. We only need AccessShareLock on
@@ -1297,6 +1305,7 @@ acquire_inherited_sample_rows(Relation onerel, int elevel,
relblocks = (double *) palloc(list_length(tableOIDs) * sizeof(double));
totalblocks = 0;
nrels = 0;
+ has_child = false;
foreach(lc, tableOIDs)
{
Oid childOID = lfirst_oid(lc);
@@ -1318,8 +1327,7 @@ acquire_inherited_sample_rows(Relation onerel, int elevel,
/* Check table type (MATVIEW can't happen, but might as well allow) */
if (childrel->rd_rel->relkind == RELKIND_RELATION ||
- childrel->rd_rel->relkind == RELKIND_MATVIEW ||
- childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ childrel->rd_rel->relkind == RELKIND_MATVIEW)
{
/* Regular table, so use the regular row acquisition function */
acquirefunc = acquire_sample_rows;
@@ -1351,13 +1359,17 @@ acquire_inherited_sample_rows(Relation onerel, int elevel,
}
else
{
- /* ignore, but release the lock on it */
- Assert(childrel != onerel);
- heap_close(childrel, AccessShareLock);
+ /*
+ * ignore, but release the lock on it. could be a partitioned
+ * table.
+ */
+ if (childrel != onerel)
+ heap_close(childrel, AccessShareLock);
continue;
}
/* OK, we'll process this child */
+ has_child = true;
rels[nrels] = childrel;
acquirefuncs[nrels] = acquirefunc;
relblocks[nrels] = (double) relpages;
@@ -1366,9 +1378,10 @@ acquire_inherited_sample_rows(Relation onerel, int elevel,
}
/*
- * If we don't have at least two tables to consider, fail.
+ * If we don't have at least one child table to consider, fail. If the
+ * relation is a partitioned table, it's not counted as a child table.
*/
- if (nrels < 2)
+ if (!has_child)
{
ereport(elevel,
(errmsg("skipping analyze of \"%s.%s\" inheritance tree --- this inheritance tree contains no analyzable child tables",
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 3cea220421..317012068b 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -1349,6 +1349,10 @@ ExecuteTruncate(TruncateStmt *stmt)
{
Relation rel = (Relation) lfirst(cell);
+ /* Skip partitioned tables as there is nothing to do */
+ if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ continue;
+
/*
* Normally, we need a transaction-safe truncation here. However, if
* the table was either created in the current (sub)transaction or has
@@ -1459,7 +1463,11 @@ truncate_check_rel(Relation rel)
{
AclResult aclresult;
- /* Only allow truncate on regular tables */
+ /*
+ * Only allow truncate on regular tables and partitioned tables (although,
+ * the latter are only being included here for the following checks; no
+ * physical truncation will occur in their case.)
+ */
if (rel->rd_rel->relkind != RELKIND_RELATION &&
rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
ereport(ERROR,
@@ -4006,8 +4014,9 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode)
{
AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
- /* Foreign tables have no storage. */
- if (tab->relkind == RELKIND_FOREIGN_TABLE)
+ /* Foreign tables have no storage, nor do partitioned tables. */
+ if (tab->relkind == RELKIND_FOREIGN_TABLE ||
+ tab->relkind == RELKIND_PARTITIONED_TABLE)
continue;
/*
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 812fb4a48f..3a9b965266 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -32,6 +32,7 @@
#include "access/xact.h"
#include "catalog/namespace.h"
#include "catalog/pg_database.h"
+#include "catalog/pg_inherits_fn.h"
#include "catalog/pg_namespace.h"
#include "commands/cluster.h"
#include "commands/vacuum.h"
@@ -394,6 +395,9 @@ get_rel_oids(Oid relid, const RangeVar *vacrel)
{
/* Process a specific relation */
Oid relid;
+ HeapTuple tuple;
+ Form_pg_class classForm;
+ bool include_parts;
/*
* Since we don't take a lock here, the relation might be gone, or the
@@ -406,9 +410,29 @@ get_rel_oids(Oid relid, const RangeVar *vacrel)
*/
relid = RangeVarGetRelid(vacrel, NoLock, false);
- /* Make a relation list entry for this guy */
+ /*
+ * To check whether the relation is a partitioned table, fetch its
+ * syscache entry.
+ */
+ tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for relation %u", relid);
+ classForm = (Form_pg_class) GETSTRUCT(tuple);
+ include_parts = (classForm->relkind == RELKIND_PARTITIONED_TABLE);
+ ReleaseSysCache(tuple);
+
+ /*
+ * Make relation list entries for this guy and its partitions, if any.
+ * Note that the list returned by find_all_inheritors() include the
+ * passed-in OID at its head. Also note that we did not request a
+ * lock to be taken to match what would be done otherwise.
+ */
oldcontext = MemoryContextSwitchTo(vac_context);
- oid_list = lappend_oid(oid_list, relid);
+ if (include_parts)
+ oid_list = list_concat(oid_list,
+ find_all_inheritors(relid, NoLock, NULL));
+ else
+ oid_list = lappend_oid(oid_list, relid);
MemoryContextSwitchTo(oldcontext);
}
else
@@ -429,8 +453,14 @@ get_rel_oids(Oid relid, const RangeVar *vacrel)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
+ /*
+ * We include partitioned tables here; depending on which
+ * operation is to be performed, caller will decide whether to
+ * process or ignore them.
+ */
if (classForm->relkind != RELKIND_RELATION &&
- classForm->relkind != RELKIND_MATVIEW)
+ classForm->relkind != RELKIND_MATVIEW &&
+ classForm->relkind != RELKIND_PARTITIONED_TABLE)
continue;
/* Make a relation list entry for this guy */
@@ -1350,6 +1380,21 @@ vacuum_rel(Oid relid, RangeVar *relation, int options, VacuumParams *params)
}
/*
+ * Ignore partitioned tables as there is no work to be done. Since we
+ * release the lock here, it's possible that any partitions added from
+ * this point on will not get processed, but that seems harmless.
+ */
+ if (onerel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ relation_close(onerel, lmode);
+ PopActiveSnapshot();
+ CommitTransactionCommand();
+
+ /* It's OK for other commands to look at this table */
+ return true;
+ }
+
+ /*
* Get a session-level lock too. This will protect our access to the
* relation across multiple transactions, so that we can vacuum the
* relation's TOAST table (if any) secure in the knowledge that no one is
--
2.11.0
[text/x-diff] 0002-Avoid-creating-scan-nodes-for-partitioned-tables.patch (21.1K, ../../47288cf1-f72c-dfc2-5ff0-4af962ae5c1b@lab.ntt.co.jp/3-0002-Avoid-creating-scan-nodes-for-partitioned-tables.patch)
download | inline diff:
From 8fe84fd968121dc17e749db8ba9d5516736dbf0b Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Mon, 6 Feb 2017 17:26:48 +0900
Subject: [PATCH 2/3] Avoid creating scan nodes for partitioned tables
* Currently, we create scan nodes for inheritance parents in their role
as an inheritance set member. Partitioned tables do not contain any
data, so it's useless to create scan nodes for them. So we need not
create AppendRelInfo's for them in the planner prep phase.
* The planner prep phase turns off inheritance on the parent RTE if
there isn't at least one child member (other than the parent itself
which in normal cases is also a child member), which means the latter
phases will not consider creating an Append plan and instead create a
scan node. Avoid this if the RTE is a partitioned table, by noticing
such cases in set_rel_size(). Per suggestion from Ashutosh Bapat.
* Since we do not add the RTE corresponding to the root partitioned
table as the 1st child member of the inheritance set,
inheritance_planner() must not assume the same when assigning
nominalRelation to a ModifyTable node.
* In ExecInitModifyTable(), use nominalRelation to initialize tuple
routing information, instead of the first resultRelInfo. We set
ModifyTable.nominalRelation to the root parent RTE in the
partitioned table case (implicitly in the INSERT case, whereas
explicitly in the UPDATE/DELETE cases).
---
src/backend/executor/nodeModifyTable.c | 18 +++--
src/backend/optimizer/path/allpaths.c | 8 ++
src/backend/optimizer/plan/planner.c | 14 +++-
src/backend/optimizer/prep/prepunion.c | 32 ++++++--
src/test/regress/expected/inherit.out | 124 ++++++++++--------------------
src/test/regress/expected/tablesample.out | 4 +-
src/test/regress/sql/inherit.sql | 8 ++
7 files changed, 108 insertions(+), 100 deletions(-)
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 95e158970c..188ce8f8d4 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -45,6 +45,7 @@
#include "foreign/fdwapi.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
+#include "parser/parsetree.h"
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
#include "utils/builtins.h"
@@ -1634,7 +1635,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
Plan *subplan;
ListCell *l;
int i;
- Relation rel;
+ Relation nominalRel;
+ RangeTblEntry *nominalRTE;
/* check for unsupported flags */
Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
@@ -1726,9 +1728,10 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
estate->es_result_relation_info = saved_resultRelInfo;
/* Build state for INSERT tuple routing */
- rel = mtstate->resultRelInfo->ri_RelationDesc;
+ nominalRTE = rt_fetch(node->nominalRelation, estate->es_range_table);
+ nominalRel = heap_open(nominalRTE->relid, NoLock);
if (operation == CMD_INSERT &&
- rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ nominalRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
{
PartitionDispatch *partition_dispatch_info;
ResultRelInfo *partitions;
@@ -1737,7 +1740,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
int num_parted,
num_partitions;
- ExecSetupPartitionTupleRouting(rel,
+ ExecSetupPartitionTupleRouting(nominalRel,
&partition_dispatch_info,
&partitions,
&partition_tupconv_maps,
@@ -1801,7 +1804,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
/* varno = node->nominalRelation */
mapped_wcoList = map_partition_varattnos(wcoList,
node->nominalRelation,
- partrel, rel);
+ partrel, nominalRel);
foreach(ll, mapped_wcoList)
{
WithCheckOption *wco = (WithCheckOption *) lfirst(ll);
@@ -1876,7 +1879,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
/* varno = node->nominalRelation */
rlist = map_partition_varattnos(returningList,
node->nominalRelation,
- partrel, rel);
+ partrel, nominalRel);
rliststate = (List *) ExecInitExpr((Expr *) rlist, &mtstate->ps);
resultRelInfo->ri_projectReturning =
ExecBuildProjectionInfo(rliststate, econtext, slot,
@@ -1897,6 +1900,9 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
mtstate->ps.ps_ExprContext = NULL;
}
+ /* We're done using it. */
+ heap_close(nominalRel, NoLock);
+
/*
* If needed, Initialize target list, projection and qual for ON CONFLICT
* DO UPDATE.
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 633b5c1608..f2c8d27193 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -342,6 +342,14 @@ set_rel_size(PlannerInfo *root, RelOptInfo *rel,
/* Foreign table */
set_foreign_size(root, rel, rte);
}
+ else if (rte->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ /*
+ * A partitioned table without leaf partitions is marked
+ * as a dummy rel.
+ */
+ set_dummy_rel_pathlist(rel);
+ }
else if (rte->tablesample != NULL)
{
/* Sampled relation */
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index ca0ae7883e..b5698f0ce7 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -996,10 +996,20 @@ inheritance_planner(PlannerInfo *root)
RelOptInfo *final_rel;
ListCell *lc;
Index rti;
+ RangeTblEntry *parent_rte;
Assert(parse->commandType != CMD_INSERT);
/*
+ * If the parent RTE is a partitioned table, we should use that as the
+ * nominal relation, because we do not have the duplicate parent RTE,
+ * unlike in the case of a non-partitioned inheritance parent.
+ */
+ parent_rte = rt_fetch(parentRTindex, root->parse->rtable);
+ if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
+ nominalRelation = parentRTindex;
+
+ /*
* We generate a modified instance of the original Query for each target
* relation, plan that, and put all the plans into a list that will be
* controlled by a single ModifyTable node. All the instances share the
@@ -1060,7 +1070,6 @@ inheritance_planner(PlannerInfo *root)
{
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
PlannerInfo *subroot;
- RangeTblEntry *parent_rte;
RangeTblEntry *child_rte;
RelOptInfo *sub_final_rel;
Path *subpath;
@@ -1214,6 +1223,9 @@ inheritance_planner(PlannerInfo *root)
* will not be otherwise referenced in the plan, doing so would give
* rise to confusing use of multiple aliases in EXPLAIN output for
* what the user will think is the "same" table.)
+ *
+ * If the parent is a partitioned table, we already set the nominal
+ * relation.
*/
if (nominalRelation < 0)
nominalRelation = appinfo->child_relid;
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 1389db18ba..b4c65c4a90 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -1364,6 +1364,7 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
List *inhOIDs;
List *appinfos;
ListCell *l;
+ bool has_child;
/* Does RT entry allow inheritance? */
if (!rte->inh)
@@ -1435,6 +1436,7 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
/* Scan the inheritance set and expand it */
appinfos = NIL;
+ has_child = false;
foreach(l, inhOIDs)
{
Oid childOID = lfirst_oid(l);
@@ -1450,6 +1452,22 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
newrelation = oldrelation;
/*
+ * Since partitioned tables themselves do not contain data, later
+ * planning steps should not create scan nodes for them. So do not
+ * create the child RTE and AppendRelInfo.
+ */
+ if (newrelation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ /*
+ * Don't lose the lock taken for us by find_all_inheritors()
+ * lest its partitions change under us.
+ */
+ if (newrelation != oldrelation)
+ heap_close(newrelation, NoLock);
+ continue;
+ }
+
+ /*
* It is possible that the parent table has children that are temp
* tables of other backends. We cannot safely access such tables
* (because of buffering issues), and the best thing to do seems to be
@@ -1461,6 +1479,9 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
continue;
}
+ /* We have a child table. */
+ has_child = true;
+
/*
* Build an RTE for the child, and attach to query's rangetable list.
* We copy most fields of the parent's RTE, but replace relation OID
@@ -1545,12 +1566,13 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
heap_close(oldrelation, NoLock);
/*
- * If all the children were temp tables, pretend it's a non-inheritance
- * situation. The duplicate RTE we added for the parent table is
- * harmless, so we don't bother to get rid of it; ditto for the useless
- * PlanRowMark node.
+ * If all the children were temp tables or if the parent is a partitioned
+ * table without any leaf partitions, pretend it's a non-inheritance
+ * situation. The duplicate RTE for the parent table we added in the
+ * non-partitioned table case is harmless, so we don't bother to get rid
+ * of it; ditto for the useless PlanRowMark node.
*/
- if (list_length(appinfos) < 2)
+ if (!has_child)
{
/* Clear flag before returning */
rte->inh = false;
diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out
index a8c8b28a75..55b147432f 100644
--- a/src/test/regress/expected/inherit.out
+++ b/src/test/regress/expected/inherit.out
@@ -1598,6 +1598,14 @@ reset enable_bitmapscan;
create table list_parted (
a varchar
) partition by list (a);
+-- test scanning partitioned table without any partitions
+explain (costs off) select * from list_parted;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
create table part_ab_cd partition of list_parted for values in ('ab', 'cd');
create table part_ef_gh partition of list_parted for values in ('ef', 'gh');
create table part_null_xy partition of list_parted for values in (null, 'xy');
@@ -1605,77 +1613,74 @@ explain (costs off) select * from list_parted;
QUERY PLAN
--------------------------------
Append
- -> Seq Scan on list_parted
-> Seq Scan on part_ab_cd
-> Seq Scan on part_ef_gh
-> Seq Scan on part_null_xy
-(5 rows)
+(4 rows)
explain (costs off) select * from list_parted where a is null;
QUERY PLAN
--------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (a IS NULL)
-> Seq Scan on part_null_xy
Filter: (a IS NULL)
-(5 rows)
+(3 rows)
explain (costs off) select * from list_parted where a is not null;
QUERY PLAN
---------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (a IS NOT NULL)
-> Seq Scan on part_ab_cd
Filter: (a IS NOT NULL)
-> Seq Scan on part_ef_gh
Filter: (a IS NOT NULL)
-> Seq Scan on part_null_xy
Filter: (a IS NOT NULL)
-(9 rows)
+(7 rows)
explain (costs off) select * from list_parted where a in ('ab', 'cd', 'ef');
QUERY PLAN
----------------------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-> Seq Scan on part_ab_cd
Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-> Seq Scan on part_ef_gh
Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-(7 rows)
+(5 rows)
explain (costs off) select * from list_parted where a = 'ab' or a in (null, 'cd');
QUERY PLAN
---------------------------------------------------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_ab_cd
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_ef_gh
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_null_xy
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-(9 rows)
+(7 rows)
explain (costs off) select * from list_parted where a = 'ab';
QUERY PLAN
------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: ((a)::text = 'ab'::text)
-> Seq Scan on part_ab_cd
Filter: ((a)::text = 'ab'::text)
-(5 rows)
+(3 rows)
create table range_list_parted (
a int,
b char(2)
) partition by range (a);
create table part_1_10 partition of range_list_parted for values from (1) to (10) partition by list (b);
+-- test scanning partitioned table without any leaf partitions
+explain (costs off) select * from range_list_parted;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
create table part_1_10_ab partition of part_1_10 for values in ('ab');
create table part_1_10_cd partition of part_1_10 for values in ('cd');
create table part_10_20 partition of range_list_parted for values from (10) to (20) partition by list (b);
@@ -1689,14 +1694,9 @@ create table part_40_inf_ab partition of part_40_inf for values in ('ab');
create table part_40_inf_cd partition of part_40_inf for values in ('cd');
create table part_40_inf_null partition of part_40_inf for values in (null);
explain (costs off) select * from range_list_parted;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- -> Seq Scan on part_1_10
- -> Seq Scan on part_10_20
- -> Seq Scan on part_21_30
- -> Seq Scan on part_40_inf
-> Seq Scan on part_1_10_ab
-> Seq Scan on part_1_10_cd
-> Seq Scan on part_10_20_ab
@@ -1706,36 +1706,22 @@ explain (costs off) select * from range_list_parted;
-> Seq Scan on part_40_inf_ab
-> Seq Scan on part_40_inf_cd
-> Seq Scan on part_40_inf_null
-(15 rows)
+(10 rows)
explain (costs off) select * from range_list_parted where a = 5;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+--------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (a = 5)
- -> Seq Scan on part_1_10
- Filter: (a = 5)
-> Seq Scan on part_1_10_ab
Filter: (a = 5)
-> Seq Scan on part_1_10_cd
Filter: (a = 5)
-(9 rows)
+(5 rows)
explain (costs off) select * from range_list_parted where b = 'ab';
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_1_10
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_10_20
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_21_30
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_40_inf
- Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_1_10_ab
Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_10_20_ab
@@ -1744,27 +1730,19 @@ explain (costs off) select * from range_list_parted where b = 'ab';
Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_40_inf_ab
Filter: (b = 'ab'::bpchar)
-(19 rows)
+(9 rows)
explain (costs off) select * from range_list_parted where a between 3 and 23 and b in ('ab');
QUERY PLAN
-----------------------------------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_1_10
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_10_20
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_21_30
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_1_10_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_10_20_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_21_30_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-(15 rows)
+(7 rows)
/* Should select no rows because range partition key cannot be null */
explain (costs off) select * from range_list_parted where a is null;
@@ -1776,37 +1754,17 @@ explain (costs off) select * from range_list_parted where a is null;
/* Should only select rows from the null-accepting partition */
explain (costs off) select * from range_list_parted where b is null;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (b IS NULL)
- -> Seq Scan on part_1_10
- Filter: (b IS NULL)
- -> Seq Scan on part_10_20
- Filter: (b IS NULL)
- -> Seq Scan on part_21_30
- Filter: (b IS NULL)
- -> Seq Scan on part_40_inf
- Filter: (b IS NULL)
-> Seq Scan on part_40_inf_null
Filter: (b IS NULL)
-(13 rows)
+(3 rows)
explain (costs off) select * from range_list_parted where a is not null and a < 67;
QUERY PLAN
------------------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_1_10
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_10_20
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_21_30
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_40_inf
- Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_1_10_ab
Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_1_10_cd
@@ -1825,23 +1783,19 @@ explain (costs off) select * from range_list_parted where a is not null and a <
Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_40_inf_null
Filter: ((a IS NOT NULL) AND (a < 67))
-(29 rows)
+(19 rows)
explain (costs off) select * from range_list_parted where a >= 30;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (a >= 30)
- -> Seq Scan on part_40_inf
- Filter: (a >= 30)
-> Seq Scan on part_40_inf_ab
Filter: (a >= 30)
-> Seq Scan on part_40_inf_cd
Filter: (a >= 30)
-> Seq Scan on part_40_inf_null
Filter: (a >= 30)
-(11 rows)
+(7 rows)
drop table list_parted cascade;
NOTICE: drop cascades to 3 other objects
diff --git a/src/test/regress/expected/tablesample.out b/src/test/regress/expected/tablesample.out
index b18e420e9b..d3794140fb 100644
--- a/src/test/regress/expected/tablesample.out
+++ b/src/test/regress/expected/tablesample.out
@@ -322,12 +322,10 @@ explain (costs off)
QUERY PLAN
-------------------------------------------
Append
- -> Sample Scan on parted_sample
- Sampling: bernoulli ('100'::real)
-> Sample Scan on parted_sample_1
Sampling: bernoulli ('100'::real)
-> Sample Scan on parted_sample_2
Sampling: bernoulli ('100'::real)
-(7 rows)
+(5 rows)
drop table parted_sample, parted_sample_1, parted_sample_2;
diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql
index a8b7eb1c8d..04cc4ffa23 100644
--- a/src/test/regress/sql/inherit.sql
+++ b/src/test/regress/sql/inherit.sql
@@ -570,6 +570,10 @@ reset enable_bitmapscan;
create table list_parted (
a varchar
) partition by list (a);
+
+-- test scanning partitioned table without any partitions
+explain (costs off) select * from list_parted;
+
create table part_ab_cd partition of list_parted for values in ('ab', 'cd');
create table part_ef_gh partition of list_parted for values in ('ef', 'gh');
create table part_null_xy partition of list_parted for values in (null, 'xy');
@@ -586,6 +590,10 @@ create table range_list_parted (
b char(2)
) partition by range (a);
create table part_1_10 partition of range_list_parted for values from (1) to (10) partition by list (b);
+
+-- test scanning partitioned table without any leaf partitions
+explain (costs off) select * from range_list_parted;
+
create table part_1_10_ab partition of part_1_10 for values in ('ab');
create table part_1_10_cd partition of part_1_10 for values in ('cd');
create table part_10_20 partition of range_list_parted for values from (10) to (20) partition by list (b);
--
2.11.0
[text/x-diff] 0003-Do-not-allocate-storage-for-partitioned-tables.patch (3.1K, ../../47288cf1-f72c-dfc2-5ff0-4af962ae5c1b@lab.ntt.co.jp/4-0003-Do-not-allocate-storage-for-partitioned-tables.patch)
download | inline diff:
From 5417e0b9afebede5adaa82e7ea70d2906845c86a Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Tue, 24 Jan 2017 14:22:34 +0900
Subject: [PATCH 3/3] Do not allocate storage for partitioned tables.
Currently, it is not possible to insert any data into a partitioned
table. So, they're empty at all times, which means it is wasteful to
allocate relfilenode and related storage objects.
---
src/backend/access/common/reloptions.c | 3 +--
src/backend/catalog/heap.c | 17 ++++++++++-------
2 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 42b4ea410f..79a75152f0 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -932,7 +932,6 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
case RELKIND_RELATION:
case RELKIND_TOASTVALUE:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
options = heap_reloptions(classForm->relkind, datum, false);
break;
case RELKIND_VIEW:
@@ -942,6 +941,7 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
options = index_reloptions(amoptions, datum, false);
break;
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
options = NULL;
break;
default:
@@ -1384,7 +1384,6 @@ heap_reloptions(char relkind, Datum reloptions, bool validate)
return (bytea *) rdopts;
case RELKIND_RELATION:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
default:
/* other relkinds are not supported */
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 41c0056556..2f5090b183 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -291,6 +291,7 @@ heap_create(const char *relname,
case RELKIND_VIEW:
case RELKIND_COMPOSITE_TYPE:
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
create_storage = false;
/*
@@ -1345,14 +1346,13 @@ heap_create_with_catalog(const char *relname,
if (oncommit != ONCOMMIT_NOOP)
register_on_commit_action(relid, oncommit);
- if (relpersistence == RELPERSISTENCE_UNLOGGED)
- {
- Assert(relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW ||
- relkind == RELKIND_TOASTVALUE ||
- relkind == RELKIND_PARTITIONED_TABLE);
-
+ /*
+ * We do not want to create any storage objects for a partitioned
+ * table, including the init fork.
+ */
+ if (relpersistence == RELPERSISTENCE_UNLOGGED &&
+ relkind != RELKIND_PARTITIONED_TABLE)
heap_create_init_fork(new_rel_desc);
- }
/*
* ok, the relation has been cataloged, so close our relations and return
@@ -1376,6 +1376,9 @@ heap_create_with_catalog(const char *relname,
void
heap_create_init_fork(Relation rel)
{
+ Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
+ rel->rd_rel->relkind == RELKIND_MATVIEW ||
+ rel->rd_rel->relkind == RELKIND_TOASTVALUE);
RelationOpenSmgr(rel);
smgrcreate(rel->rd_smgr, INIT_FORKNUM, false);
log_smgrcreate(&rel->rd_smgr->smgr_rnode.node, INIT_FORKNUM);
--
2.11.0
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-03-02 12:48 ` Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
0 siblings, 1 reply; 96+ messages in thread
From: Robert Haas @ 2017-03-02 12:48 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On Thu, Mar 2, 2017 at 3:52 PM, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
>> think we should omit this logic (and change the documentation to
>> match). That is, a database-wide ANALYZE should update the statistics
>> for each child as well as for the parent. Otherwise direct queries
>> against the children (and partitionwise joins, once we have that) are
>> going to go haywire.
>
> OK, done. I updated both analyze.sgml and vacuum.sgml to be more up to
> date. Both pages previously omitted materialized views.
>
> Attached updated patches.
Thanks, committed 0001 with a slight change to the wording.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
@ 2017-03-03 01:02 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-07 16:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
0 siblings, 2 replies; 96+ messages in thread
From: Amit Langote @ 2017-03-03 01:02 UTC (permalink / raw)
To: Robert Haas <robertmhaas@gmail.com>; +Cc: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On 2017/03/02 21:48, Robert Haas wrote:
> On Thu, Mar 2, 2017 at 3:52 PM, Amit Langote
> <Langote_Amit_f8@lab.ntt.co.jp> wrote:
>>> think we should omit this logic (and change the documentation to
>>> match). That is, a database-wide ANALYZE should update the statistics
>>> for each child as well as for the parent. Otherwise direct queries
>>> against the children (and partitionwise joins, once we have that) are
>>> going to go haywire.
>>
>> OK, done. I updated both analyze.sgml and vacuum.sgml to be more up to
>> date. Both pages previously omitted materialized views.
>>
>> Attached updated patches.
>
> Thanks, committed 0001 with a slight change to the wording.
Thanks. I noticed that 'and' is duplicated in a line added by the commit
to analyze.sgml. Attached 0001 fixes that. 0002 and 0003 same as the
last version.
Thanks,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Attachments:
[text/x-diff] 0001-Fix-duplicated-and-in-analyze.sgml.patch (1.1K, ../../04e417c8-cd7a-9ed5-e41e-677056b5e9c9@lab.ntt.co.jp/2-0001-Fix-duplicated-and-in-analyze.sgml.patch)
download | inline diff:
From 8a7bc891a9f54b72e111ccfe98fb96c75eb4e546 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Fri, 3 Mar 2017 09:57:11 +0900
Subject: [PATCH 1/3] Fix duplicated 'and' in analyze.sgml
---
doc/src/sgml/ref/analyze.sgml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/doc/src/sgml/ref/analyze.sgml b/doc/src/sgml/ref/analyze.sgml
index 49727e22df..45dee101df 100644
--- a/doc/src/sgml/ref/analyze.sgml
+++ b/doc/src/sgml/ref/analyze.sgml
@@ -64,7 +64,7 @@ ANALYZE [ VERBOSE ] [ <replaceable class="PARAMETER">table_name</replaceable> [
<para>
The name (possibly schema-qualified) of a specific table to
analyze. If omitted, all regular tables, partitioned tables, and
- and materialized views in the current database are analyzed (but not
+ materialized views in the current database are analyzed (but not
foreign tables). If the specified table is a partitioned table, both the
inheritance statistics of the partitioned table as a whole and
statistics of the individual partitions are updated.
--
2.11.0
[text/x-diff] 0002-Avoid-creating-scan-nodes-for-partitioned-tables.patch (21.1K, ../../04e417c8-cd7a-9ed5-e41e-677056b5e9c9@lab.ntt.co.jp/3-0002-Avoid-creating-scan-nodes-for-partitioned-tables.patch)
download | inline diff:
From 9776733add8ae509eb6ef6a226a17e81b057677b Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Mon, 6 Feb 2017 17:26:48 +0900
Subject: [PATCH 2/3] Avoid creating scan nodes for partitioned tables
* Currently, we create scan nodes for inheritance parents in their role
as an inheritance set member. Partitioned tables do not contain any
data, so it's useless to create scan nodes for them. So we need not
create AppendRelInfo's for them in the planner prep phase.
* The planner prep phase turns off inheritance on the parent RTE if
there isn't at least one child member (other than the parent itself
which in normal cases is also a child member), which means the latter
phases will not consider creating an Append plan and instead create a
scan node. Avoid this if the RTE is a partitioned table, by noticing
such cases in set_rel_size(). Per suggestion from Ashutosh Bapat.
* Since we do not add the RTE corresponding to the root partitioned
table as the 1st child member of the inheritance set,
inheritance_planner() must not assume the same when assigning
nominalRelation to a ModifyTable node.
* In ExecInitModifyTable(), use nominalRelation to initialize tuple
routing information, instead of the first resultRelInfo. We set
ModifyTable.nominalRelation to the root parent RTE in the
partitioned table case (implicitly in the INSERT case, whereas
explicitly in the UPDATE/DELETE cases).
---
src/backend/executor/nodeModifyTable.c | 18 +++--
src/backend/optimizer/path/allpaths.c | 8 ++
src/backend/optimizer/plan/planner.c | 14 +++-
src/backend/optimizer/prep/prepunion.c | 32 ++++++--
src/test/regress/expected/inherit.out | 124 ++++++++++--------------------
src/test/regress/expected/tablesample.out | 4 +-
src/test/regress/sql/inherit.sql | 8 ++
7 files changed, 108 insertions(+), 100 deletions(-)
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 95e158970c..188ce8f8d4 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -45,6 +45,7 @@
#include "foreign/fdwapi.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
+#include "parser/parsetree.h"
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
#include "utils/builtins.h"
@@ -1634,7 +1635,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
Plan *subplan;
ListCell *l;
int i;
- Relation rel;
+ Relation nominalRel;
+ RangeTblEntry *nominalRTE;
/* check for unsupported flags */
Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
@@ -1726,9 +1728,10 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
estate->es_result_relation_info = saved_resultRelInfo;
/* Build state for INSERT tuple routing */
- rel = mtstate->resultRelInfo->ri_RelationDesc;
+ nominalRTE = rt_fetch(node->nominalRelation, estate->es_range_table);
+ nominalRel = heap_open(nominalRTE->relid, NoLock);
if (operation == CMD_INSERT &&
- rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ nominalRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
{
PartitionDispatch *partition_dispatch_info;
ResultRelInfo *partitions;
@@ -1737,7 +1740,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
int num_parted,
num_partitions;
- ExecSetupPartitionTupleRouting(rel,
+ ExecSetupPartitionTupleRouting(nominalRel,
&partition_dispatch_info,
&partitions,
&partition_tupconv_maps,
@@ -1801,7 +1804,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
/* varno = node->nominalRelation */
mapped_wcoList = map_partition_varattnos(wcoList,
node->nominalRelation,
- partrel, rel);
+ partrel, nominalRel);
foreach(ll, mapped_wcoList)
{
WithCheckOption *wco = (WithCheckOption *) lfirst(ll);
@@ -1876,7 +1879,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
/* varno = node->nominalRelation */
rlist = map_partition_varattnos(returningList,
node->nominalRelation,
- partrel, rel);
+ partrel, nominalRel);
rliststate = (List *) ExecInitExpr((Expr *) rlist, &mtstate->ps);
resultRelInfo->ri_projectReturning =
ExecBuildProjectionInfo(rliststate, econtext, slot,
@@ -1897,6 +1900,9 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
mtstate->ps.ps_ExprContext = NULL;
}
+ /* We're done using it. */
+ heap_close(nominalRel, NoLock);
+
/*
* If needed, Initialize target list, projection and qual for ON CONFLICT
* DO UPDATE.
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 633b5c1608..f2c8d27193 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -342,6 +342,14 @@ set_rel_size(PlannerInfo *root, RelOptInfo *rel,
/* Foreign table */
set_foreign_size(root, rel, rte);
}
+ else if (rte->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ /*
+ * A partitioned table without leaf partitions is marked
+ * as a dummy rel.
+ */
+ set_dummy_rel_pathlist(rel);
+ }
else if (rte->tablesample != NULL)
{
/* Sampled relation */
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index ca0ae7883e..b5698f0ce7 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -996,10 +996,20 @@ inheritance_planner(PlannerInfo *root)
RelOptInfo *final_rel;
ListCell *lc;
Index rti;
+ RangeTblEntry *parent_rte;
Assert(parse->commandType != CMD_INSERT);
/*
+ * If the parent RTE is a partitioned table, we should use that as the
+ * nominal relation, because we do not have the duplicate parent RTE,
+ * unlike in the case of a non-partitioned inheritance parent.
+ */
+ parent_rte = rt_fetch(parentRTindex, root->parse->rtable);
+ if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
+ nominalRelation = parentRTindex;
+
+ /*
* We generate a modified instance of the original Query for each target
* relation, plan that, and put all the plans into a list that will be
* controlled by a single ModifyTable node. All the instances share the
@@ -1060,7 +1070,6 @@ inheritance_planner(PlannerInfo *root)
{
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
PlannerInfo *subroot;
- RangeTblEntry *parent_rte;
RangeTblEntry *child_rte;
RelOptInfo *sub_final_rel;
Path *subpath;
@@ -1214,6 +1223,9 @@ inheritance_planner(PlannerInfo *root)
* will not be otherwise referenced in the plan, doing so would give
* rise to confusing use of multiple aliases in EXPLAIN output for
* what the user will think is the "same" table.)
+ *
+ * If the parent is a partitioned table, we already set the nominal
+ * relation.
*/
if (nominalRelation < 0)
nominalRelation = appinfo->child_relid;
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 1389db18ba..b4c65c4a90 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -1364,6 +1364,7 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
List *inhOIDs;
List *appinfos;
ListCell *l;
+ bool has_child;
/* Does RT entry allow inheritance? */
if (!rte->inh)
@@ -1435,6 +1436,7 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
/* Scan the inheritance set and expand it */
appinfos = NIL;
+ has_child = false;
foreach(l, inhOIDs)
{
Oid childOID = lfirst_oid(l);
@@ -1450,6 +1452,22 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
newrelation = oldrelation;
/*
+ * Since partitioned tables themselves do not contain data, later
+ * planning steps should not create scan nodes for them. So do not
+ * create the child RTE and AppendRelInfo.
+ */
+ if (newrelation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ /*
+ * Don't lose the lock taken for us by find_all_inheritors()
+ * lest its partitions change under us.
+ */
+ if (newrelation != oldrelation)
+ heap_close(newrelation, NoLock);
+ continue;
+ }
+
+ /*
* It is possible that the parent table has children that are temp
* tables of other backends. We cannot safely access such tables
* (because of buffering issues), and the best thing to do seems to be
@@ -1461,6 +1479,9 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
continue;
}
+ /* We have a child table. */
+ has_child = true;
+
/*
* Build an RTE for the child, and attach to query's rangetable list.
* We copy most fields of the parent's RTE, but replace relation OID
@@ -1545,12 +1566,13 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
heap_close(oldrelation, NoLock);
/*
- * If all the children were temp tables, pretend it's a non-inheritance
- * situation. The duplicate RTE we added for the parent table is
- * harmless, so we don't bother to get rid of it; ditto for the useless
- * PlanRowMark node.
+ * If all the children were temp tables or if the parent is a partitioned
+ * table without any leaf partitions, pretend it's a non-inheritance
+ * situation. The duplicate RTE for the parent table we added in the
+ * non-partitioned table case is harmless, so we don't bother to get rid
+ * of it; ditto for the useless PlanRowMark node.
*/
- if (list_length(appinfos) < 2)
+ if (!has_child)
{
/* Clear flag before returning */
rte->inh = false;
diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out
index a8c8b28a75..55b147432f 100644
--- a/src/test/regress/expected/inherit.out
+++ b/src/test/regress/expected/inherit.out
@@ -1598,6 +1598,14 @@ reset enable_bitmapscan;
create table list_parted (
a varchar
) partition by list (a);
+-- test scanning partitioned table without any partitions
+explain (costs off) select * from list_parted;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
create table part_ab_cd partition of list_parted for values in ('ab', 'cd');
create table part_ef_gh partition of list_parted for values in ('ef', 'gh');
create table part_null_xy partition of list_parted for values in (null, 'xy');
@@ -1605,77 +1613,74 @@ explain (costs off) select * from list_parted;
QUERY PLAN
--------------------------------
Append
- -> Seq Scan on list_parted
-> Seq Scan on part_ab_cd
-> Seq Scan on part_ef_gh
-> Seq Scan on part_null_xy
-(5 rows)
+(4 rows)
explain (costs off) select * from list_parted where a is null;
QUERY PLAN
--------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (a IS NULL)
-> Seq Scan on part_null_xy
Filter: (a IS NULL)
-(5 rows)
+(3 rows)
explain (costs off) select * from list_parted where a is not null;
QUERY PLAN
---------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (a IS NOT NULL)
-> Seq Scan on part_ab_cd
Filter: (a IS NOT NULL)
-> Seq Scan on part_ef_gh
Filter: (a IS NOT NULL)
-> Seq Scan on part_null_xy
Filter: (a IS NOT NULL)
-(9 rows)
+(7 rows)
explain (costs off) select * from list_parted where a in ('ab', 'cd', 'ef');
QUERY PLAN
----------------------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-> Seq Scan on part_ab_cd
Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-> Seq Scan on part_ef_gh
Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-(7 rows)
+(5 rows)
explain (costs off) select * from list_parted where a = 'ab' or a in (null, 'cd');
QUERY PLAN
---------------------------------------------------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_ab_cd
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_ef_gh
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_null_xy
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-(9 rows)
+(7 rows)
explain (costs off) select * from list_parted where a = 'ab';
QUERY PLAN
------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: ((a)::text = 'ab'::text)
-> Seq Scan on part_ab_cd
Filter: ((a)::text = 'ab'::text)
-(5 rows)
+(3 rows)
create table range_list_parted (
a int,
b char(2)
) partition by range (a);
create table part_1_10 partition of range_list_parted for values from (1) to (10) partition by list (b);
+-- test scanning partitioned table without any leaf partitions
+explain (costs off) select * from range_list_parted;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
create table part_1_10_ab partition of part_1_10 for values in ('ab');
create table part_1_10_cd partition of part_1_10 for values in ('cd');
create table part_10_20 partition of range_list_parted for values from (10) to (20) partition by list (b);
@@ -1689,14 +1694,9 @@ create table part_40_inf_ab partition of part_40_inf for values in ('ab');
create table part_40_inf_cd partition of part_40_inf for values in ('cd');
create table part_40_inf_null partition of part_40_inf for values in (null);
explain (costs off) select * from range_list_parted;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- -> Seq Scan on part_1_10
- -> Seq Scan on part_10_20
- -> Seq Scan on part_21_30
- -> Seq Scan on part_40_inf
-> Seq Scan on part_1_10_ab
-> Seq Scan on part_1_10_cd
-> Seq Scan on part_10_20_ab
@@ -1706,36 +1706,22 @@ explain (costs off) select * from range_list_parted;
-> Seq Scan on part_40_inf_ab
-> Seq Scan on part_40_inf_cd
-> Seq Scan on part_40_inf_null
-(15 rows)
+(10 rows)
explain (costs off) select * from range_list_parted where a = 5;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+--------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (a = 5)
- -> Seq Scan on part_1_10
- Filter: (a = 5)
-> Seq Scan on part_1_10_ab
Filter: (a = 5)
-> Seq Scan on part_1_10_cd
Filter: (a = 5)
-(9 rows)
+(5 rows)
explain (costs off) select * from range_list_parted where b = 'ab';
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_1_10
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_10_20
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_21_30
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_40_inf
- Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_1_10_ab
Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_10_20_ab
@@ -1744,27 +1730,19 @@ explain (costs off) select * from range_list_parted where b = 'ab';
Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_40_inf_ab
Filter: (b = 'ab'::bpchar)
-(19 rows)
+(9 rows)
explain (costs off) select * from range_list_parted where a between 3 and 23 and b in ('ab');
QUERY PLAN
-----------------------------------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_1_10
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_10_20
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_21_30
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_1_10_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_10_20_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_21_30_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-(15 rows)
+(7 rows)
/* Should select no rows because range partition key cannot be null */
explain (costs off) select * from range_list_parted where a is null;
@@ -1776,37 +1754,17 @@ explain (costs off) select * from range_list_parted where a is null;
/* Should only select rows from the null-accepting partition */
explain (costs off) select * from range_list_parted where b is null;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (b IS NULL)
- -> Seq Scan on part_1_10
- Filter: (b IS NULL)
- -> Seq Scan on part_10_20
- Filter: (b IS NULL)
- -> Seq Scan on part_21_30
- Filter: (b IS NULL)
- -> Seq Scan on part_40_inf
- Filter: (b IS NULL)
-> Seq Scan on part_40_inf_null
Filter: (b IS NULL)
-(13 rows)
+(3 rows)
explain (costs off) select * from range_list_parted where a is not null and a < 67;
QUERY PLAN
------------------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_1_10
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_10_20
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_21_30
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_40_inf
- Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_1_10_ab
Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_1_10_cd
@@ -1825,23 +1783,19 @@ explain (costs off) select * from range_list_parted where a is not null and a <
Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_40_inf_null
Filter: ((a IS NOT NULL) AND (a < 67))
-(29 rows)
+(19 rows)
explain (costs off) select * from range_list_parted where a >= 30;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (a >= 30)
- -> Seq Scan on part_40_inf
- Filter: (a >= 30)
-> Seq Scan on part_40_inf_ab
Filter: (a >= 30)
-> Seq Scan on part_40_inf_cd
Filter: (a >= 30)
-> Seq Scan on part_40_inf_null
Filter: (a >= 30)
-(11 rows)
+(7 rows)
drop table list_parted cascade;
NOTICE: drop cascades to 3 other objects
diff --git a/src/test/regress/expected/tablesample.out b/src/test/regress/expected/tablesample.out
index b18e420e9b..d3794140fb 100644
--- a/src/test/regress/expected/tablesample.out
+++ b/src/test/regress/expected/tablesample.out
@@ -322,12 +322,10 @@ explain (costs off)
QUERY PLAN
-------------------------------------------
Append
- -> Sample Scan on parted_sample
- Sampling: bernoulli ('100'::real)
-> Sample Scan on parted_sample_1
Sampling: bernoulli ('100'::real)
-> Sample Scan on parted_sample_2
Sampling: bernoulli ('100'::real)
-(7 rows)
+(5 rows)
drop table parted_sample, parted_sample_1, parted_sample_2;
diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql
index a8b7eb1c8d..04cc4ffa23 100644
--- a/src/test/regress/sql/inherit.sql
+++ b/src/test/regress/sql/inherit.sql
@@ -570,6 +570,10 @@ reset enable_bitmapscan;
create table list_parted (
a varchar
) partition by list (a);
+
+-- test scanning partitioned table without any partitions
+explain (costs off) select * from list_parted;
+
create table part_ab_cd partition of list_parted for values in ('ab', 'cd');
create table part_ef_gh partition of list_parted for values in ('ef', 'gh');
create table part_null_xy partition of list_parted for values in (null, 'xy');
@@ -586,6 +590,10 @@ create table range_list_parted (
b char(2)
) partition by range (a);
create table part_1_10 partition of range_list_parted for values from (1) to (10) partition by list (b);
+
+-- test scanning partitioned table without any leaf partitions
+explain (costs off) select * from range_list_parted;
+
create table part_1_10_ab partition of part_1_10 for values in ('ab');
create table part_1_10_cd partition of part_1_10 for values in ('cd');
create table part_10_20 partition of range_list_parted for values from (10) to (20) partition by list (b);
--
2.11.0
[text/x-diff] 0003-Do-not-allocate-storage-for-partitioned-tables.patch (3.1K, ../../04e417c8-cd7a-9ed5-e41e-677056b5e9c9@lab.ntt.co.jp/4-0003-Do-not-allocate-storage-for-partitioned-tables.patch)
download | inline diff:
From d03e9bca2d90447174a0e92f65c98b0f4c52f6a8 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Tue, 24 Jan 2017 14:22:34 +0900
Subject: [PATCH 3/3] Do not allocate storage for partitioned tables.
Currently, it is not possible to insert any data into a partitioned
table. So, they're empty at all times, which means it is wasteful to
allocate relfilenode and related storage objects.
---
src/backend/access/common/reloptions.c | 3 +--
src/backend/catalog/heap.c | 17 ++++++++++-------
2 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 42b4ea410f..79a75152f0 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -932,7 +932,6 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
case RELKIND_RELATION:
case RELKIND_TOASTVALUE:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
options = heap_reloptions(classForm->relkind, datum, false);
break;
case RELKIND_VIEW:
@@ -942,6 +941,7 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
options = index_reloptions(amoptions, datum, false);
break;
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
options = NULL;
break;
default:
@@ -1384,7 +1384,6 @@ heap_reloptions(char relkind, Datum reloptions, bool validate)
return (bytea *) rdopts;
case RELKIND_RELATION:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
default:
/* other relkinds are not supported */
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 41c0056556..2f5090b183 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -291,6 +291,7 @@ heap_create(const char *relname,
case RELKIND_VIEW:
case RELKIND_COMPOSITE_TYPE:
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
create_storage = false;
/*
@@ -1345,14 +1346,13 @@ heap_create_with_catalog(const char *relname,
if (oncommit != ONCOMMIT_NOOP)
register_on_commit_action(relid, oncommit);
- if (relpersistence == RELPERSISTENCE_UNLOGGED)
- {
- Assert(relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW ||
- relkind == RELKIND_TOASTVALUE ||
- relkind == RELKIND_PARTITIONED_TABLE);
-
+ /*
+ * We do not want to create any storage objects for a partitioned
+ * table, including the init fork.
+ */
+ if (relpersistence == RELPERSISTENCE_UNLOGGED &&
+ relkind != RELKIND_PARTITIONED_TABLE)
heap_create_init_fork(new_rel_desc);
- }
/*
* ok, the relation has been cataloged, so close our relations and return
@@ -1376,6 +1376,9 @@ heap_create_with_catalog(const char *relname,
void
heap_create_init_fork(Relation rel)
{
+ Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
+ rel->rd_rel->relkind == RELKIND_MATVIEW ||
+ rel->rd_rel->relkind == RELKIND_TOASTVALUE);
RelationOpenSmgr(rel);
smgrcreate(rel->rd_smgr, INIT_FORKNUM, false);
log_smgrcreate(&rel->rd_smgr->smgr_rnode.node, INIT_FORKNUM);
--
2.11.0
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-03-06 06:41 ` Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
1 sibling, 1 reply; 96+ messages in thread
From: Michael Paquier @ 2017-03-06 06:41 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: Robert Haas <robertmhaas@gmail.com>; Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On Fri, Mar 3, 2017 at 10:02 AM, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
> Thanks. I noticed that 'and' is duplicated in a line added by the commit
> to analyze.sgml. Attached 0001 fixes that. 0002 and 0003 same as the
> last version.
/*
- * If all the children were temp tables, pretend it's a non-inheritance
- * situation. The duplicate RTE we added for the parent table is
- * harmless, so we don't bother to get rid of it; ditto for the useless
- * PlanRowMark node.
+ * If all the children were temp tables or if the parent is a partitioned
+ * table without any leaf partitions, pretend it's a non-inheritance
+ * situation. The duplicate RTE for the parent table we added in the
+ * non-partitioned table case is harmless, so we don't bother to get rid
+ * of it; ditto for the useless PlanRowMark node.
*/
- if (list_length(appinfos) < 2)
+ if (!has_child)
This comment is not completely correct. Children can be temp tables,
they just cannot be temp tables of other backends. It seems to me that
you could still keep this code simple and remove has_child..
@@ -932,7 +932,6 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
case RELKIND_RELATION:
case RELKIND_TOASTVALUE:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
options = heap_reloptions(classForm->relkind, datum, false);
break;
Partitioned tables cannot have reloptions? What about all the
autovacuum_* parameters then? Those are mainly not storage-related.
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
@ 2017-03-06 07:18 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 07:49 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-06 08:22 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
0 siblings, 3 replies; 96+ messages in thread
From: Amit Langote @ 2017-03-06 07:18 UTC (permalink / raw)
To: Michael Paquier <michael.paquier@gmail.com>; +Cc: Robert Haas <robertmhaas@gmail.com>; Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
Thanks for the review.
On 2017/03/06 15:41, Michael Paquier wrote:
> On Fri, Mar 3, 2017 at 10:02 AM, Amit Langote
> <Langote_Amit_f8@lab.ntt.co.jp> wrote:
>> Thanks. I noticed that 'and' is duplicated in a line added by the commit
>> to analyze.sgml. Attached 0001 fixes that. 0002 and 0003 same as the
>> last version.
>
> /*
> - * If all the children were temp tables, pretend it's a non-inheritance
> - * situation. The duplicate RTE we added for the parent table is
> - * harmless, so we don't bother to get rid of it; ditto for the useless
> - * PlanRowMark node.
> + * If all the children were temp tables or if the parent is a partitioned
> + * table without any leaf partitions, pretend it's a non-inheritance
> + * situation. The duplicate RTE for the parent table we added in the
> + * non-partitioned table case is harmless, so we don't bother to get rid
> + * of it; ditto for the useless PlanRowMark node.
> */
> - if (list_length(appinfos) < 2)
> + if (!has_child)
> This comment is not completely correct. Children can be temp tables,
> they just cannot be temp tables of other backends. It seems to me that
> you could still keep this code simple and remove has_child..
I updated the comment. I recall having posted a patch for that once, but
perhaps went unnoticed.
About has_child, the other option is to make the minimum length of
appinfos list relkind-based, but the condition quickly becomes ugly. Do
you have a suggestion?
> @@ -932,7 +932,6 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
> case RELKIND_RELATION:
> case RELKIND_TOASTVALUE:
> case RELKIND_MATVIEW:
> - case RELKIND_PARTITIONED_TABLE:
> options = heap_reloptions(classForm->relkind, datum, false);
> break;
> Partitioned tables cannot have reloptions? What about all the
> autovacuum_* parameters then? Those are mainly not storage-related.
AFAIK, none of the heap reloptions will be applicable to partitioned table
relations once we eliminate storage.
About autovacuum_* parameters - we currently don't handle partitioned
tables in autovacuum.c, because no statistics are reported for them. That
is, relation_needs_vacanalyze() will never return true for dovacuum,
doanalyze and wraparound if it is passed a RELKIND_PARTITIONED_TABLE
relation. That's something to be fixed separately though. When we add
autovacuum support for partitioned tables, we may want to add a new set of
reloptions (new because partitioned tables still won't support all options
returned by heap_reloptions()). Am I missing something?
Thanks,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Attachments:
[text/x-diff] 0001-Fix-duplicated-and-in-analyze.sgml.patch (1.1K, ../../0a8e440f-e938-457a-e7ef-b5281060bd42@lab.ntt.co.jp/2-0001-Fix-duplicated-and-in-analyze.sgml.patch)
download | inline diff:
From 7cea5e205742c14893a8f52f213118b7de091062 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Fri, 3 Mar 2017 09:57:11 +0900
Subject: [PATCH 1/3] Fix duplicated 'and' in analyze.sgml
---
doc/src/sgml/ref/analyze.sgml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/doc/src/sgml/ref/analyze.sgml b/doc/src/sgml/ref/analyze.sgml
index 49727e22df..45dee101df 100644
--- a/doc/src/sgml/ref/analyze.sgml
+++ b/doc/src/sgml/ref/analyze.sgml
@@ -64,7 +64,7 @@ ANALYZE [ VERBOSE ] [ <replaceable class="PARAMETER">table_name</replaceable> [
<para>
The name (possibly schema-qualified) of a specific table to
analyze. If omitted, all regular tables, partitioned tables, and
- and materialized views in the current database are analyzed (but not
+ materialized views in the current database are analyzed (but not
foreign tables). If the specified table is a partitioned table, both the
inheritance statistics of the partitioned table as a whole and
statistics of the individual partitions are updated.
--
2.11.0
[text/x-diff] 0002-Avoid-creating-scan-nodes-for-partitioned-tables.patch (21.1K, ../../0a8e440f-e938-457a-e7ef-b5281060bd42@lab.ntt.co.jp/3-0002-Avoid-creating-scan-nodes-for-partitioned-tables.patch)
download | inline diff:
From 8ad7b95c56cd261b4581447aed1f3a6519b8ae06 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Mon, 6 Feb 2017 17:26:48 +0900
Subject: [PATCH 2/3] Avoid creating scan nodes for partitioned tables
* Currently, we create scan nodes for inheritance parents in their role
as an inheritance set member. Partitioned tables do not contain any
data, so it's useless to create scan nodes for them. So we need not
create AppendRelInfo's for them in the planner prep phase.
* The planner prep phase turns off inheritance on the parent RTE if
there isn't at least one child member (other than the parent itself
which in normal cases is also a child member), which means the latter
phases will not consider creating an Append plan and instead create a
scan node. Avoid this if the RTE is a partitioned table, by noticing
such cases in set_rel_size(). Per suggestion from Ashutosh Bapat.
* Since we do not add the RTE corresponding to the root partitioned
table as the 1st child member of the inheritance set,
inheritance_planner() must not assume the same when assigning
nominalRelation to a ModifyTable node.
* In ExecInitModifyTable(), use nominalRelation to initialize tuple
routing information, instead of the first resultRelInfo. We set
ModifyTable.nominalRelation to the root parent RTE in the
partitioned table case (implicitly in the INSERT case, whereas
explicitly in the UPDATE/DELETE cases).
---
src/backend/executor/nodeModifyTable.c | 18 +++--
src/backend/optimizer/path/allpaths.c | 8 ++
src/backend/optimizer/plan/planner.c | 14 +++-
src/backend/optimizer/prep/prepunion.c | 32 ++++++--
src/test/regress/expected/inherit.out | 124 ++++++++++--------------------
src/test/regress/expected/tablesample.out | 4 +-
src/test/regress/sql/inherit.sql | 8 ++
7 files changed, 108 insertions(+), 100 deletions(-)
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 95e158970c..188ce8f8d4 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -45,6 +45,7 @@
#include "foreign/fdwapi.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
+#include "parser/parsetree.h"
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
#include "utils/builtins.h"
@@ -1634,7 +1635,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
Plan *subplan;
ListCell *l;
int i;
- Relation rel;
+ Relation nominalRel;
+ RangeTblEntry *nominalRTE;
/* check for unsupported flags */
Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
@@ -1726,9 +1728,10 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
estate->es_result_relation_info = saved_resultRelInfo;
/* Build state for INSERT tuple routing */
- rel = mtstate->resultRelInfo->ri_RelationDesc;
+ nominalRTE = rt_fetch(node->nominalRelation, estate->es_range_table);
+ nominalRel = heap_open(nominalRTE->relid, NoLock);
if (operation == CMD_INSERT &&
- rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ nominalRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
{
PartitionDispatch *partition_dispatch_info;
ResultRelInfo *partitions;
@@ -1737,7 +1740,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
int num_parted,
num_partitions;
- ExecSetupPartitionTupleRouting(rel,
+ ExecSetupPartitionTupleRouting(nominalRel,
&partition_dispatch_info,
&partitions,
&partition_tupconv_maps,
@@ -1801,7 +1804,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
/* varno = node->nominalRelation */
mapped_wcoList = map_partition_varattnos(wcoList,
node->nominalRelation,
- partrel, rel);
+ partrel, nominalRel);
foreach(ll, mapped_wcoList)
{
WithCheckOption *wco = (WithCheckOption *) lfirst(ll);
@@ -1876,7 +1879,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
/* varno = node->nominalRelation */
rlist = map_partition_varattnos(returningList,
node->nominalRelation,
- partrel, rel);
+ partrel, nominalRel);
rliststate = (List *) ExecInitExpr((Expr *) rlist, &mtstate->ps);
resultRelInfo->ri_projectReturning =
ExecBuildProjectionInfo(rliststate, econtext, slot,
@@ -1897,6 +1900,9 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
mtstate->ps.ps_ExprContext = NULL;
}
+ /* We're done using it. */
+ heap_close(nominalRel, NoLock);
+
/*
* If needed, Initialize target list, projection and qual for ON CONFLICT
* DO UPDATE.
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 633b5c1608..f2c8d27193 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -342,6 +342,14 @@ set_rel_size(PlannerInfo *root, RelOptInfo *rel,
/* Foreign table */
set_foreign_size(root, rel, rte);
}
+ else if (rte->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ /*
+ * A partitioned table without leaf partitions is marked
+ * as a dummy rel.
+ */
+ set_dummy_rel_pathlist(rel);
+ }
else if (rte->tablesample != NULL)
{
/* Sampled relation */
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index ca0ae7883e..b5698f0ce7 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -996,10 +996,20 @@ inheritance_planner(PlannerInfo *root)
RelOptInfo *final_rel;
ListCell *lc;
Index rti;
+ RangeTblEntry *parent_rte;
Assert(parse->commandType != CMD_INSERT);
/*
+ * If the parent RTE is a partitioned table, we should use that as the
+ * nominal relation, because we do not have the duplicate parent RTE,
+ * unlike in the case of a non-partitioned inheritance parent.
+ */
+ parent_rte = rt_fetch(parentRTindex, root->parse->rtable);
+ if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
+ nominalRelation = parentRTindex;
+
+ /*
* We generate a modified instance of the original Query for each target
* relation, plan that, and put all the plans into a list that will be
* controlled by a single ModifyTable node. All the instances share the
@@ -1060,7 +1070,6 @@ inheritance_planner(PlannerInfo *root)
{
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
PlannerInfo *subroot;
- RangeTblEntry *parent_rte;
RangeTblEntry *child_rte;
RelOptInfo *sub_final_rel;
Path *subpath;
@@ -1214,6 +1223,9 @@ inheritance_planner(PlannerInfo *root)
* will not be otherwise referenced in the plan, doing so would give
* rise to confusing use of multiple aliases in EXPLAIN output for
* what the user will think is the "same" table.)
+ *
+ * If the parent is a partitioned table, we already set the nominal
+ * relation.
*/
if (nominalRelation < 0)
nominalRelation = appinfo->child_relid;
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 1389db18ba..7bd4928945 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -1364,6 +1364,7 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
List *inhOIDs;
List *appinfos;
ListCell *l;
+ bool has_child;
/* Does RT entry allow inheritance? */
if (!rte->inh)
@@ -1435,6 +1436,7 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
/* Scan the inheritance set and expand it */
appinfos = NIL;
+ has_child = false;
foreach(l, inhOIDs)
{
Oid childOID = lfirst_oid(l);
@@ -1450,6 +1452,22 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
newrelation = oldrelation;
/*
+ * Since partitioned tables themselves do not contain data, later
+ * planning steps should not create scan nodes for them. So do not
+ * create the child RTE and AppendRelInfo.
+ */
+ if (newrelation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ /*
+ * Don't lose the lock taken for us by find_all_inheritors()
+ * lest its partitions change under us.
+ */
+ if (newrelation != oldrelation)
+ heap_close(newrelation, NoLock);
+ continue;
+ }
+
+ /*
* It is possible that the parent table has children that are temp
* tables of other backends. We cannot safely access such tables
* (because of buffering issues), and the best thing to do seems to be
@@ -1461,6 +1479,9 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
continue;
}
+ /* We have a child table. */
+ has_child = true;
+
/*
* Build an RTE for the child, and attach to query's rangetable list.
* We copy most fields of the parent's RTE, but replace relation OID
@@ -1545,12 +1566,13 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
heap_close(oldrelation, NoLock);
/*
- * If all the children were temp tables, pretend it's a non-inheritance
- * situation. The duplicate RTE we added for the parent table is
- * harmless, so we don't bother to get rid of it; ditto for the useless
- * PlanRowMark node.
+ * If all the children were temp tables of other backends or if the parent
+ * is a partitioned table without any leaf partitions, pretend it's a
+ * non-inheritance situation. The duplicate RTE for the parent table we
+ * added in the non-partitioned table case is harmless, so we don't bother
+ * to get rid of it; ditto for the useless PlanRowMark node.
*/
- if (list_length(appinfos) < 2)
+ if (!has_child)
{
/* Clear flag before returning */
rte->inh = false;
diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out
index a8c8b28a75..55b147432f 100644
--- a/src/test/regress/expected/inherit.out
+++ b/src/test/regress/expected/inherit.out
@@ -1598,6 +1598,14 @@ reset enable_bitmapscan;
create table list_parted (
a varchar
) partition by list (a);
+-- test scanning partitioned table without any partitions
+explain (costs off) select * from list_parted;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
create table part_ab_cd partition of list_parted for values in ('ab', 'cd');
create table part_ef_gh partition of list_parted for values in ('ef', 'gh');
create table part_null_xy partition of list_parted for values in (null, 'xy');
@@ -1605,77 +1613,74 @@ explain (costs off) select * from list_parted;
QUERY PLAN
--------------------------------
Append
- -> Seq Scan on list_parted
-> Seq Scan on part_ab_cd
-> Seq Scan on part_ef_gh
-> Seq Scan on part_null_xy
-(5 rows)
+(4 rows)
explain (costs off) select * from list_parted where a is null;
QUERY PLAN
--------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (a IS NULL)
-> Seq Scan on part_null_xy
Filter: (a IS NULL)
-(5 rows)
+(3 rows)
explain (costs off) select * from list_parted where a is not null;
QUERY PLAN
---------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (a IS NOT NULL)
-> Seq Scan on part_ab_cd
Filter: (a IS NOT NULL)
-> Seq Scan on part_ef_gh
Filter: (a IS NOT NULL)
-> Seq Scan on part_null_xy
Filter: (a IS NOT NULL)
-(9 rows)
+(7 rows)
explain (costs off) select * from list_parted where a in ('ab', 'cd', 'ef');
QUERY PLAN
----------------------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-> Seq Scan on part_ab_cd
Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-> Seq Scan on part_ef_gh
Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-(7 rows)
+(5 rows)
explain (costs off) select * from list_parted where a = 'ab' or a in (null, 'cd');
QUERY PLAN
---------------------------------------------------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_ab_cd
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_ef_gh
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_null_xy
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-(9 rows)
+(7 rows)
explain (costs off) select * from list_parted where a = 'ab';
QUERY PLAN
------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: ((a)::text = 'ab'::text)
-> Seq Scan on part_ab_cd
Filter: ((a)::text = 'ab'::text)
-(5 rows)
+(3 rows)
create table range_list_parted (
a int,
b char(2)
) partition by range (a);
create table part_1_10 partition of range_list_parted for values from (1) to (10) partition by list (b);
+-- test scanning partitioned table without any leaf partitions
+explain (costs off) select * from range_list_parted;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
create table part_1_10_ab partition of part_1_10 for values in ('ab');
create table part_1_10_cd partition of part_1_10 for values in ('cd');
create table part_10_20 partition of range_list_parted for values from (10) to (20) partition by list (b);
@@ -1689,14 +1694,9 @@ create table part_40_inf_ab partition of part_40_inf for values in ('ab');
create table part_40_inf_cd partition of part_40_inf for values in ('cd');
create table part_40_inf_null partition of part_40_inf for values in (null);
explain (costs off) select * from range_list_parted;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- -> Seq Scan on part_1_10
- -> Seq Scan on part_10_20
- -> Seq Scan on part_21_30
- -> Seq Scan on part_40_inf
-> Seq Scan on part_1_10_ab
-> Seq Scan on part_1_10_cd
-> Seq Scan on part_10_20_ab
@@ -1706,36 +1706,22 @@ explain (costs off) select * from range_list_parted;
-> Seq Scan on part_40_inf_ab
-> Seq Scan on part_40_inf_cd
-> Seq Scan on part_40_inf_null
-(15 rows)
+(10 rows)
explain (costs off) select * from range_list_parted where a = 5;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+--------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (a = 5)
- -> Seq Scan on part_1_10
- Filter: (a = 5)
-> Seq Scan on part_1_10_ab
Filter: (a = 5)
-> Seq Scan on part_1_10_cd
Filter: (a = 5)
-(9 rows)
+(5 rows)
explain (costs off) select * from range_list_parted where b = 'ab';
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_1_10
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_10_20
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_21_30
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_40_inf
- Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_1_10_ab
Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_10_20_ab
@@ -1744,27 +1730,19 @@ explain (costs off) select * from range_list_parted where b = 'ab';
Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_40_inf_ab
Filter: (b = 'ab'::bpchar)
-(19 rows)
+(9 rows)
explain (costs off) select * from range_list_parted where a between 3 and 23 and b in ('ab');
QUERY PLAN
-----------------------------------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_1_10
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_10_20
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_21_30
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_1_10_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_10_20_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_21_30_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-(15 rows)
+(7 rows)
/* Should select no rows because range partition key cannot be null */
explain (costs off) select * from range_list_parted where a is null;
@@ -1776,37 +1754,17 @@ explain (costs off) select * from range_list_parted where a is null;
/* Should only select rows from the null-accepting partition */
explain (costs off) select * from range_list_parted where b is null;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (b IS NULL)
- -> Seq Scan on part_1_10
- Filter: (b IS NULL)
- -> Seq Scan on part_10_20
- Filter: (b IS NULL)
- -> Seq Scan on part_21_30
- Filter: (b IS NULL)
- -> Seq Scan on part_40_inf
- Filter: (b IS NULL)
-> Seq Scan on part_40_inf_null
Filter: (b IS NULL)
-(13 rows)
+(3 rows)
explain (costs off) select * from range_list_parted where a is not null and a < 67;
QUERY PLAN
------------------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_1_10
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_10_20
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_21_30
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_40_inf
- Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_1_10_ab
Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_1_10_cd
@@ -1825,23 +1783,19 @@ explain (costs off) select * from range_list_parted where a is not null and a <
Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_40_inf_null
Filter: ((a IS NOT NULL) AND (a < 67))
-(29 rows)
+(19 rows)
explain (costs off) select * from range_list_parted where a >= 30;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (a >= 30)
- -> Seq Scan on part_40_inf
- Filter: (a >= 30)
-> Seq Scan on part_40_inf_ab
Filter: (a >= 30)
-> Seq Scan on part_40_inf_cd
Filter: (a >= 30)
-> Seq Scan on part_40_inf_null
Filter: (a >= 30)
-(11 rows)
+(7 rows)
drop table list_parted cascade;
NOTICE: drop cascades to 3 other objects
diff --git a/src/test/regress/expected/tablesample.out b/src/test/regress/expected/tablesample.out
index b18e420e9b..d3794140fb 100644
--- a/src/test/regress/expected/tablesample.out
+++ b/src/test/regress/expected/tablesample.out
@@ -322,12 +322,10 @@ explain (costs off)
QUERY PLAN
-------------------------------------------
Append
- -> Sample Scan on parted_sample
- Sampling: bernoulli ('100'::real)
-> Sample Scan on parted_sample_1
Sampling: bernoulli ('100'::real)
-> Sample Scan on parted_sample_2
Sampling: bernoulli ('100'::real)
-(7 rows)
+(5 rows)
drop table parted_sample, parted_sample_1, parted_sample_2;
diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql
index a8b7eb1c8d..04cc4ffa23 100644
--- a/src/test/regress/sql/inherit.sql
+++ b/src/test/regress/sql/inherit.sql
@@ -570,6 +570,10 @@ reset enable_bitmapscan;
create table list_parted (
a varchar
) partition by list (a);
+
+-- test scanning partitioned table without any partitions
+explain (costs off) select * from list_parted;
+
create table part_ab_cd partition of list_parted for values in ('ab', 'cd');
create table part_ef_gh partition of list_parted for values in ('ef', 'gh');
create table part_null_xy partition of list_parted for values in (null, 'xy');
@@ -586,6 +590,10 @@ create table range_list_parted (
b char(2)
) partition by range (a);
create table part_1_10 partition of range_list_parted for values from (1) to (10) partition by list (b);
+
+-- test scanning partitioned table without any leaf partitions
+explain (costs off) select * from range_list_parted;
+
create table part_1_10_ab partition of part_1_10 for values in ('ab');
create table part_1_10_cd partition of part_1_10 for values in ('cd');
create table part_10_20 partition of range_list_parted for values from (10) to (20) partition by list (b);
--
2.11.0
[text/x-diff] 0003-Do-not-allocate-storage-for-partitioned-tables.patch (3.1K, ../../0a8e440f-e938-457a-e7ef-b5281060bd42@lab.ntt.co.jp/4-0003-Do-not-allocate-storage-for-partitioned-tables.patch)
download | inline diff:
From 7cb068236e7ff38599d285f10ff7445d53c2626a Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Tue, 24 Jan 2017 14:22:34 +0900
Subject: [PATCH 3/3] Do not allocate storage for partitioned tables.
Currently, it is not possible to insert any data into a partitioned
table. So, they're empty at all times, which means it is wasteful to
allocate relfilenode and related storage objects.
---
src/backend/access/common/reloptions.c | 3 +--
src/backend/catalog/heap.c | 17 ++++++++++-------
2 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 42b4ea410f..79a75152f0 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -932,7 +932,6 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
case RELKIND_RELATION:
case RELKIND_TOASTVALUE:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
options = heap_reloptions(classForm->relkind, datum, false);
break;
case RELKIND_VIEW:
@@ -942,6 +941,7 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
options = index_reloptions(amoptions, datum, false);
break;
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
options = NULL;
break;
default:
@@ -1384,7 +1384,6 @@ heap_reloptions(char relkind, Datum reloptions, bool validate)
return (bytea *) rdopts;
case RELKIND_RELATION:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
default:
/* other relkinds are not supported */
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 41c0056556..2f5090b183 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -291,6 +291,7 @@ heap_create(const char *relname,
case RELKIND_VIEW:
case RELKIND_COMPOSITE_TYPE:
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
create_storage = false;
/*
@@ -1345,14 +1346,13 @@ heap_create_with_catalog(const char *relname,
if (oncommit != ONCOMMIT_NOOP)
register_on_commit_action(relid, oncommit);
- if (relpersistence == RELPERSISTENCE_UNLOGGED)
- {
- Assert(relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW ||
- relkind == RELKIND_TOASTVALUE ||
- relkind == RELKIND_PARTITIONED_TABLE);
-
+ /*
+ * We do not want to create any storage objects for a partitioned
+ * table, including the init fork.
+ */
+ if (relpersistence == RELPERSISTENCE_UNLOGGED &&
+ relkind != RELKIND_PARTITIONED_TABLE)
heap_create_init_fork(new_rel_desc);
- }
/*
* ok, the relation has been cataloged, so close our relations and return
@@ -1376,6 +1376,9 @@ heap_create_with_catalog(const char *relname,
void
heap_create_init_fork(Relation rel)
{
+ Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
+ rel->rd_rel->relkind == RELKIND_MATVIEW ||
+ rel->rd_rel->relkind == RELKIND_TOASTVALUE);
RelationOpenSmgr(rel);
smgrcreate(rel->rd_smgr, INIT_FORKNUM, false);
log_smgrcreate(&rel->rd_smgr->smgr_rnode.node, INIT_FORKNUM);
--
2.11.0
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-03-06 07:49 ` Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-06 07:56 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2 siblings, 1 reply; 96+ messages in thread
From: Ashutosh Bapat @ 2017-03-06 07:49 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: Michael Paquier <michael.paquier@gmail.com>; Robert Haas <robertmhaas@gmail.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On Mon, Mar 6, 2017 at 12:48 PM, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
> Thanks for the review.
>
> On 2017/03/06 15:41, Michael Paquier wrote:
>> On Fri, Mar 3, 2017 at 10:02 AM, Amit Langote
>> <Langote_Amit_f8@lab.ntt.co.jp> wrote:
>>> Thanks. I noticed that 'and' is duplicated in a line added by the commit
>>> to analyze.sgml. Attached 0001 fixes that. 0002 and 0003 same as the
>>> last version.
>>
>> /*
>> - * If all the children were temp tables, pretend it's a non-inheritance
>> - * situation. The duplicate RTE we added for the parent table is
>> - * harmless, so we don't bother to get rid of it; ditto for the useless
>> - * PlanRowMark node.
>> + * If all the children were temp tables or if the parent is a partitioned
>> + * table without any leaf partitions, pretend it's a non-inheritance
>> + * situation. The duplicate RTE for the parent table we added in the
>> + * non-partitioned table case is harmless, so we don't bother to get rid
>> + * of it; ditto for the useless PlanRowMark node.
>> */
>> - if (list_length(appinfos) < 2)
>> + if (!has_child)
>> This comment is not completely correct. Children can be temp tables,
>> they just cannot be temp tables of other backends. It seems to me that
>> you could still keep this code simple and remove has_child..
>
> I updated the comment. I recall having posted a patch for that once, but
> perhaps went unnoticed.
The existing comment only specifies "temp tables" and not "temp table
of other backends". The new comment keeps that part same and adds
partitioned table case. So, I don't see any reason to change the "temp
tables" to "temp table of other backends" in this patch.
>
> About has_child, the other option is to make the minimum length of
> appinfos list relkind-based, but the condition quickly becomes ugly. Do
> you have a suggestion?
>
+1.
--
Best Wishes,
Ashutosh Bapat
EnterpriseDB Corporation
The Postgres Database Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 07:49 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
@ 2017-03-06 07:56 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 08:01 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
0 siblings, 1 reply; 96+ messages in thread
From: Amit Langote @ 2017-03-06 07:56 UTC (permalink / raw)
To: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; +Cc: Michael Paquier <michael.paquier@gmail.com>; Robert Haas <robertmhaas@gmail.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On 2017/03/06 16:49, Ashutosh Bapat wrote:
> On Mon, Mar 6, 2017 at 12:48 PM, Amit Langote wrote:
>> On 2017/03/06 15:41, Michael Paquier wrote:
>>> This comment is not completely correct. Children can be temp tables,
>>> they just cannot be temp tables of other backends. It seems to me that
>>> you could still keep this code simple and remove has_child..
>>
>> I updated the comment. I recall having posted a patch for that once, but
>> perhaps went unnoticed.
>
> The existing comment only specifies "temp tables" and not "temp table
> of other backends". The new comment keeps that part same and adds
> partitioned table case. So, I don't see any reason to change the "temp
> tables" to "temp table of other backends" in this patch.
Hmm. A separate patch might be fine but why not fix the incorrect part
while we are updating the whole comment anyway.
Thanks,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 07:49 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-06 07:56 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-03-06 08:01 ` Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-06 08:23 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
0 siblings, 1 reply; 96+ messages in thread
From: Ashutosh Bapat @ 2017-03-06 08:01 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: Michael Paquier <michael.paquier@gmail.com>; Robert Haas <robertmhaas@gmail.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On Mon, Mar 6, 2017 at 1:26 PM, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
> On 2017/03/06 16:49, Ashutosh Bapat wrote:
>> On Mon, Mar 6, 2017 at 12:48 PM, Amit Langote wrote:
>>> On 2017/03/06 15:41, Michael Paquier wrote:
>>>> This comment is not completely correct. Children can be temp tables,
>>>> they just cannot be temp tables of other backends. It seems to me that
>>>> you could still keep this code simple and remove has_child..
>>>
>>> I updated the comment. I recall having posted a patch for that once, but
>>> perhaps went unnoticed.
>>
>> The existing comment only specifies "temp tables" and not "temp table
>> of other backends". The new comment keeps that part same and adds
>> partitioned table case. So, I don't see any reason to change the "temp
>> tables" to "temp table of other backends" in this patch.
>
> Hmm. A separate patch might be fine but why not fix the incorrect part
> while we are updating the whole comment anyway.
There must be a reason why that comment is written the way it's
written. I guess, "from other backends" part of "temp tables" story
has been explained just few lines above and the author/s didn't want
to repeat it again. There's no point in changing it while we are not
touching temp tables handling.
--
Best Wishes,
Ashutosh Bapat
EnterpriseDB Corporation
The Postgres Database Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 07:49 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-06 07:56 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 08:01 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
@ 2017-03-06 08:23 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 08:29 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
0 siblings, 1 reply; 96+ messages in thread
From: Amit Langote @ 2017-03-06 08:23 UTC (permalink / raw)
To: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; +Cc: Michael Paquier <michael.paquier@gmail.com>; Robert Haas <robertmhaas@gmail.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On 2017/03/06 17:01, Ashutosh Bapat wrote:
> On Mon, Mar 6, 2017 at 1:26 PM, Amit Langote
> <Langote_Amit_f8@lab.ntt.co.jp> wrote:
>> On 2017/03/06 16:49, Ashutosh Bapat wrote:
>>> On Mon, Mar 6, 2017 at 12:48 PM, Amit Langote wrote:
>>>> On 2017/03/06 15:41, Michael Paquier wrote:
>>>>> This comment is not completely correct. Children can be temp tables,
>>>>> they just cannot be temp tables of other backends. It seems to me that
>>>>> you could still keep this code simple and remove has_child..
>>>>
>>>> I updated the comment. I recall having posted a patch for that once, but
>>>> perhaps went unnoticed.
>>>
>>> The existing comment only specifies "temp tables" and not "temp table
>>> of other backends". The new comment keeps that part same and adds
>>> partitioned table case. So, I don't see any reason to change the "temp
>>> tables" to "temp table of other backends" in this patch.
>>
>> Hmm. A separate patch might be fine but why not fix the incorrect part
>> while we are updating the whole comment anyway.
>
> There must be a reason why that comment is written the way it's
> written. I guess, "from other backends" part of "temp tables" story
> has been explained just few lines above and the author/s didn't want
> to repeat it again.
That's perhaps true. I guess it depends on who reads it. Someone might
think the comment is incorrect because *not all* temporary child tables
are excluded.
> There's no point in changing it while we are not
> touching temp tables handling.
We can leave it for the committer to decide, maybe. Committers often
rewrite surrounding comments to improve wording, correcting factual
errors, etc.
Thanks,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 07:49 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-06 07:56 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 08:01 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-06 08:23 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-03-06 08:29 ` Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
0 siblings, 0 replies; 96+ messages in thread
From: Ashutosh Bapat @ 2017-03-06 08:29 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: Michael Paquier <michael.paquier@gmail.com>; Robert Haas <robertmhaas@gmail.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
>
> We can leave it for the committer to decide, maybe. Committers often
> rewrite surrounding comments to improve wording, correcting factual
> errors, etc.
>
Sure.
--
Best Wishes,
Ashutosh Bapat
EnterpriseDB Corporation
The Postgres Database Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-03-06 08:22 ` Michael Paquier <michael.paquier@gmail.com>
2017-03-07 01:56 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2 siblings, 1 reply; 96+ messages in thread
From: Michael Paquier @ 2017-03-06 08:22 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: Robert Haas <robertmhaas@gmail.com>; Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On Mon, Mar 6, 2017 at 4:18 PM, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
> About autovacuum_* parameters - we currently don't handle partitioned
> tables in autovacuum.c, because no statistics are reported for them. That
> is, relation_needs_vacanalyze() will never return true for dovacuum,
> doanalyze and wraparound if it is passed a RELKIND_PARTITIONED_TABLE
> relation. That's something to be fixed separately though. When we add
> autovacuum support for partitioned tables, we may want to add a new set of
> reloptions (new because partitioned tables still won't support all options
> returned by heap_reloptions()). Am I missing something?
OK. I got confused by the fact that settings on parents should
super-seed the settings of the children. Or if you want if a value is
set on the parent by default it would apply to the child if it has no
value set, which is where autovacuum_enabled makes sense even for
partitioned tables. Leading to the point that parents could have
reloptions, with a new category of the type RELOPT_KIND_PARTITION.
Still, it is sensible as well to bypass the parents in autovacuum as
well, now that I read it. And the handling is more simple.
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 08:22 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
@ 2017-03-07 01:56 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
0 siblings, 0 replies; 96+ messages in thread
From: Amit Langote @ 2017-03-07 01:56 UTC (permalink / raw)
To: Michael Paquier <michael.paquier@gmail.com>; +Cc: Robert Haas <robertmhaas@gmail.com>; Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On 2017/03/06 17:22, Michael Paquier wrote:
> On Mon, Mar 6, 2017 at 4:18 PM, Amit Langote
> <Langote_Amit_f8@lab.ntt.co.jp> wrote:
>> About autovacuum_* parameters - we currently don't handle partitioned
>> tables in autovacuum.c, because no statistics are reported for them. That
>> is, relation_needs_vacanalyze() will never return true for dovacuum,
>> doanalyze and wraparound if it is passed a RELKIND_PARTITIONED_TABLE
>> relation. That's something to be fixed separately though. When we add
>> autovacuum support for partitioned tables, we may want to add a new set of
>> reloptions (new because partitioned tables still won't support all options
>> returned by heap_reloptions()). Am I missing something?
>
> OK. I got confused by the fact that settings on parents should
> super-seed the settings of the children. Or if you want if a value is
> set on the parent by default it would apply to the child if it has no
> value set, which is where autovacuum_enabled makes sense even for
> partitioned tables.
Hmm, setting autovacuum_enabled on partitioned parent should be made to
work after we have fixed autovacuum support for partitioned tables. Using
the parent's value as a default for partitions may not be what we'd want
eventually.
> Leading to the point that parents could have
> reloptions, with a new category of the type RELOPT_KIND_PARTITION.
> Still, it is sensible as well to bypass the parents in autovacuum as
> well, now that I read it. And the handling is more simple.
We will need it though, because lack of automatically updated
"inheritance" (or whole tree) statistics on partitioned tables is a problem.
Thanks,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-03-07 05:11 ` Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2 siblings, 1 reply; 96+ messages in thread
From: Ashutosh Bapat @ 2017-03-07 05:11 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: Michael Paquier <michael.paquier@gmail.com>; Robert Haas <robertmhaas@gmail.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
I see that all the changes by Amit and myself to what was earlier 0003
patch are now part of 0002 patch. The patch looks ready for committer.
Some comments about 0003 patch.
CREATE TABLE syntax seems to allow specifying reloptions for a
partitioned table. But extractRelOptions() and heap_reloptions() seem
to be ignoring those. Is that intentional? There are two callers of
extractRelOptions(), extract_autovac_opts() and
RelationParseRelOptions(). There's an assert in extract_autovac_opts()
preventing that function from getting called for partitioned table.
RelationParseRelOptions() seems to filter the relations before calling
extractRelOptions(). I am wondering whether it's better to leave
extractRelOptions() and filter partitioned relations in
RelationParseRelOptions().
Do we need similar condition modification in the other caller of i.e.
heap_create_init_fork(), ExecuteTruncate()?
On Mon, Mar 6, 2017 at 12:48 PM, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
> Thanks for the review.
>
> On 2017/03/06 15:41, Michael Paquier wrote:
>> On Fri, Mar 3, 2017 at 10:02 AM, Amit Langote
>> <Langote_Amit_f8@lab.ntt.co.jp> wrote:
>>> Thanks. I noticed that 'and' is duplicated in a line added by the commit
>>> to analyze.sgml. Attached 0001 fixes that. 0002 and 0003 same as the
>>> last version.
>>
>> /*
>> - * If all the children were temp tables, pretend it's a non-inheritance
>> - * situation. The duplicate RTE we added for the parent table is
>> - * harmless, so we don't bother to get rid of it; ditto for the useless
>> - * PlanRowMark node.
>> + * If all the children were temp tables or if the parent is a partitioned
>> + * table without any leaf partitions, pretend it's a non-inheritance
>> + * situation. The duplicate RTE for the parent table we added in the
>> + * non-partitioned table case is harmless, so we don't bother to get rid
>> + * of it; ditto for the useless PlanRowMark node.
>> */
>> - if (list_length(appinfos) < 2)
>> + if (!has_child)
>> This comment is not completely correct. Children can be temp tables,
>> they just cannot be temp tables of other backends. It seems to me that
>> you could still keep this code simple and remove has_child..
>
> I updated the comment. I recall having posted a patch for that once, but
> perhaps went unnoticed.
>
> About has_child, the other option is to make the minimum length of
> appinfos list relkind-based, but the condition quickly becomes ugly. Do
> you have a suggestion?
>
>> @@ -932,7 +932,6 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
>> case RELKIND_RELATION:
>> case RELKIND_TOASTVALUE:
>> case RELKIND_MATVIEW:
>> - case RELKIND_PARTITIONED_TABLE:
>> options = heap_reloptions(classForm->relkind, datum, false);
>> break;
>> Partitioned tables cannot have reloptions? What about all the
>> autovacuum_* parameters then? Those are mainly not storage-related.
>
> AFAIK, none of the heap reloptions will be applicable to partitioned table
> relations once we eliminate storage.
>
> About autovacuum_* parameters - we currently don't handle partitioned
> tables in autovacuum.c, because no statistics are reported for them. That
> is, relation_needs_vacanalyze() will never return true for dovacuum,
> doanalyze and wraparound if it is passed a RELKIND_PARTITIONED_TABLE
> relation. That's something to be fixed separately though. When we add
> autovacuum support for partitioned tables, we may want to add a new set of
> reloptions (new because partitioned tables still won't support all options
> returned by heap_reloptions()). Am I missing something?
>
> Thanks,
> Amit
--
Best Wishes,
Ashutosh Bapat
EnterpriseDB Corporation
The Postgres Database Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
@ 2017-03-07 17:27 ` Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
0 siblings, 1 reply; 96+ messages in thread
From: Robert Haas @ 2017-03-07 17:27 UTC (permalink / raw)
To: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; +Cc: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; Michael Paquier <michael.paquier@gmail.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On Tue, Mar 7, 2017 at 12:11 AM, Ashutosh Bapat
<ashutosh.bapat@enterprisedb.com> wrote:
> I see that all the changes by Amit and myself to what was earlier 0003
> patch are now part of 0002 patch. The patch looks ready for committer.
Reviewing 0002:
This patch seems to have falsified the header comments for
expand_inherited_rtentry.
I don't quite understand the need for the change to set_rel_size().
The rte->inh case is handled before reaching the new code, and IIUC
the !rte->inh case should never happen given the changes to
expand_inherited_rtentry. Or am I confused? If not, I think we
should just add an Assert() to the "plain relation" case that this is
not RELKIND_PARTITIONED_TABLE (with a comment explaining why it can't
happen).
In inheritance_planner, this comment addition does not seem adequate:
+ * If the parent is a partitioned table, we already set the nominal
+ * relation.
That basically contradicts the previous paragraph. I think you need
to adjust the previous paragraph instead of adding a new one, probably
in multiple places. For example, the parenthesized bit now only
applies in the non-partitioned case.
- rel = mtstate->resultRelInfo->ri_RelationDesc;
+ nominalRTE = rt_fetch(node->nominalRelation, estate->es_range_table);
+ nominalRel = heap_open(nominalRTE->relid, NoLock);
No lock?
Another thing that bothers me about this is that, apparently, the use
of nominalRelation is no longer strictly for EXPLAIN, as the comments
in plannodes.h/relation.h still claim that it is. I'm not sure how to
adjust that exactly; there's not a lot of room in those comments to
give all the details. Maybe they should simply say something like /*
Parent RT index */ instead of /* Parent RT index for use of EXPLAIN
*/. But we can't just go around changing the meaning of things
without updating the comments accordingly. A related question is
whether we should really be using nominalRelation for this or whether
there's some other way we should be getting at the parent -- I don't
have another idea, though.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
@ 2017-03-08 10:36 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
0 siblings, 1 reply; 96+ messages in thread
From: Amit Langote @ 2017-03-08 10:36 UTC (permalink / raw)
To: Robert Haas <robertmhaas@gmail.com>; Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; +Cc: Michael Paquier <michael.paquier@gmail.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On 2017/03/08 2:27, Robert Haas wrote:
> On Tue, Mar 7, 2017 at 12:11 AM, Ashutosh Bapat
> <ashutosh.bapat@enterprisedb.com> wrote:
>> I see that all the changes by Amit and myself to what was earlier 0003
>> patch are now part of 0002 patch. The patch looks ready for committer.
>
> Reviewing 0002:
Thanks for the review.
>
> This patch seems to have falsified the header comments for
> expand_inherited_rtentry.
Oops, updated.
> I don't quite understand the need for the change to set_rel_size().
> The rte->inh case is handled before reaching the new code, and IIUC
> the !rte->inh case should never happen given the changes to
> expand_inherited_rtentry. Or am I confused?
In expand_inherited_rtentry(), patch only changes the rule about the
minimum number of child RTEs required to keep rte->inh true. In the
traditional case, it is 2 (the table itself and at least one child). For
a partitioned table, since we don't want to scan the table itself, that
becomes 1 (at least one leaf partition).
So, it's still possible for rte->inh to become false if the required
minimum is not met, even for partitioned tables.
> If not, I think we
> should just add an Assert() to the "plain relation" case that this is
> not RELKIND_PARTITIONED_TABLE (with a comment explaining why it can't
> happen).
How about adding Assert(rte->relkind != RELKIND_PARTITIONED_TABLE) at the
beginning of the following functions as the updated patch does:
set_plain_rel_size()
set_tablesample_rel_size()
set_plain_rel_pathlist()
set_tablesample_rel_pathlist()
> In inheritance_planner, this comment addition does not seem adequate:
>
> + * If the parent is a partitioned table, we already set the nominal
> + * relation.
>
> That basically contradicts the previous paragraph. I think you need
> to adjust the previous paragraph instead of adding a new one, probably
> in multiple places. For example, the parenthesized bit now only
> applies in the non-partitioned case.
Hmm, that's true. I rewrote the entire comment.
>
> - rel = mtstate->resultRelInfo->ri_RelationDesc;
> + nominalRTE = rt_fetch(node->nominalRelation, estate->es_range_table);
> + nominalRel = heap_open(nominalRTE->relid, NoLock);
>
> No lock?
Hmm, I think I missed that a partitioned parent table would not be locked
by the *executor* at all after applying this patch. As of now, InitPlan()
takes care of locking all the result relations in the
PlannedStmt.resultRelations list. This patch removes partitioned
parent(s) from appearing in this list. But that makes me wonder - aren't
the locks taken by expand_inherited_rtentry() kept long enough? Why does
InitPlan need to acquire them again? I see this comment in
expand_inherited_rtentry:
* If the parent relation is the query's result relation, then we need
* RowExclusiveLock. Otherwise, if it's accessed FOR UPDATE/SHARE, we
* need RowShareLock; otherwise AccessShareLock. We can't just grab
* AccessShareLock because then the executor would be trying to upgrade
* the lock, leading to possible deadlocks. (This code should match the
* parser and rewriter.)
So, I assumed all the necessary locking is being taken care of here.
Anyway, I changed NoLock to RowExclusiveLock here for now, but maybe it's
either not necessary or a way should be found to do that in InitPlan along
with other result relations.
> Another thing that bothers me about this is that, apparently, the use
> of nominalRelation is no longer strictly for EXPLAIN, as the comments
> in plannodes.h/relation.h still claim that it is. I'm not sure how to
> adjust that exactly; there's not a lot of room in those comments to
> give all the details. Maybe they should simply say something like /*
> Parent RT index */ instead of /* Parent RT index for use of EXPLAIN
> */. But we can't just go around changing the meaning of things
> without updating the comments accordingly.
It seems that this comment and one more need to be updated. The other
comment change is in explain.c as follows:
* Adds the relid of each referenced RTE to *rels_used. The result controls
* which RTEs are assigned aliases by select_rtable_names_for_explain.
* This ensures that we don't confusingly assign un-suffixed aliases to RTEs
- * that never appear in the EXPLAIN output (such as inheritance parents).
+ * that never appear in the EXPLAIN output (such as non-partitioned
+ * inheritance parents).
*/
static bool
ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
I studied the EXPLAIN code a bit to see whether the problem cited for
using inheritance parent RTE as nominalRelation (for example, in comments
in inheritance_planner) apply to the partitioned parent RTE case, which it
doesn't. The partitioned parent RTE won't appear anywhere else in the
plan. So, different aliases for what's the same table/RTE won't happen in
the partitioned parent case.
> A related question is
> whether we should really be using nominalRelation for this or whether
> there's some other way we should be getting at the parent -- I don't
> have another idea, though.
This is just for the ModifyTable node. Instead of adding any new member,
I thought nominalRelation would work fine. But as I said above regarding
locking, we *may* need to find a different place for the partitioned
parent RTE (other than ModifyTable.nominalRelation).
Thanks,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Attachments:
[text/x-diff] 0001-Avoid-creating-scan-nodes-for-partitioned-tables.patch (27.8K, ../../30f05f6d-7341-b9b0-a089-2b626abc133b@lab.ntt.co.jp/2-0001-Avoid-creating-scan-nodes-for-partitioned-tables.patch)
download | inline diff:
From b65f546ee13bef408521d3f7b75f680b609c761f Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Mon, 6 Feb 2017 17:26:48 +0900
Subject: [PATCH 1/2] Avoid creating scan nodes for partitioned tables
* Currently, we create scan nodes for inheritance parents in their role
as an inheritance set member. Partitioned tables do not contain any
data, so it's useless to create scan nodes for them. So we need not
create AppendRelInfo's for them in the planner prep phase.
* The planner prep phase turns off inheritance on the parent RTE if
there isn't at least one child member (other than the parent itself
which in normal cases is also a child member), which means the latter
phases will not consider creating an Append plan and instead create a
scan node. Avoid this if the RTE is a partitioned table, by noticing
such cases in set_rel_size(). Per suggestion from Ashutosh Bapat.
* Since we do not add the RTE corresponding to the root partitioned
table as the 1st child member of the inheritance set,
inheritance_planner() must not assume the same when assigning
nominalRelation to a ModifyTable node.
* In ExecInitModifyTable(), use nominalRelation to initialize tuple
routing information, instead of the first resultRelInfo. We set
ModifyTable.nominalRelation to the root parent RTE in the
partitioned table case (implicitly in the INSERT case, whereas
explicitly in the UPDATE/DELETE cases).
---
src/backend/commands/explain.c | 3 +-
src/backend/executor/nodeModifyTable.c | 20 +++--
src/backend/optimizer/path/allpaths.c | 32 ++++++++
src/backend/optimizer/plan/planner.c | 34 +++++---
src/backend/optimizer/prep/prepunion.c | 47 +++++++++--
src/include/nodes/plannodes.h | 2 +-
src/include/nodes/relation.h | 2 +-
src/test/regress/expected/inherit.out | 124 ++++++++++--------------------
src/test/regress/expected/tablesample.out | 4 +-
src/test/regress/sql/inherit.sql | 8 ++
10 files changed, 161 insertions(+), 115 deletions(-)
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index c9e0a3e42d..a640ef55a9 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -764,7 +764,8 @@ elapsed_time(instr_time *starttime)
* Adds the relid of each referenced RTE to *rels_used. The result controls
* which RTEs are assigned aliases by select_rtable_names_for_explain.
* This ensures that we don't confusingly assign un-suffixed aliases to RTEs
- * that never appear in the EXPLAIN output (such as inheritance parents).
+ * that never appear in the EXPLAIN output (such as non-partitioned
+ * inheritance parents).
*/
static bool
ExplainPreScanNode(PlanState *planstate, Bitmapset **rels_used)
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 95e158970c..3bdf778d34 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -45,6 +45,7 @@
#include "foreign/fdwapi.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
+#include "parser/parsetree.h"
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
#include "utils/builtins.h"
@@ -1634,7 +1635,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
Plan *subplan;
ListCell *l;
int i;
- Relation rel;
+ Relation nominalRel;
+ RangeTblEntry *nominalRTE;
/* check for unsupported flags */
Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
@@ -1726,9 +1728,12 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
estate->es_result_relation_info = saved_resultRelInfo;
/* Build state for INSERT tuple routing */
- rel = mtstate->resultRelInfo->ri_RelationDesc;
+ nominalRTE = rt_fetch(node->nominalRelation, estate->es_range_table);
+
+ /* This is the first time we're locking nominalRelation in the executor */
+ nominalRel = heap_open(nominalRTE->relid, RowExclusiveLock);
if (operation == CMD_INSERT &&
- rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ nominalRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
{
PartitionDispatch *partition_dispatch_info;
ResultRelInfo *partitions;
@@ -1737,7 +1742,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
int num_parted,
num_partitions;
- ExecSetupPartitionTupleRouting(rel,
+ ExecSetupPartitionTupleRouting(nominalRel,
&partition_dispatch_info,
&partitions,
&partition_tupconv_maps,
@@ -1801,7 +1806,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
/* varno = node->nominalRelation */
mapped_wcoList = map_partition_varattnos(wcoList,
node->nominalRelation,
- partrel, rel);
+ partrel, nominalRel);
foreach(ll, mapped_wcoList)
{
WithCheckOption *wco = (WithCheckOption *) lfirst(ll);
@@ -1876,7 +1881,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
/* varno = node->nominalRelation */
rlist = map_partition_varattnos(returningList,
node->nominalRelation,
- partrel, rel);
+ partrel, nominalRel);
rliststate = (List *) ExecInitExpr((Expr *) rlist, &mtstate->ps);
resultRelInfo->ri_projectReturning =
ExecBuildProjectionInfo(rliststate, econtext, slot,
@@ -1897,6 +1902,9 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
mtstate->ps.ps_ExprContext = NULL;
}
+ /* We're done using nominalRel, but keep the lock */
+ heap_close(nominalRel, NoLock);
+
/*
* If needed, Initialize target list, projection and qual for ON CONFLICT
* DO UPDATE.
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 87a3faff09..11c55d7847 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -342,6 +342,14 @@ set_rel_size(PlannerInfo *root, RelOptInfo *rel,
/* Foreign table */
set_foreign_size(root, rel, rte);
}
+ else if (rte->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ /*
+ * A partitioned table without leaf partitions is marked
+ * as a dummy rel.
+ */
+ set_dummy_rel_pathlist(rel);
+ }
else if (rte->tablesample != NULL)
{
/* Sampled relation */
@@ -484,6 +492,12 @@ static void
set_plain_rel_size(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
{
/*
+ * A partitioned table can never happen, because it's either handled using
+ * an Append (rte->inh == true) or is a dummy rel.
+ */
+ Assert(rte->relkind != RELKIND_PARTITIONED_TABLE);
+
+ /*
* Test any partial indexes of rel for applicability. We must do this
* first since partial unique indexes can affect size estimates.
*/
@@ -650,6 +664,12 @@ set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
Relids required_outer;
/*
+ * A partitioned table can never happen, because it's either handled using
+ * an Append (rte->inh == true) or is a dummy rel.
+ */
+ Assert(rte->relkind != RELKIND_PARTITIONED_TABLE);
+
+ /*
* We don't support pushing join clauses into the quals of a seqscan, but
* it could still have required parameterization due to LATERAL refs in
* its tlist.
@@ -702,6 +722,12 @@ set_tablesample_rel_size(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
double tuples;
/*
+ * A partitioned table can never happen, because it's either handled using
+ * an Append (rte->inh == true) or is a dummy rel.
+ */
+ Assert(rte->relkind != RELKIND_PARTITIONED_TABLE);
+
+ /*
* Test any partial indexes of rel for applicability. We must do this
* first since partial unique indexes can affect size estimates.
*/
@@ -740,6 +766,12 @@ set_tablesample_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *
Path *path;
/*
+ * A partitioned table can never happen, because it's either handled using
+ * an Append (rte->inh == true) or is a dummy rel.
+ */
+ Assert(rte->relkind != RELKIND_PARTITIONED_TABLE);
+
+ /*
* We don't support pushing join clauses into the quals of a samplescan,
* but it could still have required parameterization due to LATERAL refs
* in its tlist or TABLESAMPLE arguments.
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index ca0ae7883e..c3472e4c25 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -996,6 +996,7 @@ inheritance_planner(PlannerInfo *root)
RelOptInfo *final_rel;
ListCell *lc;
Index rti;
+ RangeTblEntry *parent_rte;
Assert(parse->commandType != CMD_INSERT);
@@ -1054,13 +1055,21 @@ inheritance_planner(PlannerInfo *root)
}
/*
+ * If the parent RTE is a partitioned table, we should use that as the
+ * nominal relation, because we do not have the duplicate parent RTE,
+ * unlike in the case of a non-partitioned inheritance parent.
+ */
+ parent_rte = rt_fetch(parentRTindex, root->parse->rtable);
+ if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
+ nominalRelation = parentRTindex;
+
+ /*
* And now we can get on with generating a plan for each child table.
*/
foreach(lc, root->append_rel_list)
{
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
PlannerInfo *subroot;
- RangeTblEntry *parent_rte;
RangeTblEntry *child_rte;
RelOptInfo *sub_final_rel;
Path *subpath;
@@ -1205,15 +1214,20 @@ inheritance_planner(PlannerInfo *root)
grouping_planner(subroot, true, 0.0 /* retrieve all tuples */ );
/*
- * We'll use the first child relation (even if it's excluded) as the
- * nominal target relation of the ModifyTable node. Because of the
- * way expand_inherited_rtentry works, this should always be the RTE
- * representing the parent table in its role as a simple member of the
- * inheritance set. (It would be logically cleaner to use the
- * inheritance parent RTE as the nominal target; but since that RTE
- * will not be otherwise referenced in the plan, doing so would give
- * rise to confusing use of multiple aliases in EXPLAIN output for
- * what the user will think is the "same" table.)
+ * Set the nomimal target relation of the ModifyTable node if not
+ * already done. We use the inheritance parent RTE as the nominal
+ * target relation if it's a partitioned table (see just above this
+ * loop). In the non-partitioned parent case, we'll use the first
+ * child relation (even if it's excluded) as the nominal target
+ * relation. Because of the way expand_inherited_rtentry works, the
+ * latter should be the RTE representing the parent table in its role
+ * as a simple member of the inheritance set. It would be logically
+ * cleaner to *always* use the inheritance parent RTE; but since that
+ * RTE will not be otherwise referenced in the plan, doing so would
+ * give rise to confusing use of multiple aliases in EXPLAIN output
+ * for what the user will think is the "same" table in the
+ * non-partitioned parent case. It's not a problem in the partitioned
+ * parent case, because there is only one parent RTE in that case.
*/
if (nominalRelation < 0)
nominalRelation = appinfo->child_relid;
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 1389db18ba..1a62a53b75 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -1348,10 +1348,15 @@ expand_inherited_tables(PlannerInfo *root)
* Note that the original RTE is considered to represent the whole
* inheritance set. The first of the generated RTEs is an RTE for the same
* table, but with inh = false, to represent the parent table in its role
- * as a simple member of the inheritance set.
+ * as a simple member of the inheritance set. That's not true if the table
+ * is a partitioned table. In the case of partitioned tables, we generate
+ * child RTEs only for the leaf partitions, because other relations in the
+ * partition hierarchy do not contain any rows.
*
- * A childless table is never considered to be an inheritance set; therefore
- * a parent RTE must always have at least two associated AppendRelInfos.
+ * A childless table (which in the partitioned table case means one without
+ * leaf partitions) is never considered to be an inheritance set; therefore
+ * a parent RTE must always have at least one associated AppendRelInfo that
+ * is not itself.
*/
static void
expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
@@ -1364,6 +1369,7 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
List *inhOIDs;
List *appinfos;
ListCell *l;
+ bool has_child;
/* Does RT entry allow inheritance? */
if (!rte->inh)
@@ -1435,6 +1441,7 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
/* Scan the inheritance set and expand it */
appinfos = NIL;
+ has_child = false;
foreach(l, inhOIDs)
{
Oid childOID = lfirst_oid(l);
@@ -1450,6 +1457,22 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
newrelation = oldrelation;
/*
+ * Since partitioned tables themselves do not contain data, later
+ * planning steps should not create scan nodes for them. So do not
+ * create the child RTE and AppendRelInfo.
+ */
+ if (newrelation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ /*
+ * Don't lose the lock taken for us by find_all_inheritors()
+ * lest its partitions change under us.
+ */
+ if (newrelation != oldrelation)
+ heap_close(newrelation, NoLock);
+ continue;
+ }
+
+ /*
* It is possible that the parent table has children that are temp
* tables of other backends. We cannot safely access such tables
* (because of buffering issues), and the best thing to do seems to be
@@ -1462,6 +1485,13 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
}
/*
+ * We have at least one child table other than the parent table (or a
+ * leaf partition in the partitioned table case.)
+ */
+ if (newrelation != oldrelation)
+ has_child = true;
+
+ /*
* Build an RTE for the child, and attach to query's rangetable list.
* We copy most fields of the parent's RTE, but replace relation OID
* and relkind, and set inh = false. Also, set requiredPerms to zero
@@ -1545,12 +1575,13 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
heap_close(oldrelation, NoLock);
/*
- * If all the children were temp tables, pretend it's a non-inheritance
- * situation. The duplicate RTE we added for the parent table is
- * harmless, so we don't bother to get rid of it; ditto for the useless
- * PlanRowMark node.
+ * If all the children were temp tables of other backends or if the parent
+ * is a partitioned table without any leaf partitions, pretend it's a
+ * non-inheritance situation. The duplicate RTE for the parent table we
+ * added in the non-partitioned table case is harmless, so we don't bother
+ * to get rid of it; ditto for the useless PlanRowMark node.
*/
- if (list_length(appinfos) < 2)
+ if (!has_child)
{
/* Clear flag before returning */
rte->inh = false;
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index f72f7a8978..6413700a93 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -201,7 +201,7 @@ typedef struct ModifyTable
Plan plan;
CmdType operation; /* INSERT, UPDATE, or DELETE */
bool canSetTag; /* do we set the command tag/es_processed? */
- Index nominalRelation; /* Parent RT index for use of EXPLAIN */
+ Index nominalRelation; /* Parent RT index */
List *resultRelations; /* integer list of RT indexes */
int resultRelIndex; /* index of first resultRel in plan's list */
List *plans; /* plan(s) producing source data */
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index f7ac6f600f..b9872d861c 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -1468,7 +1468,7 @@ typedef struct ModifyTablePath
Path path;
CmdType operation; /* INSERT, UPDATE, or DELETE */
bool canSetTag; /* do we set the command tag/es_processed? */
- Index nominalRelation; /* Parent RT index for use of EXPLAIN */
+ Index nominalRelation; /* Parent RT index */
List *resultRelations; /* integer list of RT indexes */
List *subpaths; /* Path(s) producing source data */
List *subroots; /* per-target-table PlannerInfos */
diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out
index 795d9f575c..a172497c83 100644
--- a/src/test/regress/expected/inherit.out
+++ b/src/test/regress/expected/inherit.out
@@ -1598,6 +1598,14 @@ reset enable_bitmapscan;
create table list_parted (
a varchar
) partition by list (a);
+-- test scanning partitioned table without any partitions
+explain (costs off) select * from list_parted;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
create table part_ab_cd partition of list_parted for values in ('ab', 'cd');
create table part_ef_gh partition of list_parted for values in ('ef', 'gh');
create table part_null_xy partition of list_parted for values in (null, 'xy');
@@ -1605,77 +1613,74 @@ explain (costs off) select * from list_parted;
QUERY PLAN
--------------------------------
Append
- -> Seq Scan on list_parted
-> Seq Scan on part_ab_cd
-> Seq Scan on part_ef_gh
-> Seq Scan on part_null_xy
-(5 rows)
+(4 rows)
explain (costs off) select * from list_parted where a is null;
QUERY PLAN
--------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (a IS NULL)
-> Seq Scan on part_null_xy
Filter: (a IS NULL)
-(5 rows)
+(3 rows)
explain (costs off) select * from list_parted where a is not null;
QUERY PLAN
---------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (a IS NOT NULL)
-> Seq Scan on part_ab_cd
Filter: (a IS NOT NULL)
-> Seq Scan on part_ef_gh
Filter: (a IS NOT NULL)
-> Seq Scan on part_null_xy
Filter: (a IS NOT NULL)
-(9 rows)
+(7 rows)
explain (costs off) select * from list_parted where a in ('ab', 'cd', 'ef');
QUERY PLAN
----------------------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-> Seq Scan on part_ab_cd
Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-> Seq Scan on part_ef_gh
Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-(7 rows)
+(5 rows)
explain (costs off) select * from list_parted where a = 'ab' or a in (null, 'cd');
QUERY PLAN
---------------------------------------------------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_ab_cd
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_ef_gh
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_null_xy
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-(9 rows)
+(7 rows)
explain (costs off) select * from list_parted where a = 'ab';
QUERY PLAN
------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: ((a)::text = 'ab'::text)
-> Seq Scan on part_ab_cd
Filter: ((a)::text = 'ab'::text)
-(5 rows)
+(3 rows)
create table range_list_parted (
a int,
b char(2)
) partition by range (a);
create table part_1_10 partition of range_list_parted for values from (1) to (10) partition by list (b);
+-- test scanning partitioned table without any leaf partitions
+explain (costs off) select * from range_list_parted;
+ QUERY PLAN
+--------------------------
+ Result
+ One-Time Filter: false
+(2 rows)
+
create table part_1_10_ab partition of part_1_10 for values in ('ab');
create table part_1_10_cd partition of part_1_10 for values in ('cd');
create table part_10_20 partition of range_list_parted for values from (10) to (20) partition by list (b);
@@ -1689,14 +1694,9 @@ create table part_40_inf_ab partition of part_40_inf for values in ('ab');
create table part_40_inf_cd partition of part_40_inf for values in ('cd');
create table part_40_inf_null partition of part_40_inf for values in (null);
explain (costs off) select * from range_list_parted;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- -> Seq Scan on part_1_10
- -> Seq Scan on part_10_20
- -> Seq Scan on part_21_30
- -> Seq Scan on part_40_inf
-> Seq Scan on part_1_10_ab
-> Seq Scan on part_1_10_cd
-> Seq Scan on part_10_20_ab
@@ -1706,36 +1706,22 @@ explain (costs off) select * from range_list_parted;
-> Seq Scan on part_40_inf_ab
-> Seq Scan on part_40_inf_cd
-> Seq Scan on part_40_inf_null
-(15 rows)
+(10 rows)
explain (costs off) select * from range_list_parted where a = 5;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+--------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (a = 5)
- -> Seq Scan on part_1_10
- Filter: (a = 5)
-> Seq Scan on part_1_10_ab
Filter: (a = 5)
-> Seq Scan on part_1_10_cd
Filter: (a = 5)
-(9 rows)
+(5 rows)
explain (costs off) select * from range_list_parted where b = 'ab';
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_1_10
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_10_20
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_21_30
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_40_inf
- Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_1_10_ab
Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_10_20_ab
@@ -1744,27 +1730,19 @@ explain (costs off) select * from range_list_parted where b = 'ab';
Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_40_inf_ab
Filter: (b = 'ab'::bpchar)
-(19 rows)
+(9 rows)
explain (costs off) select * from range_list_parted where a between 3 and 23 and b in ('ab');
QUERY PLAN
-----------------------------------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_1_10
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_10_20
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_21_30
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_1_10_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_10_20_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_21_30_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-(15 rows)
+(7 rows)
/* Should select no rows because range partition key cannot be null */
explain (costs off) select * from range_list_parted where a is null;
@@ -1776,37 +1754,17 @@ explain (costs off) select * from range_list_parted where a is null;
/* Should only select rows from the null-accepting partition */
explain (costs off) select * from range_list_parted where b is null;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (b IS NULL)
- -> Seq Scan on part_1_10
- Filter: (b IS NULL)
- -> Seq Scan on part_10_20
- Filter: (b IS NULL)
- -> Seq Scan on part_21_30
- Filter: (b IS NULL)
- -> Seq Scan on part_40_inf
- Filter: (b IS NULL)
-> Seq Scan on part_40_inf_null
Filter: (b IS NULL)
-(13 rows)
+(3 rows)
explain (costs off) select * from range_list_parted where a is not null and a < 67;
QUERY PLAN
------------------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_1_10
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_10_20
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_21_30
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_40_inf
- Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_1_10_ab
Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_1_10_cd
@@ -1825,23 +1783,19 @@ explain (costs off) select * from range_list_parted where a is not null and a <
Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_40_inf_null
Filter: ((a IS NOT NULL) AND (a < 67))
-(29 rows)
+(19 rows)
explain (costs off) select * from range_list_parted where a >= 30;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (a >= 30)
- -> Seq Scan on part_40_inf
- Filter: (a >= 30)
-> Seq Scan on part_40_inf_ab
Filter: (a >= 30)
-> Seq Scan on part_40_inf_cd
Filter: (a >= 30)
-> Seq Scan on part_40_inf_null
Filter: (a >= 30)
-(11 rows)
+(7 rows)
drop table list_parted;
drop table range_list_parted;
diff --git a/src/test/regress/expected/tablesample.out b/src/test/regress/expected/tablesample.out
index b18e420e9b..d3794140fb 100644
--- a/src/test/regress/expected/tablesample.out
+++ b/src/test/regress/expected/tablesample.out
@@ -322,12 +322,10 @@ explain (costs off)
QUERY PLAN
-------------------------------------------
Append
- -> Sample Scan on parted_sample
- Sampling: bernoulli ('100'::real)
-> Sample Scan on parted_sample_1
Sampling: bernoulli ('100'::real)
-> Sample Scan on parted_sample_2
Sampling: bernoulli ('100'::real)
-(7 rows)
+(5 rows)
drop table parted_sample, parted_sample_1, parted_sample_2;
diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql
index 836ec22c20..a78a585430 100644
--- a/src/test/regress/sql/inherit.sql
+++ b/src/test/regress/sql/inherit.sql
@@ -570,6 +570,10 @@ reset enable_bitmapscan;
create table list_parted (
a varchar
) partition by list (a);
+
+-- test scanning partitioned table without any partitions
+explain (costs off) select * from list_parted;
+
create table part_ab_cd partition of list_parted for values in ('ab', 'cd');
create table part_ef_gh partition of list_parted for values in ('ef', 'gh');
create table part_null_xy partition of list_parted for values in (null, 'xy');
@@ -586,6 +590,10 @@ create table range_list_parted (
b char(2)
) partition by range (a);
create table part_1_10 partition of range_list_parted for values from (1) to (10) partition by list (b);
+
+-- test scanning partitioned table without any leaf partitions
+explain (costs off) select * from range_list_parted;
+
create table part_1_10_ab partition of part_1_10 for values in ('ab');
create table part_1_10_cd partition of part_1_10 for values in ('cd');
create table part_10_20 partition of range_list_parted for values from (10) to (20) partition by list (b);
--
2.11.0
[text/x-diff] 0002-Do-not-allocate-storage-for-partitioned-tables.patch (3.1K, ../../30f05f6d-7341-b9b0-a089-2b626abc133b@lab.ntt.co.jp/3-0002-Do-not-allocate-storage-for-partitioned-tables.patch)
download | inline diff:
From 3dd4c9ddf2bbf6982e1701065544e56dade9b8ed Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Tue, 24 Jan 2017 14:22:34 +0900
Subject: [PATCH 2/2] Do not allocate storage for partitioned tables.
Currently, it is not possible to insert any data into a partitioned
table. So, they're empty at all times, which means it is wasteful to
allocate relfilenode and related storage objects.
---
src/backend/access/common/reloptions.c | 3 +--
src/backend/catalog/heap.c | 17 ++++++++++-------
2 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index c50649135f..58df48a9dc 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -968,7 +968,6 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
case RELKIND_RELATION:
case RELKIND_TOASTVALUE:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
options = heap_reloptions(classForm->relkind, datum, false);
break;
case RELKIND_VIEW:
@@ -978,6 +977,7 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
options = index_reloptions(amoptions, datum, false);
break;
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
options = NULL;
break;
default:
@@ -1420,7 +1420,6 @@ heap_reloptions(char relkind, Datum reloptions, bool validate)
return (bytea *) rdopts;
case RELKIND_RELATION:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
default:
/* other relkinds are not supported */
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 41c0056556..2f5090b183 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -291,6 +291,7 @@ heap_create(const char *relname,
case RELKIND_VIEW:
case RELKIND_COMPOSITE_TYPE:
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
create_storage = false;
/*
@@ -1345,14 +1346,13 @@ heap_create_with_catalog(const char *relname,
if (oncommit != ONCOMMIT_NOOP)
register_on_commit_action(relid, oncommit);
- if (relpersistence == RELPERSISTENCE_UNLOGGED)
- {
- Assert(relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW ||
- relkind == RELKIND_TOASTVALUE ||
- relkind == RELKIND_PARTITIONED_TABLE);
-
+ /*
+ * We do not want to create any storage objects for a partitioned
+ * table, including the init fork.
+ */
+ if (relpersistence == RELPERSISTENCE_UNLOGGED &&
+ relkind != RELKIND_PARTITIONED_TABLE)
heap_create_init_fork(new_rel_desc);
- }
/*
* ok, the relation has been cataloged, so close our relations and return
@@ -1376,6 +1376,9 @@ heap_create_with_catalog(const char *relname,
void
heap_create_init_fork(Relation rel)
{
+ Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
+ rel->rd_rel->relkind == RELKIND_MATVIEW ||
+ rel->rd_rel->relkind == RELKIND_TOASTVALUE);
RelationOpenSmgr(rel);
smgrcreate(rel->rd_smgr, INIT_FORKNUM, false);
log_smgrcreate(&rel->rd_smgr->smgr_rnode.node, INIT_FORKNUM);
--
2.11.0
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-03-08 13:36 ` Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
0 siblings, 1 reply; 96+ messages in thread
From: Robert Haas @ 2017-03-08 13:36 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; Michael Paquier <michael.paquier@gmail.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On Wed, Mar 8, 2017 at 5:36 AM, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
>> I don't quite understand the need for the change to set_rel_size().
>> The rte->inh case is handled before reaching the new code, and IIUC
>> the !rte->inh case should never happen given the changes to
>> expand_inherited_rtentry. Or am I confused?
>
> In expand_inherited_rtentry(), patch only changes the rule about the
> minimum number of child RTEs required to keep rte->inh true. In the
> traditional case, it is 2 (the table itself and at least one child). For
> a partitioned table, since we don't want to scan the table itself, that
> becomes 1 (at least one leaf partition).
>
> So, it's still possible for rte->inh to become false if the required
> minimum is not met, even for partitioned tables.
OK.
>> - rel = mtstate->resultRelInfo->ri_RelationDesc;
>> + nominalRTE = rt_fetch(node->nominalRelation, estate->es_range_table);
>> + nominalRel = heap_open(nominalRTE->relid, NoLock);
>>
>> No lock?
>
> Hmm, I think I missed that a partitioned parent table would not be locked
> by the *executor* at all after applying this patch. As of now, InitPlan()
> takes care of locking all the result relations in the
> PlannedStmt.resultRelations list. This patch removes partitioned
> parent(s) from appearing in this list. But that makes me wonder - aren't
> the locks taken by expand_inherited_rtentry() kept long enough? Why does
> InitPlan need to acquire them again? I see this comment in
> expand_inherited_rtentry:
Parse-time locks, plan-time locks, and execution-time locks are all
separate. See the header comments for AcquireRewriteLocks in
rewriteHandler.c; think about a view, where the parsed query has been
stored and is later rewritten and planned. Similarly, a plan can be
reused even after the transaction that created that plan has
committed; see AcquireExecutorLocks in plancache.c.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
@ 2017-03-10 08:57 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
0 siblings, 1 reply; 96+ messages in thread
From: Amit Langote @ 2017-03-10 08:57 UTC (permalink / raw)
To: Robert Haas <robertmhaas@gmail.com>; +Cc: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; Michael Paquier <michael.paquier@gmail.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On 2017/03/08 22:36, Robert Haas wrote:
> On Wed, Mar 8, 2017 at 5:36 AM, Amit Langote wrote:
>>> - rel = mtstate->resultRelInfo->ri_RelationDesc;
>>> + nominalRTE = rt_fetch(node->nominalRelation, estate->es_range_table);
>>> + nominalRel = heap_open(nominalRTE->relid, NoLock);
>>>
>>> No lock?
>>
>> Hmm, I think I missed that a partitioned parent table would not be locked
>> by the *executor* at all after applying this patch. As of now, InitPlan()
>> takes care of locking all the result relations in the
>> PlannedStmt.resultRelations list. This patch removes partitioned
>> parent(s) from appearing in this list. But that makes me wonder - aren't
>> the locks taken by expand_inherited_rtentry() kept long enough? Why does
>> InitPlan need to acquire them again? I see this comment in
>> expand_inherited_rtentry:
>
> Parse-time locks, plan-time locks, and execution-time locks are all
> separate. See the header comments for AcquireRewriteLocks in
> rewriteHandler.c; think about a view, where the parsed query has been
> stored and is later rewritten and planned. Similarly, a plan can be
> reused even after the transaction that created that plan has
> committed; see AcquireExecutorLocks in plancache.c.
Thanks for those references.
I took a step back here and thought a bit more about the implications this
patch. It occurred to me that the complete absence of partitioned table
RT entries in the plan-tree has more consequences than I originally
imagined. I will post an updated patch by Monday latest.
Thanks,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-03-13 10:24 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
0 siblings, 2 replies; 96+ messages in thread
From: Amit Langote @ 2017-03-13 10:24 UTC (permalink / raw)
To: Robert Haas <robertmhaas@gmail.com>; +Cc: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; Michael Paquier <michael.paquier@gmail.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On 2017/03/10 17:57, Amit Langote wrote:
> On 2017/03/08 22:36, Robert Haas wrote:
>> On Wed, Mar 8, 2017 at 5:36 AM, Amit Langote wrote:
>>>> - rel = mtstate->resultRelInfo->ri_RelationDesc;
>>>> + nominalRTE = rt_fetch(node->nominalRelation, estate->es_range_table);
>>>> + nominalRel = heap_open(nominalRTE->relid, NoLock);
>>>>
>>>> No lock?
>>>
>>> Hmm, I think I missed that a partitioned parent table would not be locked
>>> by the *executor* at all after applying this patch. As of now, InitPlan()
>>> takes care of locking all the result relations in the
>>> PlannedStmt.resultRelations list. This patch removes partitioned
>>> parent(s) from appearing in this list. But that makes me wonder - aren't
>>> the locks taken by expand_inherited_rtentry() kept long enough? Why does
>>> InitPlan need to acquire them again? I see this comment in
>>> expand_inherited_rtentry:
>>
>> Parse-time locks, plan-time locks, and execution-time locks are all
>> separate. See the header comments for AcquireRewriteLocks in
>> rewriteHandler.c; think about a view, where the parsed query has been
>> stored and is later rewritten and planned. Similarly, a plan can be
>> reused even after the transaction that created that plan has
>> committed; see AcquireExecutorLocks in plancache.c.
>
> Thanks for those references.
>
> I took a step back here and thought a bit more about the implications this
> patch. It occurred to me that the complete absence of partitioned table
> RT entries in the plan-tree has more consequences than I originally
> imagined. I will post an updated patch by Monday latest.
Here is the updated patch.
Since this patch proposes to avoid creating scan nodes for non-leaf tables
in a partition tree, they won't be referenced anywhere in the resulting
plan tree. So the executor will not lock those tables in the
select/update/delete cases. Insert is different since we lock all tables
in the partition tree when setting up tuple-routing in
ExecInitModifyTable. Not taking executor locks on the tables means that
the cached plans that should be invalidated upon adding/removing a
partition somewhere in the partition tree won't be.
First I thought that we could remember just the root table RT index using
a new Index field partitionRoot in Append, MergeAppend, and ModifyTable
nodes and use it to locate and lock the root table during executor node
initialization. But soon realized that that's not enough, because it
ignores the fact that adding/removing partitions at lower levels does not
require taking a lock on the root table; only the immediate parent. So
any cached select/update/delete plans won't be invalidated when a new
lower-level partition is added/removed, because the immediate parent would
not have been added to the query's range table and hence the
PlannedStmt.relationOids list. Remember that the latter is used by
plancache.c to remember the relations that a given cached plan depends on
remaining unchanged. So the patch now adds a list member called
partitioned_rels to Append, MergeAppend, and ModifyTable nodes and stores
the RT indexes of all the non-leaf tables in a partition tree with root
table RT index at the head (note that these RT indexes are of the RTEs
added by expand_inherited_rtenrty; also see below). Since the
partitioned_rels list is constructed when building paths and must be
propagated to the plan nodes, the same field is also present in the
corresponding Path nodes. ExecInit* routines for the aforementioned nodes
now locate and lock the non-leaf tables using the RT indexes in
partitioned_rels. Leaf tables are locked, as before, either by InitPlan
(update/delete result relations case) or by ExecInitAppend or
ExecInitMergeAppend when initializing the appendplans/mergeplans (select
case).
The previous proposal was for expand_inherited_rtentry to not create RT
entries and AppendRelInfo's for the non-leaf tables, but I think that
doesn't work, as I tried to explain above. We need RTEs because that
seems to be the only way currently for informing the executor of the
non-leaf tables. We need AppendRelInfo's to store the RT indexes of those
RTEs for the latter planning steps to collect them in partitioned_rels
mentioned above. So with the latest patch, we do create the RT entry and
AppendRelInfo for non-leaf tables. AppendRelInfo created in this case is
a minimal one; only parent_relid and child_relid are valid. To make the
latter planning steps ignore these minimal AppendRelInfo's, every
AppendRelInfo is now marked with child_relkind. Only
set_append_rel_pathlist() and inheritance_planner() process them to
collect the child_relid into the partitioned_rels list to be stored in
AppendPath/MergeAppendPath and ModifyTablePath, respectively.
Thoughts?
Thanks,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-03-13 10:30 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 08:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
1 sibling, 1 reply; 96+ messages in thread
From: Amit Langote @ 2017-03-13 10:30 UTC (permalink / raw)
To: Robert Haas <robertmhaas@gmail.com>; +Cc: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; Michael Paquier <michael.paquier@gmail.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On 2017/03/13 19:24, Amit Langote wrote:
> On 2017/03/10 17:57, Amit Langote wrote:
>> On 2017/03/08 22:36, Robert Haas wrote:
>>> On Wed, Mar 8, 2017 at 5:36 AM, Amit Langote wrote:
>>>>> - rel = mtstate->resultRelInfo->ri_RelationDesc;
>>>>> + nominalRTE = rt_fetch(node->nominalRelation, estate->es_range_table);
>>>>> + nominalRel = heap_open(nominalRTE->relid, NoLock);
>>>>>
>>>>> No lock?
>>>>
>>>> Hmm, I think I missed that a partitioned parent table would not be locked
>>>> by the *executor* at all after applying this patch. As of now, InitPlan()
>>>> takes care of locking all the result relations in the
>>>> PlannedStmt.resultRelations list. This patch removes partitioned
>>>> parent(s) from appearing in this list. But that makes me wonder - aren't
>>>> the locks taken by expand_inherited_rtentry() kept long enough? Why does
>>>> InitPlan need to acquire them again? I see this comment in
>>>> expand_inherited_rtentry:
>>>
>>> Parse-time locks, plan-time locks, and execution-time locks are all
>>> separate. See the header comments for AcquireRewriteLocks in
>>> rewriteHandler.c; think about a view, where the parsed query has been
>>> stored and is later rewritten and planned. Similarly, a plan can be
>>> reused even after the transaction that created that plan has
>>> committed; see AcquireExecutorLocks in plancache.c.
>>
>> Thanks for those references.
>>
>> I took a step back here and thought a bit more about the implications this
>> patch. It occurred to me that the complete absence of partitioned table
>> RT entries in the plan-tree has more consequences than I originally
>> imagined. I will post an updated patch by Monday latest.
>
> Here is the updated patch.
>
> Since this patch proposes to avoid creating scan nodes for non-leaf tables
> in a partition tree, they won't be referenced anywhere in the resulting
> plan tree. So the executor will not lock those tables in the
> select/update/delete cases. Insert is different since we lock all tables
> in the partition tree when setting up tuple-routing in
> ExecInitModifyTable. Not taking executor locks on the tables means that
> the cached plans that should be invalidated upon adding/removing a
> partition somewhere in the partition tree won't be.
>
> First I thought that we could remember just the root table RT index using
> a new Index field partitionRoot in Append, MergeAppend, and ModifyTable
> nodes and use it to locate and lock the root table during executor node
> initialization. But soon realized that that's not enough, because it
> ignores the fact that adding/removing partitions at lower levels does not
> require taking a lock on the root table; only the immediate parent. So
> any cached select/update/delete plans won't be invalidated when a new
> lower-level partition is added/removed, because the immediate parent would
> not have been added to the query's range table and hence the
> PlannedStmt.relationOids list. Remember that the latter is used by
> plancache.c to remember the relations that a given cached plan depends on
> remaining unchanged. So the patch now adds a list member called
> partitioned_rels to Append, MergeAppend, and ModifyTable nodes and stores
> the RT indexes of all the non-leaf tables in a partition tree with root
> table RT index at the head (note that these RT indexes are of the RTEs
> added by expand_inherited_rtenrty; also see below). Since the
> partitioned_rels list is constructed when building paths and must be
> propagated to the plan nodes, the same field is also present in the
> corresponding Path nodes. ExecInit* routines for the aforementioned nodes
> now locate and lock the non-leaf tables using the RT indexes in
> partitioned_rels. Leaf tables are locked, as before, either by InitPlan
> (update/delete result relations case) or by ExecInitAppend or
> ExecInitMergeAppend when initializing the appendplans/mergeplans (select
> case).
>
> The previous proposal was for expand_inherited_rtentry to not create RT
> entries and AppendRelInfo's for the non-leaf tables, but I think that
> doesn't work, as I tried to explain above. We need RTEs because that
> seems to be the only way currently for informing the executor of the
> non-leaf tables. We need AppendRelInfo's to store the RT indexes of those
> RTEs for the latter planning steps to collect them in partitioned_rels
> mentioned above. So with the latest patch, we do create the RT entry and
> AppendRelInfo for non-leaf tables. AppendRelInfo created in this case is
> a minimal one; only parent_relid and child_relid are valid. To make the
> latter planning steps ignore these minimal AppendRelInfo's, every
> AppendRelInfo is now marked with child_relkind. Only
> set_append_rel_pathlist() and inheritance_planner() process them to
> collect the child_relid into the partitioned_rels list to be stored in
> AppendPath/MergeAppendPath and ModifyTablePath, respectively.
Sorry, forgot to attach the patches themselves. Attached this time.
Thanks,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Attachments:
[text/x-diff] 0001-Avoid-creating-scan-nodes-for-partitioned-tables.patch (51.5K, ../../a4e2be66-67c6-c8c0-080b-1af22a14b566@lab.ntt.co.jp/2-0001-Avoid-creating-scan-nodes-for-partitioned-tables.patch)
download | inline diff:
From c1b514b9214775977ef23e0206962f1e8a5e1966 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Fri, 10 Mar 2017 13:48:31 +0900
Subject: [PATCH 1/2] Avoid creating scan nodes for partitioned tables
* Currently, we create scan nodes for inheritance parents in their role
as an inheritance set member. Partitioned tables do not contain any
data, so it's useless to create scan nodes for them. So we generate
only a minimal AppendRelInfo for partitioned child tables. No need
to generate translated_vars, for example. We need to hold on to
the child_relid's, because we want to save it into the Append/
MergeAppend/ModifyTable node we will generate for the inheritance
tree.
* The planner prep phase turns off inheritance on the parent RTE if
there isn't at least one child member other than the parent itself
which is also a child member. That means set_rel_size/pathlist will
not create an Append node but a scan node for the parent RTE. We want
to avoid that if the parent is a partitioned table, by noticing that
in set_rel_size(). Per suggestion from Ashutosh Bapat.
* Add a new partitioned_rels field to ModifyTable, Append, and MergeAppend
nodes, which holds the RT indexes of all the non-leaf tables in a
partition tree. Use the same to lock those tables during execution.
The usual method employed by InitPlan to lock the tables does not work
for partitioned tables, because they do not appear in the subplans list
of either of those nodes.
* In inheritance_planner, set ModifyTable.nominalRelation to parent RT
index in the partitioned inheritance parent case, so that EXPLAIN uses
the root tables's original RT index to label a given ModifyTable node.
Regression test outputs are adjusted to match the new plan shape.
---
src/backend/executor/nodeAppend.c | 39 +++++++++
src/backend/executor/nodeMergeAppend.c | 39 +++++++++
src/backend/executor/nodeModifyTable.c | 36 +++++++-
src/backend/nodes/copyfuncs.c | 4 +
src/backend/nodes/equalfuncs.c | 1 +
src/backend/nodes/outfuncs.c | 7 ++
src/backend/nodes/readfuncs.c | 3 +
src/backend/optimizer/path/allpaths.c | 49 +++++++++--
src/backend/optimizer/path/joinrels.c | 2 +-
src/backend/optimizer/plan/createplan.c | 14 ++--
src/backend/optimizer/plan/initsplan.c | 6 ++
src/backend/optimizer/plan/planner.c | 61 +++++++++++---
src/backend/optimizer/plan/setrefs.c | 12 +++
src/backend/optimizer/prep/prepunion.c | 59 ++++++++-----
src/backend/optimizer/util/pathnode.c | 10 ++-
src/backend/utils/cache/plancache.c | 7 ++
src/include/nodes/plannodes.h | 6 ++
src/include/nodes/relation.h | 4 +
src/include/optimizer/pathnode.h | 8 +-
src/test/regress/expected/inherit.out | 134 +++++++++++-------------------
src/test/regress/expected/tablesample.out | 4 +-
src/test/regress/sql/inherit.sql | 22 +++++
22 files changed, 386 insertions(+), 141 deletions(-)
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index 6986caee6b..26be346199 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -59,6 +59,8 @@
#include "executor/execdebug.h"
#include "executor/nodeAppend.h"
+#include "parser/parsetree.h"
+#include "storage/lmgr.h"
static bool exec_append_initialize_next(AppendState *appendstate);
@@ -129,6 +131,43 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
Assert(!(eflags & EXEC_FLAG_MARK));
/*
+ * Lock the non-leaf tables in the partition tree controlled by this
+ * node; leaf tables will be locked below when initializing the node's
+ * subplans. Note that this occurs only if the root inheritance parent
+ * is a partitioned table.
+ */
+ if (node->partitioned_rels)
+ {
+ foreach(lc, node->partitioned_rels)
+ {
+ Index rti = lfirst_int(lc);
+ PlanRowMark *rc = NULL;
+ ListCell *l;
+ Oid relid;
+ LOCKMODE lockmode;
+
+ relid = getrelid(rti, estate->es_range_table);
+
+ /* If there is a RowMark, we better adjust the lockmode */
+ foreach(l, estate->es_plannedstmt->rowMarks)
+ {
+ rc = (PlanRowMark *) lfirst(l);
+
+ if (rc->rti == rti)
+ break;
+ }
+
+ Assert(rc == NULL || rc->isParent);
+ if (rc != NULL && RowMarkRequiresRowShareLock(rc->markType))
+ lockmode = RowShareLock;
+ else
+ lockmode = AccessShareLock;
+
+ LockRelationOid(relid, lockmode);
+ }
+ }
+
+ /*
* Set up empty vector of subplan states
*/
nplans = list_length(node->appendplans);
diff --git a/src/backend/executor/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c
index 7a20bf07a4..0b5f82cf20 100644
--- a/src/backend/executor/nodeMergeAppend.c
+++ b/src/backend/executor/nodeMergeAppend.c
@@ -42,6 +42,8 @@
#include "executor/nodeMergeAppend.h"
#include "lib/binaryheap.h"
+#include "parser/parsetree.h"
+#include "storage/lmgr.h"
/*
* We have one slot for each item in the heap array. We use SlotNumber
@@ -72,6 +74,43 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
/*
+ * Lock the non-leaf tables in the partition tree controlled by this
+ * node; leaf tables will be locked below when initializing the node's
+ * subplans. Note that this occurs only if the root inheritance parent
+ * is a partitioned table.
+ */
+ if (node->partitioned_rels)
+ {
+ foreach(lc, node->partitioned_rels)
+ {
+ Index rti = lfirst_int(lc);
+ PlanRowMark *rc = NULL;
+ ListCell *l;
+ Oid relid;
+ LOCKMODE lockmode;
+
+ relid = getrelid(rti, estate->es_range_table);
+
+ /* If there is a RowMark, we better adjust the lockmode */
+ foreach(l, estate->es_plannedstmt->rowMarks)
+ {
+ rc = (PlanRowMark *) lfirst(l);
+
+ if (rc->rti == rti)
+ break;
+ }
+
+ Assert(rc == NULL || rc->isParent);
+ if (rc != NULL && RowMarkRequiresRowShareLock(rc->markType))
+ lockmode = RowShareLock;
+ else
+ lockmode = AccessShareLock;
+
+ LockRelationOid(relid, lockmode);
+ }
+ }
+
+ /*
* Set up empty vector of subplan states
*/
nplans = list_length(node->mergeplans);
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 95e158970c..9f548bdfac 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -45,6 +45,7 @@
#include "foreign/fdwapi.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
+#include "parser/parsetree.h"
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
#include "utils/builtins.h"
@@ -1725,8 +1726,34 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
estate->es_result_relation_info = saved_resultRelInfo;
+ /*
+ * During UPDATE/DELETE of a partitioned table, node->partitioned_rels
+ * contains the RT indexes of non-leaf tables of the partition tree.
+ * Leaf tables have already been locked by InitPlan when setting up the
+ * ResultRelInfo's.
+ */
+ if (node->partitioned_rels)
+ {
+ Index root_table_rti;
+ Oid root_table_oid;
+
+ foreach(l, node->partitioned_rels)
+ {
+ Oid relid;
+
+ relid = getrelid(lfirst_int(l), estate->es_range_table);
+ LockRelationOid(relid, RowExclusiveLock);
+ }
+
+ /* We have the root table RT index at the head of the list */
+ root_table_rti = linitial_int(node->partitioned_rels);
+ root_table_oid = getrelid(root_table_rti, estate->es_range_table);
+ rel = heap_open(root_table_oid, NoLock); /* locked just above */
+ }
+ else
+ rel = mtstate->resultRelInfo->ri_RelationDesc;
+
/* Build state for INSERT tuple routing */
- rel = mtstate->resultRelInfo->ri_RelationDesc;
if (operation == CMD_INSERT &&
rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
{
@@ -1898,6 +1925,13 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
}
/*
+ * Close the root partitioned rel if we opened it above, but keep the
+ * lock.
+ */
+ if (rel != mtstate->resultRelInfo->ri_RelationDesc)
+ heap_close(rel, NoLock);
+
+ /*
* If needed, Initialize target list, projection and qual for ON CONFLICT
* DO UPDATE.
*/
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index bfc2ac1716..8bcac4f9dd 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -200,6 +200,7 @@ _copyModifyTable(const ModifyTable *from)
COPY_SCALAR_FIELD(operation);
COPY_SCALAR_FIELD(canSetTag);
COPY_SCALAR_FIELD(nominalRelation);
+ COPY_NODE_FIELD(partitioned_rels);
COPY_NODE_FIELD(resultRelations);
COPY_SCALAR_FIELD(resultRelIndex);
COPY_NODE_FIELD(plans);
@@ -235,6 +236,7 @@ _copyAppend(const Append *from)
/*
* copy remainder of node
*/
+ COPY_NODE_FIELD(partitioned_rels);
COPY_NODE_FIELD(appendplans);
return newnode;
@@ -256,6 +258,7 @@ _copyMergeAppend(const MergeAppend *from)
/*
* copy remainder of node
*/
+ COPY_NODE_FIELD(partitioned_rels);
COPY_NODE_FIELD(mergeplans);
COPY_SCALAR_FIELD(numCols);
COPY_POINTER_FIELD(sortColIdx, from->numCols * sizeof(AttrNumber));
@@ -2198,6 +2201,7 @@ _copyAppendRelInfo(const AppendRelInfo *from)
COPY_SCALAR_FIELD(child_relid);
COPY_SCALAR_FIELD(parent_reltype);
COPY_SCALAR_FIELD(child_reltype);
+ COPY_SCALAR_FIELD(child_relkind);
COPY_NODE_FIELD(translated_vars);
COPY_SCALAR_FIELD(parent_reloid);
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 54e9c983a0..93a13952e5 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -889,6 +889,7 @@ _equalAppendRelInfo(const AppendRelInfo *a, const AppendRelInfo *b)
COMPARE_SCALAR_FIELD(child_relid);
COMPARE_SCALAR_FIELD(parent_reltype);
COMPARE_SCALAR_FIELD(child_reltype);
+ COMPARE_SCALAR_FIELD(child_relkind);
COMPARE_NODE_FIELD(translated_vars);
COMPARE_SCALAR_FIELD(parent_reloid);
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 7418fbeded..afa36a00ec 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -344,6 +344,7 @@ _outModifyTable(StringInfo str, const ModifyTable *node)
WRITE_ENUM_FIELD(operation, CmdType);
WRITE_BOOL_FIELD(canSetTag);
WRITE_UINT_FIELD(nominalRelation);
+ WRITE_NODE_FIELD(partitioned_rels);
WRITE_NODE_FIELD(resultRelations);
WRITE_INT_FIELD(resultRelIndex);
WRITE_NODE_FIELD(plans);
@@ -368,6 +369,7 @@ _outAppend(StringInfo str, const Append *node)
_outPlanInfo(str, (const Plan *) node);
+ WRITE_NODE_FIELD(partitioned_rels);
WRITE_NODE_FIELD(appendplans);
}
@@ -380,6 +382,7 @@ _outMergeAppend(StringInfo str, const MergeAppend *node)
_outPlanInfo(str, (const Plan *) node);
+ WRITE_NODE_FIELD(partitioned_rels);
WRITE_NODE_FIELD(mergeplans);
WRITE_INT_FIELD(numCols);
@@ -1808,6 +1811,7 @@ _outAppendPath(StringInfo str, const AppendPath *node)
_outPathInfo(str, (const Path *) node);
+ WRITE_NODE_FIELD(partitioned_rels);
WRITE_NODE_FIELD(subpaths);
}
@@ -1818,6 +1822,7 @@ _outMergeAppendPath(StringInfo str, const MergeAppendPath *node)
_outPathInfo(str, (const Path *) node);
+ WRITE_NODE_FIELD(partitioned_rels);
WRITE_NODE_FIELD(subpaths);
WRITE_FLOAT_FIELD(limit_tuples, "%.0f");
}
@@ -2023,6 +2028,7 @@ _outModifyTablePath(StringInfo str, const ModifyTablePath *node)
WRITE_ENUM_FIELD(operation, CmdType);
WRITE_BOOL_FIELD(canSetTag);
WRITE_UINT_FIELD(nominalRelation);
+ WRITE_NODE_FIELD(partitioned_rels);
WRITE_NODE_FIELD(resultRelations);
WRITE_NODE_FIELD(subpaths);
WRITE_NODE_FIELD(subroots);
@@ -2415,6 +2421,7 @@ _outAppendRelInfo(StringInfo str, const AppendRelInfo *node)
WRITE_UINT_FIELD(child_relid);
WRITE_OID_FIELD(parent_reltype);
WRITE_OID_FIELD(child_reltype);
+ WRITE_CHAR_FIELD(child_relkind);
WRITE_NODE_FIELD(translated_vars);
WRITE_OID_FIELD(parent_reloid);
}
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index d3bbc02f24..f2ec174216 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1535,6 +1535,7 @@ _readModifyTable(void)
READ_ENUM_FIELD(operation, CmdType);
READ_BOOL_FIELD(canSetTag);
READ_UINT_FIELD(nominalRelation);
+ READ_NODE_FIELD(partitioned_rels);
READ_NODE_FIELD(resultRelations);
READ_INT_FIELD(resultRelIndex);
READ_NODE_FIELD(plans);
@@ -1564,6 +1565,7 @@ _readAppend(void)
ReadCommonPlan(&local_node->plan);
+ READ_NODE_FIELD(partitioned_rels);
READ_NODE_FIELD(appendplans);
READ_DONE();
@@ -1579,6 +1581,7 @@ _readMergeAppend(void)
ReadCommonPlan(&local_node->plan);
+ READ_NODE_FIELD(partitioned_rels);
READ_NODE_FIELD(mergeplans);
READ_INT_FIELD(numCols);
READ_ATTRNUMBER_ARRAY(sortColIdx, local_node->numCols);
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index b263359fde..566d1860aa 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -95,7 +95,8 @@ static void set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
Index rti, RangeTblEntry *rte);
static void generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
List *live_childrels,
- List *all_child_pathkeys);
+ List *all_child_pathkeys,
+ List *partitioned_rels);
static Path *get_cheapest_parameterized_child_path(PlannerInfo *root,
RelOptInfo *rel,
Relids required_outer);
@@ -344,6 +345,14 @@ set_rel_size(PlannerInfo *root, RelOptInfo *rel,
/* Foreign table */
set_foreign_size(root, rel, rte);
}
+ else if (rte->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ /*
+ * A partitioned table without leaf partitions is marked
+ * as a dummy rel.
+ */
+ set_dummy_rel_pathlist(rel);
+ }
else if (rte->tablesample != NULL)
{
/* Sampled relation */
@@ -878,6 +887,10 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
if (appinfo->parent_relid != parentRTindex)
continue;
+ /* Nothing to see here. */
+ if (appinfo->child_relkind == RELKIND_PARTITIONED_TABLE)
+ continue;
+
childRTindex = appinfo->child_relid;
childRTE = root->simple_rte_array[childRTindex];
@@ -1189,6 +1202,7 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
List *all_child_pathkeys = NIL;
List *all_child_outers = NIL;
ListCell *l;
+ List *partitioned_rels = NIL;
/*
* Generate access paths for each member relation, and remember the
@@ -1208,6 +1222,17 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
if (appinfo->parent_relid != parentRTindex)
continue;
+ /*
+ * Nothing to do here for partitioned child tables; just remember
+ * the RT index to put into the AppendPath.
+ */
+ if (appinfo->child_relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ partitioned_rels = lappend_int(partitioned_rels,
+ appinfo->child_relid);
+ continue;
+ }
+
/* Re-locate the child RTE and RelOptInfo */
childRTindex = appinfo->child_relid;
childRTE = root->simple_rte_array[childRTindex];
@@ -1327,7 +1352,8 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
* if we have zero or one live subpath due to constraint exclusion.)
*/
if (subpaths_valid)
- add_path(rel, (Path *) create_append_path(rel, subpaths, NULL, 0));
+ add_path(rel, (Path *) create_append_path(rel, subpaths, NULL, 0,
+ partitioned_rels));
/*
* Consider an append of partial unordered, unparameterized partial paths.
@@ -1354,7 +1380,7 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
/* Generate a partial append path. */
appendpath = create_append_path(rel, partial_subpaths, NULL,
- parallel_workers);
+ parallel_workers, partitioned_rels);
add_partial_path(rel, (Path *) appendpath);
}
@@ -1364,7 +1390,8 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
*/
if (subpaths_valid)
generate_mergeappend_paths(root, rel, live_childrels,
- all_child_pathkeys);
+ all_child_pathkeys,
+ partitioned_rels);
/*
* Build Append paths for each parameterization seen among the child rels.
@@ -1406,7 +1433,8 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
if (subpaths_valid)
add_path(rel, (Path *)
- create_append_path(rel, subpaths, required_outer, 0));
+ create_append_path(rel, subpaths, required_outer, 0,
+ partitioned_rels));
}
}
@@ -1436,7 +1464,8 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
static void
generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
List *live_childrels,
- List *all_child_pathkeys)
+ List *all_child_pathkeys,
+ List *partitioned_rels)
{
ListCell *lcp;
@@ -1500,13 +1529,15 @@ generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
rel,
startup_subpaths,
pathkeys,
- NULL));
+ NULL,
+ partitioned_rels));
if (startup_neq_total)
add_path(rel, (Path *) create_merge_append_path(root,
rel,
total_subpaths,
pathkeys,
- NULL));
+ NULL,
+ partitioned_rels));
}
}
@@ -1639,7 +1670,7 @@ set_dummy_rel_pathlist(RelOptInfo *rel)
rel->pathlist = NIL;
rel->partial_pathlist = NIL;
- add_path(rel, (Path *) create_append_path(rel, NIL, NULL, 0));
+ add_path(rel, (Path *) create_append_path(rel, NIL, NULL, 0, NIL));
/*
* We set the cheapest path immediately, to ensure that IS_DUMMY_REL()
diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c
index 0d0068360c..7dfbb7a970 100644
--- a/src/backend/optimizer/path/joinrels.c
+++ b/src/backend/optimizer/path/joinrels.c
@@ -1197,7 +1197,7 @@ mark_dummy_rel(RelOptInfo *rel)
rel->partial_pathlist = NIL;
/* Set up the dummy path */
- add_path(rel, (Path *) create_append_path(rel, NIL, NULL, 0));
+ add_path(rel, (Path *) create_append_path(rel, NIL, NULL, 0, NIL));
/* Set or update cheapest_total_path and related fields */
set_cheapest(rel);
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index d002e6d567..6b29ccc0c4 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -199,7 +199,7 @@ static CteScan *make_ctescan(List *qptlist, List *qpqual,
Index scanrelid, int ctePlanId, int cteParam);
static WorkTableScan *make_worktablescan(List *qptlist, List *qpqual,
Index scanrelid, int wtParam);
-static Append *make_append(List *appendplans, List *tlist);
+static Append *make_append(List *appendplans, List *tlist, List *partitioned_rels);
static RecursiveUnion *make_recursive_union(List *tlist,
Plan *lefttree,
Plan *righttree,
@@ -273,7 +273,7 @@ static Result *make_result(List *tlist, Node *resconstantqual, Plan *subplan);
static ProjectSet *make_project_set(List *tlist, Plan *subplan);
static ModifyTable *make_modifytable(PlannerInfo *root,
CmdType operation, bool canSetTag,
- Index nominalRelation,
+ Index nominalRelation, List *partitioned_rels,
List *resultRelations, List *subplans,
List *withCheckOptionLists, List *returningLists,
List *rowMarks, OnConflictExpr *onconflict, int epqParam);
@@ -1026,7 +1026,7 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path)
* parent-rel Vars it'll be asked to emit.
*/
- plan = make_append(subplans, tlist);
+ plan = make_append(subplans, tlist, best_path->partitioned_rels);
copy_generic_path_info(&plan->plan, (Path *) best_path);
@@ -1134,6 +1134,7 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path)
subplans = lappend(subplans, subplan);
}
+ node->partitioned_rels = best_path->partitioned_rels;
node->mergeplans = subplans;
return (Plan *) node;
@@ -2340,6 +2341,7 @@ create_modifytable_plan(PlannerInfo *root, ModifyTablePath *best_path)
best_path->operation,
best_path->canSetTag,
best_path->nominalRelation,
+ best_path->partitioned_rels,
best_path->resultRelations,
subplans,
best_path->withCheckOptionLists,
@@ -5187,7 +5189,7 @@ make_foreignscan(List *qptlist,
}
static Append *
-make_append(List *appendplans, List *tlist)
+make_append(List *appendplans, List *tlist, List *partitioned_rels)
{
Append *node = makeNode(Append);
Plan *plan = &node->plan;
@@ -5196,6 +5198,7 @@ make_append(List *appendplans, List *tlist)
plan->qual = NIL;
plan->lefttree = NULL;
plan->righttree = NULL;
+ node->partitioned_rels = partitioned_rels;
node->appendplans = appendplans;
return node;
@@ -6308,7 +6311,7 @@ make_project_set(List *tlist,
static ModifyTable *
make_modifytable(PlannerInfo *root,
CmdType operation, bool canSetTag,
- Index nominalRelation,
+ Index nominalRelation, List *partitioned_rels,
List *resultRelations, List *subplans,
List *withCheckOptionLists, List *returningLists,
List *rowMarks, OnConflictExpr *onconflict, int epqParam)
@@ -6334,6 +6337,7 @@ make_modifytable(PlannerInfo *root,
node->operation = operation;
node->canSetTag = canSetTag;
node->nominalRelation = nominalRelation;
+ node->partitioned_rels = partitioned_rels;
node->resultRelations = resultRelations;
node->resultRelIndex = -1; /* will be set correctly in setrefs.c */
node->plans = subplans;
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index b4ac224a7a..79792c406c 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -14,6 +14,7 @@
*/
#include "postgres.h"
+#include "catalog/pg_class.h"
#include "catalog/pg_type.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
@@ -642,6 +643,11 @@ create_lateral_join_info(PlannerInfo *root)
if (appinfo->parent_relid != rti)
continue;
+
+ /* Need not consider these. */
+ if (appinfo->child_relkind == RELKIND_PARTITIONED_TABLE)
+ continue;
+
childrel = root->simple_rel_array[appinfo->child_relid];
Assert(childrel->reloptkind == RELOPT_OTHER_MEMBER_REL);
Assert(childrel->direct_lateral_relids == NULL);
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 02286d9c52..4d43756ff7 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -1007,6 +1007,8 @@ inheritance_planner(PlannerInfo *root)
RelOptInfo *final_rel;
ListCell *lc;
Index rti;
+ RangeTblEntry *parent_rte;
+ List *partitioned_rels = NIL;
Assert(parse->commandType != CMD_INSERT);
@@ -1055,6 +1057,13 @@ inheritance_planner(PlannerInfo *root)
{
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
+ /*
+ * Need not consider these, because the latter planning steps
+ * simply ignore them.
+ */
+ if (appinfo->child_relkind == RELKIND_PARTITIONED_TABLE)
+ continue;
+
if (bms_is_member(appinfo->parent_relid, subqueryRTindexes) ||
bms_is_member(appinfo->child_relid, subqueryRTindexes) ||
bms_overlap(pull_varnos((Node *) appinfo->translated_vars),
@@ -1065,13 +1074,21 @@ inheritance_planner(PlannerInfo *root)
}
/*
+ * If the parent RTE is a partitioned table, we should use that as the
+ * nominal relation, because we do not have the duplicate parent RTE,
+ * unlike in the case of a non-partitioned inheritance parent.
+ */
+ parent_rte = rt_fetch(parentRTindex, root->parse->rtable);
+ if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
+ nominalRelation = parentRTindex;
+
+ /*
* And now we can get on with generating a plan for each child table.
*/
foreach(lc, root->append_rel_list)
{
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
PlannerInfo *subroot;
- RangeTblEntry *parent_rte;
RangeTblEntry *child_rte;
RelOptInfo *sub_final_rel;
Path *subpath;
@@ -1081,6 +1098,17 @@ inheritance_planner(PlannerInfo *root)
continue;
/*
+ * Nothing to do here for partitioned child tables; just remember
+ * the RT index to put into the ModifyTablePath.
+ */
+ if (appinfo->child_relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ partitioned_rels = lappend_int(partitioned_rels,
+ appinfo->child_relid);
+ continue;
+ }
+
+ /*
* We need a working copy of the PlannerInfo so that we can control
* propagation of information back to the main copy.
*/
@@ -1216,15 +1244,23 @@ inheritance_planner(PlannerInfo *root)
grouping_planner(subroot, true, 0.0 /* retrieve all tuples */ );
/*
- * We'll use the first child relation (even if it's excluded) as the
- * nominal target relation of the ModifyTable node. Because of the
- * way expand_inherited_rtentry works, this should always be the RTE
- * representing the parent table in its role as a simple member of the
- * inheritance set. (It would be logically cleaner to use the
- * inheritance parent RTE as the nominal target; but since that RTE
- * will not be otherwise referenced in the plan, doing so would give
- * rise to confusing use of multiple aliases in EXPLAIN output for
- * what the user will think is the "same" table.)
+ * Set the nomimal target relation of the ModifyTable node if not
+ * already done. We use the inheritance parent RTE as the nominal
+ * target relation if it's a partitioned table (see just above this
+ * loop). In the non-partitioned parent case, we'll use the first
+ * child relation (even if it's excluded) as the nominal target
+ * relation. Because of the way expand_inherited_rtentry works, the
+ * latter should be the RTE representing the parent table in its role
+ * as a simple member of the inheritance set.
+ *
+ * It would be logically cleaner to *always* use the inheritance
+ * parent RTE as the nominal relation; but that RTE is not otherwise
+ * referenced in the plan in the non-partitioned inheritance case.
+ * Instead the duplicate RTE is used elsewhere in the plan, so using
+ * the original parent RTE would give rise to confusing use of multiple
+ * aliases in EXPLAIN output for what the user will think is the "same"
+ * table. It's not a problem in the partitioned inheritance case,
+ * because there is duplicate RTE for the parent in that case.
*/
if (nominalRelation < 0)
nominalRelation = appinfo->child_relid;
@@ -1351,6 +1387,7 @@ inheritance_planner(PlannerInfo *root)
parse->commandType,
parse->canSetTag,
nominalRelation,
+ partitioned_rels,
resultRelations,
subpaths,
subroots,
@@ -2046,6 +2083,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
parse->commandType,
parse->canSetTag,
parse->resultRelation,
+ NIL,
list_make1_int(parse->resultRelation),
list_make1(path),
list_make1(root),
@@ -3348,7 +3386,8 @@ create_grouping_paths(PlannerInfo *root,
create_append_path(grouped_rel,
paths,
NULL,
- 0);
+ 0,
+ NIL);
path->pathtarget = target;
}
else
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 5f3027e96f..d148c2d37d 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -835,6 +835,10 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
splan->nominalRelation += rtoffset;
splan->exclRelRTI += rtoffset;
+ foreach(l, splan->partitioned_rels)
+ {
+ lfirst_int(l) += rtoffset;
+ }
foreach(l, splan->resultRelations)
{
lfirst_int(l) += rtoffset;
@@ -875,6 +879,10 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
*/
set_dummy_tlist_references(plan, rtoffset);
Assert(splan->plan.qual == NIL);
+ foreach(l, splan->partitioned_rels)
+ {
+ lfirst_int(l) += rtoffset;
+ }
foreach(l, splan->appendplans)
{
lfirst(l) = set_plan_refs(root,
@@ -893,6 +901,10 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
*/
set_dummy_tlist_references(plan, rtoffset);
Assert(splan->plan.qual == NIL);
+ foreach(l, splan->partitioned_rels)
+ {
+ lfirst_int(l) += rtoffset;
+ }
foreach(l, splan->mergeplans)
{
lfirst(l) = set_plan_refs(root,
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 1389db18ba..ece5fa7c7a 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -566,7 +566,7 @@ generate_union_path(SetOperationStmt *op, PlannerInfo *root,
/*
* Append the child results together.
*/
- path = (Path *) create_append_path(result_rel, pathlist, NULL, 0);
+ path = (Path *) create_append_path(result_rel, pathlist, NULL, 0, NIL);
/* We have to manually jam the right tlist into the path; ick */
path->pathtarget = create_pathtarget(root, tlist);
@@ -678,7 +678,7 @@ generate_nonunion_path(SetOperationStmt *op, PlannerInfo *root,
/*
* Append the child results together.
*/
- path = (Path *) create_append_path(result_rel, pathlist, NULL, 0);
+ path = (Path *) create_append_path(result_rel, pathlist, NULL, 0, NIL);
/* We have to manually jam the right tlist into the path; ick */
path->pathtarget = create_pathtarget(root, tlist);
@@ -1352,6 +1352,12 @@ expand_inherited_tables(PlannerInfo *root)
*
* A childless table is never considered to be an inheritance set; therefore
* a parent RTE must always have at least two associated AppendRelInfos.
+ *
+ * AppendRelInfo's created for each child table normally contains information
+ * necessary to create a scan plan for the table. However, for child tables
+ * that are partitioned (which contains no data), we need not create scan
+ * plans; so create a minimal AppendRelInfo in that case containing only the
+ * parent-child RT index pair.
*/
static void
expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
@@ -1488,32 +1494,42 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
appinfo = makeNode(AppendRelInfo);
appinfo->parent_relid = rti;
appinfo->child_relid = childRTindex;
- appinfo->parent_reltype = oldrelation->rd_rel->reltype;
- appinfo->child_reltype = newrelation->rd_rel->reltype;
- make_inh_translation_list(oldrelation, newrelation, childRTindex,
- &appinfo->translated_vars);
- appinfo->parent_reloid = parentOID;
- appinfos = lappend(appinfos, appinfo);
+ appinfo->child_relkind = childrte->relkind;
/*
- * Translate the column permissions bitmaps to the child's attnums (we
- * have to build the translated_vars list before we can do this). But
- * if this is the parent table, leave copyObject's result alone.
- *
- * Note: we need to do this even though the executor won't run any
- * permissions checks on the child RTE. The insertedCols/updatedCols
- * bitmaps may be examined for trigger-firing purposes.
+ * No need to fill the following information for partitioned table
+ * appinfos, because we won't be needing it.
*/
- if (childOID != parentOID)
+ if (appinfo->child_relkind != RELKIND_PARTITIONED_TABLE)
{
- childrte->selectedCols = translate_col_privs(rte->selectedCols,
+ appinfo->parent_reltype = oldrelation->rd_rel->reltype;
+ appinfo->child_reltype = newrelation->rd_rel->reltype;
+ make_inh_translation_list(oldrelation, newrelation, childRTindex,
+ &appinfo->translated_vars);
+ appinfo->parent_reloid = parentOID;
+
+ /*
+ * Translate the column permissions bitmaps to the child's attnums
+ * (we have to build the translated_vars list before we can do
+ * this). But if this is the parent table, leave copyObject's
+ * result alone. Note: we need to do this even though the executor
+ * won't run any permissions checks on the child RTE. The
+ * insertedCols/updatedCols bitmaps may be examined for
+ * trigger-firing purposes.
+ */
+ if (childOID != parentOID)
+ {
+ childrte->selectedCols = translate_col_privs(rte->selectedCols,
appinfo->translated_vars);
- childrte->insertedCols = translate_col_privs(rte->insertedCols,
+ childrte->insertedCols = translate_col_privs(rte->insertedCols,
appinfo->translated_vars);
- childrte->updatedCols = translate_col_privs(rte->updatedCols,
+ childrte->updatedCols = translate_col_privs(rte->updatedCols,
appinfo->translated_vars);
+ }
}
+ appinfos = lappend(appinfos, appinfo);
+
/*
* Build a PlanRowMark if parent is marked FOR UPDATE/SHARE.
*/
@@ -1529,7 +1545,10 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
newrc->allMarkTypes = (1 << newrc->markType);
newrc->strength = oldrc->strength;
newrc->waitPolicy = oldrc->waitPolicy;
- newrc->isParent = false;
+ /*
+ * If child is a partitioned table, this is a "dummy" parent entry
+ */
+ newrc->isParent = (rte->relkind == RELKIND_PARTITIONED_TABLE);
/* Include child's rowmark type in parent's allMarkTypes */
oldrc->allMarkTypes |= newrc->allMarkTypes;
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 8ce772d274..fca96eb001 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -1201,7 +1201,7 @@ create_tidscan_path(PlannerInfo *root, RelOptInfo *rel, List *tidquals,
*/
AppendPath *
create_append_path(RelOptInfo *rel, List *subpaths, Relids required_outer,
- int parallel_workers)
+ int parallel_workers, List *partitioned_rels)
{
AppendPath *pathnode = makeNode(AppendPath);
ListCell *l;
@@ -1216,6 +1216,7 @@ create_append_path(RelOptInfo *rel, List *subpaths, Relids required_outer,
pathnode->path.parallel_workers = parallel_workers;
pathnode->path.pathkeys = NIL; /* result is always considered
* unsorted */
+ pathnode->partitioned_rels = partitioned_rels;
pathnode->subpaths = subpaths;
/*
@@ -1258,7 +1259,8 @@ create_merge_append_path(PlannerInfo *root,
RelOptInfo *rel,
List *subpaths,
List *pathkeys,
- Relids required_outer)
+ Relids required_outer,
+ List *partitioned_rels)
{
MergeAppendPath *pathnode = makeNode(MergeAppendPath);
Cost input_startup_cost;
@@ -1274,6 +1276,7 @@ create_merge_append_path(PlannerInfo *root,
pathnode->path.parallel_safe = rel->consider_parallel;
pathnode->path.parallel_workers = 0;
pathnode->path.pathkeys = pathkeys;
+ pathnode->partitioned_rels = partitioned_rels;
pathnode->subpaths = subpaths;
/*
@@ -3105,7 +3108,7 @@ create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
ModifyTablePath *
create_modifytable_path(PlannerInfo *root, RelOptInfo *rel,
CmdType operation, bool canSetTag,
- Index nominalRelation,
+ Index nominalRelation, List *partitioned_rels,
List *resultRelations, List *subpaths,
List *subroots,
List *withCheckOptionLists, List *returningLists,
@@ -3172,6 +3175,7 @@ create_modifytable_path(PlannerInfo *root, RelOptInfo *rel,
pathnode->operation = operation;
pathnode->canSetTag = canSetTag;
pathnode->nominalRelation = nominalRelation;
+ pathnode->partitioned_rels = partitioned_rels;
pathnode->resultRelations = resultRelations;
pathnode->subpaths = subpaths;
pathnode->subroots = subroots;
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index dffc92762b..1db784784f 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -1509,6 +1509,13 @@ AcquireExecutorLocks(List *stmt_list, bool acquire)
continue;
/*
+ * We lock the partitioned tables in the respective control nodes
+ * such as Append, ModifyTable, etc.
+ */
+ if (rte->relkind == RELKIND_PARTITIONED_TABLE)
+ continue;
+
+ /*
* Acquire the appropriate type of lock on each relation OID. Note
* that we don't actually try to open the rel, and hence will not
* fail if it's been dropped entirely --- we'll just transiently
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index b880dc16cf..8e8b8e5314 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -202,6 +202,8 @@ typedef struct ModifyTable
CmdType operation; /* INSERT, UPDATE, or DELETE */
bool canSetTag; /* do we set the command tag/es_processed? */
Index nominalRelation; /* Parent RT index for use of EXPLAIN */
+ /* RT indexes of non-leaf tables in a partition tree */
+ List *partitioned_rels;
List *resultRelations; /* integer list of RT indexes */
int resultRelIndex; /* index of first resultRel in plan's list */
List *plans; /* plan(s) producing source data */
@@ -227,6 +229,8 @@ typedef struct ModifyTable
typedef struct Append
{
Plan plan;
+ /* RT indexes of non-leaf tables in a partition tree */
+ List *partitioned_rels;
List *appendplans;
} Append;
@@ -238,6 +242,8 @@ typedef struct Append
typedef struct MergeAppend
{
Plan plan;
+ /* RT indexes of non-leaf tables in a partition tree */
+ List *partitioned_rels;
List *mergeplans;
/* remaining fields are just like the sort-key info in struct Sort */
int numCols; /* number of sort-key columns */
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index 05d6f07aea..4e9caf7e77 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -1116,6 +1116,7 @@ typedef struct CustomPath
typedef struct AppendPath
{
Path path;
+ List *partitioned_rels;
List *subpaths; /* list of component Paths */
} AppendPath;
@@ -1134,6 +1135,7 @@ typedef struct AppendPath
typedef struct MergeAppendPath
{
Path path;
+ List *partitioned_rels;
List *subpaths; /* list of component Paths */
double limit_tuples; /* hard limit on output tuples, or -1 */
} MergeAppendPath;
@@ -1482,6 +1484,7 @@ typedef struct ModifyTablePath
CmdType operation; /* INSERT, UPDATE, or DELETE */
bool canSetTag; /* do we set the command tag/es_processed? */
Index nominalRelation; /* Parent RT index for use of EXPLAIN */
+ List *partitioned_rels; /* integer list of RT indexes */
List *resultRelations; /* integer list of RT indexes */
List *subpaths; /* Path(s) producing source data */
List *subroots; /* per-target-table PlannerInfos */
@@ -1886,6 +1889,7 @@ typedef struct AppendRelInfo
*/
Oid parent_reltype; /* OID of parent's composite type */
Oid child_reltype; /* OID of child's composite type */
+ char child_relkind; /* relkind of append child rel */
/*
* The N'th element of this list is a Var or expression representing the
diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h
index 373c7221a8..81640de7ab 100644
--- a/src/include/optimizer/pathnode.h
+++ b/src/include/optimizer/pathnode.h
@@ -64,12 +64,14 @@ extern BitmapOrPath *create_bitmap_or_path(PlannerInfo *root,
extern TidPath *create_tidscan_path(PlannerInfo *root, RelOptInfo *rel,
List *tidquals, Relids required_outer);
extern AppendPath *create_append_path(RelOptInfo *rel, List *subpaths,
- Relids required_outer, int parallel_workers);
+ Relids required_outer, int parallel_workers,
+ List *partitioned_rels);
extern MergeAppendPath *create_merge_append_path(PlannerInfo *root,
RelOptInfo *rel,
List *subpaths,
List *pathkeys,
- Relids required_outer);
+ Relids required_outer,
+ List *partitioned_rels);
extern ResultPath *create_result_path(PlannerInfo *root, RelOptInfo *rel,
PathTarget *target, List *resconstantqual);
extern MaterialPath *create_material_path(RelOptInfo *rel, Path *subpath);
@@ -232,7 +234,7 @@ extern LockRowsPath *create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
extern ModifyTablePath *create_modifytable_path(PlannerInfo *root,
RelOptInfo *rel,
CmdType operation, bool canSetTag,
- Index nominalRelation,
+ Index nominalRelation, List *partitioned_rels,
List *resultRelations, List *subpaths,
List *subroots,
List *withCheckOptionLists, List *returningLists,
diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out
index 6494b205c4..6737f925c3 100644
--- a/src/test/regress/expected/inherit.out
+++ b/src/test/regress/expected/inherit.out
@@ -588,6 +588,32 @@ select tableoid::regclass::text as relname, bar.* from bar order by 1,2;
bar2 | 4 | 104
(8 rows)
+-- Check UPDATE with *partitioned* inherited target and an appendrel subquery
+create table some_tab (a int);
+insert into some_tab values (0);
+create table some_tab_child () inherits (some_tab);
+insert into some_tab_child values (1);
+create table parted_tab (a int, b char) partition by list (a);
+create table parted_tab_part1 partition of parted_tab for values in (1);
+create table parted_tab_part2 partition of parted_tab for values in (2);
+create table parted_tab_part3 partition of parted_tab for values in (3);
+insert into parted_tab values (1, 'a'), (2, 'a'), (3, 'a');
+update parted_tab set b = 'b'
+from
+ (select a from some_tab union all select a+1 from some_tab) ss
+where parted_tab.a = ss.a;
+select tableoid::regclass::text as relname, parted_tab.*
+from parted_tab order by 1,2;
+ relname | a | b
+------------------+---+---
+ parted_tab_part1 | 1 | b
+ parted_tab_part2 | 2 | b
+ parted_tab_part3 | 3 | a
+(3 rows)
+
+drop table parted_tab;
+drop table some_tab cascade;
+NOTICE: drop cascades to table some_tab_child
/* Test multiple inheritance of column defaults */
CREATE TABLE firstparent (tomorrow date default now()::date + 1);
CREATE TABLE secondparent (tomorrow date default now() :: date + 1);
@@ -1611,71 +1637,60 @@ explain (costs off) select * from list_parted;
QUERY PLAN
--------------------------------
Append
- -> Seq Scan on list_parted
-> Seq Scan on part_ab_cd
-> Seq Scan on part_ef_gh
-> Seq Scan on part_null_xy
-(5 rows)
+(4 rows)
explain (costs off) select * from list_parted where a is null;
QUERY PLAN
--------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (a IS NULL)
-> Seq Scan on part_null_xy
Filter: (a IS NULL)
-(5 rows)
+(3 rows)
explain (costs off) select * from list_parted where a is not null;
QUERY PLAN
---------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (a IS NOT NULL)
-> Seq Scan on part_ab_cd
Filter: (a IS NOT NULL)
-> Seq Scan on part_ef_gh
Filter: (a IS NOT NULL)
-> Seq Scan on part_null_xy
Filter: (a IS NOT NULL)
-(9 rows)
+(7 rows)
explain (costs off) select * from list_parted where a in ('ab', 'cd', 'ef');
QUERY PLAN
----------------------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-> Seq Scan on part_ab_cd
Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-> Seq Scan on part_ef_gh
Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-(7 rows)
+(5 rows)
explain (costs off) select * from list_parted where a = 'ab' or a in (null, 'cd');
QUERY PLAN
---------------------------------------------------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_ab_cd
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_ef_gh
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_null_xy
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-(9 rows)
+(7 rows)
explain (costs off) select * from list_parted where a = 'ab';
QUERY PLAN
------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: ((a)::text = 'ab'::text)
-> Seq Scan on part_ab_cd
Filter: ((a)::text = 'ab'::text)
-(5 rows)
+(3 rows)
create table range_list_parted (
a int,
@@ -1695,14 +1710,9 @@ create table part_40_inf_ab partition of part_40_inf for values in ('ab');
create table part_40_inf_cd partition of part_40_inf for values in ('cd');
create table part_40_inf_null partition of part_40_inf for values in (null);
explain (costs off) select * from range_list_parted;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- -> Seq Scan on part_1_10
- -> Seq Scan on part_10_20
- -> Seq Scan on part_21_30
- -> Seq Scan on part_40_inf
-> Seq Scan on part_1_10_ab
-> Seq Scan on part_1_10_cd
-> Seq Scan on part_10_20_ab
@@ -1712,36 +1722,22 @@ explain (costs off) select * from range_list_parted;
-> Seq Scan on part_40_inf_ab
-> Seq Scan on part_40_inf_cd
-> Seq Scan on part_40_inf_null
-(15 rows)
+(10 rows)
explain (costs off) select * from range_list_parted where a = 5;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+--------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (a = 5)
- -> Seq Scan on part_1_10
- Filter: (a = 5)
-> Seq Scan on part_1_10_ab
Filter: (a = 5)
-> Seq Scan on part_1_10_cd
Filter: (a = 5)
-(9 rows)
+(5 rows)
explain (costs off) select * from range_list_parted where b = 'ab';
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_1_10
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_10_20
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_21_30
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_40_inf
- Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_1_10_ab
Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_10_20_ab
@@ -1750,27 +1746,19 @@ explain (costs off) select * from range_list_parted where b = 'ab';
Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_40_inf_ab
Filter: (b = 'ab'::bpchar)
-(19 rows)
+(9 rows)
explain (costs off) select * from range_list_parted where a between 3 and 23 and b in ('ab');
QUERY PLAN
-----------------------------------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_1_10
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_10_20
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_21_30
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_1_10_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_10_20_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_21_30_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-(15 rows)
+(7 rows)
/* Should select no rows because range partition key cannot be null */
explain (costs off) select * from range_list_parted where a is null;
@@ -1782,37 +1770,17 @@ explain (costs off) select * from range_list_parted where a is null;
/* Should only select rows from the null-accepting partition */
explain (costs off) select * from range_list_parted where b is null;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (b IS NULL)
- -> Seq Scan on part_1_10
- Filter: (b IS NULL)
- -> Seq Scan on part_10_20
- Filter: (b IS NULL)
- -> Seq Scan on part_21_30
- Filter: (b IS NULL)
- -> Seq Scan on part_40_inf
- Filter: (b IS NULL)
-> Seq Scan on part_40_inf_null
Filter: (b IS NULL)
-(13 rows)
+(3 rows)
explain (costs off) select * from range_list_parted where a is not null and a < 67;
QUERY PLAN
------------------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_1_10
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_10_20
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_21_30
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_40_inf
- Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_1_10_ab
Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_1_10_cd
@@ -1831,23 +1799,19 @@ explain (costs off) select * from range_list_parted where a is not null and a <
Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_40_inf_null
Filter: ((a IS NOT NULL) AND (a < 67))
-(29 rows)
+(19 rows)
explain (costs off) select * from range_list_parted where a >= 30;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (a >= 30)
- -> Seq Scan on part_40_inf
- Filter: (a >= 30)
-> Seq Scan on part_40_inf_ab
Filter: (a >= 30)
-> Seq Scan on part_40_inf_cd
Filter: (a >= 30)
-> Seq Scan on part_40_inf_null
Filter: (a >= 30)
-(11 rows)
+(7 rows)
drop table list_parted;
drop table range_list_parted;
diff --git a/src/test/regress/expected/tablesample.out b/src/test/regress/expected/tablesample.out
index b18e420e9b..d3794140fb 100644
--- a/src/test/regress/expected/tablesample.out
+++ b/src/test/regress/expected/tablesample.out
@@ -322,12 +322,10 @@ explain (costs off)
QUERY PLAN
-------------------------------------------
Append
- -> Sample Scan on parted_sample
- Sampling: bernoulli ('100'::real)
-> Sample Scan on parted_sample_1
Sampling: bernoulli ('100'::real)
-> Sample Scan on parted_sample_2
Sampling: bernoulli ('100'::real)
-(7 rows)
+(5 rows)
drop table parted_sample, parted_sample_1, parted_sample_2;
diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql
index e3e9e34895..ff94c4d4c3 100644
--- a/src/test/regress/sql/inherit.sql
+++ b/src/test/regress/sql/inherit.sql
@@ -128,6 +128,28 @@ where bar.f1 = ss.f1;
select tableoid::regclass::text as relname, bar.* from bar order by 1,2;
+-- Check UPDATE with *partitioned* inherited target and an appendrel subquery
+create table some_tab (a int);
+insert into some_tab values (0);
+create table some_tab_child () inherits (some_tab);
+insert into some_tab_child values (1);
+create table parted_tab (a int, b char) partition by list (a);
+create table parted_tab_part1 partition of parted_tab for values in (1);
+create table parted_tab_part2 partition of parted_tab for values in (2);
+create table parted_tab_part3 partition of parted_tab for values in (3);
+insert into parted_tab values (1, 'a'), (2, 'a'), (3, 'a');
+
+update parted_tab set b = 'b'
+from
+ (select a from some_tab union all select a+1 from some_tab) ss
+where parted_tab.a = ss.a;
+
+select tableoid::regclass::text as relname, parted_tab.*
+from parted_tab order by 1,2;
+
+drop table parted_tab;
+drop table some_tab cascade;
+
/* Test multiple inheritance of column defaults */
CREATE TABLE firstparent (tomorrow date default now()::date + 1);
--
2.11.0
[text/x-diff] 0002-Do-not-allocate-storage-for-partitioned-tables.patch (3.1K, ../../a4e2be66-67c6-c8c0-080b-1af22a14b566@lab.ntt.co.jp/3-0002-Do-not-allocate-storage-for-partitioned-tables.patch)
download | inline diff:
From 8cbd2eb1911431d39516e1e58965f6594c060a64 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Tue, 24 Jan 2017 14:22:34 +0900
Subject: [PATCH 2/2] Do not allocate storage for partitioned tables.
Currently, it is not possible to insert any data into a partitioned
table. So, they're empty at all times, which means it is wasteful to
allocate relfilenode and related storage objects.
---
src/backend/access/common/reloptions.c | 3 +--
src/backend/catalog/heap.c | 17 ++++++++++-------
2 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 72e12532ab..d3b847e2e5 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -967,7 +967,6 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
case RELKIND_RELATION:
case RELKIND_TOASTVALUE:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
options = heap_reloptions(classForm->relkind, datum, false);
break;
case RELKIND_VIEW:
@@ -977,6 +976,7 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
options = index_reloptions(amoptions, datum, false);
break;
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
options = NULL;
break;
default:
@@ -1418,7 +1418,6 @@ heap_reloptions(char relkind, Datum reloptions, bool validate)
return (bytea *) rdopts;
case RELKIND_RELATION:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
default:
/* other relkinds are not supported */
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 41c0056556..2f5090b183 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -291,6 +291,7 @@ heap_create(const char *relname,
case RELKIND_VIEW:
case RELKIND_COMPOSITE_TYPE:
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
create_storage = false;
/*
@@ -1345,14 +1346,13 @@ heap_create_with_catalog(const char *relname,
if (oncommit != ONCOMMIT_NOOP)
register_on_commit_action(relid, oncommit);
- if (relpersistence == RELPERSISTENCE_UNLOGGED)
- {
- Assert(relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW ||
- relkind == RELKIND_TOASTVALUE ||
- relkind == RELKIND_PARTITIONED_TABLE);
-
+ /*
+ * We do not want to create any storage objects for a partitioned
+ * table, including the init fork.
+ */
+ if (relpersistence == RELPERSISTENCE_UNLOGGED &&
+ relkind != RELKIND_PARTITIONED_TABLE)
heap_create_init_fork(new_rel_desc);
- }
/*
* ok, the relation has been cataloged, so close our relations and return
@@ -1376,6 +1376,9 @@ heap_create_with_catalog(const char *relname,
void
heap_create_init_fork(Relation rel)
{
+ Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
+ rel->rd_rel->relkind == RELKIND_MATVIEW ||
+ rel->rd_rel->relkind == RELKIND_TOASTVALUE);
RelationOpenSmgr(rel);
smgrcreate(rel->rd_smgr, INIT_FORKNUM, false);
log_smgrcreate(&rel->rd_smgr->smgr_rnode.node, INIT_FORKNUM);
--
2.11.0
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-03-14 08:18 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
0 siblings, 0 replies; 96+ messages in thread
From: Amit Langote @ 2017-03-14 08:18 UTC (permalink / raw)
To: Robert Haas <robertmhaas@gmail.com>; +Cc: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; Michael Paquier <michael.paquier@gmail.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On 2017/03/13 19:30, Amit Langote wrote:
>> Here is the updated patch.
>>
>> Since this patch proposes to avoid creating scan nodes for non-leaf tables
>> in a partition tree, they won't be referenced anywhere in the resulting
>> plan tree. So the executor will not lock those tables in the
>> select/update/delete cases. Insert is different since we lock all tables
>> in the partition tree when setting up tuple-routing in
>> ExecInitModifyTable. Not taking executor locks on the tables means that
>> the cached plans that should be invalidated upon adding/removing a
>> partition somewhere in the partition tree won't be.
>>
>> First I thought that we could remember just the root table RT index using
>> a new Index field partitionRoot in Append, MergeAppend, and ModifyTable
>> nodes and use it to locate and lock the root table during executor node
>> initialization. But soon realized that that's not enough, because it
>> ignores the fact that adding/removing partitions at lower levels does not
>> require taking a lock on the root table; only the immediate parent. So
>> any cached select/update/delete plans won't be invalidated when a new
>> lower-level partition is added/removed, because the immediate parent would
>> not have been added to the query's range table and hence the
>> PlannedStmt.relationOids list. Remember that the latter is used by
>> plancache.c to remember the relations that a given cached plan depends on
>> remaining unchanged. So the patch now adds a list member called
>> partitioned_rels to Append, MergeAppend, and ModifyTable nodes and stores
>> the RT indexes of all the non-leaf tables in a partition tree with root
>> table RT index at the head (note that these RT indexes are of the RTEs
>> added by expand_inherited_rtenrty; also see below). Since the
>> partitioned_rels list is constructed when building paths and must be
>> propagated to the plan nodes, the same field is also present in the
>> corresponding Path nodes. ExecInit* routines for the aforementioned nodes
>> now locate and lock the non-leaf tables using the RT indexes in
>> partitioned_rels. Leaf tables are locked, as before, either by InitPlan
>> (update/delete result relations case) or by ExecInitAppend or
>> ExecInitMergeAppend when initializing the appendplans/mergeplans (select
>> case).
>>
>> The previous proposal was for expand_inherited_rtentry to not create RT
>> entries and AppendRelInfo's for the non-leaf tables, but I think that
>> doesn't work, as I tried to explain above. We need RTEs because that
>> seems to be the only way currently for informing the executor of the
>> non-leaf tables. We need AppendRelInfo's to store the RT indexes of those
>> RTEs for the latter planning steps to collect them in partitioned_rels
>> mentioned above. So with the latest patch, we do create the RT entry and
>> AppendRelInfo for non-leaf tables. AppendRelInfo created in this case is
>> a minimal one; only parent_relid and child_relid are valid. To make the
>> latter planning steps ignore these minimal AppendRelInfo's, every
>> AppendRelInfo is now marked with child_relkind. Only
>> set_append_rel_pathlist() and inheritance_planner() process them to
>> collect the child_relid into the partitioned_rels list to be stored in
>> AppendPath/MergeAppendPath and ModifyTablePath, respectively.
>
> Sorry, forgot to attach the patches themselves. Attached this time.
I made some changes to 0001:
* No need to create RelOptInfo's for partitioned RTEs added by
expand_inherited_rtentry
* Instead of storing relkind of child tables in AppendRelInfo's, simply
store if they are partitioned; IOW, change child_relkind to
child_is_partitioned
Thanks,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Attachments:
[text/x-diff] 0001-Avoid-creating-scan-nodes-for-partitioned-tables.patch (54.2K, ../../975b7629-ff74-74df-a355-23c2e5f193a4@lab.ntt.co.jp/2-0001-Avoid-creating-scan-nodes-for-partitioned-tables.patch)
download | inline diff:
From 08a6348fe88e2254b24f8e5e7f05c27b24b1d109 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Fri, 10 Mar 2017 13:48:31 +0900
Subject: [PATCH 1/2] Avoid creating scan nodes for partitioned tables
* Currently, we create scan nodes for inheritance parents in their role
as an inheritance set member. Partitioned tables do not contain any
data, so it's useless to create scan nodes for them. So we generate
only a minimal AppendRelInfo for partitioned child tables. No need
to generate translated_vars, for example. We need to hold on to
the child_relid's, because we want to save it into the Append/
MergeAppend/ModifyTable node we will generate for the inheritance
tree. Also mark such appinfos as with child_is_partitioned = true
so that later steps know to process them appropriately.
* The planner prep phase turns off inheritance on the parent RTE if
there isn't at least one child member other than the parent itself
which is also a child member. That means set_rel_size/pathlist will
not create an Append node but a scan node for the parent RTE. We want
to avoid that if the parent is a partitioned table, by noticing that
in set_rel_size(). Per suggestion from Ashutosh Bapat.
* Add a new partitioned_rels field to ModifyTable, Append, and MergeAppend
nodes, which holds the RT indexes of all the non-leaf tables in a
partition tree. Use the same to lock those tables during execution.
The usual method employed by InitPlan to lock the tables does not work
for partitioned tables, because they do not appear in the subplans list
of either of those nodes.
* In inheritance_planner, set ModifyTable.nominalRelation to parent RT
index in the partitioned inheritance parent case, so that EXPLAIN uses
the root tables's original RT index to label a given ModifyTable node.
Regression test outputs are adjusted to match the new plan shape.
---
src/backend/executor/nodeAppend.c | 39 ++++++++
src/backend/executor/nodeMergeAppend.c | 39 ++++++++
src/backend/executor/nodeModifyTable.c | 36 +++++++-
src/backend/nodes/copyfuncs.c | 4 +
src/backend/nodes/equalfuncs.c | 1 +
src/backend/nodes/outfuncs.c | 7 ++
src/backend/nodes/readfuncs.c | 3 +
src/backend/optimizer/path/allpaths.c | 49 ++++++++--
src/backend/optimizer/path/joinrels.c | 2 +-
src/backend/optimizer/plan/createplan.c | 14 ++-
src/backend/optimizer/plan/initsplan.c | 5 +
src/backend/optimizer/plan/planner.c | 63 ++++++++++---
src/backend/optimizer/plan/setrefs.c | 12 +++
src/backend/optimizer/prep/prepjointree.c | 13 ++-
src/backend/optimizer/prep/prepunion.c | 54 +++++++----
src/backend/optimizer/util/pathnode.c | 10 +-
src/backend/optimizer/util/relnode.c | 7 ++
src/backend/utils/cache/plancache.c | 7 ++
src/include/nodes/plannodes.h | 6 ++
src/include/nodes/relation.h | 4 +
src/include/optimizer/pathnode.h | 8 +-
src/test/regress/expected/inherit.out | 147 +++++++++++++-----------------
src/test/regress/expected/tablesample.out | 4 +-
src/test/regress/sql/inherit.sql | 28 ++++++
24 files changed, 420 insertions(+), 142 deletions(-)
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index 6986caee6b..26be346199 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -59,6 +59,8 @@
#include "executor/execdebug.h"
#include "executor/nodeAppend.h"
+#include "parser/parsetree.h"
+#include "storage/lmgr.h"
static bool exec_append_initialize_next(AppendState *appendstate);
@@ -129,6 +131,43 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
Assert(!(eflags & EXEC_FLAG_MARK));
/*
+ * Lock the non-leaf tables in the partition tree controlled by this
+ * node; leaf tables will be locked below when initializing the node's
+ * subplans. Note that this occurs only if the root inheritance parent
+ * is a partitioned table.
+ */
+ if (node->partitioned_rels)
+ {
+ foreach(lc, node->partitioned_rels)
+ {
+ Index rti = lfirst_int(lc);
+ PlanRowMark *rc = NULL;
+ ListCell *l;
+ Oid relid;
+ LOCKMODE lockmode;
+
+ relid = getrelid(rti, estate->es_range_table);
+
+ /* If there is a RowMark, we better adjust the lockmode */
+ foreach(l, estate->es_plannedstmt->rowMarks)
+ {
+ rc = (PlanRowMark *) lfirst(l);
+
+ if (rc->rti == rti)
+ break;
+ }
+
+ Assert(rc == NULL || rc->isParent);
+ if (rc != NULL && RowMarkRequiresRowShareLock(rc->markType))
+ lockmode = RowShareLock;
+ else
+ lockmode = AccessShareLock;
+
+ LockRelationOid(relid, lockmode);
+ }
+ }
+
+ /*
* Set up empty vector of subplan states
*/
nplans = list_length(node->appendplans);
diff --git a/src/backend/executor/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c
index 7a20bf07a4..0b5f82cf20 100644
--- a/src/backend/executor/nodeMergeAppend.c
+++ b/src/backend/executor/nodeMergeAppend.c
@@ -42,6 +42,8 @@
#include "executor/nodeMergeAppend.h"
#include "lib/binaryheap.h"
+#include "parser/parsetree.h"
+#include "storage/lmgr.h"
/*
* We have one slot for each item in the heap array. We use SlotNumber
@@ -72,6 +74,43 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
/*
+ * Lock the non-leaf tables in the partition tree controlled by this
+ * node; leaf tables will be locked below when initializing the node's
+ * subplans. Note that this occurs only if the root inheritance parent
+ * is a partitioned table.
+ */
+ if (node->partitioned_rels)
+ {
+ foreach(lc, node->partitioned_rels)
+ {
+ Index rti = lfirst_int(lc);
+ PlanRowMark *rc = NULL;
+ ListCell *l;
+ Oid relid;
+ LOCKMODE lockmode;
+
+ relid = getrelid(rti, estate->es_range_table);
+
+ /* If there is a RowMark, we better adjust the lockmode */
+ foreach(l, estate->es_plannedstmt->rowMarks)
+ {
+ rc = (PlanRowMark *) lfirst(l);
+
+ if (rc->rti == rti)
+ break;
+ }
+
+ Assert(rc == NULL || rc->isParent);
+ if (rc != NULL && RowMarkRequiresRowShareLock(rc->markType))
+ lockmode = RowShareLock;
+ else
+ lockmode = AccessShareLock;
+
+ LockRelationOid(relid, lockmode);
+ }
+ }
+
+ /*
* Set up empty vector of subplan states
*/
nplans = list_length(node->mergeplans);
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 95e158970c..9f548bdfac 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -45,6 +45,7 @@
#include "foreign/fdwapi.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
+#include "parser/parsetree.h"
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
#include "utils/builtins.h"
@@ -1725,8 +1726,34 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
estate->es_result_relation_info = saved_resultRelInfo;
+ /*
+ * During UPDATE/DELETE of a partitioned table, node->partitioned_rels
+ * contains the RT indexes of non-leaf tables of the partition tree.
+ * Leaf tables have already been locked by InitPlan when setting up the
+ * ResultRelInfo's.
+ */
+ if (node->partitioned_rels)
+ {
+ Index root_table_rti;
+ Oid root_table_oid;
+
+ foreach(l, node->partitioned_rels)
+ {
+ Oid relid;
+
+ relid = getrelid(lfirst_int(l), estate->es_range_table);
+ LockRelationOid(relid, RowExclusiveLock);
+ }
+
+ /* We have the root table RT index at the head of the list */
+ root_table_rti = linitial_int(node->partitioned_rels);
+ root_table_oid = getrelid(root_table_rti, estate->es_range_table);
+ rel = heap_open(root_table_oid, NoLock); /* locked just above */
+ }
+ else
+ rel = mtstate->resultRelInfo->ri_RelationDesc;
+
/* Build state for INSERT tuple routing */
- rel = mtstate->resultRelInfo->ri_RelationDesc;
if (operation == CMD_INSERT &&
rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
{
@@ -1898,6 +1925,13 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
}
/*
+ * Close the root partitioned rel if we opened it above, but keep the
+ * lock.
+ */
+ if (rel != mtstate->resultRelInfo->ri_RelationDesc)
+ heap_close(rel, NoLock);
+
+ /*
* If needed, Initialize target list, projection and qual for ON CONFLICT
* DO UPDATE.
*/
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index bfc2ac1716..59ced968b0 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -200,6 +200,7 @@ _copyModifyTable(const ModifyTable *from)
COPY_SCALAR_FIELD(operation);
COPY_SCALAR_FIELD(canSetTag);
COPY_SCALAR_FIELD(nominalRelation);
+ COPY_NODE_FIELD(partitioned_rels);
COPY_NODE_FIELD(resultRelations);
COPY_SCALAR_FIELD(resultRelIndex);
COPY_NODE_FIELD(plans);
@@ -235,6 +236,7 @@ _copyAppend(const Append *from)
/*
* copy remainder of node
*/
+ COPY_NODE_FIELD(partitioned_rels);
COPY_NODE_FIELD(appendplans);
return newnode;
@@ -256,6 +258,7 @@ _copyMergeAppend(const MergeAppend *from)
/*
* copy remainder of node
*/
+ COPY_NODE_FIELD(partitioned_rels);
COPY_NODE_FIELD(mergeplans);
COPY_SCALAR_FIELD(numCols);
COPY_POINTER_FIELD(sortColIdx, from->numCols * sizeof(AttrNumber));
@@ -2198,6 +2201,7 @@ _copyAppendRelInfo(const AppendRelInfo *from)
COPY_SCALAR_FIELD(child_relid);
COPY_SCALAR_FIELD(parent_reltype);
COPY_SCALAR_FIELD(child_reltype);
+ COPY_SCALAR_FIELD(child_is_partitioned);
COPY_NODE_FIELD(translated_vars);
COPY_SCALAR_FIELD(parent_reloid);
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 54e9c983a0..c2c3644d22 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -889,6 +889,7 @@ _equalAppendRelInfo(const AppendRelInfo *a, const AppendRelInfo *b)
COMPARE_SCALAR_FIELD(child_relid);
COMPARE_SCALAR_FIELD(parent_reltype);
COMPARE_SCALAR_FIELD(child_reltype);
+ COMPARE_SCALAR_FIELD(child_is_partitioned);
COMPARE_NODE_FIELD(translated_vars);
COMPARE_SCALAR_FIELD(parent_reloid);
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 7418fbeded..3b4ae0e2df 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -344,6 +344,7 @@ _outModifyTable(StringInfo str, const ModifyTable *node)
WRITE_ENUM_FIELD(operation, CmdType);
WRITE_BOOL_FIELD(canSetTag);
WRITE_UINT_FIELD(nominalRelation);
+ WRITE_NODE_FIELD(partitioned_rels);
WRITE_NODE_FIELD(resultRelations);
WRITE_INT_FIELD(resultRelIndex);
WRITE_NODE_FIELD(plans);
@@ -368,6 +369,7 @@ _outAppend(StringInfo str, const Append *node)
_outPlanInfo(str, (const Plan *) node);
+ WRITE_NODE_FIELD(partitioned_rels);
WRITE_NODE_FIELD(appendplans);
}
@@ -380,6 +382,7 @@ _outMergeAppend(StringInfo str, const MergeAppend *node)
_outPlanInfo(str, (const Plan *) node);
+ WRITE_NODE_FIELD(partitioned_rels);
WRITE_NODE_FIELD(mergeplans);
WRITE_INT_FIELD(numCols);
@@ -1808,6 +1811,7 @@ _outAppendPath(StringInfo str, const AppendPath *node)
_outPathInfo(str, (const Path *) node);
+ WRITE_NODE_FIELD(partitioned_rels);
WRITE_NODE_FIELD(subpaths);
}
@@ -1818,6 +1822,7 @@ _outMergeAppendPath(StringInfo str, const MergeAppendPath *node)
_outPathInfo(str, (const Path *) node);
+ WRITE_NODE_FIELD(partitioned_rels);
WRITE_NODE_FIELD(subpaths);
WRITE_FLOAT_FIELD(limit_tuples, "%.0f");
}
@@ -2023,6 +2028,7 @@ _outModifyTablePath(StringInfo str, const ModifyTablePath *node)
WRITE_ENUM_FIELD(operation, CmdType);
WRITE_BOOL_FIELD(canSetTag);
WRITE_UINT_FIELD(nominalRelation);
+ WRITE_NODE_FIELD(partitioned_rels);
WRITE_NODE_FIELD(resultRelations);
WRITE_NODE_FIELD(subpaths);
WRITE_NODE_FIELD(subroots);
@@ -2415,6 +2421,7 @@ _outAppendRelInfo(StringInfo str, const AppendRelInfo *node)
WRITE_UINT_FIELD(child_relid);
WRITE_OID_FIELD(parent_reltype);
WRITE_OID_FIELD(child_reltype);
+ WRITE_BOOL_FIELD(child_is_partitioned);
WRITE_NODE_FIELD(translated_vars);
WRITE_OID_FIELD(parent_reloid);
}
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index d3bbc02f24..f2ec174216 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1535,6 +1535,7 @@ _readModifyTable(void)
READ_ENUM_FIELD(operation, CmdType);
READ_BOOL_FIELD(canSetTag);
READ_UINT_FIELD(nominalRelation);
+ READ_NODE_FIELD(partitioned_rels);
READ_NODE_FIELD(resultRelations);
READ_INT_FIELD(resultRelIndex);
READ_NODE_FIELD(plans);
@@ -1564,6 +1565,7 @@ _readAppend(void)
ReadCommonPlan(&local_node->plan);
+ READ_NODE_FIELD(partitioned_rels);
READ_NODE_FIELD(appendplans);
READ_DONE();
@@ -1579,6 +1581,7 @@ _readMergeAppend(void)
ReadCommonPlan(&local_node->plan);
+ READ_NODE_FIELD(partitioned_rels);
READ_NODE_FIELD(mergeplans);
READ_INT_FIELD(numCols);
READ_ATTRNUMBER_ARRAY(sortColIdx, local_node->numCols);
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index b263359fde..dcae3c8531 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -95,7 +95,8 @@ static void set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
Index rti, RangeTblEntry *rte);
static void generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
List *live_childrels,
- List *all_child_pathkeys);
+ List *all_child_pathkeys,
+ List *partitioned_rels);
static Path *get_cheapest_parameterized_child_path(PlannerInfo *root,
RelOptInfo *rel,
Relids required_outer);
@@ -344,6 +345,14 @@ set_rel_size(PlannerInfo *root, RelOptInfo *rel,
/* Foreign table */
set_foreign_size(root, rel, rte);
}
+ else if (rte->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ /*
+ * A partitioned table without leaf partitions is marked
+ * as a dummy rel.
+ */
+ set_dummy_rel_pathlist(rel);
+ }
else if (rte->tablesample != NULL)
{
/* Sampled relation */
@@ -878,6 +887,10 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
if (appinfo->parent_relid != parentRTindex)
continue;
+ /* Nothing to see here. */
+ if (appinfo->child_is_partitioned)
+ continue;
+
childRTindex = appinfo->child_relid;
childRTE = root->simple_rte_array[childRTindex];
@@ -1189,6 +1202,7 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
List *all_child_pathkeys = NIL;
List *all_child_outers = NIL;
ListCell *l;
+ List *partitioned_rels = NIL;
/*
* Generate access paths for each member relation, and remember the
@@ -1208,6 +1222,17 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
if (appinfo->parent_relid != parentRTindex)
continue;
+ /*
+ * Nothing to do here for partitioned child tables; just remember
+ * the RT index to put into the AppendPath.
+ */
+ if (appinfo->child_is_partitioned)
+ {
+ partitioned_rels = lappend_int(partitioned_rels,
+ appinfo->child_relid);
+ continue;
+ }
+
/* Re-locate the child RTE and RelOptInfo */
childRTindex = appinfo->child_relid;
childRTE = root->simple_rte_array[childRTindex];
@@ -1327,7 +1352,8 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
* if we have zero or one live subpath due to constraint exclusion.)
*/
if (subpaths_valid)
- add_path(rel, (Path *) create_append_path(rel, subpaths, NULL, 0));
+ add_path(rel, (Path *) create_append_path(rel, subpaths, NULL, 0,
+ partitioned_rels));
/*
* Consider an append of partial unordered, unparameterized partial paths.
@@ -1354,7 +1380,7 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
/* Generate a partial append path. */
appendpath = create_append_path(rel, partial_subpaths, NULL,
- parallel_workers);
+ parallel_workers, partitioned_rels);
add_partial_path(rel, (Path *) appendpath);
}
@@ -1364,7 +1390,8 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
*/
if (subpaths_valid)
generate_mergeappend_paths(root, rel, live_childrels,
- all_child_pathkeys);
+ all_child_pathkeys,
+ partitioned_rels);
/*
* Build Append paths for each parameterization seen among the child rels.
@@ -1406,7 +1433,8 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
if (subpaths_valid)
add_path(rel, (Path *)
- create_append_path(rel, subpaths, required_outer, 0));
+ create_append_path(rel, subpaths, required_outer, 0,
+ partitioned_rels));
}
}
@@ -1436,7 +1464,8 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
static void
generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
List *live_childrels,
- List *all_child_pathkeys)
+ List *all_child_pathkeys,
+ List *partitioned_rels)
{
ListCell *lcp;
@@ -1500,13 +1529,15 @@ generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
rel,
startup_subpaths,
pathkeys,
- NULL));
+ NULL,
+ partitioned_rels));
if (startup_neq_total)
add_path(rel, (Path *) create_merge_append_path(root,
rel,
total_subpaths,
pathkeys,
- NULL));
+ NULL,
+ partitioned_rels));
}
}
@@ -1639,7 +1670,7 @@ set_dummy_rel_pathlist(RelOptInfo *rel)
rel->pathlist = NIL;
rel->partial_pathlist = NIL;
- add_path(rel, (Path *) create_append_path(rel, NIL, NULL, 0));
+ add_path(rel, (Path *) create_append_path(rel, NIL, NULL, 0, NIL));
/*
* We set the cheapest path immediately, to ensure that IS_DUMMY_REL()
diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c
index 0d0068360c..7dfbb7a970 100644
--- a/src/backend/optimizer/path/joinrels.c
+++ b/src/backend/optimizer/path/joinrels.c
@@ -1197,7 +1197,7 @@ mark_dummy_rel(RelOptInfo *rel)
rel->partial_pathlist = NIL;
/* Set up the dummy path */
- add_path(rel, (Path *) create_append_path(rel, NIL, NULL, 0));
+ add_path(rel, (Path *) create_append_path(rel, NIL, NULL, 0, NIL));
/* Set or update cheapest_total_path and related fields */
set_cheapest(rel);
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index d002e6d567..6b29ccc0c4 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -199,7 +199,7 @@ static CteScan *make_ctescan(List *qptlist, List *qpqual,
Index scanrelid, int ctePlanId, int cteParam);
static WorkTableScan *make_worktablescan(List *qptlist, List *qpqual,
Index scanrelid, int wtParam);
-static Append *make_append(List *appendplans, List *tlist);
+static Append *make_append(List *appendplans, List *tlist, List *partitioned_rels);
static RecursiveUnion *make_recursive_union(List *tlist,
Plan *lefttree,
Plan *righttree,
@@ -273,7 +273,7 @@ static Result *make_result(List *tlist, Node *resconstantqual, Plan *subplan);
static ProjectSet *make_project_set(List *tlist, Plan *subplan);
static ModifyTable *make_modifytable(PlannerInfo *root,
CmdType operation, bool canSetTag,
- Index nominalRelation,
+ Index nominalRelation, List *partitioned_rels,
List *resultRelations, List *subplans,
List *withCheckOptionLists, List *returningLists,
List *rowMarks, OnConflictExpr *onconflict, int epqParam);
@@ -1026,7 +1026,7 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path)
* parent-rel Vars it'll be asked to emit.
*/
- plan = make_append(subplans, tlist);
+ plan = make_append(subplans, tlist, best_path->partitioned_rels);
copy_generic_path_info(&plan->plan, (Path *) best_path);
@@ -1134,6 +1134,7 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path)
subplans = lappend(subplans, subplan);
}
+ node->partitioned_rels = best_path->partitioned_rels;
node->mergeplans = subplans;
return (Plan *) node;
@@ -2340,6 +2341,7 @@ create_modifytable_plan(PlannerInfo *root, ModifyTablePath *best_path)
best_path->operation,
best_path->canSetTag,
best_path->nominalRelation,
+ best_path->partitioned_rels,
best_path->resultRelations,
subplans,
best_path->withCheckOptionLists,
@@ -5187,7 +5189,7 @@ make_foreignscan(List *qptlist,
}
static Append *
-make_append(List *appendplans, List *tlist)
+make_append(List *appendplans, List *tlist, List *partitioned_rels)
{
Append *node = makeNode(Append);
Plan *plan = &node->plan;
@@ -5196,6 +5198,7 @@ make_append(List *appendplans, List *tlist)
plan->qual = NIL;
plan->lefttree = NULL;
plan->righttree = NULL;
+ node->partitioned_rels = partitioned_rels;
node->appendplans = appendplans;
return node;
@@ -6308,7 +6311,7 @@ make_project_set(List *tlist,
static ModifyTable *
make_modifytable(PlannerInfo *root,
CmdType operation, bool canSetTag,
- Index nominalRelation,
+ Index nominalRelation, List *partitioned_rels,
List *resultRelations, List *subplans,
List *withCheckOptionLists, List *returningLists,
List *rowMarks, OnConflictExpr *onconflict, int epqParam)
@@ -6334,6 +6337,7 @@ make_modifytable(PlannerInfo *root,
node->operation = operation;
node->canSetTag = canSetTag;
node->nominalRelation = nominalRelation;
+ node->partitioned_rels = partitioned_rels;
node->resultRelations = resultRelations;
node->resultRelIndex = -1; /* will be set correctly in setrefs.c */
node->plans = subplans;
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index b4ac224a7a..d55730fdce 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -642,6 +642,11 @@ create_lateral_join_info(PlannerInfo *root)
if (appinfo->parent_relid != rti)
continue;
+
+ /* Nothing to do here for these. */
+ if (appinfo->child_is_partitioned)
+ continue;
+
childrel = root->simple_rel_array[appinfo->child_relid];
Assert(childrel->reloptkind == RELOPT_OTHER_MEMBER_REL);
Assert(childrel->direct_lateral_relids == NULL);
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 02286d9c52..7a104fb78d 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -1007,6 +1007,8 @@ inheritance_planner(PlannerInfo *root)
RelOptInfo *final_rel;
ListCell *lc;
Index rti;
+ RangeTblEntry *parent_rte;
+ List *partitioned_rels = NIL;
Assert(parse->commandType != CMD_INSERT);
@@ -1055,6 +1057,13 @@ inheritance_planner(PlannerInfo *root)
{
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
+ /*
+ * Need not consider these, because we don't generate a plan
+ * for them below.
+ */
+ if (appinfo->child_is_partitioned)
+ continue;
+
if (bms_is_member(appinfo->parent_relid, subqueryRTindexes) ||
bms_is_member(appinfo->child_relid, subqueryRTindexes) ||
bms_overlap(pull_varnos((Node *) appinfo->translated_vars),
@@ -1065,13 +1074,21 @@ inheritance_planner(PlannerInfo *root)
}
/*
+ * If the parent RTE is a partitioned table, we should use that as the
+ * nominal relation, because we do not have the duplicate parent RTE,
+ * unlike in the case of a non-partitioned inheritance parent.
+ */
+ parent_rte = rt_fetch(parentRTindex, root->parse->rtable);
+ if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
+ nominalRelation = parentRTindex;
+
+ /*
* And now we can get on with generating a plan for each child table.
*/
foreach(lc, root->append_rel_list)
{
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
PlannerInfo *subroot;
- RangeTblEntry *parent_rte;
RangeTblEntry *child_rte;
RelOptInfo *sub_final_rel;
Path *subpath;
@@ -1081,6 +1098,17 @@ inheritance_planner(PlannerInfo *root)
continue;
/*
+ * Nothing to do here for partitioned child tables; just remember
+ * the RT index to put into the ModifyTablePath.
+ */
+ if (appinfo->child_is_partitioned)
+ {
+ partitioned_rels = lappend_int(partitioned_rels,
+ appinfo->child_relid);
+ continue;
+ }
+
+ /*
* We need a working copy of the PlannerInfo so that we can control
* propagation of information back to the main copy.
*/
@@ -1216,15 +1244,25 @@ inheritance_planner(PlannerInfo *root)
grouping_planner(subroot, true, 0.0 /* retrieve all tuples */ );
/*
- * We'll use the first child relation (even if it's excluded) as the
- * nominal target relation of the ModifyTable node. Because of the
- * way expand_inherited_rtentry works, this should always be the RTE
- * representing the parent table in its role as a simple member of the
- * inheritance set. (It would be logically cleaner to use the
- * inheritance parent RTE as the nominal target; but since that RTE
- * will not be otherwise referenced in the plan, doing so would give
- * rise to confusing use of multiple aliases in EXPLAIN output for
- * what the user will think is the "same" table.)
+ * Set the nomimal target relation of the ModifyTable node if not
+ * already done. We use the inheritance parent RTE as the nominal
+ * target relation if it's a partitioned table (see just above this
+ * loop). In the non-partitioned parent case, we'll use the first
+ * child relation (even if it's excluded) as the nominal target
+ * relation. Because of the way expand_inherited_rtentry works, the
+ * latter should be the RTE representing the parent table in its role
+ * as a simple member of the inheritance set.
+ *
+ * It would be logically cleaner to *always* use the inheritance
+ * parent RTE as the nominal relation; but that RTE is not otherwise
+ * referenced in the plan in the non-partitioned inheritance case.
+ * Instead the duplicate child RTE created by expand_inherited_rtentry
+ * is used elsewhere in the plan, so using the original parent RTE
+ * would give rise to confusing use of multiple aliases in EXPLAIN
+ * output for what the user will think is the "same" table. OTOH,
+ * it's not a problem in the partitioned inheritance case, because
+ * the duplicate child RTE added for the parent does not appear
+ * anywhere else in the plan tree.
*/
if (nominalRelation < 0)
nominalRelation = appinfo->child_relid;
@@ -1351,6 +1389,7 @@ inheritance_planner(PlannerInfo *root)
parse->commandType,
parse->canSetTag,
nominalRelation,
+ partitioned_rels,
resultRelations,
subpaths,
subroots,
@@ -2046,6 +2085,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
parse->commandType,
parse->canSetTag,
parse->resultRelation,
+ NIL,
list_make1_int(parse->resultRelation),
list_make1(path),
list_make1(root),
@@ -3348,7 +3388,8 @@ create_grouping_paths(PlannerInfo *root,
create_append_path(grouped_rel,
paths,
NULL,
- 0);
+ 0,
+ NIL);
path->pathtarget = target;
}
else
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 5f3027e96f..d148c2d37d 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -835,6 +835,10 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
splan->nominalRelation += rtoffset;
splan->exclRelRTI += rtoffset;
+ foreach(l, splan->partitioned_rels)
+ {
+ lfirst_int(l) += rtoffset;
+ }
foreach(l, splan->resultRelations)
{
lfirst_int(l) += rtoffset;
@@ -875,6 +879,10 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
*/
set_dummy_tlist_references(plan, rtoffset);
Assert(splan->plan.qual == NIL);
+ foreach(l, splan->partitioned_rels)
+ {
+ lfirst_int(l) += rtoffset;
+ }
foreach(l, splan->appendplans)
{
lfirst(l) = set_plan_refs(root,
@@ -893,6 +901,10 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
*/
set_dummy_tlist_references(plan, rtoffset);
Assert(splan->plan.qual == NIL);
+ foreach(l, splan->partitioned_rels)
+ {
+ lfirst_int(l) += rtoffset;
+ }
foreach(l, splan->mergeplans)
{
lfirst(l) = set_plan_refs(root,
diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c
index 048815d7b0..b89e340ef2 100644
--- a/src/backend/optimizer/prep/prepjointree.c
+++ b/src/backend/optimizer/prep/prepjointree.c
@@ -1072,8 +1072,11 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
if (appinfo == containing_appendrel)
rvcontext.need_phvs = false;
- appinfo->translated_vars = (List *)
- pullup_replace_vars((Node *) appinfo->translated_vars, &rvcontext);
+
+ if (!appinfo->child_is_partitioned)
+ appinfo->translated_vars = (List *)
+ pullup_replace_vars((Node *) appinfo->translated_vars,
+ &rvcontext);
rvcontext.need_phvs = save_need_phvs;
}
@@ -1327,6 +1330,7 @@ pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root, int parentRTindex,
appinfo->child_relid = childRTindex;
appinfo->parent_reltype = InvalidOid;
appinfo->child_reltype = InvalidOid;
+ appinfo->child_is_partitioned = false;
make_setop_translation_list(setOpQuery, childRTindex,
&appinfo->translated_vars);
appinfo->parent_reloid = InvalidOid;
@@ -2926,8 +2930,9 @@ fix_append_rel_relids(List *append_rel_list, int varno, Relids subrelids)
}
/* Also finish fixups for its translated vars */
- substitute_multiple_relids((Node *) appinfo->translated_vars,
- varno, subrelids);
+ if (!appinfo->child_is_partitioned)
+ substitute_multiple_relids((Node *) appinfo->translated_vars,
+ varno, subrelids);
}
}
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 1389db18ba..8a4089bf97 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -566,7 +566,7 @@ generate_union_path(SetOperationStmt *op, PlannerInfo *root,
/*
* Append the child results together.
*/
- path = (Path *) create_append_path(result_rel, pathlist, NULL, 0);
+ path = (Path *) create_append_path(result_rel, pathlist, NULL, 0, NIL);
/* We have to manually jam the right tlist into the path; ick */
path->pathtarget = create_pathtarget(root, tlist);
@@ -678,7 +678,7 @@ generate_nonunion_path(SetOperationStmt *op, PlannerInfo *root,
/*
* Append the child results together.
*/
- path = (Path *) create_append_path(result_rel, pathlist, NULL, 0);
+ path = (Path *) create_append_path(result_rel, pathlist, NULL, 0, NIL);
/* We have to manually jam the right tlist into the path; ick */
path->pathtarget = create_pathtarget(root, tlist);
@@ -1352,6 +1352,12 @@ expand_inherited_tables(PlannerInfo *root)
*
* A childless table is never considered to be an inheritance set; therefore
* a parent RTE must always have at least two associated AppendRelInfos.
+ *
+ * AppendRelInfo's created for each child table normally contains information
+ * necessary to create a scan plan for the table. However, for child tables
+ * that are partitioned (which contains no data), we need not create scan
+ * plans; so create a minimal AppendRelInfo in that case containing only the
+ * parent-child RT index pair.
*/
static void
expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
@@ -1490,30 +1496,41 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
appinfo->child_relid = childRTindex;
appinfo->parent_reltype = oldrelation->rd_rel->reltype;
appinfo->child_reltype = newrelation->rd_rel->reltype;
- make_inh_translation_list(oldrelation, newrelation, childRTindex,
- &appinfo->translated_vars);
+ appinfo->child_is_partitioned =
+ (childrte->relkind == RELKIND_PARTITIONED_TABLE);
appinfo->parent_reloid = parentOID;
- appinfos = lappend(appinfos, appinfo);
/*
- * Translate the column permissions bitmaps to the child's attnums (we
- * have to build the translated_vars list before we can do this). But
- * if this is the parent table, leave copyObject's result alone.
- *
- * Note: we need to do this even though the executor won't run any
- * permissions checks on the child RTE. The insertedCols/updatedCols
- * bitmaps may be examined for trigger-firing purposes.
+ * No need to fill the following information for partitioned table
+ * appinfos, because we won't be needing it later.
*/
- if (childOID != parentOID)
+ if (!appinfo->child_is_partitioned)
{
- childrte->selectedCols = translate_col_privs(rte->selectedCols,
+ make_inh_translation_list(oldrelation, newrelation, childRTindex,
+ &appinfo->translated_vars);
+
+ /*
+ * Translate the column permissions bitmaps to the child's attnums
+ * (we have to build the translated_vars list before we can do
+ * this). But if this is the parent table, leave copyObject's
+ * result alone. Note: we need to do this even though the executor
+ * won't run any permissions checks on the child RTE. The
+ * insertedCols/updatedCols bitmaps may be examined for
+ * trigger-firing purposes.
+ */
+ if (childOID != parentOID)
+ {
+ childrte->selectedCols = translate_col_privs(rte->selectedCols,
appinfo->translated_vars);
- childrte->insertedCols = translate_col_privs(rte->insertedCols,
+ childrte->insertedCols = translate_col_privs(rte->insertedCols,
appinfo->translated_vars);
- childrte->updatedCols = translate_col_privs(rte->updatedCols,
+ childrte->updatedCols = translate_col_privs(rte->updatedCols,
appinfo->translated_vars);
+ }
}
+ appinfos = lappend(appinfos, appinfo);
+
/*
* Build a PlanRowMark if parent is marked FOR UPDATE/SHARE.
*/
@@ -1529,7 +1546,10 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
newrc->allMarkTypes = (1 << newrc->markType);
newrc->strength = oldrc->strength;
newrc->waitPolicy = oldrc->waitPolicy;
- newrc->isParent = false;
+ /*
+ * If child is a partitioned table, this is a "dummy" parent entry
+ */
+ newrc->isParent = (rte->relkind == RELKIND_PARTITIONED_TABLE);
/* Include child's rowmark type in parent's allMarkTypes */
oldrc->allMarkTypes |= newrc->allMarkTypes;
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 8ce772d274..fca96eb001 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -1201,7 +1201,7 @@ create_tidscan_path(PlannerInfo *root, RelOptInfo *rel, List *tidquals,
*/
AppendPath *
create_append_path(RelOptInfo *rel, List *subpaths, Relids required_outer,
- int parallel_workers)
+ int parallel_workers, List *partitioned_rels)
{
AppendPath *pathnode = makeNode(AppendPath);
ListCell *l;
@@ -1216,6 +1216,7 @@ create_append_path(RelOptInfo *rel, List *subpaths, Relids required_outer,
pathnode->path.parallel_workers = parallel_workers;
pathnode->path.pathkeys = NIL; /* result is always considered
* unsorted */
+ pathnode->partitioned_rels = partitioned_rels;
pathnode->subpaths = subpaths;
/*
@@ -1258,7 +1259,8 @@ create_merge_append_path(PlannerInfo *root,
RelOptInfo *rel,
List *subpaths,
List *pathkeys,
- Relids required_outer)
+ Relids required_outer,
+ List *partitioned_rels)
{
MergeAppendPath *pathnode = makeNode(MergeAppendPath);
Cost input_startup_cost;
@@ -1274,6 +1276,7 @@ create_merge_append_path(PlannerInfo *root,
pathnode->path.parallel_safe = rel->consider_parallel;
pathnode->path.parallel_workers = 0;
pathnode->path.pathkeys = pathkeys;
+ pathnode->partitioned_rels = partitioned_rels;
pathnode->subpaths = subpaths;
/*
@@ -3105,7 +3108,7 @@ create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
ModifyTablePath *
create_modifytable_path(PlannerInfo *root, RelOptInfo *rel,
CmdType operation, bool canSetTag,
- Index nominalRelation,
+ Index nominalRelation, List *partitioned_rels,
List *resultRelations, List *subpaths,
List *subroots,
List *withCheckOptionLists, List *returningLists,
@@ -3172,6 +3175,7 @@ create_modifytable_path(PlannerInfo *root, RelOptInfo *rel,
pathnode->operation = operation;
pathnode->canSetTag = canSetTag;
pathnode->nominalRelation = nominalRelation;
+ pathnode->partitioned_rels = partitioned_rels;
pathnode->resultRelations = resultRelations;
pathnode->subpaths = subpaths;
pathnode->subroots = subroots;
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index caf8291e10..28b71b2c5d 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -204,6 +204,13 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind)
if (appinfo->parent_relid != relid)
continue;
+ /*
+ * Since we won't be creating any paths for these, don't need a
+ * RelOptInfo.
+ */
+ if (appinfo->child_is_partitioned)
+ continue;
+
(void) build_simple_rel(root, appinfo->child_relid,
RELOPT_OTHER_MEMBER_REL);
}
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index dffc92762b..1db784784f 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -1509,6 +1509,13 @@ AcquireExecutorLocks(List *stmt_list, bool acquire)
continue;
/*
+ * We lock the partitioned tables in the respective control nodes
+ * such as Append, ModifyTable, etc.
+ */
+ if (rte->relkind == RELKIND_PARTITIONED_TABLE)
+ continue;
+
+ /*
* Acquire the appropriate type of lock on each relation OID. Note
* that we don't actually try to open the rel, and hence will not
* fail if it's been dropped entirely --- we'll just transiently
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index b880dc16cf..8e8b8e5314 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -202,6 +202,8 @@ typedef struct ModifyTable
CmdType operation; /* INSERT, UPDATE, or DELETE */
bool canSetTag; /* do we set the command tag/es_processed? */
Index nominalRelation; /* Parent RT index for use of EXPLAIN */
+ /* RT indexes of non-leaf tables in a partition tree */
+ List *partitioned_rels;
List *resultRelations; /* integer list of RT indexes */
int resultRelIndex; /* index of first resultRel in plan's list */
List *plans; /* plan(s) producing source data */
@@ -227,6 +229,8 @@ typedef struct ModifyTable
typedef struct Append
{
Plan plan;
+ /* RT indexes of non-leaf tables in a partition tree */
+ List *partitioned_rels;
List *appendplans;
} Append;
@@ -238,6 +242,8 @@ typedef struct Append
typedef struct MergeAppend
{
Plan plan;
+ /* RT indexes of non-leaf tables in a partition tree */
+ List *partitioned_rels;
List *mergeplans;
/* remaining fields are just like the sort-key info in struct Sort */
int numCols; /* number of sort-key columns */
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index 05d6f07aea..9ebdfb1d1f 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -1116,6 +1116,7 @@ typedef struct CustomPath
typedef struct AppendPath
{
Path path;
+ List *partitioned_rels;
List *subpaths; /* list of component Paths */
} AppendPath;
@@ -1134,6 +1135,7 @@ typedef struct AppendPath
typedef struct MergeAppendPath
{
Path path;
+ List *partitioned_rels;
List *subpaths; /* list of component Paths */
double limit_tuples; /* hard limit on output tuples, or -1 */
} MergeAppendPath;
@@ -1482,6 +1484,7 @@ typedef struct ModifyTablePath
CmdType operation; /* INSERT, UPDATE, or DELETE */
bool canSetTag; /* do we set the command tag/es_processed? */
Index nominalRelation; /* Parent RT index for use of EXPLAIN */
+ List *partitioned_rels; /* integer list of RT indexes */
List *resultRelations; /* integer list of RT indexes */
List *subpaths; /* Path(s) producing source data */
List *subroots; /* per-target-table PlannerInfos */
@@ -1886,6 +1889,7 @@ typedef struct AppendRelInfo
*/
Oid parent_reltype; /* OID of parent's composite type */
Oid child_reltype; /* OID of child's composite type */
+ bool child_is_partitioned; /* is child a partitioned table? */
/*
* The N'th element of this list is a Var or expression representing the
diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h
index 373c7221a8..81640de7ab 100644
--- a/src/include/optimizer/pathnode.h
+++ b/src/include/optimizer/pathnode.h
@@ -64,12 +64,14 @@ extern BitmapOrPath *create_bitmap_or_path(PlannerInfo *root,
extern TidPath *create_tidscan_path(PlannerInfo *root, RelOptInfo *rel,
List *tidquals, Relids required_outer);
extern AppendPath *create_append_path(RelOptInfo *rel, List *subpaths,
- Relids required_outer, int parallel_workers);
+ Relids required_outer, int parallel_workers,
+ List *partitioned_rels);
extern MergeAppendPath *create_merge_append_path(PlannerInfo *root,
RelOptInfo *rel,
List *subpaths,
List *pathkeys,
- Relids required_outer);
+ Relids required_outer,
+ List *partitioned_rels);
extern ResultPath *create_result_path(PlannerInfo *root, RelOptInfo *rel,
PathTarget *target, List *resconstantqual);
extern MaterialPath *create_material_path(RelOptInfo *rel, Path *subpath);
@@ -232,7 +234,7 @@ extern LockRowsPath *create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
extern ModifyTablePath *create_modifytable_path(PlannerInfo *root,
RelOptInfo *rel,
CmdType operation, bool canSetTag,
- Index nominalRelation,
+ Index nominalRelation, List *partitioned_rels,
List *resultRelations, List *subpaths,
List *subroots,
List *withCheckOptionLists, List *returningLists,
diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out
index 6494b205c4..6163ed8117 100644
--- a/src/test/regress/expected/inherit.out
+++ b/src/test/regress/expected/inherit.out
@@ -588,6 +588,45 @@ select tableoid::regclass::text as relname, bar.* from bar order by 1,2;
bar2 | 4 | 104
(8 rows)
+-- Check UPDATE with *partitioned* inherited target and an appendrel subquery
+create table some_tab (a int);
+insert into some_tab values (0);
+create table some_tab_child () inherits (some_tab);
+insert into some_tab_child values (1);
+create table parted_tab (a int, b char) partition by list (a);
+create table parted_tab_part1 partition of parted_tab for values in (1);
+create table parted_tab_part2 partition of parted_tab for values in (2);
+create table parted_tab_part3 partition of parted_tab for values in (3);
+insert into parted_tab values (1, 'a'), (2, 'a'), (3, 'a');
+update parted_tab set b = 'b'
+from
+ (select a from some_tab union all select a+1 from some_tab) ss (a)
+where parted_tab.a = ss.a;
+select tableoid::regclass::text as relname, parted_tab.* from parted_tab order by 1,2;
+ relname | a | b
+------------------+---+---
+ parted_tab_part1 | 1 | b
+ parted_tab_part2 | 2 | b
+ parted_tab_part3 | 3 | a
+(3 rows)
+
+truncate parted_tab;
+insert into parted_tab values (1, 'a'), (2, 'a'), (3, 'a');
+update parted_tab set b = 'b'
+from
+ (select 0 from parted_tab union all select 1 from parted_tab) ss (a)
+where parted_tab.a = ss.a;
+select tableoid::regclass::text as relname, parted_tab.* from parted_tab order by 1,2;
+ relname | a | b
+------------------+---+---
+ parted_tab_part1 | 1 | b
+ parted_tab_part2 | 2 | a
+ parted_tab_part3 | 3 | a
+(3 rows)
+
+drop table parted_tab;
+drop table some_tab cascade;
+NOTICE: drop cascades to table some_tab_child
/* Test multiple inheritance of column defaults */
CREATE TABLE firstparent (tomorrow date default now()::date + 1);
CREATE TABLE secondparent (tomorrow date default now() :: date + 1);
@@ -1611,71 +1650,60 @@ explain (costs off) select * from list_parted;
QUERY PLAN
--------------------------------
Append
- -> Seq Scan on list_parted
-> Seq Scan on part_ab_cd
-> Seq Scan on part_ef_gh
-> Seq Scan on part_null_xy
-(5 rows)
+(4 rows)
explain (costs off) select * from list_parted where a is null;
QUERY PLAN
--------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (a IS NULL)
-> Seq Scan on part_null_xy
Filter: (a IS NULL)
-(5 rows)
+(3 rows)
explain (costs off) select * from list_parted where a is not null;
QUERY PLAN
---------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (a IS NOT NULL)
-> Seq Scan on part_ab_cd
Filter: (a IS NOT NULL)
-> Seq Scan on part_ef_gh
Filter: (a IS NOT NULL)
-> Seq Scan on part_null_xy
Filter: (a IS NOT NULL)
-(9 rows)
+(7 rows)
explain (costs off) select * from list_parted where a in ('ab', 'cd', 'ef');
QUERY PLAN
----------------------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-> Seq Scan on part_ab_cd
Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-> Seq Scan on part_ef_gh
Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-(7 rows)
+(5 rows)
explain (costs off) select * from list_parted where a = 'ab' or a in (null, 'cd');
QUERY PLAN
---------------------------------------------------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_ab_cd
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_ef_gh
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_null_xy
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-(9 rows)
+(7 rows)
explain (costs off) select * from list_parted where a = 'ab';
QUERY PLAN
------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: ((a)::text = 'ab'::text)
-> Seq Scan on part_ab_cd
Filter: ((a)::text = 'ab'::text)
-(5 rows)
+(3 rows)
create table range_list_parted (
a int,
@@ -1695,14 +1723,9 @@ create table part_40_inf_ab partition of part_40_inf for values in ('ab');
create table part_40_inf_cd partition of part_40_inf for values in ('cd');
create table part_40_inf_null partition of part_40_inf for values in (null);
explain (costs off) select * from range_list_parted;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- -> Seq Scan on part_1_10
- -> Seq Scan on part_10_20
- -> Seq Scan on part_21_30
- -> Seq Scan on part_40_inf
-> Seq Scan on part_1_10_ab
-> Seq Scan on part_1_10_cd
-> Seq Scan on part_10_20_ab
@@ -1712,36 +1735,22 @@ explain (costs off) select * from range_list_parted;
-> Seq Scan on part_40_inf_ab
-> Seq Scan on part_40_inf_cd
-> Seq Scan on part_40_inf_null
-(15 rows)
+(10 rows)
explain (costs off) select * from range_list_parted where a = 5;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+--------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (a = 5)
- -> Seq Scan on part_1_10
- Filter: (a = 5)
-> Seq Scan on part_1_10_ab
Filter: (a = 5)
-> Seq Scan on part_1_10_cd
Filter: (a = 5)
-(9 rows)
+(5 rows)
explain (costs off) select * from range_list_parted where b = 'ab';
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_1_10
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_10_20
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_21_30
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_40_inf
- Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_1_10_ab
Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_10_20_ab
@@ -1750,27 +1759,19 @@ explain (costs off) select * from range_list_parted where b = 'ab';
Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_40_inf_ab
Filter: (b = 'ab'::bpchar)
-(19 rows)
+(9 rows)
explain (costs off) select * from range_list_parted where a between 3 and 23 and b in ('ab');
QUERY PLAN
-----------------------------------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_1_10
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_10_20
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_21_30
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_1_10_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_10_20_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_21_30_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-(15 rows)
+(7 rows)
/* Should select no rows because range partition key cannot be null */
explain (costs off) select * from range_list_parted where a is null;
@@ -1782,37 +1783,17 @@ explain (costs off) select * from range_list_parted where a is null;
/* Should only select rows from the null-accepting partition */
explain (costs off) select * from range_list_parted where b is null;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (b IS NULL)
- -> Seq Scan on part_1_10
- Filter: (b IS NULL)
- -> Seq Scan on part_10_20
- Filter: (b IS NULL)
- -> Seq Scan on part_21_30
- Filter: (b IS NULL)
- -> Seq Scan on part_40_inf
- Filter: (b IS NULL)
-> Seq Scan on part_40_inf_null
Filter: (b IS NULL)
-(13 rows)
+(3 rows)
explain (costs off) select * from range_list_parted where a is not null and a < 67;
QUERY PLAN
------------------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_1_10
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_10_20
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_21_30
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_40_inf
- Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_1_10_ab
Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_1_10_cd
@@ -1831,23 +1812,19 @@ explain (costs off) select * from range_list_parted where a is not null and a <
Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_40_inf_null
Filter: ((a IS NOT NULL) AND (a < 67))
-(29 rows)
+(19 rows)
explain (costs off) select * from range_list_parted where a >= 30;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (a >= 30)
- -> Seq Scan on part_40_inf
- Filter: (a >= 30)
-> Seq Scan on part_40_inf_ab
Filter: (a >= 30)
-> Seq Scan on part_40_inf_cd
Filter: (a >= 30)
-> Seq Scan on part_40_inf_null
Filter: (a >= 30)
-(11 rows)
+(7 rows)
drop table list_parted;
drop table range_list_parted;
diff --git a/src/test/regress/expected/tablesample.out b/src/test/regress/expected/tablesample.out
index b18e420e9b..d3794140fb 100644
--- a/src/test/regress/expected/tablesample.out
+++ b/src/test/regress/expected/tablesample.out
@@ -322,12 +322,10 @@ explain (costs off)
QUERY PLAN
-------------------------------------------
Append
- -> Sample Scan on parted_sample
- Sampling: bernoulli ('100'::real)
-> Sample Scan on parted_sample_1
Sampling: bernoulli ('100'::real)
-> Sample Scan on parted_sample_2
Sampling: bernoulli ('100'::real)
-(7 rows)
+(5 rows)
drop table parted_sample, parted_sample_1, parted_sample_2;
diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql
index e3e9e34895..d43b75c4a7 100644
--- a/src/test/regress/sql/inherit.sql
+++ b/src/test/regress/sql/inherit.sql
@@ -128,6 +128,34 @@ where bar.f1 = ss.f1;
select tableoid::regclass::text as relname, bar.* from bar order by 1,2;
+-- Check UPDATE with *partitioned* inherited target and an appendrel subquery
+create table some_tab (a int);
+insert into some_tab values (0);
+create table some_tab_child () inherits (some_tab);
+insert into some_tab_child values (1);
+create table parted_tab (a int, b char) partition by list (a);
+create table parted_tab_part1 partition of parted_tab for values in (1);
+create table parted_tab_part2 partition of parted_tab for values in (2);
+create table parted_tab_part3 partition of parted_tab for values in (3);
+insert into parted_tab values (1, 'a'), (2, 'a'), (3, 'a');
+
+update parted_tab set b = 'b'
+from
+ (select a from some_tab union all select a+1 from some_tab) ss (a)
+where parted_tab.a = ss.a;
+select tableoid::regclass::text as relname, parted_tab.* from parted_tab order by 1,2;
+
+truncate parted_tab;
+insert into parted_tab values (1, 'a'), (2, 'a'), (3, 'a');
+update parted_tab set b = 'b'
+from
+ (select 0 from parted_tab union all select 1 from parted_tab) ss (a)
+where parted_tab.a = ss.a;
+select tableoid::regclass::text as relname, parted_tab.* from parted_tab order by 1,2;
+
+drop table parted_tab;
+drop table some_tab cascade;
+
/* Test multiple inheritance of column defaults */
CREATE TABLE firstparent (tomorrow date default now()::date + 1);
--
2.11.0
[text/x-diff] 0002-Do-not-allocate-storage-for-partitioned-tables.patch (3.1K, ../../975b7629-ff74-74df-a355-23c2e5f193a4@lab.ntt.co.jp/3-0002-Do-not-allocate-storage-for-partitioned-tables.patch)
download | inline diff:
From c457edc4d04ad3454d485362840264e02f4eea50 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Tue, 24 Jan 2017 14:22:34 +0900
Subject: [PATCH 2/2] Do not allocate storage for partitioned tables.
Currently, it is not possible to insert any data into a partitioned
table. So, they're empty at all times, which means it is wasteful to
allocate relfilenode and related storage objects.
---
src/backend/access/common/reloptions.c | 3 +--
src/backend/catalog/heap.c | 17 ++++++++++-------
2 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 72e12532ab..d3b847e2e5 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -967,7 +967,6 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
case RELKIND_RELATION:
case RELKIND_TOASTVALUE:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
options = heap_reloptions(classForm->relkind, datum, false);
break;
case RELKIND_VIEW:
@@ -977,6 +976,7 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
options = index_reloptions(amoptions, datum, false);
break;
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
options = NULL;
break;
default:
@@ -1418,7 +1418,6 @@ heap_reloptions(char relkind, Datum reloptions, bool validate)
return (bytea *) rdopts;
case RELKIND_RELATION:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
default:
/* other relkinds are not supported */
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 41c0056556..2f5090b183 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -291,6 +291,7 @@ heap_create(const char *relname,
case RELKIND_VIEW:
case RELKIND_COMPOSITE_TYPE:
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
create_storage = false;
/*
@@ -1345,14 +1346,13 @@ heap_create_with_catalog(const char *relname,
if (oncommit != ONCOMMIT_NOOP)
register_on_commit_action(relid, oncommit);
- if (relpersistence == RELPERSISTENCE_UNLOGGED)
- {
- Assert(relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW ||
- relkind == RELKIND_TOASTVALUE ||
- relkind == RELKIND_PARTITIONED_TABLE);
-
+ /*
+ * We do not want to create any storage objects for a partitioned
+ * table, including the init fork.
+ */
+ if (relpersistence == RELPERSISTENCE_UNLOGGED &&
+ relkind != RELKIND_PARTITIONED_TABLE)
heap_create_init_fork(new_rel_desc);
- }
/*
* ok, the relation has been cataloged, so close our relations and return
@@ -1376,6 +1376,9 @@ heap_create_with_catalog(const char *relname,
void
heap_create_init_fork(Relation rel)
{
+ Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
+ rel->rd_rel->relkind == RELKIND_MATVIEW ||
+ rel->rd_rel->relkind == RELKIND_TOASTVALUE);
RelationOpenSmgr(rel);
smgrcreate(rel->rd_smgr, INIT_FORKNUM, false);
log_smgrcreate(&rel->rd_smgr->smgr_rnode.node, INIT_FORKNUM);
--
2.11.0
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-03-14 22:09 ` Robert Haas <robertmhaas@gmail.com>
2017-03-15 04:38 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
1 sibling, 2 replies; 96+ messages in thread
From: Robert Haas @ 2017-03-14 22:09 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; Michael Paquier <michael.paquier@gmail.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On Mon, Mar 13, 2017 at 6:24 AM, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
> The previous proposal was for expand_inherited_rtentry to not create RT
> entries and AppendRelInfo's for the non-leaf tables, but I think that
> doesn't work, as I tried to explain above. We need RTEs because that
> seems to be the only way currently for informing the executor of the
> non-leaf tables. We need AppendRelInfo's to store the RT indexes of those
> RTEs for the latter planning steps to collect them in partitioned_rels
> mentioned above. So with the latest patch, we do create the RT entry and
> AppendRelInfo for non-leaf tables. AppendRelInfo created in this case is
> a minimal one; only parent_relid and child_relid are valid. To make the
> latter planning steps ignore these minimal AppendRelInfo's, every
> AppendRelInfo is now marked with child_relkind. Only
> set_append_rel_pathlist() and inheritance_planner() process them to
> collect the child_relid into the partitioned_rels list to be stored in
> AppendPath/MergeAppendPath and ModifyTablePath, respectively.
I see your point, but I still think this kind of stinks. You've got
all kinds of logic that is now conditional on child_is_partitioned,
and that seems like a recipe for bugs and future maintenance
difficulties. It would be much nicer if we could come up with a
design that doesn't create the AppendRelInfo in the first place,
because then all of that stuff could just work. Can we get away with
creating an RTE for each partitioned table (other than the parent,
perhaps; for that one it would be nice to use the inh-flagged RTE we
already have) but NOT creating an AppendRelInfo to go with it? If
we've got the list of RTIs for the new RTEs associated with the append
path in some other form, can't we get by without also having an
AppendRelInfo to hold onto that translation?
The comments in InitPlan() explain why locks on result relations are
taken in that function directly rather than during the ExecInitNode
pass over the tree; it's because we need to make sure we take the
strongest lock on any given relation first. But the changes in
ExecInitAppend and ExecInitMergeAppend are problematic in that regard;
some AccessShareLocks may already have been taken, and now we're
taking locks that in some case may be RowShareLock, which could cause
a lock upgrade. Remember that there's no reason that you couldn't
join a table to one of its own partitions, or something like that. I
think you need to try to jigger things so that InitPlan() takes all
locks stronger than AccessShareLock that are required anywhere in the
query, and then other nodes can take anything at AccessShareLock that
they need.
I think that eliding the Append node when there's only one child may
be unsafe in the case where the child's attribute numbers are
different from the parent's attribute numbers. I remember Tom making
some comment about this when I was working on MergeAppend, although I
no longer remember the specific details.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
@ 2017-03-15 04:38 ` Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-15 06:32 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
1 sibling, 1 reply; 96+ messages in thread
From: Ashutosh Bapat @ 2017-03-15 04:38 UTC (permalink / raw)
To: Robert Haas <robertmhaas@gmail.com>; +Cc: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; Michael Paquier <michael.paquier@gmail.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On Wed, Mar 15, 2017 at 3:39 AM, Robert Haas <robertmhaas@gmail.com> wrote:
> On Mon, Mar 13, 2017 at 6:24 AM, Amit Langote
> <Langote_Amit_f8@lab.ntt.co.jp> wrote:
>> The previous proposal was for expand_inherited_rtentry to not create RT
>> entries and AppendRelInfo's for the non-leaf tables, but I think that
>> doesn't work, as I tried to explain above. We need RTEs because that
>> seems to be the only way currently for informing the executor of the
>> non-leaf tables. We need AppendRelInfo's to store the RT indexes of those
>> RTEs for the latter planning steps to collect them in partitioned_rels
>> mentioned above. So with the latest patch, we do create the RT entry and
>> AppendRelInfo for non-leaf tables. AppendRelInfo created in this case is
>> a minimal one; only parent_relid and child_relid are valid. To make the
>> latter planning steps ignore these minimal AppendRelInfo's, every
>> AppendRelInfo is now marked with child_relkind. Only
>> set_append_rel_pathlist() and inheritance_planner() process them to
>> collect the child_relid into the partitioned_rels list to be stored in
>> AppendPath/MergeAppendPath and ModifyTablePath, respectively.
>
> I see your point, but I still think this kind of stinks. You've got
> all kinds of logic that is now conditional on child_is_partitioned,
> and that seems like a recipe for bugs and future maintenance
> difficulties. It would be much nicer if we could come up with a
> design that doesn't create the AppendRelInfo in the first place,
> because then all of that stuff could just work. Can we get away with
> creating an RTE for each partitioned table (other than the parent,
> perhaps; for that one it would be nice to use the inh-flagged RTE we
> already have) but NOT creating an AppendRelInfo to go with it? If
> we've got the list of RTIs for the new RTEs associated with the append
> path in some other form, can't we get by without also having an
> AppendRelInfo to hold onto that translation?
>
Will it help to retain the partition hierarchy as inheritance
hierarchy and then collapse it while creating append paths. That will
be needed by partition-wise join, will be helpful in partition pruning
without using constraints and so on. So, may be could use that
infrastructure to simplify the logic here. The patch is available as
0013 in [1].
[1] CAFjFpRfqotRR6cM3sooBHMHEVdkFfAZ6PyYg4GRZsoMuW08HjQ@mail.gmail.com
--
Best Wishes,
Ashutosh Bapat
EnterpriseDB Corporation
The Postgres Database Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-15 04:38 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
@ 2017-03-15 06:32 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 07:47 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
0 siblings, 1 reply; 96+ messages in thread
From: Amit Langote @ 2017-03-15 06:32 UTC (permalink / raw)
To: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; Robert Haas <robertmhaas@gmail.com>; +Cc: Michael Paquier <michael.paquier@gmail.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On 2017/03/15 13:38, Ashutosh Bapat wrote:
> On Wed, Mar 15, 2017 at 3:39 AM, Robert Haas <robertmhaas@gmail.com> wrote:
>> On Mon, Mar 13, 2017 at 6:24 AM, Amit Langote
>> <Langote_Amit_f8@lab.ntt.co.jp> wrote:
>>> The previous proposal was for expand_inherited_rtentry to not create RT
>>> entries and AppendRelInfo's for the non-leaf tables, but I think that
>>> doesn't work, as I tried to explain above. We need RTEs because that
>>> seems to be the only way currently for informing the executor of the
>>> non-leaf tables. We need AppendRelInfo's to store the RT indexes of those
>>> RTEs for the latter planning steps to collect them in partitioned_rels
>>> mentioned above. So with the latest patch, we do create the RT entry and
>>> AppendRelInfo for non-leaf tables. AppendRelInfo created in this case is
>>> a minimal one; only parent_relid and child_relid are valid. To make the
>>> latter planning steps ignore these minimal AppendRelInfo's, every
>>> AppendRelInfo is now marked with child_relkind. Only
>>> set_append_rel_pathlist() and inheritance_planner() process them to
>>> collect the child_relid into the partitioned_rels list to be stored in
>>> AppendPath/MergeAppendPath and ModifyTablePath, respectively.
>>
>> I see your point, but I still think this kind of stinks. You've got
>> all kinds of logic that is now conditional on child_is_partitioned,
>> and that seems like a recipe for bugs and future maintenance
>> difficulties. It would be much nicer if we could come up with a
>> design that doesn't create the AppendRelInfo in the first place,
>> because then all of that stuff could just work. Can we get away with
>> creating an RTE for each partitioned table (other than the parent,
>> perhaps; for that one it would be nice to use the inh-flagged RTE we
>> already have) but NOT creating an AppendRelInfo to go with it? If
>> we've got the list of RTIs for the new RTEs associated with the append
>> path in some other form, can't we get by without also having an
>> AppendRelInfo to hold onto that translation?
>>
>
> Will it help to retain the partition hierarchy as inheritance
> hierarchy and then collapse it while creating append paths. That will
> be needed by partition-wise join, will be helpful in partition pruning
> without using constraints and so on. So, may be could use that
> infrastructure to simplify the logic here. The patch is available as
> 0013 in [1].
>
> [1] CAFjFpRfqotRR6cM3sooBHMHEVdkFfAZ6PyYg4GRZsoMuW08HjQ@mail.gmail.com
IMHO, it would be better to keep those patches separate because the
problems being solved are different. By the way, one of the reasons that
patch (as I had written it) was skipped was because it didn't cover the
inheritance_planner() case [1]. Your patch 0013 at the link should be
updated (maybe I should report on the partitionwise joins thread as well)
in some way to handle the update/delete case, because this happens:
create table p (a int, b char) partition by list (a);
create table p1 partition of p for values in (1) partition by list (b);
create table p1a partition of p1 for values in ('a');
create table p2 partition of p for values in (2);
explain (costs off) update p set a = a, b = 'b';
QUERY PLAN
-----------------------------------
Update on p
Update on p
Update on p1 p
Update on p2
-> Seq Scan on p
-> Result
-> Append
-> Seq Scan on p1
-> Seq Scan on p1a
-> Seq Scan on p2
(10 rows)
update p set a = a, b = 'b';
server closed the connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
The connection to the server was lost. Attempting reset: Failed.
Thanks,
Amit
[1]
https://www.postgresql.org/message-id/CA%2BTgmobMy%3DrqM%3DMTN_FUEfD-PiWSCSonH%2BZ1_SjL6ZmQ2GGz1w%40...
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-15 04:38 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-15 06:32 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-03-16 07:47 ` Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
0 siblings, 0 replies; 96+ messages in thread
From: Ashutosh Bapat @ 2017-03-16 07:47 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: Robert Haas <robertmhaas@gmail.com>; Michael Paquier <michael.paquier@gmail.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
>>
>> Will it help to retain the partition hierarchy as inheritance
>> hierarchy and then collapse it while creating append paths. That will
>> be needed by partition-wise join, will be helpful in partition pruning
>> without using constraints and so on. So, may be could use that
>> infrastructure to simplify the logic here. The patch is available as
>> 0013 in [1].
>>
>> [1] CAFjFpRfqotRR6cM3sooBHMHEVdkFfAZ6PyYg4GRZsoMuW08HjQ@mail.gmail.com
>
> IMHO, it would be better to keep those patches separate because the
> problems being solved are different. By the way, one of the reasons that
> patch (as I had written it) was skipped was because it didn't cover the
> inheritance_planner() case [1]. Your patch 0013 at the link should be
> updated (maybe I should report on the partitionwise joins thread as well)
> in some way to handle the update/delete case, because this happens:
>
> create table p (a int, b char) partition by list (a);
> create table p1 partition of p for values in (1) partition by list (b);
> create table p1a partition of p1 for values in ('a');
> create table p2 partition of p for values in (2);
>
> explain (costs off) update p set a = a, b = 'b';
> QUERY PLAN
> -----------------------------------
> Update on p
> Update on p
> Update on p1 p
> Update on p2
> -> Seq Scan on p
> -> Result
> -> Append
> -> Seq Scan on p1
> -> Seq Scan on p1a
> -> Seq Scan on p2
> (10 rows)
>
> update p set a = a, b = 'b';
> server closed the connection unexpectedly
> This probably means the server terminated abnormally
> before or while processing the request.
> The connection to the server was lost. Attempting reset: Failed.
Thanks for pointing that out. I am able to reproduce the crash. I
think, we will need to teach it to add the indirect children as well.
Looks like we are missing a testcase for this scenario. I had run
regression with that patch, and didn't catch any failures and crashes.
--
Best Wishes,
Ashutosh Bapat
EnterpriseDB Corporation
The Postgres Database Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
@ 2017-03-16 10:03 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-21 16:19 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
1 sibling, 2 replies; 96+ messages in thread
From: Amit Langote @ 2017-03-16 10:03 UTC (permalink / raw)
To: Robert Haas <robertmhaas@gmail.com>; +Cc: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; Michael Paquier <michael.paquier@gmail.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On 2017/03/15 7:09, Robert Haas wrote:
> On Mon, Mar 13, 2017 at 6:24 AM, Amit Langote
> <Langote_Amit_f8@lab.ntt.co.jp> wrote:
>> The previous proposal was for expand_inherited_rtentry to not create RT
>> entries and AppendRelInfo's for the non-leaf tables, but I think that
>> doesn't work, as I tried to explain above. We need RTEs because that
>> seems to be the only way currently for informing the executor of the
>> non-leaf tables. We need AppendRelInfo's to store the RT indexes of those
>> RTEs for the latter planning steps to collect them in partitioned_rels
>> mentioned above. So with the latest patch, we do create the RT entry and
>> AppendRelInfo for non-leaf tables. AppendRelInfo created in this case is
>> a minimal one; only parent_relid and child_relid are valid. To make the
>> latter planning steps ignore these minimal AppendRelInfo's, every
>> AppendRelInfo is now marked with child_relkind. Only
>> set_append_rel_pathlist() and inheritance_planner() process them to
>> collect the child_relid into the partitioned_rels list to be stored in
>> AppendPath/MergeAppendPath and ModifyTablePath, respectively.
>
> I see your point, but I still think this kind of stinks. You've got
> all kinds of logic that is now conditional on child_is_partitioned,
> and that seems like a recipe for bugs and future maintenance
> difficulties. It would be much nicer if we could come up with a
> design that doesn't create the AppendRelInfo in the first place,
> because then all of that stuff could just work. Can we get away with
> creating an RTE for each partitioned table (other than the parent,
> perhaps; for that one it would be nice to use the inh-flagged RTE we
> already have) but NOT creating an AppendRelInfo to go with it? If
> we've got the list of RTIs for the new RTEs associated with the append
> path in some other form, can't we get by without also having an
> AppendRelInfo to hold onto that translation?
I think we'll need to store *somewhere* the mapping of which inh=false
partitioned table RTE is the child of which inh=true (IOW, parent)
partitioned table RTE. I've come to think that AppendRelInfos, although
contain extraneous information that won't be used, are better than
inventing something new altogether for time being. AppendRelInfos are
referred to a few times by query_planner() steps before we eventually get
to either set_append_rel_pathlist() or inheritance_planner(), so not
changing that approach seems less worrisome for now. So now if we both
create child RTEs and AppendRelInfos for the partitioned tables, we don't
need to change expand_inherited_rtentry() at all with this patch.
Finally, set_append_rel_size/pathlist() and inheritance_planner() skip the
child partitioned table RTEs, because no path/plan need to be created. We
can do away with having to create RelOptInfos for child partitioned table
RTEs, which I found to be not that invasive.
We seem to agree that we need to carry the partitioned table RT indexes
over to the executor somehow so that they are locked properly during
execution. To that end, Append, MergeAppend, and ModifyTable (and the
corresponding path nodes) nodes will contain a list of those RT indexes in
a field called partitioned_rels. In the result relation case, the list
from ModifyTable is copied to a field in PlannerGlobal called
nonleafResultRelations (next to the old resultRelations) and further to a
field of the same name in PlannedStmt. I considered if it can be done
without a new field, but realized that the old resultRelations is tied
closely with how the EState manages result relations.
InitPlan() and AcquireExecutorLocks() lock the tables denoted by the RT
indexes in PlannedStmt.nonleafResultRelations using RowExclusiveLock, just
like they would those in PlannedStmt.resultRelations.
Since expand_inherited_rtentries() adds PlanRowMarks for partitioned
tables just like previously, InitPlan() and AcquireExecutorLocks() will
lock them with RowShareLock if needed.
Finally, ExecInitAppend() and ExecInitMergeAppend() must acquire
AccessShareLock on the partition tables, if not already locked by InitPlan().
> The comments in InitPlan() explain why locks on result relations are
> taken in that function directly rather than during the ExecInitNode
> pass over the tree; it's because we need to make sure we take the
> strongest lock on any given relation first. But the changes in
> ExecInitAppend and ExecInitMergeAppend are problematic in that regard;
> some AccessShareLocks may already have been taken, and now we're
> taking locks that in some case may be RowShareLock, which could cause
> a lock upgrade. Remember that there's no reason that you couldn't
> join a table to one of its own partitions, or something like that. I
> think you need to try to jigger things so that InitPlan() takes all
> locks stronger than AccessShareLock that are required anywhere in the
> query, and then other nodes can take anything at AccessShareLock that
> they need.
Thanks for the explanation. If the scheme in the new patch that I
described above sounds OK, I think it takes care of locking the
partitioned tables without the upgrade hazards.
> I think that eliding the Append node when there's only one child may
> be unsafe in the case where the child's attribute numbers are
> different from the parent's attribute numbers. I remember Tom making
> some comment about this when I was working on MergeAppend, although I
> no longer remember the specific details.
Append node elision does not occur in the one-child case. With the patch:
create table q (a int) partition by list (a);
explain select * from q;
QUERY PLAN
------------------------------------------
Result (cost=0.00..0.00 rows=0 width=4)
One-Time Filter: false
(2 rows)
create table q1 partition of q for values in (1);
explain select * from q;
QUERY PLAN
------------------------------------------------------------
Append (cost=0.00..35.50 rows=2550 width=4)
-> Seq Scan on q1 (cost=0.00..35.50 rows=2550 width=4)
(2 rows)
Maybe that should be done, but this patch doesn't implement that.
Thanks,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Attachments:
[text/x-diff] 0001-Avoid-creating-scan-nodes-for-partitioned-tables.patch (56.3K, ../../b7f2d81d-9c9b-ba4e-5e00-edf626567256@lab.ntt.co.jp/2-0001-Avoid-creating-scan-nodes-for-partitioned-tables.patch)
download | inline diff:
From 2c2edb76b15e81d76cda56362aeadad4c11fcd6a Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Fri, 10 Mar 2017 13:48:31 +0900
Subject: [PATCH 1/2] Avoid creating scan nodes for partitioned tables
* Currently, we create scan nodes for inheritance parents in their role
as an inheritance set member. Partitioned tables do not contain any
data, so it's useless to create scan nodes for them. set_append_rel_size
and set_append_rel_pathlist must ignore partitioned child tables. Also
then, we don't need to allocate RelOptInfos for partitioned table
otherrels.
* The planner prep phase turns off inheritance on the parent RTE if it
sees that Append won't be needed because there is no child table other
than the parent itself (or in the partitioned table case, there are no
leaf partitions in the tree). set_rel_size() must create a dummy path
for such an RTE if it corresponds to a partitioned table; it must not
try to do, for example, set_plain_rel_size() on such RTEs.
* Since partitioned tables do not appear in the plan trees (although
added to the query range table), there is no way of locating and
locking them during execution. To mitigate that, add a list field
called partitioned_rels to Append, MergeAppend, and ModifyTable nodes
and store in it the RT indexes of the non-leaf tables of the partition
tree controlled by one of these nodes. For InitPlan() to be able to
locate and lock partitioned result relations, copy ModifyTable node's
partitioned_rels list to field in PlannedStmt called
nonleafResultRelations.
* In inheritance_planner(), set ModifyTable.nominalRelation to parent RT
index in the partitioned inheritance parent case, so that EXPLAIN uses
the root tables's original RT index to label a given ModifyTable node.
Regression test outputs are adjusted to match the new plan shape.
---
src/backend/executor/execMain.c | 24 +++++
src/backend/executor/execParallel.c | 1 +
src/backend/executor/execUtils.c | 59 ++++++++++++
src/backend/executor/nodeAppend.c | 6 ++
src/backend/executor/nodeMergeAppend.c | 6 ++
src/backend/executor/nodeModifyTable.c | 22 ++++-
src/backend/nodes/copyfuncs.c | 4 +
src/backend/nodes/outfuncs.c | 8 ++
src/backend/nodes/readfuncs.c | 4 +
src/backend/optimizer/path/allpaths.c | 56 +++++++++---
src/backend/optimizer/path/joinrels.c | 2 +-
src/backend/optimizer/plan/createplan.c | 14 ++-
src/backend/optimizer/plan/initsplan.c | 12 +++
src/backend/optimizer/plan/planner.c | 65 ++++++++++---
src/backend/optimizer/plan/setrefs.c | 15 +++
src/backend/optimizer/prep/prepjointree.c | 1 +
src/backend/optimizer/prep/prepunion.c | 5 +-
src/backend/optimizer/util/pathnode.c | 10 +-
src/backend/optimizer/util/relnode.c | 11 +++
src/backend/utils/cache/plancache.c | 3 +-
src/include/executor/executor.h | 1 +
src/include/nodes/plannodes.h | 9 ++
src/include/nodes/relation.h | 8 ++
src/include/optimizer/pathnode.h | 8 +-
src/test/regress/expected/inherit.out | 147 +++++++++++++-----------------
src/test/regress/expected/tablesample.out | 4 +-
src/test/regress/sql/inherit.sql | 28 ++++++
27 files changed, 406 insertions(+), 127 deletions(-)
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index f5cd65d8a0..f58f3937fd 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -844,6 +844,22 @@ InitPlan(QueryDesc *queryDesc, int eflags)
estate->es_num_result_relations = numResultRelations;
/* es_result_relation_info is NULL except when within ModifyTable */
estate->es_result_relation_info = NULL;
+
+ /*
+ * In the partitioned table case, lock the non-leaf tables too.
+ * We don't need ResultRelInfos for them.
+ */
+ if (plannedstmt->nonleafResultRelations)
+ {
+ foreach(l, plannedstmt->nonleafResultRelations)
+ {
+ Index resultRelationIndex = lfirst_int(l);
+ Oid resultRelationOid;
+
+ resultRelationOid = getrelid(resultRelationIndex, rangeTable);
+ LockRelationOid(resultRelationOid, RowExclusiveLock);
+ }
+ }
}
else
{
@@ -904,6 +920,14 @@ InitPlan(QueryDesc *queryDesc, int eflags)
if (relation)
CheckValidRowMarkRel(relation, rc->markType);
+ /* We don't need the actual ExecRowMarks for partitioned tables */
+ if (relation &&
+ relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ heap_close(relation, NoLock); /* keep the lock */
+ continue;
+ }
+
erm = (ExecRowMark *) palloc(sizeof(ExecRowMark));
erm->relation = relation;
erm->relid = relid;
diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c
index a1289e5f12..86db73be43 100644
--- a/src/backend/executor/execParallel.c
+++ b/src/backend/executor/execParallel.c
@@ -161,6 +161,7 @@ ExecSerializePlan(Plan *plan, EState *estate)
pstmt->planTree = plan;
pstmt->rtable = estate->es_range_table;
pstmt->resultRelations = NIL;
+ pstmt->nonleafResultRelations = NIL;
pstmt->subplans = estate->es_plannedstmt->subplans;
pstmt->rewindPlanIDs = NULL;
pstmt->rowMarks = NIL;
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 3d6a3801c0..4528f6bd46 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -43,6 +43,7 @@
#include "executor/executor.h"
#include "nodes/nodeFuncs.h"
#include "parser/parsetree.h"
+#include "storage/lmgr.h"
#include "utils/memutils.h"
#include "utils/rel.h"
@@ -953,3 +954,61 @@ ShutdownExprContext(ExprContext *econtext, bool isCommit)
MemoryContextSwitchTo(oldcontext);
}
+
+/*
+ * ExecLockNonLeafAppendTables
+ *
+ * Locates using the RT indexes and lock (if needed) the non-leaf tables in
+ * the partition tree controlled by a given Append or MergeAppend node.
+ */
+void
+ExecLockNonLeafAppendTables(List *partitioned_rels, EState *estate)
+{
+ PlannedStmt *stmt = estate->es_plannedstmt;
+ ListCell *lc;
+
+ if (partitioned_rels == NIL)
+ return;
+
+ foreach(lc, partitioned_rels)
+ {
+ ListCell *l;
+ Index rti = lfirst_int(lc);
+ bool is_result_rel = false;
+ Oid relid = getrelid(rti, estate->es_range_table);
+
+ /* If this is a result relation, already locked in InitPlan */
+ foreach(l, stmt->nonleafResultRelations)
+ {
+ if (rti == lfirst_int(l))
+ {
+ is_result_rel = true;
+ break;
+ }
+ }
+
+ /*
+ * Not a result relation; check if there is a RowMark, in which
+ * case too, already locked in InitPlan.
+ */
+ if (!is_result_rel)
+ {
+ bool is_rowmark_rel = false;
+
+ foreach(l, stmt->rowMarks)
+ {
+ PlanRowMark *rc = (PlanRowMark *) lfirst(l);
+
+ if (rc->rti == rti)
+ {
+ is_rowmark_rel = true;
+ break;
+ }
+ }
+
+ /* InitPlan didn't lock us after all. */
+ if (!is_rowmark_rel)
+ LockRelationOid(relid, AccessShareLock);
+ }
+ }
+}
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index 6986caee6b..de6e4d6fee 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -129,6 +129,12 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
Assert(!(eflags & EXEC_FLAG_MARK));
/*
+ * Lock the non-leaf tables in the partition tree controlled by this
+ * node. It's a no-op for non-partitioned parent tables.
+ */
+ ExecLockNonLeafAppendTables(node->partitioned_rels, estate);
+
+ /*
* Set up empty vector of subplan states
*/
nplans = list_length(node->appendplans);
diff --git a/src/backend/executor/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c
index 7a20bf07a4..8a2e78266b 100644
--- a/src/backend/executor/nodeMergeAppend.c
+++ b/src/backend/executor/nodeMergeAppend.c
@@ -72,6 +72,12 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
/*
+ * Lock the non-leaf tables in the partition tree controlled by this
+ * node. It's a no-op for non-partitioned parent tables.
+ */
+ ExecLockNonLeafAppendTables(node->partitioned_rels, estate);
+
+ /*
* Set up empty vector of subplan states
*/
nplans = list_length(node->mergeplans);
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 95e158970c..efbf19e491 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -45,6 +45,7 @@
#include "foreign/fdwapi.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
+#include "parser/parsetree.h"
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
#include "utils/builtins.h"
@@ -1725,8 +1726,20 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
estate->es_result_relation_info = saved_resultRelInfo;
+ /* The root table RT index is at the head of the partitioned_rels list */
+ if (node->partitioned_rels)
+ {
+ Index root_rti;
+ Oid root_oid;
+
+ root_rti = linitial_int(node->partitioned_rels);
+ root_oid = getrelid(root_rti, estate->es_range_table);
+ rel = heap_open(root_oid, NoLock); /* locked by InitPlan */
+ }
+ else
+ rel = mtstate->resultRelInfo->ri_RelationDesc;
+
/* Build state for INSERT tuple routing */
- rel = mtstate->resultRelInfo->ri_RelationDesc;
if (operation == CMD_INSERT &&
rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
{
@@ -1898,6 +1911,13 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
}
/*
+ * Close the root partitioned rel if we opened it above, but keep the
+ * lock.
+ */
+ if (rel != mtstate->resultRelInfo->ri_RelationDesc)
+ heap_close(rel, NoLock);
+
+ /*
* If needed, Initialize target list, projection and qual for ON CONFLICT
* DO UPDATE.
*/
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 25fd051d6e..f0cbbaef27 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -90,6 +90,7 @@ _copyPlannedStmt(const PlannedStmt *from)
COPY_NODE_FIELD(planTree);
COPY_NODE_FIELD(rtable);
COPY_NODE_FIELD(resultRelations);
+ COPY_NODE_FIELD(nonleafResultRelations);
COPY_NODE_FIELD(subplans);
COPY_BITMAPSET_FIELD(rewindPlanIDs);
COPY_NODE_FIELD(rowMarks);
@@ -200,6 +201,7 @@ _copyModifyTable(const ModifyTable *from)
COPY_SCALAR_FIELD(operation);
COPY_SCALAR_FIELD(canSetTag);
COPY_SCALAR_FIELD(nominalRelation);
+ COPY_NODE_FIELD(partitioned_rels);
COPY_NODE_FIELD(resultRelations);
COPY_SCALAR_FIELD(resultRelIndex);
COPY_NODE_FIELD(plans);
@@ -235,6 +237,7 @@ _copyAppend(const Append *from)
/*
* copy remainder of node
*/
+ COPY_NODE_FIELD(partitioned_rels);
COPY_NODE_FIELD(appendplans);
return newnode;
@@ -256,6 +259,7 @@ _copyMergeAppend(const MergeAppend *from)
/*
* copy remainder of node
*/
+ COPY_NODE_FIELD(partitioned_rels);
COPY_NODE_FIELD(mergeplans);
COPY_SCALAR_FIELD(numCols);
COPY_POINTER_FIELD(sortColIdx, from->numCols * sizeof(AttrNumber));
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 7418fbeded..624004ce51 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -252,6 +252,7 @@ _outPlannedStmt(StringInfo str, const PlannedStmt *node)
WRITE_NODE_FIELD(planTree);
WRITE_NODE_FIELD(rtable);
WRITE_NODE_FIELD(resultRelations);
+ WRITE_NODE_FIELD(nonleafResultRelations);
WRITE_NODE_FIELD(subplans);
WRITE_BITMAPSET_FIELD(rewindPlanIDs);
WRITE_NODE_FIELD(rowMarks);
@@ -344,6 +345,7 @@ _outModifyTable(StringInfo str, const ModifyTable *node)
WRITE_ENUM_FIELD(operation, CmdType);
WRITE_BOOL_FIELD(canSetTag);
WRITE_UINT_FIELD(nominalRelation);
+ WRITE_NODE_FIELD(partitioned_rels);
WRITE_NODE_FIELD(resultRelations);
WRITE_INT_FIELD(resultRelIndex);
WRITE_NODE_FIELD(plans);
@@ -368,6 +370,7 @@ _outAppend(StringInfo str, const Append *node)
_outPlanInfo(str, (const Plan *) node);
+ WRITE_NODE_FIELD(partitioned_rels);
WRITE_NODE_FIELD(appendplans);
}
@@ -380,6 +383,7 @@ _outMergeAppend(StringInfo str, const MergeAppend *node)
_outPlanInfo(str, (const Plan *) node);
+ WRITE_NODE_FIELD(partitioned_rels);
WRITE_NODE_FIELD(mergeplans);
WRITE_INT_FIELD(numCols);
@@ -1808,6 +1812,7 @@ _outAppendPath(StringInfo str, const AppendPath *node)
_outPathInfo(str, (const Path *) node);
+ WRITE_NODE_FIELD(partitioned_rels);
WRITE_NODE_FIELD(subpaths);
}
@@ -1818,6 +1823,7 @@ _outMergeAppendPath(StringInfo str, const MergeAppendPath *node)
_outPathInfo(str, (const Path *) node);
+ WRITE_NODE_FIELD(partitioned_rels);
WRITE_NODE_FIELD(subpaths);
WRITE_FLOAT_FIELD(limit_tuples, "%.0f");
}
@@ -2023,6 +2029,7 @@ _outModifyTablePath(StringInfo str, const ModifyTablePath *node)
WRITE_ENUM_FIELD(operation, CmdType);
WRITE_BOOL_FIELD(canSetTag);
WRITE_UINT_FIELD(nominalRelation);
+ WRITE_NODE_FIELD(partitioned_rels);
WRITE_NODE_FIELD(resultRelations);
WRITE_NODE_FIELD(subpaths);
WRITE_NODE_FIELD(subroots);
@@ -2099,6 +2106,7 @@ _outPlannerGlobal(StringInfo str, const PlannerGlobal *node)
WRITE_NODE_FIELD(finalrtable);
WRITE_NODE_FIELD(finalrowmarks);
WRITE_NODE_FIELD(resultRelations);
+ WRITE_NODE_FIELD(nonleafResultRelations);
WRITE_NODE_FIELD(relationOids);
WRITE_NODE_FIELD(invalItems);
WRITE_INT_FIELD(nParamExec);
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index d3bbc02f24..474f221a75 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1444,6 +1444,7 @@ _readPlannedStmt(void)
READ_NODE_FIELD(planTree);
READ_NODE_FIELD(rtable);
READ_NODE_FIELD(resultRelations);
+ READ_NODE_FIELD(nonleafResultRelations);
READ_NODE_FIELD(subplans);
READ_BITMAPSET_FIELD(rewindPlanIDs);
READ_NODE_FIELD(rowMarks);
@@ -1535,6 +1536,7 @@ _readModifyTable(void)
READ_ENUM_FIELD(operation, CmdType);
READ_BOOL_FIELD(canSetTag);
READ_UINT_FIELD(nominalRelation);
+ READ_NODE_FIELD(partitioned_rels);
READ_NODE_FIELD(resultRelations);
READ_INT_FIELD(resultRelIndex);
READ_NODE_FIELD(plans);
@@ -1564,6 +1566,7 @@ _readAppend(void)
ReadCommonPlan(&local_node->plan);
+ READ_NODE_FIELD(partitioned_rels);
READ_NODE_FIELD(appendplans);
READ_DONE();
@@ -1579,6 +1582,7 @@ _readMergeAppend(void)
ReadCommonPlan(&local_node->plan);
+ READ_NODE_FIELD(partitioned_rels);
READ_NODE_FIELD(mergeplans);
READ_INT_FIELD(numCols);
READ_ATTRNUMBER_ARRAY(sortColIdx, local_node->numCols);
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 43bfd23804..d38286d558 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -95,7 +95,8 @@ static void set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
Index rti, RangeTblEntry *rte);
static void generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
List *live_childrels,
- List *all_child_pathkeys);
+ List *all_child_pathkeys,
+ List *partitioned_rels);
static Path *get_cheapest_parameterized_child_path(PlannerInfo *root,
RelOptInfo *rel,
Relids required_outer);
@@ -130,7 +131,7 @@ static void recurse_push_qual(Node *setOp, Query *topquery,
RangeTblEntry *rte, Index rti, Node *qual);
static void remove_unused_subquery_outputs(Query *subquery, RelOptInfo *rel);
static void add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
- List *live_childrels);
+ List *live_childrels, List *partitioned_rels);
/*
@@ -346,6 +347,14 @@ set_rel_size(PlannerInfo *root, RelOptInfo *rel,
/* Foreign table */
set_foreign_size(root, rel, rte);
}
+ else if (rte->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ /*
+ * A partitioned table without leaf partitions is marked
+ * as a dummy rel.
+ */
+ set_dummy_rel_pathlist(rel);
+ }
else if (rte->tablesample != NULL)
{
/* Sampled relation */
@@ -883,6 +892,10 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
childRTindex = appinfo->child_relid;
childRTE = root->simple_rte_array[childRTindex];
+ /* Partitioned *child* tables are empty. */
+ if (childRTE->relkind == RELKIND_PARTITIONED_TABLE && !childRTE->inh)
+ continue;
+
/*
* The child rel's RelOptInfo was already created during
* add_base_rels_to_query.
@@ -1185,6 +1198,7 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
int parentRTindex = rti;
List *live_childrels = NIL;
ListCell *l;
+ List *partitioned_rels = NIL;
/*
* Generate access paths for each member relation, and remember the
@@ -1207,6 +1221,18 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
childrel = root->simple_rel_array[childRTindex];
/*
+ * For partitioned *child* tables, no need to create paths.
+ * Need to store the RT indexes in the append path that will be
+ * created for the parent.
+ */
+ if (childRTE->relkind == RELKIND_PARTITIONED_TABLE && !childRTE->inh)
+ {
+ Assert(childrel == NULL);
+ partitioned_rels = lappend_int(partitioned_rels, childRTindex);
+ continue;
+ }
+
+ /*
* If set_append_rel_size() decided the parent appendrel was
* parallel-unsafe at some point after visiting this child rel, we
* need to propagate the unsafety marking down to the child, so that
@@ -1233,7 +1259,7 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
}
/* Add paths to the "append" relation. */
- add_paths_to_append_rel(root, rel, live_childrels);
+ add_paths_to_append_rel(root, rel, live_childrels, partitioned_rels);
}
@@ -1250,7 +1276,7 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
*/
static void
add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
- List *live_childrels)
+ List *live_childrels, List *partitioned_rels)
{
List *subpaths = NIL;
bool subpaths_valid = true;
@@ -1359,7 +1385,8 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
* if we have zero or one live subpath due to constraint exclusion.)
*/
if (subpaths_valid)
- add_path(rel, (Path *) create_append_path(rel, subpaths, NULL, 0));
+ add_path(rel, (Path *) create_append_path(rel, subpaths, NULL, 0,
+ partitioned_rels));
/*
* Consider an append of partial unordered, unparameterized partial paths.
@@ -1386,7 +1413,7 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
/* Generate a partial append path. */
appendpath = create_append_path(rel, partial_subpaths, NULL,
- parallel_workers);
+ parallel_workers, partitioned_rels);
add_partial_path(rel, (Path *) appendpath);
}
@@ -1396,7 +1423,8 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
*/
if (subpaths_valid)
generate_mergeappend_paths(root, rel, live_childrels,
- all_child_pathkeys);
+ all_child_pathkeys,
+ partitioned_rels);
/*
* Build Append paths for each parameterization seen among the child rels.
@@ -1438,7 +1466,8 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
if (subpaths_valid)
add_path(rel, (Path *)
- create_append_path(rel, subpaths, required_outer, 0));
+ create_append_path(rel, subpaths, required_outer, 0,
+ partitioned_rels));
}
}
@@ -1468,7 +1497,8 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
static void
generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
List *live_childrels,
- List *all_child_pathkeys)
+ List *all_child_pathkeys,
+ List *partitioned_rels)
{
ListCell *lcp;
@@ -1532,13 +1562,15 @@ generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
rel,
startup_subpaths,
pathkeys,
- NULL));
+ NULL,
+ partitioned_rels));
if (startup_neq_total)
add_path(rel, (Path *) create_merge_append_path(root,
rel,
total_subpaths,
pathkeys,
- NULL));
+ NULL,
+ partitioned_rels));
}
}
@@ -1671,7 +1703,7 @@ set_dummy_rel_pathlist(RelOptInfo *rel)
rel->pathlist = NIL;
rel->partial_pathlist = NIL;
- add_path(rel, (Path *) create_append_path(rel, NIL, NULL, 0));
+ add_path(rel, (Path *) create_append_path(rel, NIL, NULL, 0, NIL));
/*
* We set the cheapest path immediately, to ensure that IS_DUMMY_REL()
diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c
index 0551668976..6a0c67b9ab 100644
--- a/src/backend/optimizer/path/joinrels.c
+++ b/src/backend/optimizer/path/joinrels.c
@@ -1217,7 +1217,7 @@ mark_dummy_rel(RelOptInfo *rel)
rel->partial_pathlist = NIL;
/* Set up the dummy path */
- add_path(rel, (Path *) create_append_path(rel, NIL, NULL, 0));
+ add_path(rel, (Path *) create_append_path(rel, NIL, NULL, 0, NIL));
/* Set or update cheapest_total_path and related fields */
set_cheapest(rel);
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 89e1946fc2..c80c9992c9 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -199,7 +199,7 @@ static CteScan *make_ctescan(List *qptlist, List *qpqual,
Index scanrelid, int ctePlanId, int cteParam);
static WorkTableScan *make_worktablescan(List *qptlist, List *qpqual,
Index scanrelid, int wtParam);
-static Append *make_append(List *appendplans, List *tlist);
+static Append *make_append(List *appendplans, List *tlist, List *partitioned_rels);
static RecursiveUnion *make_recursive_union(List *tlist,
Plan *lefttree,
Plan *righttree,
@@ -273,7 +273,7 @@ static Result *make_result(List *tlist, Node *resconstantqual, Plan *subplan);
static ProjectSet *make_project_set(List *tlist, Plan *subplan);
static ModifyTable *make_modifytable(PlannerInfo *root,
CmdType operation, bool canSetTag,
- Index nominalRelation,
+ Index nominalRelation, List *partitioned_rels,
List *resultRelations, List *subplans,
List *withCheckOptionLists, List *returningLists,
List *rowMarks, OnConflictExpr *onconflict, int epqParam);
@@ -1026,7 +1026,7 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path)
* parent-rel Vars it'll be asked to emit.
*/
- plan = make_append(subplans, tlist);
+ plan = make_append(subplans, tlist, best_path->partitioned_rels);
copy_generic_path_info(&plan->plan, (Path *) best_path);
@@ -1134,6 +1134,7 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path)
subplans = lappend(subplans, subplan);
}
+ node->partitioned_rels = best_path->partitioned_rels;
node->mergeplans = subplans;
return (Plan *) node;
@@ -2314,6 +2315,7 @@ create_modifytable_plan(PlannerInfo *root, ModifyTablePath *best_path)
best_path->operation,
best_path->canSetTag,
best_path->nominalRelation,
+ best_path->partitioned_rels,
best_path->resultRelations,
subplans,
best_path->withCheckOptionLists,
@@ -5161,7 +5163,7 @@ make_foreignscan(List *qptlist,
}
static Append *
-make_append(List *appendplans, List *tlist)
+make_append(List *appendplans, List *tlist, List *partitioned_rels)
{
Append *node = makeNode(Append);
Plan *plan = &node->plan;
@@ -5170,6 +5172,7 @@ make_append(List *appendplans, List *tlist)
plan->qual = NIL;
plan->lefttree = NULL;
plan->righttree = NULL;
+ node->partitioned_rels = partitioned_rels;
node->appendplans = appendplans;
return node;
@@ -6282,7 +6285,7 @@ make_project_set(List *tlist,
static ModifyTable *
make_modifytable(PlannerInfo *root,
CmdType operation, bool canSetTag,
- Index nominalRelation,
+ Index nominalRelation, List *partitioned_rels,
List *resultRelations, List *subplans,
List *withCheckOptionLists, List *returningLists,
List *rowMarks, OnConflictExpr *onconflict, int epqParam)
@@ -6308,6 +6311,7 @@ make_modifytable(PlannerInfo *root,
node->operation = operation;
node->canSetTag = canSetTag;
node->nominalRelation = nominalRelation;
+ node->partitioned_rels = partitioned_rels;
node->resultRelations = resultRelations;
node->resultRelIndex = -1; /* will be set correctly in setrefs.c */
node->plans = subplans;
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index b4ac224a7a..681045d2ae 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -14,6 +14,7 @@
*/
#include "postgres.h"
+#include "catalog/pg_class.h"
#include "catalog/pg_type.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
@@ -638,10 +639,21 @@ create_lateral_join_info(PlannerInfo *root)
foreach(lc, root->append_rel_list)
{
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
+ RangeTblEntry *childrte;
RelOptInfo *childrel;
if (appinfo->parent_relid != rti)
continue;
+
+ /*
+ * Ignore partitioned *child* rels. We must not ignore
+ * however if the child itself is an appendrel.
+ */
+ childrte = root->simple_rte_array[appinfo->child_relid];
+ if (childrte->relkind == RELKIND_PARTITIONED_TABLE &&
+ !childrte->inh)
+ continue;
+
childrel = root->simple_rel_array[appinfo->child_relid];
Assert(childrel->reloptkind == RELOPT_OTHER_MEMBER_REL);
Assert(childrel->direct_lateral_relids == NULL);
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 02286d9c52..3091d182c9 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -212,6 +212,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
glob->finalrtable = NIL;
glob->finalrowmarks = NIL;
glob->resultRelations = NIL;
+ glob->nonleafResultRelations = NIL;
glob->relationOids = NIL;
glob->invalItems = NIL;
glob->nParamExec = 0;
@@ -380,6 +381,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
Assert(glob->finalrtable == NIL);
Assert(glob->finalrowmarks == NIL);
Assert(glob->resultRelations == NIL);
+ Assert(glob->nonleafResultRelations == NIL);
top_plan = set_plan_references(root, top_plan);
/* ... and the subplans (both regular subplans and initplans) */
Assert(list_length(glob->subplans) == list_length(glob->subroots));
@@ -405,6 +407,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
result->planTree = top_plan;
result->rtable = glob->finalrtable;
result->resultRelations = glob->resultRelations;
+ result->nonleafResultRelations = glob->nonleafResultRelations;
result->subplans = glob->subplans;
result->rewindPlanIDs = glob->rewindPlanIDs;
result->rowMarks = glob->finalrowmarks;
@@ -1007,6 +1010,8 @@ inheritance_planner(PlannerInfo *root)
RelOptInfo *final_rel;
ListCell *lc;
Index rti;
+ RangeTblEntry *parent_rte;
+ List *partitioned_rels = NIL;
Assert(parse->commandType != CMD_INSERT);
@@ -1065,13 +1070,24 @@ inheritance_planner(PlannerInfo *root)
}
/*
+ * If the parent RTE is a partitioned table, we should use that as the
+ * nominal relation, because the RTEs added for partitioned tables
+ * (including the root parent) as child members of the inheritance set
+ * do not appear anywhere else in the plan. Situation is exactly the
+ * opposite in the case of non-partitioned inheritance parent as
+ * described below.
+ */
+ parent_rte = rt_fetch(parentRTindex, root->parse->rtable);
+ if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
+ nominalRelation = parentRTindex;
+
+ /*
* And now we can get on with generating a plan for each child table.
*/
foreach(lc, root->append_rel_list)
{
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
PlannerInfo *subroot;
- RangeTblEntry *parent_rte;
RangeTblEntry *child_rte;
RelOptInfo *sub_final_rel;
Path *subpath;
@@ -1104,6 +1120,19 @@ inheritance_planner(PlannerInfo *root)
*/
parent_rte = rt_fetch(parentRTindex, subroot->parse->rtable);
child_rte = rt_fetch(appinfo->child_relid, subroot->parse->rtable);
+
+ /*
+ * For partitioned child tables, no need to create a plan. Need
+ * to store the RT index in the modifytable path that will be created
+ * for the parent.
+ */
+ if (child_rte->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ partitioned_rels = lappend_int(partitioned_rels,
+ appinfo->child_relid);
+ continue;
+ }
+
child_rte->securityQuals = parent_rte->securityQuals;
parent_rte->securityQuals = NIL;
@@ -1216,15 +1245,25 @@ inheritance_planner(PlannerInfo *root)
grouping_planner(subroot, true, 0.0 /* retrieve all tuples */ );
/*
- * We'll use the first child relation (even if it's excluded) as the
- * nominal target relation of the ModifyTable node. Because of the
- * way expand_inherited_rtentry works, this should always be the RTE
- * representing the parent table in its role as a simple member of the
- * inheritance set. (It would be logically cleaner to use the
- * inheritance parent RTE as the nominal target; but since that RTE
- * will not be otherwise referenced in the plan, doing so would give
- * rise to confusing use of multiple aliases in EXPLAIN output for
- * what the user will think is the "same" table.)
+ * Set the nomimal target relation of the ModifyTable node if not
+ * already done. We use the inheritance parent RTE as the nominal
+ * target relation if it's a partitioned table (see just above this
+ * loop). In the non-partitioned parent case, we'll use the first
+ * child relation (even if it's excluded) as the nominal target
+ * relation. Because of the way expand_inherited_rtentry works, the
+ * latter should be the RTE representing the parent table in its role
+ * as a simple member of the inheritance set.
+ *
+ * It would be logically cleaner to *always* use the inheritance
+ * parent RTE as the nominal relation; but that RTE is not otherwise
+ * referenced in the plan in the non-partitioned inheritance case.
+ * Instead the duplicate child RTE created by expand_inherited_rtentry
+ * is used elsewhere in the plan, so using the original parent RTE
+ * would give rise to confusing use of multiple aliases in EXPLAIN
+ * output for what the user will think is the "same" table. OTOH,
+ * it's not a problem in the partitioned inheritance case, because
+ * the duplicate child RTE added for the parent does not appear
+ * anywhere else in the plan tree.
*/
if (nominalRelation < 0)
nominalRelation = appinfo->child_relid;
@@ -1351,6 +1390,7 @@ inheritance_planner(PlannerInfo *root)
parse->commandType,
parse->canSetTag,
nominalRelation,
+ partitioned_rels,
resultRelations,
subpaths,
subroots,
@@ -2046,6 +2086,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
parse->commandType,
parse->canSetTag,
parse->resultRelation,
+ NIL,
list_make1_int(parse->resultRelation),
list_make1(path),
list_make1(root),
@@ -3348,7 +3389,8 @@ create_grouping_paths(PlannerInfo *root,
create_append_path(grouped_rel,
paths,
NULL,
- 0);
+ 0,
+ NIL);
path->pathtarget = target;
}
else
@@ -5418,6 +5460,7 @@ plan_cluster_use_sort(Oid tableOid, Oid indexOid)
/* Build RelOptInfo */
rel = build_simple_rel(root, 1, RELOPT_BASEREL);
+ Assert(rel != NULL);
/* Locate IndexOptInfo for the target index */
indexInfo = NULL;
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 5f3027e96f..892131343c 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -835,6 +835,10 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
splan->nominalRelation += rtoffset;
splan->exclRelRTI += rtoffset;
+ foreach(l, splan->partitioned_rels)
+ {
+ lfirst_int(l) += rtoffset;
+ }
foreach(l, splan->resultRelations)
{
lfirst_int(l) += rtoffset;
@@ -863,6 +867,9 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
root->glob->resultRelations =
list_concat(root->glob->resultRelations,
list_copy(splan->resultRelations));
+ root->glob->nonleafResultRelations =
+ list_concat(root->glob->nonleafResultRelations,
+ list_copy(splan->partitioned_rels));
}
break;
case T_Append:
@@ -875,6 +882,10 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
*/
set_dummy_tlist_references(plan, rtoffset);
Assert(splan->plan.qual == NIL);
+ foreach(l, splan->partitioned_rels)
+ {
+ lfirst_int(l) += rtoffset;
+ }
foreach(l, splan->appendplans)
{
lfirst(l) = set_plan_refs(root,
@@ -893,6 +904,10 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
*/
set_dummy_tlist_references(plan, rtoffset);
Assert(splan->plan.qual == NIL);
+ foreach(l, splan->partitioned_rels)
+ {
+ lfirst_int(l) += rtoffset;
+ }
foreach(l, splan->mergeplans)
{
lfirst(l) = set_plan_refs(root,
diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c
index 048815d7b0..ed7f5a5cc2 100644
--- a/src/backend/optimizer/prep/prepjointree.c
+++ b/src/backend/optimizer/prep/prepjointree.c
@@ -1072,6 +1072,7 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
if (appinfo == containing_appendrel)
rvcontext.need_phvs = false;
+
appinfo->translated_vars = (List *)
pullup_replace_vars((Node *) appinfo->translated_vars, &rvcontext);
rvcontext.need_phvs = save_need_phvs;
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 1389db18ba..580d2760e7 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -272,6 +272,7 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
* forward to setrefs.c processing.
*/
rel = build_simple_rel(root, rtr->rtindex, RELOPT_BASEREL);
+ Assert(rel != NULL);
/* plan_params should not be in use in current query level */
Assert(root->plan_params == NIL);
@@ -566,7 +567,7 @@ generate_union_path(SetOperationStmt *op, PlannerInfo *root,
/*
* Append the child results together.
*/
- path = (Path *) create_append_path(result_rel, pathlist, NULL, 0);
+ path = (Path *) create_append_path(result_rel, pathlist, NULL, 0, NIL);
/* We have to manually jam the right tlist into the path; ick */
path->pathtarget = create_pathtarget(root, tlist);
@@ -678,7 +679,7 @@ generate_nonunion_path(SetOperationStmt *op, PlannerInfo *root,
/*
* Append the child results together.
*/
- path = (Path *) create_append_path(result_rel, pathlist, NULL, 0);
+ path = (Path *) create_append_path(result_rel, pathlist, NULL, 0, NIL);
/* We have to manually jam the right tlist into the path; ick */
path->pathtarget = create_pathtarget(root, tlist);
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 8ce772d274..fca96eb001 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -1201,7 +1201,7 @@ create_tidscan_path(PlannerInfo *root, RelOptInfo *rel, List *tidquals,
*/
AppendPath *
create_append_path(RelOptInfo *rel, List *subpaths, Relids required_outer,
- int parallel_workers)
+ int parallel_workers, List *partitioned_rels)
{
AppendPath *pathnode = makeNode(AppendPath);
ListCell *l;
@@ -1216,6 +1216,7 @@ create_append_path(RelOptInfo *rel, List *subpaths, Relids required_outer,
pathnode->path.parallel_workers = parallel_workers;
pathnode->path.pathkeys = NIL; /* result is always considered
* unsorted */
+ pathnode->partitioned_rels = partitioned_rels;
pathnode->subpaths = subpaths;
/*
@@ -1258,7 +1259,8 @@ create_merge_append_path(PlannerInfo *root,
RelOptInfo *rel,
List *subpaths,
List *pathkeys,
- Relids required_outer)
+ Relids required_outer,
+ List *partitioned_rels)
{
MergeAppendPath *pathnode = makeNode(MergeAppendPath);
Cost input_startup_cost;
@@ -1274,6 +1276,7 @@ create_merge_append_path(PlannerInfo *root,
pathnode->path.parallel_safe = rel->consider_parallel;
pathnode->path.parallel_workers = 0;
pathnode->path.pathkeys = pathkeys;
+ pathnode->partitioned_rels = partitioned_rels;
pathnode->subpaths = subpaths;
/*
@@ -3105,7 +3108,7 @@ create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
ModifyTablePath *
create_modifytable_path(PlannerInfo *root, RelOptInfo *rel,
CmdType operation, bool canSetTag,
- Index nominalRelation,
+ Index nominalRelation, List *partitioned_rels,
List *resultRelations, List *subpaths,
List *subroots,
List *withCheckOptionLists, List *returningLists,
@@ -3172,6 +3175,7 @@ create_modifytable_path(PlannerInfo *root, RelOptInfo *rel,
pathnode->operation = operation;
pathnode->canSetTag = canSetTag;
pathnode->nominalRelation = nominalRelation;
+ pathnode->partitioned_rels = partitioned_rels;
pathnode->resultRelations = resultRelations;
pathnode->subpaths = subpaths;
pathnode->subroots = subroots;
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index 6ab78545c3..e7edf2a0e3 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -16,6 +16,7 @@
#include <limits.h>
+#include "catalog/pg_class.h"
#include "miscadmin.h"
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
@@ -102,6 +103,16 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind)
rte = root->simple_rte_array[relid];
Assert(rte != NULL);
+ /*
+ * No need to build RelOptInfos for appendrel otherrels that are
+ * partitioned tables, except when it is an appendrel itself (inh=true
+ * in the following condition). For an example of the latter, consider
+ * UNION ALL subqueries referencing partitioned tables.
+ */
+ if (reloptkind == RELOPT_OTHER_MEMBER_REL &&
+ rte->relkind == RELKIND_PARTITIONED_TABLE && !rte->inh)
+ return NULL;
+
rel = makeNode(RelOptInfo);
rel->reloptkind = reloptkind;
rel->relids = bms_make_singleton(relid);
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index fa02374811..d284ab7d3d 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -1514,7 +1514,8 @@ AcquireExecutorLocks(List *stmt_list, bool acquire)
* fail if it's been dropped entirely --- we'll just transiently
* acquire a non-conflicting lock.
*/
- if (list_member_int(plannedstmt->resultRelations, rt_index))
+ if (list_member_int(plannedstmt->resultRelations, rt_index) ||
+ list_member_int(plannedstmt->nonleafResultRelations, rt_index))
lockmode = RowExclusiveLock;
else if ((rc = get_plan_rowmark(plannedstmt->rowMarks, rt_index)) != NULL &&
RowMarkRequiresRowShareLock(rc->markType))
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 02dbe7b228..e64d6fb93f 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -375,6 +375,7 @@ extern void RegisterExprContextCallback(ExprContext *econtext,
extern void UnregisterExprContextCallback(ExprContext *econtext,
ExprContextCallbackFunction function,
Datum arg);
+extern void ExecLockNonLeafAppendTables(List *partitioned_rels, EState *estate);
/*
* prototypes from functions in execIndexing.c
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index b880dc16cf..897270c7d1 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -65,6 +65,9 @@ typedef struct PlannedStmt
/* rtable indexes of target relations for INSERT/UPDATE/DELETE */
List *resultRelations; /* integer list of RT indexes, or NIL */
+ /* rtable indexes of non-leaf target relations for INSERT/UPDATE/DELETE */
+ List *nonleafResultRelations;
+
List *subplans; /* Plan trees for SubPlan expressions */
Bitmapset *rewindPlanIDs; /* indices of subplans that require REWIND */
@@ -202,6 +205,8 @@ typedef struct ModifyTable
CmdType operation; /* INSERT, UPDATE, or DELETE */
bool canSetTag; /* do we set the command tag/es_processed? */
Index nominalRelation; /* Parent RT index for use of EXPLAIN */
+ /* RT indexes of non-leaf tables in a partition tree */
+ List *partitioned_rels;
List *resultRelations; /* integer list of RT indexes */
int resultRelIndex; /* index of first resultRel in plan's list */
List *plans; /* plan(s) producing source data */
@@ -227,6 +232,8 @@ typedef struct ModifyTable
typedef struct Append
{
Plan plan;
+ /* RT indexes of non-leaf tables in a partition tree */
+ List *partitioned_rels;
List *appendplans;
} Append;
@@ -238,6 +245,8 @@ typedef struct Append
typedef struct MergeAppend
{
Plan plan;
+ /* RT indexes of non-leaf tables in a partition tree */
+ List *partitioned_rels;
List *mergeplans;
/* remaining fields are just like the sort-key info in struct Sort */
int numCols; /* number of sort-key columns */
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index 05d6f07aea..ee540bd857 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -107,6 +107,8 @@ typedef struct PlannerGlobal
List *resultRelations; /* "flat" list of integer RT indexes */
+ List *nonleafResultRelations; /* "flat" list of integer RT indexes */
+
List *relationOids; /* OIDs of relations the plan depends on */
List *invalItems; /* other dependencies, as PlanInvalItems */
@@ -1116,6 +1118,8 @@ typedef struct CustomPath
typedef struct AppendPath
{
Path path;
+ /* RT indexes of non-leaf tables in a partition tree */
+ List *partitioned_rels;
List *subpaths; /* list of component Paths */
} AppendPath;
@@ -1134,6 +1138,8 @@ typedef struct AppendPath
typedef struct MergeAppendPath
{
Path path;
+ /* RT indexes of non-leaf tables in a partition tree */
+ List *partitioned_rels;
List *subpaths; /* list of component Paths */
double limit_tuples; /* hard limit on output tuples, or -1 */
} MergeAppendPath;
@@ -1482,6 +1488,8 @@ typedef struct ModifyTablePath
CmdType operation; /* INSERT, UPDATE, or DELETE */
bool canSetTag; /* do we set the command tag/es_processed? */
Index nominalRelation; /* Parent RT index for use of EXPLAIN */
+ /* RT indexes of non-leaf tables in a partition tree */
+ List *partitioned_rels;
List *resultRelations; /* integer list of RT indexes */
List *subpaths; /* Path(s) producing source data */
List *subroots; /* per-target-table PlannerInfos */
diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h
index 373c7221a8..81640de7ab 100644
--- a/src/include/optimizer/pathnode.h
+++ b/src/include/optimizer/pathnode.h
@@ -64,12 +64,14 @@ extern BitmapOrPath *create_bitmap_or_path(PlannerInfo *root,
extern TidPath *create_tidscan_path(PlannerInfo *root, RelOptInfo *rel,
List *tidquals, Relids required_outer);
extern AppendPath *create_append_path(RelOptInfo *rel, List *subpaths,
- Relids required_outer, int parallel_workers);
+ Relids required_outer, int parallel_workers,
+ List *partitioned_rels);
extern MergeAppendPath *create_merge_append_path(PlannerInfo *root,
RelOptInfo *rel,
List *subpaths,
List *pathkeys,
- Relids required_outer);
+ Relids required_outer,
+ List *partitioned_rels);
extern ResultPath *create_result_path(PlannerInfo *root, RelOptInfo *rel,
PathTarget *target, List *resconstantqual);
extern MaterialPath *create_material_path(RelOptInfo *rel, Path *subpath);
@@ -232,7 +234,7 @@ extern LockRowsPath *create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
extern ModifyTablePath *create_modifytable_path(PlannerInfo *root,
RelOptInfo *rel,
CmdType operation, bool canSetTag,
- Index nominalRelation,
+ Index nominalRelation, List *partitioned_rels,
List *resultRelations, List *subpaths,
List *subroots,
List *withCheckOptionLists, List *returningLists,
diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out
index 6494b205c4..6163ed8117 100644
--- a/src/test/regress/expected/inherit.out
+++ b/src/test/regress/expected/inherit.out
@@ -588,6 +588,45 @@ select tableoid::regclass::text as relname, bar.* from bar order by 1,2;
bar2 | 4 | 104
(8 rows)
+-- Check UPDATE with *partitioned* inherited target and an appendrel subquery
+create table some_tab (a int);
+insert into some_tab values (0);
+create table some_tab_child () inherits (some_tab);
+insert into some_tab_child values (1);
+create table parted_tab (a int, b char) partition by list (a);
+create table parted_tab_part1 partition of parted_tab for values in (1);
+create table parted_tab_part2 partition of parted_tab for values in (2);
+create table parted_tab_part3 partition of parted_tab for values in (3);
+insert into parted_tab values (1, 'a'), (2, 'a'), (3, 'a');
+update parted_tab set b = 'b'
+from
+ (select a from some_tab union all select a+1 from some_tab) ss (a)
+where parted_tab.a = ss.a;
+select tableoid::regclass::text as relname, parted_tab.* from parted_tab order by 1,2;
+ relname | a | b
+------------------+---+---
+ parted_tab_part1 | 1 | b
+ parted_tab_part2 | 2 | b
+ parted_tab_part3 | 3 | a
+(3 rows)
+
+truncate parted_tab;
+insert into parted_tab values (1, 'a'), (2, 'a'), (3, 'a');
+update parted_tab set b = 'b'
+from
+ (select 0 from parted_tab union all select 1 from parted_tab) ss (a)
+where parted_tab.a = ss.a;
+select tableoid::regclass::text as relname, parted_tab.* from parted_tab order by 1,2;
+ relname | a | b
+------------------+---+---
+ parted_tab_part1 | 1 | b
+ parted_tab_part2 | 2 | a
+ parted_tab_part3 | 3 | a
+(3 rows)
+
+drop table parted_tab;
+drop table some_tab cascade;
+NOTICE: drop cascades to table some_tab_child
/* Test multiple inheritance of column defaults */
CREATE TABLE firstparent (tomorrow date default now()::date + 1);
CREATE TABLE secondparent (tomorrow date default now() :: date + 1);
@@ -1611,71 +1650,60 @@ explain (costs off) select * from list_parted;
QUERY PLAN
--------------------------------
Append
- -> Seq Scan on list_parted
-> Seq Scan on part_ab_cd
-> Seq Scan on part_ef_gh
-> Seq Scan on part_null_xy
-(5 rows)
+(4 rows)
explain (costs off) select * from list_parted where a is null;
QUERY PLAN
--------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (a IS NULL)
-> Seq Scan on part_null_xy
Filter: (a IS NULL)
-(5 rows)
+(3 rows)
explain (costs off) select * from list_parted where a is not null;
QUERY PLAN
---------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (a IS NOT NULL)
-> Seq Scan on part_ab_cd
Filter: (a IS NOT NULL)
-> Seq Scan on part_ef_gh
Filter: (a IS NOT NULL)
-> Seq Scan on part_null_xy
Filter: (a IS NOT NULL)
-(9 rows)
+(7 rows)
explain (costs off) select * from list_parted where a in ('ab', 'cd', 'ef');
QUERY PLAN
----------------------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-> Seq Scan on part_ab_cd
Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-> Seq Scan on part_ef_gh
Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-(7 rows)
+(5 rows)
explain (costs off) select * from list_parted where a = 'ab' or a in (null, 'cd');
QUERY PLAN
---------------------------------------------------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_ab_cd
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_ef_gh
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_null_xy
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-(9 rows)
+(7 rows)
explain (costs off) select * from list_parted where a = 'ab';
QUERY PLAN
------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: ((a)::text = 'ab'::text)
-> Seq Scan on part_ab_cd
Filter: ((a)::text = 'ab'::text)
-(5 rows)
+(3 rows)
create table range_list_parted (
a int,
@@ -1695,14 +1723,9 @@ create table part_40_inf_ab partition of part_40_inf for values in ('ab');
create table part_40_inf_cd partition of part_40_inf for values in ('cd');
create table part_40_inf_null partition of part_40_inf for values in (null);
explain (costs off) select * from range_list_parted;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- -> Seq Scan on part_1_10
- -> Seq Scan on part_10_20
- -> Seq Scan on part_21_30
- -> Seq Scan on part_40_inf
-> Seq Scan on part_1_10_ab
-> Seq Scan on part_1_10_cd
-> Seq Scan on part_10_20_ab
@@ -1712,36 +1735,22 @@ explain (costs off) select * from range_list_parted;
-> Seq Scan on part_40_inf_ab
-> Seq Scan on part_40_inf_cd
-> Seq Scan on part_40_inf_null
-(15 rows)
+(10 rows)
explain (costs off) select * from range_list_parted where a = 5;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+--------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (a = 5)
- -> Seq Scan on part_1_10
- Filter: (a = 5)
-> Seq Scan on part_1_10_ab
Filter: (a = 5)
-> Seq Scan on part_1_10_cd
Filter: (a = 5)
-(9 rows)
+(5 rows)
explain (costs off) select * from range_list_parted where b = 'ab';
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_1_10
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_10_20
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_21_30
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_40_inf
- Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_1_10_ab
Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_10_20_ab
@@ -1750,27 +1759,19 @@ explain (costs off) select * from range_list_parted where b = 'ab';
Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_40_inf_ab
Filter: (b = 'ab'::bpchar)
-(19 rows)
+(9 rows)
explain (costs off) select * from range_list_parted where a between 3 and 23 and b in ('ab');
QUERY PLAN
-----------------------------------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_1_10
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_10_20
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_21_30
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_1_10_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_10_20_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_21_30_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-(15 rows)
+(7 rows)
/* Should select no rows because range partition key cannot be null */
explain (costs off) select * from range_list_parted where a is null;
@@ -1782,37 +1783,17 @@ explain (costs off) select * from range_list_parted where a is null;
/* Should only select rows from the null-accepting partition */
explain (costs off) select * from range_list_parted where b is null;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (b IS NULL)
- -> Seq Scan on part_1_10
- Filter: (b IS NULL)
- -> Seq Scan on part_10_20
- Filter: (b IS NULL)
- -> Seq Scan on part_21_30
- Filter: (b IS NULL)
- -> Seq Scan on part_40_inf
- Filter: (b IS NULL)
-> Seq Scan on part_40_inf_null
Filter: (b IS NULL)
-(13 rows)
+(3 rows)
explain (costs off) select * from range_list_parted where a is not null and a < 67;
QUERY PLAN
------------------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_1_10
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_10_20
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_21_30
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_40_inf
- Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_1_10_ab
Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_1_10_cd
@@ -1831,23 +1812,19 @@ explain (costs off) select * from range_list_parted where a is not null and a <
Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_40_inf_null
Filter: ((a IS NOT NULL) AND (a < 67))
-(29 rows)
+(19 rows)
explain (costs off) select * from range_list_parted where a >= 30;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (a >= 30)
- -> Seq Scan on part_40_inf
- Filter: (a >= 30)
-> Seq Scan on part_40_inf_ab
Filter: (a >= 30)
-> Seq Scan on part_40_inf_cd
Filter: (a >= 30)
-> Seq Scan on part_40_inf_null
Filter: (a >= 30)
-(11 rows)
+(7 rows)
drop table list_parted;
drop table range_list_parted;
diff --git a/src/test/regress/expected/tablesample.out b/src/test/regress/expected/tablesample.out
index b18e420e9b..d3794140fb 100644
--- a/src/test/regress/expected/tablesample.out
+++ b/src/test/regress/expected/tablesample.out
@@ -322,12 +322,10 @@ explain (costs off)
QUERY PLAN
-------------------------------------------
Append
- -> Sample Scan on parted_sample
- Sampling: bernoulli ('100'::real)
-> Sample Scan on parted_sample_1
Sampling: bernoulli ('100'::real)
-> Sample Scan on parted_sample_2
Sampling: bernoulli ('100'::real)
-(7 rows)
+(5 rows)
drop table parted_sample, parted_sample_1, parted_sample_2;
diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql
index e3e9e34895..d43b75c4a7 100644
--- a/src/test/regress/sql/inherit.sql
+++ b/src/test/regress/sql/inherit.sql
@@ -128,6 +128,34 @@ where bar.f1 = ss.f1;
select tableoid::regclass::text as relname, bar.* from bar order by 1,2;
+-- Check UPDATE with *partitioned* inherited target and an appendrel subquery
+create table some_tab (a int);
+insert into some_tab values (0);
+create table some_tab_child () inherits (some_tab);
+insert into some_tab_child values (1);
+create table parted_tab (a int, b char) partition by list (a);
+create table parted_tab_part1 partition of parted_tab for values in (1);
+create table parted_tab_part2 partition of parted_tab for values in (2);
+create table parted_tab_part3 partition of parted_tab for values in (3);
+insert into parted_tab values (1, 'a'), (2, 'a'), (3, 'a');
+
+update parted_tab set b = 'b'
+from
+ (select a from some_tab union all select a+1 from some_tab) ss (a)
+where parted_tab.a = ss.a;
+select tableoid::regclass::text as relname, parted_tab.* from parted_tab order by 1,2;
+
+truncate parted_tab;
+insert into parted_tab values (1, 'a'), (2, 'a'), (3, 'a');
+update parted_tab set b = 'b'
+from
+ (select 0 from parted_tab union all select 1 from parted_tab) ss (a)
+where parted_tab.a = ss.a;
+select tableoid::regclass::text as relname, parted_tab.* from parted_tab order by 1,2;
+
+drop table parted_tab;
+drop table some_tab cascade;
+
/* Test multiple inheritance of column defaults */
CREATE TABLE firstparent (tomorrow date default now()::date + 1);
--
2.11.0
[text/x-diff] 0002-Do-not-allocate-storage-for-partitioned-tables.patch (3.1K, ../../b7f2d81d-9c9b-ba4e-5e00-edf626567256@lab.ntt.co.jp/3-0002-Do-not-allocate-storage-for-partitioned-tables.patch)
download | inline diff:
From 4b1074ae7b11fa92a2740505a278c2d18365cfdc Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Tue, 24 Jan 2017 14:22:34 +0900
Subject: [PATCH 2/2] Do not allocate storage for partitioned tables.
Currently, it is not possible to insert any data into a partitioned
table. So, they're empty at all times, which means it is wasteful to
allocate relfilenode and related storage objects.
---
src/backend/access/common/reloptions.c | 3 +--
src/backend/catalog/heap.c | 17 ++++++++++-------
2 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 72e12532ab..d3b847e2e5 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -967,7 +967,6 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
case RELKIND_RELATION:
case RELKIND_TOASTVALUE:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
options = heap_reloptions(classForm->relkind, datum, false);
break;
case RELKIND_VIEW:
@@ -977,6 +976,7 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
options = index_reloptions(amoptions, datum, false);
break;
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
options = NULL;
break;
default:
@@ -1418,7 +1418,6 @@ heap_reloptions(char relkind, Datum reloptions, bool validate)
return (bytea *) rdopts;
case RELKIND_RELATION:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
default:
/* other relkinds are not supported */
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 41c0056556..2f5090b183 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -291,6 +291,7 @@ heap_create(const char *relname,
case RELKIND_VIEW:
case RELKIND_COMPOSITE_TYPE:
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
create_storage = false;
/*
@@ -1345,14 +1346,13 @@ heap_create_with_catalog(const char *relname,
if (oncommit != ONCOMMIT_NOOP)
register_on_commit_action(relid, oncommit);
- if (relpersistence == RELPERSISTENCE_UNLOGGED)
- {
- Assert(relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW ||
- relkind == RELKIND_TOASTVALUE ||
- relkind == RELKIND_PARTITIONED_TABLE);
-
+ /*
+ * We do not want to create any storage objects for a partitioned
+ * table, including the init fork.
+ */
+ if (relpersistence == RELPERSISTENCE_UNLOGGED &&
+ relkind != RELKIND_PARTITIONED_TABLE)
heap_create_init_fork(new_rel_desc);
- }
/*
* ok, the relation has been cataloged, so close our relations and return
@@ -1376,6 +1376,9 @@ heap_create_with_catalog(const char *relname,
void
heap_create_init_fork(Relation rel)
{
+ Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
+ rel->rd_rel->relkind == RELKIND_MATVIEW ||
+ rel->rd_rel->relkind == RELKIND_TOASTVALUE);
RelationOpenSmgr(rel);
smgrcreate(rel->rd_smgr, INIT_FORKNUM, false);
log_smgrcreate(&rel->rd_smgr->smgr_rnode.node, INIT_FORKNUM);
--
2.11.0
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-03-16 13:16 ` Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
1 sibling, 1 reply; 96+ messages in thread
From: Robert Haas @ 2017-03-16 13:16 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; Michael Paquier <michael.paquier@gmail.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On Thu, Mar 16, 2017 at 6:03 AM, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
> I think we'll need to store *somewhere* the mapping of which inh=false
> partitioned table RTE is the child of which inh=true (IOW, parent)
> partitioned table RTE.
I mean, for the children you're going to scan, that seems to be
necessary so that you can do things like translate targetlists to use
the correct varno. But for the children you're not going to scan,
well, you need to know which ones they are so you can lock them, but
do you really need the parent-child mappings? Or just a list of which
ones there are?
> I've come to think that AppendRelInfos, although
> contain extraneous information that won't be used, are better than
> inventing something new altogether for time being. AppendRelInfos are
> referred to a few times by query_planner() steps before we eventually get
> to either set_append_rel_pathlist() or inheritance_planner(), so not
> changing that approach seems less worrisome for now. So now if we both
> create child RTEs and AppendRelInfos for the partitioned tables, we don't
> need to change expand_inherited_rtentry() at all with this patch.
> Finally, set_append_rel_size/pathlist() and inheritance_planner() skip the
> child partitioned table RTEs, because no path/plan need to be created. We
> can do away with having to create RelOptInfos for child partitioned table
> RTEs, which I found to be not that invasive.
Yes, but on the flip side, you're having to add code in a lot of
places -- I think I counted 7 -- where you turn around and ignore
those AppendRelInfos. That's a lot; how do we know we've got them
all? I'm not sure what the patch would look like the other way, but
I'm hoping that you could just keep the list of partitioned table RTIs
someplace that mostly gets ignored, and then all of that special
handling could be ripped out.
> Append node elision does not occur in the one-child case. With the patch:
Oh, OK. Somehow the commit message you included led me to the
contrary conclusion.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
@ 2017-03-17 08:57 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-20 16:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
0 siblings, 1 reply; 96+ messages in thread
From: Amit Langote @ 2017-03-17 08:57 UTC (permalink / raw)
To: Robert Haas <robertmhaas@gmail.com>; +Cc: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; Michael Paquier <michael.paquier@gmail.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On 2017/03/16 22:16, Robert Haas wrote:
> On Thu, Mar 16, 2017 at 6:03 AM, Amit Langote
> <Langote_Amit_f8@lab.ntt.co.jp> wrote:
>> I think we'll need to store *somewhere* the mapping of which inh=false
>> partitioned table RTE is the child of which inh=true (IOW, parent)
>> partitioned table RTE.
>
> I mean, for the children you're going to scan, that seems to be
> necessary so that you can do things like translate targetlists to use
> the correct varno. But for the children you're not going to scan,
> well, you need to know which ones they are so you can lock them, but
> do you really need the parent-child mappings? Or just a list of which
> ones there are?
I thought we'd want to keep the RT indexes segregated per controlling
node, which is why we'd want to store the mapping somehow. There may be
multiple partitioned tables in a query and one of them might be the result
relation. If we propagate all of them in one list to the executor,
InitPlan wouldn't know which ones are target relations, for example. But
I guess you don't mean passing all of them in one big list to the executor.
>> I've come to think that AppendRelInfos, although
>> contain extraneous information that won't be used, are better than
>> inventing something new altogether for time being. AppendRelInfos are
>> referred to a few times by query_planner() steps before we eventually get
>> to either set_append_rel_pathlist() or inheritance_planner(), so not
>> changing that approach seems less worrisome for now. So now if we both
>> create child RTEs and AppendRelInfos for the partitioned tables, we don't
>> need to change expand_inherited_rtentry() at all with this patch.
>> Finally, set_append_rel_size/pathlist() and inheritance_planner() skip the
>> child partitioned table RTEs, because no path/plan need to be created. We
>> can do away with having to create RelOptInfos for child partitioned table
>> RTEs, which I found to be not that invasive.
>
> Yes, but on the flip side, you're having to add code in a lot of
> places -- I think I counted 7 -- where you turn around and ignore
> those AppendRelInfos.
Perhaps you were looking at the previous version with "minimal" appinfos
containing the child_is_partitioned field? Following are the instances in
the latest patch posted yesterday:
- In set_append_re_size, do not count the partitioned child tables
- In set_append_rel_pathlist, do not create paths, but add to the list of
the partitioned tables to be included in the final Append path
- In create_lateral_join_info(), no need to propagate lateral join info to
partitioned child tables
- In inheritance_planner, no need to create plans for partitioned child
tables, but add to the list of the partitioned tables to be included in
the final ModifyTable path
In the previous version, because AppendRelInfo structure was itself
modified, there were more instances because more places would need to know
about the new kinds of appinfos (the minimal ones), which isn't the case
with the latest patch. Although admittedly, there will be a lot of
useless manipulation of those appinfos whose only purpose is to carry the
parent-child relid mapping up to where we finally consume that
information. Anyway, I've tried to implement an approach that doesn't
create AppendRelInfos for partitioned child tables as described below.
> That's a lot; how do we know we've got them
> all? I'm not sure what the patch would look like the other way, but
> I'm hoping that you could just keep the list of partitioned table RTIs
> someplace that mostly gets ignored, and then all of that special
> handling could be ripped out.
Since we'll want to save the RT indexes when we create child RTEs, that is
in expand_inherited_rtentry(), we'd do use a data structure that parallels
root->append_rel_list. The structure might consist of a the parent_relid
and a list of partitioned child RT indexes. Since we build this
information early during subquery_planner() it might equally be subject to
errors of omission, although that somehow sounds less likely.
I've tried to implement something like that in the attached updated 0001.
The mapping structure PartitionedChildRelInfo (a Node in fact) consists of
parent_relid and the list of partitioned child RT indexes. A global list
of these nodes is maintained in the root PlannerInfo called pcinfo_list.
In set_append_rel_pathlist() and inheritance_planner(), we search the
aforementioned list and copy the correct list to
Append/MergeAppend/ModifyTable path created for the parent. Thoughts?
I also noticed that PlanRowMarks that are created by
expand_inherited_rtentry() for partitioned child tables are problematic -
they must somehow be ignored in the executor. One way to do that is to
set isParent (making it a dummy entry) when initializing them, which is
what the patch does. Comment is updated to say that just like inheritance
parent relations, PlanRowMarks for partitioned child tables are also
marked as dummy.
Thanks,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Attachments:
[text/x-diff] 0001-Avoid-creating-scan-nodes-for-partitioned-tables.patch (64.5K, ../../ac0aac85-91a4-3079-d859-f2deb59df4ca@lab.ntt.co.jp/2-0001-Avoid-creating-scan-nodes-for-partitioned-tables.patch)
download | inline diff:
From dc44fa6e20180402641c39b815681dd1611bd102 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Fri, 10 Mar 2017 13:48:31 +0900
Subject: [PATCH 1/2] Avoid creating scan nodes for partitioned tables
There are quite a few changes here:
* Currently, we create scan nodes for inheritance parents in their role
as an inheritance set member. Partitioned tables do not contain any
data, so it's useless to create scan nodes for them. So, it's not
necessary to create AppendRelInfos for partitioned child tables in
expand_inherited_rtentry(). Although, create the RTEs and record the
RT indexes in a list. The list is associated with the parent_relid
using the new PartitionedChildRelInfo nodes, which are kept in a global
list called pcinfo_list in the root PlannerInfo, similar to
append_rel_list. For a given parent RTE set_append_rel_pathlist and
inheritance_planner() must copy the aforementioned list of partitioned
child RT indexes to Append/MergeAppend and ModifyTable paths,
respectively. The list is then carried over to a new field called
partitioned_rels in Append, MergeAppend, and ModifyTable nodes.
* For partitioned parent RTEs with inh=false, set_rel_size() must not
try to do set_plain_rel_size(). Instead mark such rels as "dummy",
because they are empty. Happens with partitioned tables without any
leaf partitions.
* In case of UPDATE/DELETE on a partitioned table, executor can already
know the leaf result relations via PlannedStmt.resultRelations, but
not the non-leaf partitioned tables. InitPlan must lock *all* the
result relations before initializing the plan tree to avoid lock
upgrade hazards, so we must include non-leaf result relations as well.
For that add a new field nonleafResultRelations to PlannedStmt, which
is intitialized by copying ModifyTable.partitioned_rels.
* PlanRowMarks for partitioned child tables are created with isParent
set to true so that executor ignores them. However those tables must
be locked with the appropriate lockmode by noticing that they exist,
even if no ExecRowMarks are created. InitPlan() punts on those;
instead it is the first Append or MergeAppend that's initialized that
refers to those table which locks them appropriately.
* In inheritance_planner(), set ModifyTable.nominalRelation to parent RT
index in the partitioned inheritance parent case, so that EXPLAIN uses
the root tables's original RT index to label a given ModifyTable node.
Regression test outputs are adjusted to match the new plan shape.
---
src/backend/executor/execMain.c | 22 ++++-
src/backend/executor/execParallel.c | 1 +
src/backend/executor/execUtils.c | 58 ++++++++++++
src/backend/executor/nodeAppend.c | 6 ++
src/backend/executor/nodeMergeAppend.c | 6 ++
src/backend/executor/nodeModifyTable.c | 22 ++++-
src/backend/nodes/copyfuncs.c | 21 +++++
src/backend/nodes/equalfuncs.c | 12 +++
src/backend/nodes/outfuncs.c | 21 +++++
src/backend/nodes/readfuncs.c | 4 +
src/backend/optimizer/path/allpaths.c | 58 +++++++++---
src/backend/optimizer/path/joinrels.c | 2 +-
src/backend/optimizer/plan/createplan.c | 14 ++-
src/backend/optimizer/plan/planner.c | 70 +++++++++++---
src/backend/optimizer/plan/setrefs.c | 15 +++
src/backend/optimizer/prep/prepunion.c | 103 ++++++++++++++-------
src/backend/optimizer/util/pathnode.c | 10 +-
src/backend/utils/cache/plancache.c | 3 +-
src/include/executor/executor.h | 1 +
src/include/nodes/nodes.h | 1 +
src/include/nodes/plannodes.h | 20 +++-
src/include/nodes/relation.h | 25 +++++
src/include/optimizer/pathnode.h | 8 +-
src/test/regress/expected/inherit.out | 147 +++++++++++++-----------------
src/test/regress/expected/tablesample.out | 4 +-
src/test/regress/sql/inherit.sql | 28 ++++++
26 files changed, 519 insertions(+), 163 deletions(-)
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index f5cd65d8a0..c68ba24d19 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -844,6 +844,22 @@ InitPlan(QueryDesc *queryDesc, int eflags)
estate->es_num_result_relations = numResultRelations;
/* es_result_relation_info is NULL except when within ModifyTable */
estate->es_result_relation_info = NULL;
+
+ /*
+ * In the partitioned table case, lock the non-leaf tables too.
+ * We don't need ResultRelInfos for them.
+ */
+ if (plannedstmt->nonleafResultRelations)
+ {
+ foreach(l, plannedstmt->nonleafResultRelations)
+ {
+ Index resultRelationIndex = lfirst_int(l);
+ Oid resultRelationOid;
+
+ resultRelationOid = getrelid(resultRelationIndex, rangeTable);
+ LockRelationOid(resultRelationOid, RowExclusiveLock);
+ }
+ }
}
else
{
@@ -858,7 +874,11 @@ InitPlan(QueryDesc *queryDesc, int eflags)
/*
* Similarly, we have to lock relations selected FOR [KEY] UPDATE/SHARE
* before we initialize the plan tree, else we'd be risking lock upgrades.
- * While we are at it, build the ExecRowMark list.
+ * While we are at it, build the ExecRowMark list. Any partitioned child
+ * table will be locked by the first Append or MergeAppend node that
+ * references it. (Note that RowMarks corresponding to partitioned child
+ * tables are present in the same list as others viz.
+ * plannedstmt->rowMarks.)
*/
estate->es_rowMarks = NIL;
foreach(l, plannedstmt->rowMarks)
diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c
index a1289e5f12..86db73be43 100644
--- a/src/backend/executor/execParallel.c
+++ b/src/backend/executor/execParallel.c
@@ -161,6 +161,7 @@ ExecSerializePlan(Plan *plan, EState *estate)
pstmt->planTree = plan;
pstmt->rtable = estate->es_range_table;
pstmt->resultRelations = NIL;
+ pstmt->nonleafResultRelations = NIL;
pstmt->subplans = estate->es_plannedstmt->subplans;
pstmt->rewindPlanIDs = NULL;
pstmt->rowMarks = NIL;
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 3d6a3801c0..3e842aaa27 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -43,6 +43,7 @@
#include "executor/executor.h"
#include "nodes/nodeFuncs.h"
#include "parser/parsetree.h"
+#include "storage/lmgr.h"
#include "utils/memutils.h"
#include "utils/rel.h"
@@ -953,3 +954,60 @@ ShutdownExprContext(ExprContext *econtext, bool isCommit)
MemoryContextSwitchTo(oldcontext);
}
+
+/*
+ * ExecLockNonLeafAppendTables
+ *
+ * Locates using the RT indexes and lock (if needed) the non-leaf tables in
+ * the partition tree controlled by a given Append or MergeAppend node.
+ */
+void
+ExecLockNonLeafAppendTables(List *partitioned_rels, EState *estate)
+{
+ PlannedStmt *stmt = estate->es_plannedstmt;
+ ListCell *lc;
+
+ if (partitioned_rels == NIL)
+ return;
+
+ foreach(lc, partitioned_rels)
+ {
+ ListCell *l;
+ Index rti = lfirst_int(lc);
+ bool is_result_rel = false;
+ Oid relid = getrelid(rti, estate->es_range_table);
+
+ /* If this is a result relation, already locked in InitPlan */
+ foreach(l, stmt->nonleafResultRelations)
+ {
+ if (rti == lfirst_int(l))
+ {
+ is_result_rel = true;
+ break;
+ }
+ }
+
+ /*
+ * Not a result relation; check if there is a RowMark that requires
+ * taking a RowShareLock on this rel.
+ */
+ if (!is_result_rel)
+ {
+ PlanRowMark *rc = NULL;
+
+ foreach(l, stmt->rowMarks)
+ {
+ if (((PlanRowMark *) lfirst(l))->rti == rti)
+ {
+ rc = lfirst(l);
+ break;
+ }
+ }
+
+ if (rc && RowMarkRequiresRowShareLock(rc->markType))
+ LockRelationOid(relid, RowShareLock);
+ else
+ LockRelationOid(relid, AccessShareLock);
+ }
+ }
+}
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index 6986caee6b..de6e4d6fee 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -129,6 +129,12 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
Assert(!(eflags & EXEC_FLAG_MARK));
/*
+ * Lock the non-leaf tables in the partition tree controlled by this
+ * node. It's a no-op for non-partitioned parent tables.
+ */
+ ExecLockNonLeafAppendTables(node->partitioned_rels, estate);
+
+ /*
* Set up empty vector of subplan states
*/
nplans = list_length(node->appendplans);
diff --git a/src/backend/executor/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c
index 7a20bf07a4..8a2e78266b 100644
--- a/src/backend/executor/nodeMergeAppend.c
+++ b/src/backend/executor/nodeMergeAppend.c
@@ -72,6 +72,12 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
/*
+ * Lock the non-leaf tables in the partition tree controlled by this
+ * node. It's a no-op for non-partitioned parent tables.
+ */
+ ExecLockNonLeafAppendTables(node->partitioned_rels, estate);
+
+ /*
* Set up empty vector of subplan states
*/
nplans = list_length(node->mergeplans);
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 95e158970c..efbf19e491 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -45,6 +45,7 @@
#include "foreign/fdwapi.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
+#include "parser/parsetree.h"
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
#include "utils/builtins.h"
@@ -1725,8 +1726,20 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
estate->es_result_relation_info = saved_resultRelInfo;
+ /* The root table RT index is at the head of the partitioned_rels list */
+ if (node->partitioned_rels)
+ {
+ Index root_rti;
+ Oid root_oid;
+
+ root_rti = linitial_int(node->partitioned_rels);
+ root_oid = getrelid(root_rti, estate->es_range_table);
+ rel = heap_open(root_oid, NoLock); /* locked by InitPlan */
+ }
+ else
+ rel = mtstate->resultRelInfo->ri_RelationDesc;
+
/* Build state for INSERT tuple routing */
- rel = mtstate->resultRelInfo->ri_RelationDesc;
if (operation == CMD_INSERT &&
rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
{
@@ -1898,6 +1911,13 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
}
/*
+ * Close the root partitioned rel if we opened it above, but keep the
+ * lock.
+ */
+ if (rel != mtstate->resultRelInfo->ri_RelationDesc)
+ heap_close(rel, NoLock);
+
+ /*
* If needed, Initialize target list, projection and qual for ON CONFLICT
* DO UPDATE.
*/
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 25fd051d6e..7cf31b35fd 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -90,6 +90,7 @@ _copyPlannedStmt(const PlannedStmt *from)
COPY_NODE_FIELD(planTree);
COPY_NODE_FIELD(rtable);
COPY_NODE_FIELD(resultRelations);
+ COPY_NODE_FIELD(nonleafResultRelations);
COPY_NODE_FIELD(subplans);
COPY_BITMAPSET_FIELD(rewindPlanIDs);
COPY_NODE_FIELD(rowMarks);
@@ -200,6 +201,7 @@ _copyModifyTable(const ModifyTable *from)
COPY_SCALAR_FIELD(operation);
COPY_SCALAR_FIELD(canSetTag);
COPY_SCALAR_FIELD(nominalRelation);
+ COPY_NODE_FIELD(partitioned_rels);
COPY_NODE_FIELD(resultRelations);
COPY_SCALAR_FIELD(resultRelIndex);
COPY_NODE_FIELD(plans);
@@ -235,6 +237,7 @@ _copyAppend(const Append *from)
/*
* copy remainder of node
*/
+ COPY_NODE_FIELD(partitioned_rels);
COPY_NODE_FIELD(appendplans);
return newnode;
@@ -256,6 +259,7 @@ _copyMergeAppend(const MergeAppend *from)
/*
* copy remainder of node
*/
+ COPY_NODE_FIELD(partitioned_rels);
COPY_NODE_FIELD(mergeplans);
COPY_SCALAR_FIELD(numCols);
COPY_POINTER_FIELD(sortColIdx, from->numCols * sizeof(AttrNumber));
@@ -2205,6 +2209,20 @@ _copyAppendRelInfo(const AppendRelInfo *from)
}
/*
+ * _copyPartitionedChildRelInfo
+ */
+static PartitionedChildRelInfo *
+_copyPartitionedChildRelInfo(const PartitionedChildRelInfo *from)
+{
+ PartitionedChildRelInfo *newnode = makeNode(PartitionedChildRelInfo);
+
+ COPY_SCALAR_FIELD(parent_relid);
+ COPY_NODE_FIELD(child_rels);
+
+ return newnode;
+}
+
+/*
* _copyPlaceHolderInfo
*/
static PlaceHolderInfo *
@@ -4892,6 +4910,9 @@ copyObject(const void *from)
case T_AppendRelInfo:
retval = _copyAppendRelInfo(from);
break;
+ case T_PartitionedChildRelInfo:
+ retval = _copyPartitionedChildRelInfo(from);
+ break;
case T_PlaceHolderInfo:
retval = _copyPlaceHolderInfo(from);
break;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 67529e3f86..d444222e38 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -896,6 +896,15 @@ _equalAppendRelInfo(const AppendRelInfo *a, const AppendRelInfo *b)
}
static bool
+_equalPartitionedChildRelInfo(const PartitionedChildRelInfo *a, const PartitionedChildRelInfo *b)
+{
+ COMPARE_SCALAR_FIELD(parent_relid);
+ COMPARE_NODE_FIELD(child_rels);
+
+ return true;
+}
+
+static bool
_equalPlaceHolderInfo(const PlaceHolderInfo *a, const PlaceHolderInfo *b)
{
COMPARE_SCALAR_FIELD(phid);
@@ -3102,6 +3111,9 @@ equal(const void *a, const void *b)
case T_AppendRelInfo:
retval = _equalAppendRelInfo(a, b);
break;
+ case T_PartitionedChildRelInfo:
+ retval = _equalPartitionedChildRelInfo(a, b);
+ break;
case T_PlaceHolderInfo:
retval = _equalPlaceHolderInfo(a, b);
break;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 7418fbeded..1b9005fa53 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -252,6 +252,7 @@ _outPlannedStmt(StringInfo str, const PlannedStmt *node)
WRITE_NODE_FIELD(planTree);
WRITE_NODE_FIELD(rtable);
WRITE_NODE_FIELD(resultRelations);
+ WRITE_NODE_FIELD(nonleafResultRelations);
WRITE_NODE_FIELD(subplans);
WRITE_BITMAPSET_FIELD(rewindPlanIDs);
WRITE_NODE_FIELD(rowMarks);
@@ -344,6 +345,7 @@ _outModifyTable(StringInfo str, const ModifyTable *node)
WRITE_ENUM_FIELD(operation, CmdType);
WRITE_BOOL_FIELD(canSetTag);
WRITE_UINT_FIELD(nominalRelation);
+ WRITE_NODE_FIELD(partitioned_rels);
WRITE_NODE_FIELD(resultRelations);
WRITE_INT_FIELD(resultRelIndex);
WRITE_NODE_FIELD(plans);
@@ -368,6 +370,7 @@ _outAppend(StringInfo str, const Append *node)
_outPlanInfo(str, (const Plan *) node);
+ WRITE_NODE_FIELD(partitioned_rels);
WRITE_NODE_FIELD(appendplans);
}
@@ -380,6 +383,7 @@ _outMergeAppend(StringInfo str, const MergeAppend *node)
_outPlanInfo(str, (const Plan *) node);
+ WRITE_NODE_FIELD(partitioned_rels);
WRITE_NODE_FIELD(mergeplans);
WRITE_INT_FIELD(numCols);
@@ -1808,6 +1812,7 @@ _outAppendPath(StringInfo str, const AppendPath *node)
_outPathInfo(str, (const Path *) node);
+ WRITE_NODE_FIELD(partitioned_rels);
WRITE_NODE_FIELD(subpaths);
}
@@ -1818,6 +1823,7 @@ _outMergeAppendPath(StringInfo str, const MergeAppendPath *node)
_outPathInfo(str, (const Path *) node);
+ WRITE_NODE_FIELD(partitioned_rels);
WRITE_NODE_FIELD(subpaths);
WRITE_FLOAT_FIELD(limit_tuples, "%.0f");
}
@@ -2023,6 +2029,7 @@ _outModifyTablePath(StringInfo str, const ModifyTablePath *node)
WRITE_ENUM_FIELD(operation, CmdType);
WRITE_BOOL_FIELD(canSetTag);
WRITE_UINT_FIELD(nominalRelation);
+ WRITE_NODE_FIELD(partitioned_rels);
WRITE_NODE_FIELD(resultRelations);
WRITE_NODE_FIELD(subpaths);
WRITE_NODE_FIELD(subroots);
@@ -2099,6 +2106,7 @@ _outPlannerGlobal(StringInfo str, const PlannerGlobal *node)
WRITE_NODE_FIELD(finalrtable);
WRITE_NODE_FIELD(finalrowmarks);
WRITE_NODE_FIELD(resultRelations);
+ WRITE_NODE_FIELD(nonleafResultRelations);
WRITE_NODE_FIELD(relationOids);
WRITE_NODE_FIELD(invalItems);
WRITE_INT_FIELD(nParamExec);
@@ -2137,6 +2145,7 @@ _outPlannerInfo(StringInfo str, const PlannerInfo *node)
WRITE_NODE_FIELD(full_join_clauses);
WRITE_NODE_FIELD(join_info_list);
WRITE_NODE_FIELD(append_rel_list);
+ WRITE_NODE_FIELD(pcinfo_list);
WRITE_NODE_FIELD(rowMarks);
WRITE_NODE_FIELD(placeholder_list);
WRITE_NODE_FIELD(fkey_list);
@@ -2420,6 +2429,15 @@ _outAppendRelInfo(StringInfo str, const AppendRelInfo *node)
}
static void
+_outPartitionedChildRelInfo(StringInfo str, const PartitionedChildRelInfo *node)
+{
+ WRITE_NODE_TYPE("PARTITIONEDCHILDRELINFO");
+
+ WRITE_UINT_FIELD(parent_relid);
+ WRITE_NODE_FIELD(child_rels);
+}
+
+static void
_outPlaceHolderInfo(StringInfo str, const PlaceHolderInfo *node)
{
WRITE_NODE_TYPE("PLACEHOLDERINFO");
@@ -3906,6 +3924,9 @@ outNode(StringInfo str, const void *obj)
case T_AppendRelInfo:
_outAppendRelInfo(str, obj);
break;
+ case T_PartitionedChildRelInfo:
+ _outPartitionedChildRelInfo(str, obj);
+ break;
case T_PlaceHolderInfo:
_outPlaceHolderInfo(str, obj);
break;
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index d3bbc02f24..474f221a75 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1444,6 +1444,7 @@ _readPlannedStmt(void)
READ_NODE_FIELD(planTree);
READ_NODE_FIELD(rtable);
READ_NODE_FIELD(resultRelations);
+ READ_NODE_FIELD(nonleafResultRelations);
READ_NODE_FIELD(subplans);
READ_BITMAPSET_FIELD(rewindPlanIDs);
READ_NODE_FIELD(rowMarks);
@@ -1535,6 +1536,7 @@ _readModifyTable(void)
READ_ENUM_FIELD(operation, CmdType);
READ_BOOL_FIELD(canSetTag);
READ_UINT_FIELD(nominalRelation);
+ READ_NODE_FIELD(partitioned_rels);
READ_NODE_FIELD(resultRelations);
READ_INT_FIELD(resultRelIndex);
READ_NODE_FIELD(plans);
@@ -1564,6 +1566,7 @@ _readAppend(void)
ReadCommonPlan(&local_node->plan);
+ READ_NODE_FIELD(partitioned_rels);
READ_NODE_FIELD(appendplans);
READ_DONE();
@@ -1579,6 +1582,7 @@ _readMergeAppend(void)
ReadCommonPlan(&local_node->plan);
+ READ_NODE_FIELD(partitioned_rels);
READ_NODE_FIELD(mergeplans);
READ_INT_FIELD(numCols);
READ_ATTRNUMBER_ARRAY(sortColIdx, local_node->numCols);
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 43bfd23804..e6aa626ab1 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -95,7 +95,8 @@ static void set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
Index rti, RangeTblEntry *rte);
static void generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
List *live_childrels,
- List *all_child_pathkeys);
+ List *all_child_pathkeys,
+ List *partitioned_rels);
static Path *get_cheapest_parameterized_child_path(PlannerInfo *root,
RelOptInfo *rel,
Relids required_outer);
@@ -130,7 +131,7 @@ static void recurse_push_qual(Node *setOp, Query *topquery,
RangeTblEntry *rte, Index rti, Node *qual);
static void remove_unused_subquery_outputs(Query *subquery, RelOptInfo *rel);
static void add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
- List *live_childrels);
+ List *live_childrels, List *partitioned_rels);
/*
@@ -346,6 +347,14 @@ set_rel_size(PlannerInfo *root, RelOptInfo *rel,
/* Foreign table */
set_foreign_size(root, rel, rte);
}
+ else if (rte->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ /*
+ * A partitioned table without leaf partitions is marked
+ * as a dummy rel.
+ */
+ set_dummy_rel_pathlist(rel);
+ }
else if (rte->tablesample != NULL)
{
/* Sampled relation */
@@ -1185,6 +1194,7 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
int parentRTindex = rti;
List *live_childrels = NIL;
ListCell *l;
+ List *partitioned_rels = NIL;
/*
* Generate access paths for each member relation, and remember the
@@ -1232,8 +1242,26 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
live_childrels = lappend(live_childrels, childrel);
}
+ /*
+ * Don't forget to collect the partitioned child tables, if the parent is
+ * partitioned.
+ */
+ if (rte->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ foreach(l, root->pcinfo_list)
+ {
+ PartitionedChildRelInfo *pc = lfirst(l);
+
+ if (pc->parent_relid == rti)
+ {
+ partitioned_rels = pc->child_rels;
+ break;
+ }
+ }
+ }
+
/* Add paths to the "append" relation. */
- add_paths_to_append_rel(root, rel, live_childrels);
+ add_paths_to_append_rel(root, rel, live_childrels, partitioned_rels);
}
@@ -1250,7 +1278,7 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
*/
static void
add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
- List *live_childrels)
+ List *live_childrels, List *partitioned_rels)
{
List *subpaths = NIL;
bool subpaths_valid = true;
@@ -1359,7 +1387,8 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
* if we have zero or one live subpath due to constraint exclusion.)
*/
if (subpaths_valid)
- add_path(rel, (Path *) create_append_path(rel, subpaths, NULL, 0));
+ add_path(rel, (Path *) create_append_path(rel, subpaths, NULL, 0,
+ partitioned_rels));
/*
* Consider an append of partial unordered, unparameterized partial paths.
@@ -1386,7 +1415,7 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
/* Generate a partial append path. */
appendpath = create_append_path(rel, partial_subpaths, NULL,
- parallel_workers);
+ parallel_workers, partitioned_rels);
add_partial_path(rel, (Path *) appendpath);
}
@@ -1396,7 +1425,8 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
*/
if (subpaths_valid)
generate_mergeappend_paths(root, rel, live_childrels,
- all_child_pathkeys);
+ all_child_pathkeys,
+ partitioned_rels);
/*
* Build Append paths for each parameterization seen among the child rels.
@@ -1438,7 +1468,8 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
if (subpaths_valid)
add_path(rel, (Path *)
- create_append_path(rel, subpaths, required_outer, 0));
+ create_append_path(rel, subpaths, required_outer, 0,
+ partitioned_rels));
}
}
@@ -1468,7 +1499,8 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
static void
generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
List *live_childrels,
- List *all_child_pathkeys)
+ List *all_child_pathkeys,
+ List *partitioned_rels)
{
ListCell *lcp;
@@ -1532,13 +1564,15 @@ generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
rel,
startup_subpaths,
pathkeys,
- NULL));
+ NULL,
+ partitioned_rels));
if (startup_neq_total)
add_path(rel, (Path *) create_merge_append_path(root,
rel,
total_subpaths,
pathkeys,
- NULL));
+ NULL,
+ partitioned_rels));
}
}
@@ -1671,7 +1705,7 @@ set_dummy_rel_pathlist(RelOptInfo *rel)
rel->pathlist = NIL;
rel->partial_pathlist = NIL;
- add_path(rel, (Path *) create_append_path(rel, NIL, NULL, 0));
+ add_path(rel, (Path *) create_append_path(rel, NIL, NULL, 0, NIL));
/*
* We set the cheapest path immediately, to ensure that IS_DUMMY_REL()
diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c
index 0551668976..6a0c67b9ab 100644
--- a/src/backend/optimizer/path/joinrels.c
+++ b/src/backend/optimizer/path/joinrels.c
@@ -1217,7 +1217,7 @@ mark_dummy_rel(RelOptInfo *rel)
rel->partial_pathlist = NIL;
/* Set up the dummy path */
- add_path(rel, (Path *) create_append_path(rel, NIL, NULL, 0));
+ add_path(rel, (Path *) create_append_path(rel, NIL, NULL, 0, NIL));
/* Set or update cheapest_total_path and related fields */
set_cheapest(rel);
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 89e1946fc2..c80c9992c9 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -199,7 +199,7 @@ static CteScan *make_ctescan(List *qptlist, List *qpqual,
Index scanrelid, int ctePlanId, int cteParam);
static WorkTableScan *make_worktablescan(List *qptlist, List *qpqual,
Index scanrelid, int wtParam);
-static Append *make_append(List *appendplans, List *tlist);
+static Append *make_append(List *appendplans, List *tlist, List *partitioned_rels);
static RecursiveUnion *make_recursive_union(List *tlist,
Plan *lefttree,
Plan *righttree,
@@ -273,7 +273,7 @@ static Result *make_result(List *tlist, Node *resconstantqual, Plan *subplan);
static ProjectSet *make_project_set(List *tlist, Plan *subplan);
static ModifyTable *make_modifytable(PlannerInfo *root,
CmdType operation, bool canSetTag,
- Index nominalRelation,
+ Index nominalRelation, List *partitioned_rels,
List *resultRelations, List *subplans,
List *withCheckOptionLists, List *returningLists,
List *rowMarks, OnConflictExpr *onconflict, int epqParam);
@@ -1026,7 +1026,7 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path)
* parent-rel Vars it'll be asked to emit.
*/
- plan = make_append(subplans, tlist);
+ plan = make_append(subplans, tlist, best_path->partitioned_rels);
copy_generic_path_info(&plan->plan, (Path *) best_path);
@@ -1134,6 +1134,7 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path)
subplans = lappend(subplans, subplan);
}
+ node->partitioned_rels = best_path->partitioned_rels;
node->mergeplans = subplans;
return (Plan *) node;
@@ -2314,6 +2315,7 @@ create_modifytable_plan(PlannerInfo *root, ModifyTablePath *best_path)
best_path->operation,
best_path->canSetTag,
best_path->nominalRelation,
+ best_path->partitioned_rels,
best_path->resultRelations,
subplans,
best_path->withCheckOptionLists,
@@ -5161,7 +5163,7 @@ make_foreignscan(List *qptlist,
}
static Append *
-make_append(List *appendplans, List *tlist)
+make_append(List *appendplans, List *tlist, List *partitioned_rels)
{
Append *node = makeNode(Append);
Plan *plan = &node->plan;
@@ -5170,6 +5172,7 @@ make_append(List *appendplans, List *tlist)
plan->qual = NIL;
plan->lefttree = NULL;
plan->righttree = NULL;
+ node->partitioned_rels = partitioned_rels;
node->appendplans = appendplans;
return node;
@@ -6282,7 +6285,7 @@ make_project_set(List *tlist,
static ModifyTable *
make_modifytable(PlannerInfo *root,
CmdType operation, bool canSetTag,
- Index nominalRelation,
+ Index nominalRelation, List *partitioned_rels,
List *resultRelations, List *subplans,
List *withCheckOptionLists, List *returningLists,
List *rowMarks, OnConflictExpr *onconflict, int epqParam)
@@ -6308,6 +6311,7 @@ make_modifytable(PlannerInfo *root,
node->operation = operation;
node->canSetTag = canSetTag;
node->nominalRelation = nominalRelation;
+ node->partitioned_rels = partitioned_rels;
node->resultRelations = resultRelations;
node->resultRelIndex = -1; /* will be set correctly in setrefs.c */
node->plans = subplans;
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 02286d9c52..069ce9380b 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -212,6 +212,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
glob->finalrtable = NIL;
glob->finalrowmarks = NIL;
glob->resultRelations = NIL;
+ glob->nonleafResultRelations = NIL;
glob->relationOids = NIL;
glob->invalItems = NIL;
glob->nParamExec = 0;
@@ -380,6 +381,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
Assert(glob->finalrtable == NIL);
Assert(glob->finalrowmarks == NIL);
Assert(glob->resultRelations == NIL);
+ Assert(glob->nonleafResultRelations == NIL);
top_plan = set_plan_references(root, top_plan);
/* ... and the subplans (both regular subplans and initplans) */
Assert(list_length(glob->subplans) == list_length(glob->subroots));
@@ -405,6 +407,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
result->planTree = top_plan;
result->rtable = glob->finalrtable;
result->resultRelations = glob->resultRelations;
+ result->nonleafResultRelations = glob->nonleafResultRelations;
result->subplans = glob->subplans;
result->rewindPlanIDs = glob->rewindPlanIDs;
result->rowMarks = glob->finalrowmarks;
@@ -474,6 +477,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
root->multiexpr_params = NIL;
root->eq_classes = NIL;
root->append_rel_list = NIL;
+ root->pcinfo_list = NIL;
root->rowMarks = NIL;
memset(root->upper_rels, 0, sizeof(root->upper_rels));
memset(root->upper_targets, 0, sizeof(root->upper_targets));
@@ -1007,6 +1011,8 @@ inheritance_planner(PlannerInfo *root)
RelOptInfo *final_rel;
ListCell *lc;
Index rti;
+ RangeTblEntry *parent_rte;
+ List *partitioned_rels = NIL;
Assert(parse->commandType != CMD_INSERT);
@@ -1065,13 +1071,24 @@ inheritance_planner(PlannerInfo *root)
}
/*
+ * If the parent RTE is a partitioned table, we should use that as the
+ * nominal relation, because the RTEs added for partitioned tables
+ * (including the root parent) as child members of the inheritance set
+ * do not appear anywhere else in the plan. Situation is exactly the
+ * opposite in the case of non-partitioned inheritance parent as
+ * described below.
+ */
+ parent_rte = rt_fetch(parentRTindex, root->parse->rtable);
+ if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
+ nominalRelation = parentRTindex;
+
+ /*
* And now we can get on with generating a plan for each child table.
*/
foreach(lc, root->append_rel_list)
{
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
PlannerInfo *subroot;
- RangeTblEntry *parent_rte;
RangeTblEntry *child_rte;
RelOptInfo *sub_final_rel;
Path *subpath;
@@ -1216,15 +1233,25 @@ inheritance_planner(PlannerInfo *root)
grouping_planner(subroot, true, 0.0 /* retrieve all tuples */ );
/*
- * We'll use the first child relation (even if it's excluded) as the
- * nominal target relation of the ModifyTable node. Because of the
- * way expand_inherited_rtentry works, this should always be the RTE
- * representing the parent table in its role as a simple member of the
- * inheritance set. (It would be logically cleaner to use the
- * inheritance parent RTE as the nominal target; but since that RTE
- * will not be otherwise referenced in the plan, doing so would give
- * rise to confusing use of multiple aliases in EXPLAIN output for
- * what the user will think is the "same" table.)
+ * Set the nomimal target relation of the ModifyTable node if not
+ * already done. We use the inheritance parent RTE as the nominal
+ * target relation if it's a partitioned table (see just above this
+ * loop). In the non-partitioned parent case, we'll use the first
+ * child relation (even if it's excluded) as the nominal target
+ * relation. Because of the way expand_inherited_rtentry works, the
+ * latter should be the RTE representing the parent table in its role
+ * as a simple member of the inheritance set.
+ *
+ * It would be logically cleaner to *always* use the inheritance
+ * parent RTE as the nominal relation; but that RTE is not otherwise
+ * referenced in the plan in the non-partitioned inheritance case.
+ * Instead the duplicate child RTE created by expand_inherited_rtentry
+ * is used elsewhere in the plan, so using the original parent RTE
+ * would give rise to confusing use of multiple aliases in EXPLAIN
+ * output for what the user will think is the "same" table. OTOH,
+ * it's not a problem in the partitioned inheritance case, because
+ * the duplicate child RTE added for the parent does not appear
+ * anywhere else in the plan tree.
*/
if (nominalRelation < 0)
nominalRelation = appinfo->child_relid;
@@ -1298,6 +1325,24 @@ inheritance_planner(PlannerInfo *root)
Assert(!parse->onConflict);
}
+ /*
+ * Don't forget to collect the partitioned child tables, if the parent is
+ * partitioned.
+ */
+ if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ foreach(lc, root->pcinfo_list)
+ {
+ PartitionedChildRelInfo *pc = lfirst(lc);
+
+ if (pc->parent_relid == parentRTindex)
+ {
+ partitioned_rels = pc->child_rels;
+ break;
+ }
+ }
+ }
+
/* Result path must go into outer query's FINAL upperrel */
final_rel = fetch_upper_rel(root, UPPERREL_FINAL, NULL);
@@ -1351,6 +1396,7 @@ inheritance_planner(PlannerInfo *root)
parse->commandType,
parse->canSetTag,
nominalRelation,
+ partitioned_rels,
resultRelations,
subpaths,
subroots,
@@ -2046,6 +2092,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
parse->commandType,
parse->canSetTag,
parse->resultRelation,
+ NIL,
list_make1_int(parse->resultRelation),
list_make1(path),
list_make1(root),
@@ -3348,7 +3395,8 @@ create_grouping_paths(PlannerInfo *root,
create_append_path(grouped_rel,
paths,
NULL,
- 0);
+ 0,
+ NIL);
path->pathtarget = target;
}
else
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 5f3027e96f..892131343c 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -835,6 +835,10 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
splan->nominalRelation += rtoffset;
splan->exclRelRTI += rtoffset;
+ foreach(l, splan->partitioned_rels)
+ {
+ lfirst_int(l) += rtoffset;
+ }
foreach(l, splan->resultRelations)
{
lfirst_int(l) += rtoffset;
@@ -863,6 +867,9 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
root->glob->resultRelations =
list_concat(root->glob->resultRelations,
list_copy(splan->resultRelations));
+ root->glob->nonleafResultRelations =
+ list_concat(root->glob->nonleafResultRelations,
+ list_copy(splan->partitioned_rels));
}
break;
case T_Append:
@@ -875,6 +882,10 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
*/
set_dummy_tlist_references(plan, rtoffset);
Assert(splan->plan.qual == NIL);
+ foreach(l, splan->partitioned_rels)
+ {
+ lfirst_int(l) += rtoffset;
+ }
foreach(l, splan->appendplans)
{
lfirst(l) = set_plan_refs(root,
@@ -893,6 +904,10 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
*/
set_dummy_tlist_references(plan, rtoffset);
Assert(splan->plan.qual == NIL);
+ foreach(l, splan->partitioned_rels)
+ {
+ lfirst_int(l) += rtoffset;
+ }
foreach(l, splan->mergeplans)
{
lfirst(l) = set_plan_refs(root,
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 1389db18ba..4154edbf50 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -566,7 +566,7 @@ generate_union_path(SetOperationStmt *op, PlannerInfo *root,
/*
* Append the child results together.
*/
- path = (Path *) create_append_path(result_rel, pathlist, NULL, 0);
+ path = (Path *) create_append_path(result_rel, pathlist, NULL, 0, NIL);
/* We have to manually jam the right tlist into the path; ick */
path->pathtarget = create_pathtarget(root, tlist);
@@ -678,7 +678,7 @@ generate_nonunion_path(SetOperationStmt *op, PlannerInfo *root,
/*
* Append the child results together.
*/
- path = (Path *) create_append_path(result_rel, pathlist, NULL, 0);
+ path = (Path *) create_append_path(result_rel, pathlist, NULL, 0, NIL);
/* We have to manually jam the right tlist into the path; ick */
path->pathtarget = create_pathtarget(root, tlist);
@@ -1364,6 +1364,9 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
List *inhOIDs;
List *appinfos;
ListCell *l;
+ bool need_append;
+ PartitionedChildRelInfo *pcinfo;
+ List *partitioned_child_rels = NIL;
/* Does RT entry allow inheritance? */
if (!rte->inh)
@@ -1435,6 +1438,7 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
/* Scan the inheritance set and expand it */
appinfos = NIL;
+ need_append = false;
foreach(l, inhOIDs)
{
Oid childOID = lfirst_oid(l);
@@ -1483,36 +1487,46 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
childRTindex = list_length(parse->rtable);
/*
- * Build an AppendRelInfo for this parent and child.
+ * Build an AppendRelInfo for this parent and child, unless the child
+ * is a partitioned table.
*/
- appinfo = makeNode(AppendRelInfo);
- appinfo->parent_relid = rti;
- appinfo->child_relid = childRTindex;
- appinfo->parent_reltype = oldrelation->rd_rel->reltype;
- appinfo->child_reltype = newrelation->rd_rel->reltype;
- make_inh_translation_list(oldrelation, newrelation, childRTindex,
- &appinfo->translated_vars);
- appinfo->parent_reloid = parentOID;
- appinfos = lappend(appinfos, appinfo);
-
- /*
- * Translate the column permissions bitmaps to the child's attnums (we
- * have to build the translated_vars list before we can do this). But
- * if this is the parent table, leave copyObject's result alone.
- *
- * Note: we need to do this even though the executor won't run any
- * permissions checks on the child RTE. The insertedCols/updatedCols
- * bitmaps may be examined for trigger-firing purposes.
- */
- if (childOID != parentOID)
+ if (childrte->relkind != RELKIND_PARTITIONED_TABLE)
{
- childrte->selectedCols = translate_col_privs(rte->selectedCols,
+ need_append = true;
+ appinfo = makeNode(AppendRelInfo);
+ appinfo->parent_relid = rti;
+ appinfo->child_relid = childRTindex;
+ appinfo->parent_reltype = oldrelation->rd_rel->reltype;
+ appinfo->child_reltype = newrelation->rd_rel->reltype;
+ make_inh_translation_list(oldrelation, newrelation, childRTindex,
+ &appinfo->translated_vars);
+ appinfo->parent_reloid = parentOID;
+ appinfos = lappend(appinfos, appinfo);
+
+ /*
+ * Translate the column permissions bitmaps to the child's attnums
+ * (we have to build the translated_vars list before we can do
+ * this). But if this is the parent table, leave copyObject's
+ * result alone.
+ *
+ * Note: we need to do this even though the executor won't run any
+ * permissions checks on the child RTE. The
+ * insertedCols/updatedCols bitmaps may be examined for
+ * trigger-firing purposes.
+ */
+ if (childOID != parentOID)
+ {
+ childrte->selectedCols = translate_col_privs(rte->selectedCols,
appinfo->translated_vars);
- childrte->insertedCols = translate_col_privs(rte->insertedCols,
+ childrte->insertedCols = translate_col_privs(rte->insertedCols,
appinfo->translated_vars);
- childrte->updatedCols = translate_col_privs(rte->updatedCols,
+ childrte->updatedCols = translate_col_privs(rte->updatedCols,
appinfo->translated_vars);
+ }
}
+ else
+ partitioned_child_rels = lappend_int(partitioned_child_rels,
+ childRTindex);
/*
* Build a PlanRowMark if parent is marked FOR UPDATE/SHARE.
@@ -1529,7 +1543,13 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
newrc->allMarkTypes = (1 << newrc->markType);
newrc->strength = oldrc->strength;
newrc->waitPolicy = oldrc->waitPolicy;
- newrc->isParent = false;
+
+ /*
+ * We mark RowMarks for partitioned child tables as parent RowMarks
+ * so that the executor ignores them (except their existence means
+ * that the child tables be locked using appropriate mode).
+ */
+ newrc->isParent = childrte->relkind == RELKIND_PARTITIONED_TABLE;
/* Include child's rowmark type in parent's allMarkTypes */
oldrc->allMarkTypes |= newrc->allMarkTypes;
@@ -1545,18 +1565,37 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
heap_close(oldrelation, NoLock);
/*
- * If all the children were temp tables, pretend it's a non-inheritance
- * situation. The duplicate RTE we added for the parent table is
- * harmless, so we don't bother to get rid of it; ditto for the useless
- * PlanRowMark node.
+ * If all the children were temp tables or a partitioned parent did not
+ * have any leaf partitions, pretend it's a non-inheritance situation; we
+ * don't need Append node in that case. The duplicate RTE we added for
+ * the parent table in the non-partitioned parent case is harmless, so we
+ * don't bother to get rid of it; ditto for the useless PlanRowMark node.
*/
- if (list_length(appinfos) < 2)
+ if (!need_append)
{
/* Clear flag before returning */
rte->inh = false;
return;
}
+ /*
+ * We keep a list of objects in root, each of which maps a partitioned
+ * parent RT index to the list of RT indexes of its partitioned child
+ * tables. When creating an Append or a ModifyTable path for the parent,
+ * we copy the child RT index list verbatim to the path so that it could
+ * be carried over to the executor so that the latter could identify
+ * the partitioned child tables.
+ */
+ if (partitioned_child_rels != NIL)
+ {
+ pcinfo = makeNode(PartitionedChildRelInfo);
+
+ Assert(rte->relkind == RELKIND_PARTITIONED_TABLE);
+ pcinfo->parent_relid = rti;
+ pcinfo->child_rels = partitioned_child_rels;
+ root->pcinfo_list = lappend(root->pcinfo_list, pcinfo);
+ }
+
/* Otherwise, OK to add to root->append_rel_list */
root->append_rel_list = list_concat(root->append_rel_list, appinfos);
}
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 8ce772d274..fca96eb001 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -1201,7 +1201,7 @@ create_tidscan_path(PlannerInfo *root, RelOptInfo *rel, List *tidquals,
*/
AppendPath *
create_append_path(RelOptInfo *rel, List *subpaths, Relids required_outer,
- int parallel_workers)
+ int parallel_workers, List *partitioned_rels)
{
AppendPath *pathnode = makeNode(AppendPath);
ListCell *l;
@@ -1216,6 +1216,7 @@ create_append_path(RelOptInfo *rel, List *subpaths, Relids required_outer,
pathnode->path.parallel_workers = parallel_workers;
pathnode->path.pathkeys = NIL; /* result is always considered
* unsorted */
+ pathnode->partitioned_rels = partitioned_rels;
pathnode->subpaths = subpaths;
/*
@@ -1258,7 +1259,8 @@ create_merge_append_path(PlannerInfo *root,
RelOptInfo *rel,
List *subpaths,
List *pathkeys,
- Relids required_outer)
+ Relids required_outer,
+ List *partitioned_rels)
{
MergeAppendPath *pathnode = makeNode(MergeAppendPath);
Cost input_startup_cost;
@@ -1274,6 +1276,7 @@ create_merge_append_path(PlannerInfo *root,
pathnode->path.parallel_safe = rel->consider_parallel;
pathnode->path.parallel_workers = 0;
pathnode->path.pathkeys = pathkeys;
+ pathnode->partitioned_rels = partitioned_rels;
pathnode->subpaths = subpaths;
/*
@@ -3105,7 +3108,7 @@ create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
ModifyTablePath *
create_modifytable_path(PlannerInfo *root, RelOptInfo *rel,
CmdType operation, bool canSetTag,
- Index nominalRelation,
+ Index nominalRelation, List *partitioned_rels,
List *resultRelations, List *subpaths,
List *subroots,
List *withCheckOptionLists, List *returningLists,
@@ -3172,6 +3175,7 @@ create_modifytable_path(PlannerInfo *root, RelOptInfo *rel,
pathnode->operation = operation;
pathnode->canSetTag = canSetTag;
pathnode->nominalRelation = nominalRelation;
+ pathnode->partitioned_rels = partitioned_rels;
pathnode->resultRelations = resultRelations;
pathnode->subpaths = subpaths;
pathnode->subroots = subroots;
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index fa02374811..d284ab7d3d 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -1514,7 +1514,8 @@ AcquireExecutorLocks(List *stmt_list, bool acquire)
* fail if it's been dropped entirely --- we'll just transiently
* acquire a non-conflicting lock.
*/
- if (list_member_int(plannedstmt->resultRelations, rt_index))
+ if (list_member_int(plannedstmt->resultRelations, rt_index) ||
+ list_member_int(plannedstmt->nonleafResultRelations, rt_index))
lockmode = RowExclusiveLock;
else if ((rc = get_plan_rowmark(plannedstmt->rowMarks, rt_index)) != NULL &&
RowMarkRequiresRowShareLock(rc->markType))
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 02dbe7b228..e64d6fb93f 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -375,6 +375,7 @@ extern void RegisterExprContextCallback(ExprContext *econtext,
extern void UnregisterExprContextCallback(ExprContext *econtext,
ExprContextCallbackFunction function,
Datum arg);
+extern void ExecLockNonLeafAppendTables(List *partitioned_rels, EState *estate);
/*
* prototypes from functions in execIndexing.c
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 2bc7a5df11..2cbd6d77b8 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -275,6 +275,7 @@ typedef enum NodeTag
T_PlaceHolderVar,
T_SpecialJoinInfo,
T_AppendRelInfo,
+ T_PartitionedChildRelInfo,
T_PlaceHolderInfo,
T_MinMaxAggInfo,
T_PlannerParamItem,
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index b880dc16cf..4a95e16b69 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -65,6 +65,9 @@ typedef struct PlannedStmt
/* rtable indexes of target relations for INSERT/UPDATE/DELETE */
List *resultRelations; /* integer list of RT indexes, or NIL */
+ /* rtable indexes of non-leaf target relations for INSERT/UPDATE/DELETE */
+ List *nonleafResultRelations;
+
List *subplans; /* Plan trees for SubPlan expressions */
Bitmapset *rewindPlanIDs; /* indices of subplans that require REWIND */
@@ -202,6 +205,8 @@ typedef struct ModifyTable
CmdType operation; /* INSERT, UPDATE, or DELETE */
bool canSetTag; /* do we set the command tag/es_processed? */
Index nominalRelation; /* Parent RT index for use of EXPLAIN */
+ /* RT indexes of non-leaf tables in a partition tree */
+ List *partitioned_rels;
List *resultRelations; /* integer list of RT indexes */
int resultRelIndex; /* index of first resultRel in plan's list */
List *plans; /* plan(s) producing source data */
@@ -227,6 +232,8 @@ typedef struct ModifyTable
typedef struct Append
{
Plan plan;
+ /* RT indexes of non-leaf tables in a partition tree */
+ List *partitioned_rels;
List *appendplans;
} Append;
@@ -238,6 +245,8 @@ typedef struct Append
typedef struct MergeAppend
{
Plan plan;
+ /* RT indexes of non-leaf tables in a partition tree */
+ List *partitioned_rels;
List *mergeplans;
/* remaining fields are just like the sort-key info in struct Sort */
int numCols; /* number of sort-key columns */
@@ -937,11 +946,12 @@ typedef enum RowMarkType
* When the planner discovers that a relation is the root of an inheritance
* tree, it sets isParent true, and adds an additional PlanRowMark to the
* list for each child relation (including the target rel itself in its role
- * as a child). The child entries have rti == child rel's RT index and
- * prti == parent's RT index, and can therefore be recognized as children by
- * the fact that prti != rti. The parent's allMarkTypes field gets the OR
- * of (1<<markType) across all its children (this definition allows children
- * to use different markTypes).
+ * as a child). isParent is also set to true for the partitioned child
+ * relations, which are not scanned just like the root parent. The child
+ * entries have rti == child rel's RT index and prti == parent's RT index,
+ * and can therefore be recognized as children by the fact that prti != rti.
+ * The parent's allMarkTypes field gets the OR of (1<<markType) across all
+ * its children (this definition allows children to use different markTypes).
*
* The planner also adds resjunk output columns to the plan that carry
* information sufficient to identify the locked or fetched rows. When
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index 05d6f07aea..43eb3139f9 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -107,6 +107,8 @@ typedef struct PlannerGlobal
List *resultRelations; /* "flat" list of integer RT indexes */
+ List *nonleafResultRelations; /* "flat" list of integer RT indexes */
+
List *relationOids; /* OIDs of relations the plan depends on */
List *invalItems; /* other dependencies, as PlanInvalItems */
@@ -248,6 +250,8 @@ typedef struct PlannerInfo
List *append_rel_list; /* list of AppendRelInfos */
+ List *pcinfo_list; /* list of PartitionedChildRelInfos */
+
List *rowMarks; /* list of PlanRowMarks */
List *placeholder_list; /* list of PlaceHolderInfos */
@@ -1116,6 +1120,8 @@ typedef struct CustomPath
typedef struct AppendPath
{
Path path;
+ /* RT indexes of non-leaf tables in a partition tree */
+ List *partitioned_rels;
List *subpaths; /* list of component Paths */
} AppendPath;
@@ -1134,6 +1140,8 @@ typedef struct AppendPath
typedef struct MergeAppendPath
{
Path path;
+ /* RT indexes of non-leaf tables in a partition tree */
+ List *partitioned_rels;
List *subpaths; /* list of component Paths */
double limit_tuples; /* hard limit on output tuples, or -1 */
} MergeAppendPath;
@@ -1482,6 +1490,8 @@ typedef struct ModifyTablePath
CmdType operation; /* INSERT, UPDATE, or DELETE */
bool canSetTag; /* do we set the command tag/es_processed? */
Index nominalRelation; /* Parent RT index for use of EXPLAIN */
+ /* RT indexes of non-leaf tables in a partition tree */
+ List *partitioned_rels;
List *resultRelations; /* integer list of RT indexes */
List *subpaths; /* Path(s) producing source data */
List *subroots; /* per-target-table PlannerInfos */
@@ -1914,6 +1924,21 @@ typedef struct AppendRelInfo
} AppendRelInfo;
/*
+ * For a partitioned table, this maps its RT index to the list of RT indexes
+ * of partitioned child tables in the partition tree. We need to separately
+ * store this mapping because we do not create AppendRelInfo for the
+ * partitioned child tables of a parent table, since AppendRelInfos contain
+ * information that is unnecessary for partitioned child tables.
+ */
+typedef struct PartitionedChildRelInfo
+{
+ NodeTag type;
+
+ Index parent_relid;
+ List *child_rels;
+} PartitionedChildRelInfo;
+
+/*
* For each distinct placeholder expression generated during planning, we
* store a PlaceHolderInfo node in the PlannerInfo node's placeholder_list.
* This stores info that is needed centrally rather than in each copy of the
diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h
index 373c7221a8..81640de7ab 100644
--- a/src/include/optimizer/pathnode.h
+++ b/src/include/optimizer/pathnode.h
@@ -64,12 +64,14 @@ extern BitmapOrPath *create_bitmap_or_path(PlannerInfo *root,
extern TidPath *create_tidscan_path(PlannerInfo *root, RelOptInfo *rel,
List *tidquals, Relids required_outer);
extern AppendPath *create_append_path(RelOptInfo *rel, List *subpaths,
- Relids required_outer, int parallel_workers);
+ Relids required_outer, int parallel_workers,
+ List *partitioned_rels);
extern MergeAppendPath *create_merge_append_path(PlannerInfo *root,
RelOptInfo *rel,
List *subpaths,
List *pathkeys,
- Relids required_outer);
+ Relids required_outer,
+ List *partitioned_rels);
extern ResultPath *create_result_path(PlannerInfo *root, RelOptInfo *rel,
PathTarget *target, List *resconstantqual);
extern MaterialPath *create_material_path(RelOptInfo *rel, Path *subpath);
@@ -232,7 +234,7 @@ extern LockRowsPath *create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
extern ModifyTablePath *create_modifytable_path(PlannerInfo *root,
RelOptInfo *rel,
CmdType operation, bool canSetTag,
- Index nominalRelation,
+ Index nominalRelation, List *partitioned_rels,
List *resultRelations, List *subpaths,
List *subroots,
List *withCheckOptionLists, List *returningLists,
diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out
index 6494b205c4..6163ed8117 100644
--- a/src/test/regress/expected/inherit.out
+++ b/src/test/regress/expected/inherit.out
@@ -588,6 +588,45 @@ select tableoid::regclass::text as relname, bar.* from bar order by 1,2;
bar2 | 4 | 104
(8 rows)
+-- Check UPDATE with *partitioned* inherited target and an appendrel subquery
+create table some_tab (a int);
+insert into some_tab values (0);
+create table some_tab_child () inherits (some_tab);
+insert into some_tab_child values (1);
+create table parted_tab (a int, b char) partition by list (a);
+create table parted_tab_part1 partition of parted_tab for values in (1);
+create table parted_tab_part2 partition of parted_tab for values in (2);
+create table parted_tab_part3 partition of parted_tab for values in (3);
+insert into parted_tab values (1, 'a'), (2, 'a'), (3, 'a');
+update parted_tab set b = 'b'
+from
+ (select a from some_tab union all select a+1 from some_tab) ss (a)
+where parted_tab.a = ss.a;
+select tableoid::regclass::text as relname, parted_tab.* from parted_tab order by 1,2;
+ relname | a | b
+------------------+---+---
+ parted_tab_part1 | 1 | b
+ parted_tab_part2 | 2 | b
+ parted_tab_part3 | 3 | a
+(3 rows)
+
+truncate parted_tab;
+insert into parted_tab values (1, 'a'), (2, 'a'), (3, 'a');
+update parted_tab set b = 'b'
+from
+ (select 0 from parted_tab union all select 1 from parted_tab) ss (a)
+where parted_tab.a = ss.a;
+select tableoid::regclass::text as relname, parted_tab.* from parted_tab order by 1,2;
+ relname | a | b
+------------------+---+---
+ parted_tab_part1 | 1 | b
+ parted_tab_part2 | 2 | a
+ parted_tab_part3 | 3 | a
+(3 rows)
+
+drop table parted_tab;
+drop table some_tab cascade;
+NOTICE: drop cascades to table some_tab_child
/* Test multiple inheritance of column defaults */
CREATE TABLE firstparent (tomorrow date default now()::date + 1);
CREATE TABLE secondparent (tomorrow date default now() :: date + 1);
@@ -1611,71 +1650,60 @@ explain (costs off) select * from list_parted;
QUERY PLAN
--------------------------------
Append
- -> Seq Scan on list_parted
-> Seq Scan on part_ab_cd
-> Seq Scan on part_ef_gh
-> Seq Scan on part_null_xy
-(5 rows)
+(4 rows)
explain (costs off) select * from list_parted where a is null;
QUERY PLAN
--------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (a IS NULL)
-> Seq Scan on part_null_xy
Filter: (a IS NULL)
-(5 rows)
+(3 rows)
explain (costs off) select * from list_parted where a is not null;
QUERY PLAN
---------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (a IS NOT NULL)
-> Seq Scan on part_ab_cd
Filter: (a IS NOT NULL)
-> Seq Scan on part_ef_gh
Filter: (a IS NOT NULL)
-> Seq Scan on part_null_xy
Filter: (a IS NOT NULL)
-(9 rows)
+(7 rows)
explain (costs off) select * from list_parted where a in ('ab', 'cd', 'ef');
QUERY PLAN
----------------------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-> Seq Scan on part_ab_cd
Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-> Seq Scan on part_ef_gh
Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-(7 rows)
+(5 rows)
explain (costs off) select * from list_parted where a = 'ab' or a in (null, 'cd');
QUERY PLAN
---------------------------------------------------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_ab_cd
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_ef_gh
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_null_xy
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-(9 rows)
+(7 rows)
explain (costs off) select * from list_parted where a = 'ab';
QUERY PLAN
------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: ((a)::text = 'ab'::text)
-> Seq Scan on part_ab_cd
Filter: ((a)::text = 'ab'::text)
-(5 rows)
+(3 rows)
create table range_list_parted (
a int,
@@ -1695,14 +1723,9 @@ create table part_40_inf_ab partition of part_40_inf for values in ('ab');
create table part_40_inf_cd partition of part_40_inf for values in ('cd');
create table part_40_inf_null partition of part_40_inf for values in (null);
explain (costs off) select * from range_list_parted;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- -> Seq Scan on part_1_10
- -> Seq Scan on part_10_20
- -> Seq Scan on part_21_30
- -> Seq Scan on part_40_inf
-> Seq Scan on part_1_10_ab
-> Seq Scan on part_1_10_cd
-> Seq Scan on part_10_20_ab
@@ -1712,36 +1735,22 @@ explain (costs off) select * from range_list_parted;
-> Seq Scan on part_40_inf_ab
-> Seq Scan on part_40_inf_cd
-> Seq Scan on part_40_inf_null
-(15 rows)
+(10 rows)
explain (costs off) select * from range_list_parted where a = 5;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+--------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (a = 5)
- -> Seq Scan on part_1_10
- Filter: (a = 5)
-> Seq Scan on part_1_10_ab
Filter: (a = 5)
-> Seq Scan on part_1_10_cd
Filter: (a = 5)
-(9 rows)
+(5 rows)
explain (costs off) select * from range_list_parted where b = 'ab';
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_1_10
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_10_20
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_21_30
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_40_inf
- Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_1_10_ab
Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_10_20_ab
@@ -1750,27 +1759,19 @@ explain (costs off) select * from range_list_parted where b = 'ab';
Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_40_inf_ab
Filter: (b = 'ab'::bpchar)
-(19 rows)
+(9 rows)
explain (costs off) select * from range_list_parted where a between 3 and 23 and b in ('ab');
QUERY PLAN
-----------------------------------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_1_10
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_10_20
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_21_30
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_1_10_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_10_20_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_21_30_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-(15 rows)
+(7 rows)
/* Should select no rows because range partition key cannot be null */
explain (costs off) select * from range_list_parted where a is null;
@@ -1782,37 +1783,17 @@ explain (costs off) select * from range_list_parted where a is null;
/* Should only select rows from the null-accepting partition */
explain (costs off) select * from range_list_parted where b is null;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (b IS NULL)
- -> Seq Scan on part_1_10
- Filter: (b IS NULL)
- -> Seq Scan on part_10_20
- Filter: (b IS NULL)
- -> Seq Scan on part_21_30
- Filter: (b IS NULL)
- -> Seq Scan on part_40_inf
- Filter: (b IS NULL)
-> Seq Scan on part_40_inf_null
Filter: (b IS NULL)
-(13 rows)
+(3 rows)
explain (costs off) select * from range_list_parted where a is not null and a < 67;
QUERY PLAN
------------------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_1_10
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_10_20
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_21_30
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_40_inf
- Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_1_10_ab
Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_1_10_cd
@@ -1831,23 +1812,19 @@ explain (costs off) select * from range_list_parted where a is not null and a <
Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_40_inf_null
Filter: ((a IS NOT NULL) AND (a < 67))
-(29 rows)
+(19 rows)
explain (costs off) select * from range_list_parted where a >= 30;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (a >= 30)
- -> Seq Scan on part_40_inf
- Filter: (a >= 30)
-> Seq Scan on part_40_inf_ab
Filter: (a >= 30)
-> Seq Scan on part_40_inf_cd
Filter: (a >= 30)
-> Seq Scan on part_40_inf_null
Filter: (a >= 30)
-(11 rows)
+(7 rows)
drop table list_parted;
drop table range_list_parted;
diff --git a/src/test/regress/expected/tablesample.out b/src/test/regress/expected/tablesample.out
index b18e420e9b..d3794140fb 100644
--- a/src/test/regress/expected/tablesample.out
+++ b/src/test/regress/expected/tablesample.out
@@ -322,12 +322,10 @@ explain (costs off)
QUERY PLAN
-------------------------------------------
Append
- -> Sample Scan on parted_sample
- Sampling: bernoulli ('100'::real)
-> Sample Scan on parted_sample_1
Sampling: bernoulli ('100'::real)
-> Sample Scan on parted_sample_2
Sampling: bernoulli ('100'::real)
-(7 rows)
+(5 rows)
drop table parted_sample, parted_sample_1, parted_sample_2;
diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql
index e3e9e34895..d43b75c4a7 100644
--- a/src/test/regress/sql/inherit.sql
+++ b/src/test/regress/sql/inherit.sql
@@ -128,6 +128,34 @@ where bar.f1 = ss.f1;
select tableoid::regclass::text as relname, bar.* from bar order by 1,2;
+-- Check UPDATE with *partitioned* inherited target and an appendrel subquery
+create table some_tab (a int);
+insert into some_tab values (0);
+create table some_tab_child () inherits (some_tab);
+insert into some_tab_child values (1);
+create table parted_tab (a int, b char) partition by list (a);
+create table parted_tab_part1 partition of parted_tab for values in (1);
+create table parted_tab_part2 partition of parted_tab for values in (2);
+create table parted_tab_part3 partition of parted_tab for values in (3);
+insert into parted_tab values (1, 'a'), (2, 'a'), (3, 'a');
+
+update parted_tab set b = 'b'
+from
+ (select a from some_tab union all select a+1 from some_tab) ss (a)
+where parted_tab.a = ss.a;
+select tableoid::regclass::text as relname, parted_tab.* from parted_tab order by 1,2;
+
+truncate parted_tab;
+insert into parted_tab values (1, 'a'), (2, 'a'), (3, 'a');
+update parted_tab set b = 'b'
+from
+ (select 0 from parted_tab union all select 1 from parted_tab) ss (a)
+where parted_tab.a = ss.a;
+select tableoid::regclass::text as relname, parted_tab.* from parted_tab order by 1,2;
+
+drop table parted_tab;
+drop table some_tab cascade;
+
/* Test multiple inheritance of column defaults */
CREATE TABLE firstparent (tomorrow date default now()::date + 1);
--
2.11.0
[text/x-diff] 0002-Do-not-allocate-storage-for-partitioned-tables.patch (3.1K, ../../ac0aac85-91a4-3079-d859-f2deb59df4ca@lab.ntt.co.jp/3-0002-Do-not-allocate-storage-for-partitioned-tables.patch)
download | inline diff:
From c9f406a6da5581cd36059178e2f6277aef225937 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Tue, 24 Jan 2017 14:22:34 +0900
Subject: [PATCH 2/2] Do not allocate storage for partitioned tables.
Currently, it is not possible to insert any data into a partitioned
table. So, they're empty at all times, which means it is wasteful to
allocate relfilenode and related storage objects.
---
src/backend/access/common/reloptions.c | 3 +--
src/backend/catalog/heap.c | 17 ++++++++++-------
2 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 72e12532ab..d3b847e2e5 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -967,7 +967,6 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
case RELKIND_RELATION:
case RELKIND_TOASTVALUE:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
options = heap_reloptions(classForm->relkind, datum, false);
break;
case RELKIND_VIEW:
@@ -977,6 +976,7 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
options = index_reloptions(amoptions, datum, false);
break;
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
options = NULL;
break;
default:
@@ -1418,7 +1418,6 @@ heap_reloptions(char relkind, Datum reloptions, bool validate)
return (bytea *) rdopts;
case RELKIND_RELATION:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
default:
/* other relkinds are not supported */
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 41c0056556..2f5090b183 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -291,6 +291,7 @@ heap_create(const char *relname,
case RELKIND_VIEW:
case RELKIND_COMPOSITE_TYPE:
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
create_storage = false;
/*
@@ -1345,14 +1346,13 @@ heap_create_with_catalog(const char *relname,
if (oncommit != ONCOMMIT_NOOP)
register_on_commit_action(relid, oncommit);
- if (relpersistence == RELPERSISTENCE_UNLOGGED)
- {
- Assert(relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW ||
- relkind == RELKIND_TOASTVALUE ||
- relkind == RELKIND_PARTITIONED_TABLE);
-
+ /*
+ * We do not want to create any storage objects for a partitioned
+ * table, including the init fork.
+ */
+ if (relpersistence == RELPERSISTENCE_UNLOGGED &&
+ relkind != RELKIND_PARTITIONED_TABLE)
heap_create_init_fork(new_rel_desc);
- }
/*
* ok, the relation has been cataloged, so close our relations and return
@@ -1376,6 +1376,9 @@ heap_create_with_catalog(const char *relname,
void
heap_create_init_fork(Relation rel)
{
+ Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
+ rel->rd_rel->relkind == RELKIND_MATVIEW ||
+ rel->rd_rel->relkind == RELKIND_TOASTVALUE);
RelationOpenSmgr(rel);
smgrcreate(rel->rd_smgr, INIT_FORKNUM, false);
log_smgrcreate(&rel->rd_smgr->smgr_rnode.node, INIT_FORKNUM);
--
2.11.0
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-03-20 16:16 ` Robert Haas <robertmhaas@gmail.com>
2017-03-21 09:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
0 siblings, 1 reply; 96+ messages in thread
From: Robert Haas @ 2017-03-20 16:16 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; Michael Paquier <michael.paquier@gmail.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On Fri, Mar 17, 2017 at 4:57 AM, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
>> Yes, but on the flip side, you're having to add code in a lot of
>> places -- I think I counted 7 -- where you turn around and ignore
>> those AppendRelInfos.
>
> Perhaps you were looking at the previous version with "minimal" appinfos
> containing the child_is_partitioned field?
Yes, I think I was. I think this version looks a lot better.
/*
+ * Close the root partitioned rel if we opened it above, but keep the
+ * lock.
+ */
+ if (rel != mtstate->resultRelInfo->ri_RelationDesc)
+ heap_close(rel, NoLock);
We didn't take a lock above, though, so drop everything in the comment
from "but" onward.
- add_paths_to_append_rel(root, rel, live_childrels);
+ add_paths_to_append_rel(root, rel, live_childrels, partitioned_rels);
I think it would make more sense to put the new logic into
add_paths_to_append_rel, instead of passing this down as an additional
parameter.
+ * do not appear anywhere else in the plan. Situation is exactly the
The situation is...
+ if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ foreach(lc, root->pcinfo_list)
+ {
+ PartitionedChildRelInfo *pc = lfirst(lc);
+
+ if (pc->parent_relid == parentRTindex)
+ {
+ partitioned_rels = pc->child_rels;
+ break;
+ }
+ }
+ }
You seem to have a few copies of this logic. I think it would be
worth factoring it out into a separate function.
+ root->glob->nonleafResultRelations =
+ list_concat(root->glob->nonleafResultRelations,
+ list_copy(splan->partitioned_rels));
Please add a brief comment. One line is fine.
+ newrc->isParent = childrte->relkind == RELKIND_PARTITIONED_TABLE;
I'm not sure what project style is, but I personally find these kinds
of assignments easier to read with an extra set of parantheses:
newrc->isParent = (childrte->relkind == RELKIND_PARTITIONED_TABLE);
+ if (partitioned_rels == NIL)
+ return;
+
+ foreach(lc, partitioned_rels)
I think the if-test is pointless; the foreach loop is going to start
by comparing the initial value with NIL.
Why doesn't ExecSerializePlan() need to transfer a proper value for
nonleafResultRelations to workers? Seems like it should.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-20 16:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
@ 2017-03-21 09:05 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 13:49 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
0 siblings, 1 reply; 96+ messages in thread
From: Amit Langote @ 2017-03-21 09:05 UTC (permalink / raw)
To: Robert Haas <robertmhaas@gmail.com>; +Cc: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; Michael Paquier <michael.paquier@gmail.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On 2017/03/21 1:16, Robert Haas wrote:
> On Fri, Mar 17, 2017 at 4:57 AM, Amit Langote
> <Langote_Amit_f8@lab.ntt.co.jp> wrote:
>>> Yes, but on the flip side, you're having to add code in a lot of
>>> places -- I think I counted 7 -- where you turn around and ignore
>>> those AppendRelInfos.
>>
>> Perhaps you were looking at the previous version with "minimal" appinfos
>> containing the child_is_partitioned field?
>
> Yes, I think I was. I think this version looks a lot better.
Just to clarify, I assume you reviewed the latest version which does not
create AppendRelInfos, but instead creates PartitionedChildRelInfos (as
also evident from your comments below). Sorry about the confusion.
> /*
> + * Close the root partitioned rel if we opened it above, but keep the
> + * lock.
> + */
> + if (rel != mtstate->resultRelInfo->ri_RelationDesc)
> + heap_close(rel, NoLock);
>
> We didn't take a lock above, though, so drop everything in the comment
> from "but" onward.
Oh, right.
> - add_paths_to_append_rel(root, rel, live_childrels);
> + add_paths_to_append_rel(root, rel, live_childrels, partitioned_rels);
>
> I think it would make more sense to put the new logic into
> add_paths_to_append_rel, instead of passing this down as an additional
> parameter.
OK, done.
> + * do not appear anywhere else in the plan. Situation is exactly the
>
> The situation is...
Fixed.
>
> + if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
> + {
> + foreach(lc, root->pcinfo_list)
> + {
> + PartitionedChildRelInfo *pc = lfirst(lc);
> +
> + if (pc->parent_relid == parentRTindex)
> + {
> + partitioned_rels = pc->child_rels;
> + break;
> + }
> + }
> + }
>
> You seem to have a few copies of this logic. I think it would be
> worth factoring it out into a separate function.
OK, done. Put the definition in in planner.c
> + root->glob->nonleafResultRelations =
> + list_concat(root->glob->nonleafResultRelations,
> + list_copy(splan->partitioned_rels));
>
> Please add a brief comment. One line is fine.
Done.
>
> + newrc->isParent = childrte->relkind == RELKIND_PARTITIONED_TABLE;
>
> I'm not sure what project style is, but I personally find these kinds
> of assignments easier to read with an extra set of parantheses:
>
> newrc->isParent = (childrte->relkind == RELKIND_PARTITIONED_TABLE);
Ah, done.
>
> + if (partitioned_rels == NIL)
> + return;
> +
> + foreach(lc, partitioned_rels)
>
> I think the if-test is pointless; the foreach loop is going to start
> by comparing the initial value with NIL.
Right, fixed.
> Why doesn't ExecSerializePlan() need to transfer a proper value for
> nonleafResultRelations to workers? Seems like it should.
It doesn't transfer resultRelations either, presumably because workers do
not handle result relations yet. Also, both resultRelations and
nonleafResultRelations are set *only* if there is a ModifyTable node.
Attached updated patches.
Thanks,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Attachments:
[text/x-diff] 0001-Avoid-creating-scan-nodes-for-partitioned-tables.patch (66.1K, ../../6837c359-45c4-8044-34d1-736756335a15@lab.ntt.co.jp/2-0001-Avoid-creating-scan-nodes-for-partitioned-tables.patch)
download | inline diff:
From 28fe97f6a831485f5f85d20ec6a3e0df066ad612 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Fri, 10 Mar 2017 13:48:31 +0900
Subject: [PATCH 1/2] Avoid creating scan nodes for partitioned tables
There are quite a few changes here:
* Currently, we create scan nodes for inheritance parents in their role
as an inheritance set member. Partitioned tables do not contain any
data, so it's useless to create scan nodes for them. So, it's not
necessary to create AppendRelInfos for partitioned child tables in
expand_inherited_rtentry(). Although, create the RTEs and record the
RT indexes in a list. The list is associated with the parent_relid
using the new PartitionedChildRelInfo nodes, which are kept in a global
list called pcinfo_list in the root PlannerInfo, similar to
append_rel_list. For a given parent RTE, add_paths_to_append_rel() and
inheritance_planner() must copy the aforementioned list of partitioned
child RT indexes to Append/MergeAppend and ModifyTable paths,
respectively. The list is then carried over to a new field called
partitioned_rels in Append, MergeAppend, and ModifyTable nodes.
* For partitioned parent RTEs with inh=false, set_rel_size() must not
try to do set_plain_rel_size(). Instead mark such rels as "dummy",
because they are empty. Happens with partitioned tables without any
leaf partitions.
* In case of UPDATE/DELETE on a partitioned table, executor can already
know the leaf result relations with PlannedStmt.resultRelations, but
not the non-leaf relations. InitPlan must lock *all* the result
relations before initializing the plan tree to avoid lock upgrade
hazards, so we must include non-leaf result relations as well. For
that, add a new field nonleafResultRelations to PlannedStmt, which
is intitialized by copying ModifyTable.partitioned_rels.
* PlanRowMarks for partitioned child tables are created with isParent
set to true so that executor ignores them. That is, no ExecRowMarks
are created for partitioned child tables. However those tables still
must be locked with the appropriate lockmode; but InitPlan() does not,
because it sees them as dummy entries. Instead the first Append or
MergeAppend node that's initialized that refers to those table locks
them appropriately.
* In inheritance_planner(), set ModifyTable.nominalRelation to parent RT
index in the partitioned inheritance parent case, so that EXPLAIN uses
the root tables's original RT index to label a given ModifyTable node.
Regression test outputs are adjusted to match the new plan shape. New
tests are added for certain cases.
---
src/backend/executor/execMain.c | 22 ++++-
src/backend/executor/execParallel.c | 1 +
src/backend/executor/execUtils.c | 56 ++++++++++++
src/backend/executor/nodeAppend.c | 6 ++
src/backend/executor/nodeMergeAppend.c | 6 ++
src/backend/executor/nodeModifyTable.c | 19 +++-
src/backend/nodes/copyfuncs.c | 21 +++++
src/backend/nodes/equalfuncs.c | 12 +++
src/backend/nodes/outfuncs.c | 21 +++++
src/backend/nodes/readfuncs.c | 4 +
src/backend/optimizer/path/allpaths.c | 43 +++++++--
src/backend/optimizer/path/joinrels.c | 2 +-
src/backend/optimizer/plan/createplan.c | 14 ++-
src/backend/optimizer/plan/planner.c | 89 +++++++++++++++---
src/backend/optimizer/plan/setrefs.c | 21 +++++
src/backend/optimizer/prep/prepunion.c | 103 ++++++++++++++-------
src/backend/optimizer/util/pathnode.c | 10 +-
src/backend/utils/cache/plancache.c | 3 +-
src/include/executor/executor.h | 1 +
src/include/nodes/nodes.h | 1 +
src/include/nodes/plannodes.h | 20 +++-
src/include/nodes/relation.h | 37 +++++++-
src/include/optimizer/pathnode.h | 8 +-
src/include/optimizer/planner.h | 2 +
src/test/regress/expected/inherit.out | 147 +++++++++++++-----------------
src/test/regress/expected/tablesample.out | 4 +-
src/test/regress/sql/inherit.sql | 28 ++++++
27 files changed, 537 insertions(+), 164 deletions(-)
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index f5cd65d8a0..3b6961d0a8 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -844,6 +844,22 @@ InitPlan(QueryDesc *queryDesc, int eflags)
estate->es_num_result_relations = numResultRelations;
/* es_result_relation_info is NULL except when within ModifyTable */
estate->es_result_relation_info = NULL;
+
+ /*
+ * In the partitioned result relation case, lock the non-leaf result
+ * relations too. We don't however need ResultRelInfos for them.
+ */
+ if (plannedstmt->nonleafResultRelations)
+ {
+ foreach(l, plannedstmt->nonleafResultRelations)
+ {
+ Index resultRelationIndex = lfirst_int(l);
+ Oid resultRelationOid;
+
+ resultRelationOid = getrelid(resultRelationIndex, rangeTable);
+ LockRelationOid(resultRelationOid, RowExclusiveLock);
+ }
+ }
}
else
{
@@ -858,7 +874,11 @@ InitPlan(QueryDesc *queryDesc, int eflags)
/*
* Similarly, we have to lock relations selected FOR [KEY] UPDATE/SHARE
* before we initialize the plan tree, else we'd be risking lock upgrades.
- * While we are at it, build the ExecRowMark list.
+ * While we are at it, build the ExecRowMark list. Any partitioned child
+ * tables are ignored here (because, isParent=true) and will be locked by
+ * the first Append or MergeAppend node that references them. (Note that
+ * the RowMarks corresponding to partitioned child tables are present in
+ * the same list as the rest, i.e., plannedstmt->rowMarks.)
*/
estate->es_rowMarks = NIL;
foreach(l, plannedstmt->rowMarks)
diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c
index a1289e5f12..86db73be43 100644
--- a/src/backend/executor/execParallel.c
+++ b/src/backend/executor/execParallel.c
@@ -161,6 +161,7 @@ ExecSerializePlan(Plan *plan, EState *estate)
pstmt->planTree = plan;
pstmt->rtable = estate->es_range_table;
pstmt->resultRelations = NIL;
+ pstmt->nonleafResultRelations = NIL;
pstmt->subplans = estate->es_plannedstmt->subplans;
pstmt->rewindPlanIDs = NULL;
pstmt->rowMarks = NIL;
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 3d6a3801c0..a72cffeb6e 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -43,6 +43,7 @@
#include "executor/executor.h"
#include "nodes/nodeFuncs.h"
#include "parser/parsetree.h"
+#include "storage/lmgr.h"
#include "utils/memutils.h"
#include "utils/rel.h"
@@ -953,3 +954,58 @@ ShutdownExprContext(ExprContext *econtext, bool isCommit)
MemoryContextSwitchTo(oldcontext);
}
+
+/*
+ * ExecLockNonLeafAppendTables
+ *
+ * Locks, if necessary, the tables indicated by the RT indexes contained in
+ * the partitioned_rels list. These are the non-leaf tables in the partition
+ * tree controlled by a given Append or MergeAppend node.
+ */
+void
+ExecLockNonLeafAppendTables(List *partitioned_rels, EState *estate)
+{
+ PlannedStmt *stmt = estate->es_plannedstmt;
+ ListCell *lc;
+
+ foreach(lc, partitioned_rels)
+ {
+ ListCell *l;
+ Index rti = lfirst_int(lc);
+ bool is_result_rel = false;
+ Oid relid = getrelid(rti, estate->es_range_table);
+
+ /* If this is a result relation, already locked in InitPlan */
+ foreach(l, stmt->nonleafResultRelations)
+ {
+ if (rti == lfirst_int(l))
+ {
+ is_result_rel = true;
+ break;
+ }
+ }
+
+ /*
+ * Not a result relation; check if there is a RowMark that requires
+ * taking a RowShareLock on this rel.
+ */
+ if (!is_result_rel)
+ {
+ PlanRowMark *rc = NULL;
+
+ foreach(l, stmt->rowMarks)
+ {
+ if (((PlanRowMark *) lfirst(l))->rti == rti)
+ {
+ rc = lfirst(l);
+ break;
+ }
+ }
+
+ if (rc && RowMarkRequiresRowShareLock(rc->markType))
+ LockRelationOid(relid, RowShareLock);
+ else
+ LockRelationOid(relid, AccessShareLock);
+ }
+ }
+}
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index 6986caee6b..a107545b83 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -129,6 +129,12 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
Assert(!(eflags & EXEC_FLAG_MARK));
/*
+ * Lock the non-leaf tables in the partition tree controlled by this
+ * node. It's a no-op for non-partitioned parent tables.
+ */
+ ExecLockNonLeafAppendTables(node->partitioned_rels, estate);
+
+ /*
* Set up empty vector of subplan states
*/
nplans = list_length(node->appendplans);
diff --git a/src/backend/executor/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c
index 7a20bf07a4..8a2e78266b 100644
--- a/src/backend/executor/nodeMergeAppend.c
+++ b/src/backend/executor/nodeMergeAppend.c
@@ -72,6 +72,12 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
/*
+ * Lock the non-leaf tables in the partition tree controlled by this
+ * node. It's a no-op for non-partitioned parent tables.
+ */
+ ExecLockNonLeafAppendTables(node->partitioned_rels, estate);
+
+ /*
* Set up empty vector of subplan states
*/
nplans = list_length(node->mergeplans);
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 95e158970c..29c6a6e1d8 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -45,6 +45,7 @@
#include "foreign/fdwapi.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
+#include "parser/parsetree.h"
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
#include "utils/builtins.h"
@@ -1725,8 +1726,20 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
estate->es_result_relation_info = saved_resultRelInfo;
+ /* The root table RT index is at the head of the partitioned_rels list */
+ if (node->partitioned_rels)
+ {
+ Index root_rti;
+ Oid root_oid;
+
+ root_rti = linitial_int(node->partitioned_rels);
+ root_oid = getrelid(root_rti, estate->es_range_table);
+ rel = heap_open(root_oid, NoLock); /* locked by InitPlan */
+ }
+ else
+ rel = mtstate->resultRelInfo->ri_RelationDesc;
+
/* Build state for INSERT tuple routing */
- rel = mtstate->resultRelInfo->ri_RelationDesc;
if (operation == CMD_INSERT &&
rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
{
@@ -1897,6 +1910,10 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
mtstate->ps.ps_ExprContext = NULL;
}
+ /* Close the root partitioned rel if we opened it above. */
+ if (rel != mtstate->resultRelInfo->ri_RelationDesc)
+ heap_close(rel, NoLock);
+
/*
* If needed, Initialize target list, projection and qual for ON CONFLICT
* DO UPDATE.
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 25fd051d6e..7cf31b35fd 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -90,6 +90,7 @@ _copyPlannedStmt(const PlannedStmt *from)
COPY_NODE_FIELD(planTree);
COPY_NODE_FIELD(rtable);
COPY_NODE_FIELD(resultRelations);
+ COPY_NODE_FIELD(nonleafResultRelations);
COPY_NODE_FIELD(subplans);
COPY_BITMAPSET_FIELD(rewindPlanIDs);
COPY_NODE_FIELD(rowMarks);
@@ -200,6 +201,7 @@ _copyModifyTable(const ModifyTable *from)
COPY_SCALAR_FIELD(operation);
COPY_SCALAR_FIELD(canSetTag);
COPY_SCALAR_FIELD(nominalRelation);
+ COPY_NODE_FIELD(partitioned_rels);
COPY_NODE_FIELD(resultRelations);
COPY_SCALAR_FIELD(resultRelIndex);
COPY_NODE_FIELD(plans);
@@ -235,6 +237,7 @@ _copyAppend(const Append *from)
/*
* copy remainder of node
*/
+ COPY_NODE_FIELD(partitioned_rels);
COPY_NODE_FIELD(appendplans);
return newnode;
@@ -256,6 +259,7 @@ _copyMergeAppend(const MergeAppend *from)
/*
* copy remainder of node
*/
+ COPY_NODE_FIELD(partitioned_rels);
COPY_NODE_FIELD(mergeplans);
COPY_SCALAR_FIELD(numCols);
COPY_POINTER_FIELD(sortColIdx, from->numCols * sizeof(AttrNumber));
@@ -2205,6 +2209,20 @@ _copyAppendRelInfo(const AppendRelInfo *from)
}
/*
+ * _copyPartitionedChildRelInfo
+ */
+static PartitionedChildRelInfo *
+_copyPartitionedChildRelInfo(const PartitionedChildRelInfo *from)
+{
+ PartitionedChildRelInfo *newnode = makeNode(PartitionedChildRelInfo);
+
+ COPY_SCALAR_FIELD(parent_relid);
+ COPY_NODE_FIELD(child_rels);
+
+ return newnode;
+}
+
+/*
* _copyPlaceHolderInfo
*/
static PlaceHolderInfo *
@@ -4892,6 +4910,9 @@ copyObject(const void *from)
case T_AppendRelInfo:
retval = _copyAppendRelInfo(from);
break;
+ case T_PartitionedChildRelInfo:
+ retval = _copyPartitionedChildRelInfo(from);
+ break;
case T_PlaceHolderInfo:
retval = _copyPlaceHolderInfo(from);
break;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 67529e3f86..d444222e38 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -896,6 +896,15 @@ _equalAppendRelInfo(const AppendRelInfo *a, const AppendRelInfo *b)
}
static bool
+_equalPartitionedChildRelInfo(const PartitionedChildRelInfo *a, const PartitionedChildRelInfo *b)
+{
+ COMPARE_SCALAR_FIELD(parent_relid);
+ COMPARE_NODE_FIELD(child_rels);
+
+ return true;
+}
+
+static bool
_equalPlaceHolderInfo(const PlaceHolderInfo *a, const PlaceHolderInfo *b)
{
COMPARE_SCALAR_FIELD(phid);
@@ -3102,6 +3111,9 @@ equal(const void *a, const void *b)
case T_AppendRelInfo:
retval = _equalAppendRelInfo(a, b);
break;
+ case T_PartitionedChildRelInfo:
+ retval = _equalPartitionedChildRelInfo(a, b);
+ break;
case T_PlaceHolderInfo:
retval = _equalPlaceHolderInfo(a, b);
break;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 7418fbeded..1b9005fa53 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -252,6 +252,7 @@ _outPlannedStmt(StringInfo str, const PlannedStmt *node)
WRITE_NODE_FIELD(planTree);
WRITE_NODE_FIELD(rtable);
WRITE_NODE_FIELD(resultRelations);
+ WRITE_NODE_FIELD(nonleafResultRelations);
WRITE_NODE_FIELD(subplans);
WRITE_BITMAPSET_FIELD(rewindPlanIDs);
WRITE_NODE_FIELD(rowMarks);
@@ -344,6 +345,7 @@ _outModifyTable(StringInfo str, const ModifyTable *node)
WRITE_ENUM_FIELD(operation, CmdType);
WRITE_BOOL_FIELD(canSetTag);
WRITE_UINT_FIELD(nominalRelation);
+ WRITE_NODE_FIELD(partitioned_rels);
WRITE_NODE_FIELD(resultRelations);
WRITE_INT_FIELD(resultRelIndex);
WRITE_NODE_FIELD(plans);
@@ -368,6 +370,7 @@ _outAppend(StringInfo str, const Append *node)
_outPlanInfo(str, (const Plan *) node);
+ WRITE_NODE_FIELD(partitioned_rels);
WRITE_NODE_FIELD(appendplans);
}
@@ -380,6 +383,7 @@ _outMergeAppend(StringInfo str, const MergeAppend *node)
_outPlanInfo(str, (const Plan *) node);
+ WRITE_NODE_FIELD(partitioned_rels);
WRITE_NODE_FIELD(mergeplans);
WRITE_INT_FIELD(numCols);
@@ -1808,6 +1812,7 @@ _outAppendPath(StringInfo str, const AppendPath *node)
_outPathInfo(str, (const Path *) node);
+ WRITE_NODE_FIELD(partitioned_rels);
WRITE_NODE_FIELD(subpaths);
}
@@ -1818,6 +1823,7 @@ _outMergeAppendPath(StringInfo str, const MergeAppendPath *node)
_outPathInfo(str, (const Path *) node);
+ WRITE_NODE_FIELD(partitioned_rels);
WRITE_NODE_FIELD(subpaths);
WRITE_FLOAT_FIELD(limit_tuples, "%.0f");
}
@@ -2023,6 +2029,7 @@ _outModifyTablePath(StringInfo str, const ModifyTablePath *node)
WRITE_ENUM_FIELD(operation, CmdType);
WRITE_BOOL_FIELD(canSetTag);
WRITE_UINT_FIELD(nominalRelation);
+ WRITE_NODE_FIELD(partitioned_rels);
WRITE_NODE_FIELD(resultRelations);
WRITE_NODE_FIELD(subpaths);
WRITE_NODE_FIELD(subroots);
@@ -2099,6 +2106,7 @@ _outPlannerGlobal(StringInfo str, const PlannerGlobal *node)
WRITE_NODE_FIELD(finalrtable);
WRITE_NODE_FIELD(finalrowmarks);
WRITE_NODE_FIELD(resultRelations);
+ WRITE_NODE_FIELD(nonleafResultRelations);
WRITE_NODE_FIELD(relationOids);
WRITE_NODE_FIELD(invalItems);
WRITE_INT_FIELD(nParamExec);
@@ -2137,6 +2145,7 @@ _outPlannerInfo(StringInfo str, const PlannerInfo *node)
WRITE_NODE_FIELD(full_join_clauses);
WRITE_NODE_FIELD(join_info_list);
WRITE_NODE_FIELD(append_rel_list);
+ WRITE_NODE_FIELD(pcinfo_list);
WRITE_NODE_FIELD(rowMarks);
WRITE_NODE_FIELD(placeholder_list);
WRITE_NODE_FIELD(fkey_list);
@@ -2420,6 +2429,15 @@ _outAppendRelInfo(StringInfo str, const AppendRelInfo *node)
}
static void
+_outPartitionedChildRelInfo(StringInfo str, const PartitionedChildRelInfo *node)
+{
+ WRITE_NODE_TYPE("PARTITIONEDCHILDRELINFO");
+
+ WRITE_UINT_FIELD(parent_relid);
+ WRITE_NODE_FIELD(child_rels);
+}
+
+static void
_outPlaceHolderInfo(StringInfo str, const PlaceHolderInfo *node)
{
WRITE_NODE_TYPE("PLACEHOLDERINFO");
@@ -3906,6 +3924,9 @@ outNode(StringInfo str, const void *obj)
case T_AppendRelInfo:
_outAppendRelInfo(str, obj);
break;
+ case T_PartitionedChildRelInfo:
+ _outPartitionedChildRelInfo(str, obj);
+ break;
case T_PlaceHolderInfo:
_outPlaceHolderInfo(str, obj);
break;
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index d3bbc02f24..474f221a75 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1444,6 +1444,7 @@ _readPlannedStmt(void)
READ_NODE_FIELD(planTree);
READ_NODE_FIELD(rtable);
READ_NODE_FIELD(resultRelations);
+ READ_NODE_FIELD(nonleafResultRelations);
READ_NODE_FIELD(subplans);
READ_BITMAPSET_FIELD(rewindPlanIDs);
READ_NODE_FIELD(rowMarks);
@@ -1535,6 +1536,7 @@ _readModifyTable(void)
READ_ENUM_FIELD(operation, CmdType);
READ_BOOL_FIELD(canSetTag);
READ_UINT_FIELD(nominalRelation);
+ READ_NODE_FIELD(partitioned_rels);
READ_NODE_FIELD(resultRelations);
READ_INT_FIELD(resultRelIndex);
READ_NODE_FIELD(plans);
@@ -1564,6 +1566,7 @@ _readAppend(void)
ReadCommonPlan(&local_node->plan);
+ READ_NODE_FIELD(partitioned_rels);
READ_NODE_FIELD(appendplans);
READ_DONE();
@@ -1579,6 +1582,7 @@ _readMergeAppend(void)
ReadCommonPlan(&local_node->plan);
+ READ_NODE_FIELD(partitioned_rels);
READ_NODE_FIELD(mergeplans);
READ_INT_FIELD(numCols);
READ_ATTRNUMBER_ARRAY(sortColIdx, local_node->numCols);
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 43bfd23804..a1e1a87c29 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -95,7 +95,8 @@ static void set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
Index rti, RangeTblEntry *rte);
static void generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
List *live_childrels,
- List *all_child_pathkeys);
+ List *all_child_pathkeys,
+ List *partitioned_rels);
static Path *get_cheapest_parameterized_child_path(PlannerInfo *root,
RelOptInfo *rel,
Relids required_outer);
@@ -346,6 +347,14 @@ set_rel_size(PlannerInfo *root, RelOptInfo *rel,
/* Foreign table */
set_foreign_size(root, rel, rte);
}
+ else if (rte->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ /*
+ * A partitioned table without leaf partitions is marked
+ * as a dummy rel.
+ */
+ set_dummy_rel_pathlist(rel);
+ }
else if (rte->tablesample != NULL)
{
/* Sampled relation */
@@ -1259,6 +1268,16 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
List *all_child_pathkeys = NIL;
List *all_child_outers = NIL;
ListCell *l;
+ List *partitioned_rels = NIL;
+ RangeTblEntry *rte;
+
+ rte = planner_rt_fetch(rel->relid, root);
+ if (rte->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ partitioned_rels = get_partitioned_child_rels(root, rel->relid);
+ /* The root partitioned table is included as a child rel */
+ Assert(list_length(partitioned_rels) >= 1);
+ }
/*
* For every non-dummy child, remember the cheapest path. Also, identify
@@ -1359,7 +1378,8 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
* if we have zero or one live subpath due to constraint exclusion.)
*/
if (subpaths_valid)
- add_path(rel, (Path *) create_append_path(rel, subpaths, NULL, 0));
+ add_path(rel, (Path *) create_append_path(rel, subpaths, NULL, 0,
+ partitioned_rels));
/*
* Consider an append of partial unordered, unparameterized partial paths.
@@ -1386,7 +1406,7 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
/* Generate a partial append path. */
appendpath = create_append_path(rel, partial_subpaths, NULL,
- parallel_workers);
+ parallel_workers, partitioned_rels);
add_partial_path(rel, (Path *) appendpath);
}
@@ -1396,7 +1416,8 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
*/
if (subpaths_valid)
generate_mergeappend_paths(root, rel, live_childrels,
- all_child_pathkeys);
+ all_child_pathkeys,
+ partitioned_rels);
/*
* Build Append paths for each parameterization seen among the child rels.
@@ -1438,7 +1459,8 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
if (subpaths_valid)
add_path(rel, (Path *)
- create_append_path(rel, subpaths, required_outer, 0));
+ create_append_path(rel, subpaths, required_outer, 0,
+ partitioned_rels));
}
}
@@ -1468,7 +1490,8 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
static void
generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
List *live_childrels,
- List *all_child_pathkeys)
+ List *all_child_pathkeys,
+ List *partitioned_rels)
{
ListCell *lcp;
@@ -1532,13 +1555,15 @@ generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel,
rel,
startup_subpaths,
pathkeys,
- NULL));
+ NULL,
+ partitioned_rels));
if (startup_neq_total)
add_path(rel, (Path *) create_merge_append_path(root,
rel,
total_subpaths,
pathkeys,
- NULL));
+ NULL,
+ partitioned_rels));
}
}
@@ -1671,7 +1696,7 @@ set_dummy_rel_pathlist(RelOptInfo *rel)
rel->pathlist = NIL;
rel->partial_pathlist = NIL;
- add_path(rel, (Path *) create_append_path(rel, NIL, NULL, 0));
+ add_path(rel, (Path *) create_append_path(rel, NIL, NULL, 0, NIL));
/*
* We set the cheapest path immediately, to ensure that IS_DUMMY_REL()
diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c
index 0551668976..6a0c67b9ab 100644
--- a/src/backend/optimizer/path/joinrels.c
+++ b/src/backend/optimizer/path/joinrels.c
@@ -1217,7 +1217,7 @@ mark_dummy_rel(RelOptInfo *rel)
rel->partial_pathlist = NIL;
/* Set up the dummy path */
- add_path(rel, (Path *) create_append_path(rel, NIL, NULL, 0));
+ add_path(rel, (Path *) create_append_path(rel, NIL, NULL, 0, NIL));
/* Set or update cheapest_total_path and related fields */
set_cheapest(rel);
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 89e1946fc2..c80c9992c9 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -199,7 +199,7 @@ static CteScan *make_ctescan(List *qptlist, List *qpqual,
Index scanrelid, int ctePlanId, int cteParam);
static WorkTableScan *make_worktablescan(List *qptlist, List *qpqual,
Index scanrelid, int wtParam);
-static Append *make_append(List *appendplans, List *tlist);
+static Append *make_append(List *appendplans, List *tlist, List *partitioned_rels);
static RecursiveUnion *make_recursive_union(List *tlist,
Plan *lefttree,
Plan *righttree,
@@ -273,7 +273,7 @@ static Result *make_result(List *tlist, Node *resconstantqual, Plan *subplan);
static ProjectSet *make_project_set(List *tlist, Plan *subplan);
static ModifyTable *make_modifytable(PlannerInfo *root,
CmdType operation, bool canSetTag,
- Index nominalRelation,
+ Index nominalRelation, List *partitioned_rels,
List *resultRelations, List *subplans,
List *withCheckOptionLists, List *returningLists,
List *rowMarks, OnConflictExpr *onconflict, int epqParam);
@@ -1026,7 +1026,7 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path)
* parent-rel Vars it'll be asked to emit.
*/
- plan = make_append(subplans, tlist);
+ plan = make_append(subplans, tlist, best_path->partitioned_rels);
copy_generic_path_info(&plan->plan, (Path *) best_path);
@@ -1134,6 +1134,7 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path)
subplans = lappend(subplans, subplan);
}
+ node->partitioned_rels = best_path->partitioned_rels;
node->mergeplans = subplans;
return (Plan *) node;
@@ -2314,6 +2315,7 @@ create_modifytable_plan(PlannerInfo *root, ModifyTablePath *best_path)
best_path->operation,
best_path->canSetTag,
best_path->nominalRelation,
+ best_path->partitioned_rels,
best_path->resultRelations,
subplans,
best_path->withCheckOptionLists,
@@ -5161,7 +5163,7 @@ make_foreignscan(List *qptlist,
}
static Append *
-make_append(List *appendplans, List *tlist)
+make_append(List *appendplans, List *tlist, List *partitioned_rels)
{
Append *node = makeNode(Append);
Plan *plan = &node->plan;
@@ -5170,6 +5172,7 @@ make_append(List *appendplans, List *tlist)
plan->qual = NIL;
plan->lefttree = NULL;
plan->righttree = NULL;
+ node->partitioned_rels = partitioned_rels;
node->appendplans = appendplans;
return node;
@@ -6282,7 +6285,7 @@ make_project_set(List *tlist,
static ModifyTable *
make_modifytable(PlannerInfo *root,
CmdType operation, bool canSetTag,
- Index nominalRelation,
+ Index nominalRelation, List *partitioned_rels,
List *resultRelations, List *subplans,
List *withCheckOptionLists, List *returningLists,
List *rowMarks, OnConflictExpr *onconflict, int epqParam)
@@ -6308,6 +6311,7 @@ make_modifytable(PlannerInfo *root,
node->operation = operation;
node->canSetTag = canSetTag;
node->nominalRelation = nominalRelation;
+ node->partitioned_rels = partitioned_rels;
node->resultRelations = resultRelations;
node->resultRelIndex = -1; /* will be set correctly in setrefs.c */
node->plans = subplans;
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 02286d9c52..cbdea1f537 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -212,6 +212,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
glob->finalrtable = NIL;
glob->finalrowmarks = NIL;
glob->resultRelations = NIL;
+ glob->nonleafResultRelations = NIL;
glob->relationOids = NIL;
glob->invalItems = NIL;
glob->nParamExec = 0;
@@ -380,6 +381,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
Assert(glob->finalrtable == NIL);
Assert(glob->finalrowmarks == NIL);
Assert(glob->resultRelations == NIL);
+ Assert(glob->nonleafResultRelations == NIL);
top_plan = set_plan_references(root, top_plan);
/* ... and the subplans (both regular subplans and initplans) */
Assert(list_length(glob->subplans) == list_length(glob->subroots));
@@ -405,6 +407,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
result->planTree = top_plan;
result->rtable = glob->finalrtable;
result->resultRelations = glob->resultRelations;
+ result->nonleafResultRelations = glob->nonleafResultRelations;
result->subplans = glob->subplans;
result->rewindPlanIDs = glob->rewindPlanIDs;
result->rowMarks = glob->finalrowmarks;
@@ -474,6 +477,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
root->multiexpr_params = NIL;
root->eq_classes = NIL;
root->append_rel_list = NIL;
+ root->pcinfo_list = NIL;
root->rowMarks = NIL;
memset(root->upper_rels, 0, sizeof(root->upper_rels));
memset(root->upper_targets, 0, sizeof(root->upper_targets));
@@ -1007,6 +1011,8 @@ inheritance_planner(PlannerInfo *root)
RelOptInfo *final_rel;
ListCell *lc;
Index rti;
+ RangeTblEntry *parent_rte;
+ List *partitioned_rels = NIL;
Assert(parse->commandType != CMD_INSERT);
@@ -1065,13 +1071,24 @@ inheritance_planner(PlannerInfo *root)
}
/*
+ * If the parent RTE is a partitioned table, we should use that as the
+ * nominal relation, because the RTEs added for partitioned tables
+ * (including the root parent) as child members of the inheritance set
+ * do not appear anywhere else in the plan. The situation is exactly
+ * the opposite in the case of non-partitioned inheritance parent as
+ * described below.
+ */
+ parent_rte = rt_fetch(parentRTindex, root->parse->rtable);
+ if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
+ nominalRelation = parentRTindex;
+
+ /*
* And now we can get on with generating a plan for each child table.
*/
foreach(lc, root->append_rel_list)
{
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
PlannerInfo *subroot;
- RangeTblEntry *parent_rte;
RangeTblEntry *child_rte;
RelOptInfo *sub_final_rel;
Path *subpath;
@@ -1216,15 +1233,25 @@ inheritance_planner(PlannerInfo *root)
grouping_planner(subroot, true, 0.0 /* retrieve all tuples */ );
/*
- * We'll use the first child relation (even if it's excluded) as the
- * nominal target relation of the ModifyTable node. Because of the
- * way expand_inherited_rtentry works, this should always be the RTE
- * representing the parent table in its role as a simple member of the
- * inheritance set. (It would be logically cleaner to use the
- * inheritance parent RTE as the nominal target; but since that RTE
- * will not be otherwise referenced in the plan, doing so would give
- * rise to confusing use of multiple aliases in EXPLAIN output for
- * what the user will think is the "same" table.)
+ * Set the nomimal target relation of the ModifyTable node if not
+ * already done. We use the inheritance parent RTE as the nominal
+ * target relation if it's a partitioned table (see just above this
+ * loop). In the non-partitioned parent case, we'll use the first
+ * child relation (even if it's excluded) as the nominal target
+ * relation. Because of the way expand_inherited_rtentry works, the
+ * latter should be the RTE representing the parent table in its role
+ * as a simple member of the inheritance set.
+ *
+ * It would be logically cleaner to *always* use the inheritance
+ * parent RTE as the nominal relation; but that RTE is not otherwise
+ * referenced in the plan in the non-partitioned inheritance case.
+ * Instead the duplicate child RTE created by expand_inherited_rtentry
+ * is used elsewhere in the plan, so using the original parent RTE
+ * would give rise to confusing use of multiple aliases in EXPLAIN
+ * output for what the user will think is the "same" table. OTOH,
+ * it's not a problem in the partitioned inheritance case, because
+ * the duplicate child RTE added for the parent does not appear
+ * anywhere else in the plan tree.
*/
if (nominalRelation < 0)
nominalRelation = appinfo->child_relid;
@@ -1298,6 +1325,13 @@ inheritance_planner(PlannerInfo *root)
Assert(!parse->onConflict);
}
+ if (parent_rte->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ partitioned_rels = get_partitioned_child_rels(root, parentRTindex);
+ /* The root partitioned table is included as a child rel */
+ Assert(list_length(partitioned_rels) >= 1);
+ }
+
/* Result path must go into outer query's FINAL upperrel */
final_rel = fetch_upper_rel(root, UPPERREL_FINAL, NULL);
@@ -1351,6 +1385,7 @@ inheritance_planner(PlannerInfo *root)
parse->commandType,
parse->canSetTag,
nominalRelation,
+ partitioned_rels,
resultRelations,
subpaths,
subroots,
@@ -2046,6 +2081,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
parse->commandType,
parse->canSetTag,
parse->resultRelation,
+ NIL,
list_make1_int(parse->resultRelation),
list_make1(path),
list_make1(root),
@@ -3348,7 +3384,8 @@ create_grouping_paths(PlannerInfo *root,
create_append_path(grouped_rel,
paths,
NULL,
- 0);
+ 0,
+ NIL);
path->pathtarget = target;
}
else
@@ -5470,3 +5507,33 @@ plan_cluster_use_sort(Oid tableOid, Oid indexOid)
return (seqScanAndSortPath.total_cost < indexScanPath->path.total_cost);
}
+
+/*
+ * get_partitioned_child_rels
+ * Returns a list of the RT indexes of the partitioned child relations
+ * with rti as the root parent RT index.
+ *
+ * Note: Only call this function on RTEs known to be partitioned tables.
+ */
+List *
+get_partitioned_child_rels(PlannerInfo *root, Index rti)
+{
+ List *result = NIL;
+ ListCell *l;
+
+ foreach(l, root->pcinfo_list)
+ {
+ PartitionedChildRelInfo *pc = lfirst(l);
+
+ if (pc->parent_relid == rti)
+ {
+ result = pc->child_rels;
+ break;
+ }
+ }
+
+ /* The root partitioned table is included as a child rel */
+ Assert(list_length(result) >= 1);
+
+ return result;
+}
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 5f3027e96f..5930747eba 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -835,6 +835,10 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
splan->nominalRelation += rtoffset;
splan->exclRelRTI += rtoffset;
+ foreach(l, splan->partitioned_rels)
+ {
+ lfirst_int(l) += rtoffset;
+ }
foreach(l, splan->resultRelations)
{
lfirst_int(l) += rtoffset;
@@ -863,6 +867,15 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
root->glob->resultRelations =
list_concat(root->glob->resultRelations,
list_copy(splan->resultRelations));
+
+ /*
+ * If the main target relation is a partitioned table, the
+ * following list contains the RT indexes of partitioned child
+ * relations, which are not included in the above list.
+ */
+ root->glob->nonleafResultRelations =
+ list_concat(root->glob->nonleafResultRelations,
+ list_copy(splan->partitioned_rels));
}
break;
case T_Append:
@@ -875,6 +888,10 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
*/
set_dummy_tlist_references(plan, rtoffset);
Assert(splan->plan.qual == NIL);
+ foreach(l, splan->partitioned_rels)
+ {
+ lfirst_int(l) += rtoffset;
+ }
foreach(l, splan->appendplans)
{
lfirst(l) = set_plan_refs(root,
@@ -893,6 +910,10 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset)
*/
set_dummy_tlist_references(plan, rtoffset);
Assert(splan->plan.qual == NIL);
+ foreach(l, splan->partitioned_rels)
+ {
+ lfirst_int(l) += rtoffset;
+ }
foreach(l, splan->mergeplans)
{
lfirst(l) = set_plan_refs(root,
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 1389db18ba..d88738ec7c 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -566,7 +566,7 @@ generate_union_path(SetOperationStmt *op, PlannerInfo *root,
/*
* Append the child results together.
*/
- path = (Path *) create_append_path(result_rel, pathlist, NULL, 0);
+ path = (Path *) create_append_path(result_rel, pathlist, NULL, 0, NIL);
/* We have to manually jam the right tlist into the path; ick */
path->pathtarget = create_pathtarget(root, tlist);
@@ -678,7 +678,7 @@ generate_nonunion_path(SetOperationStmt *op, PlannerInfo *root,
/*
* Append the child results together.
*/
- path = (Path *) create_append_path(result_rel, pathlist, NULL, 0);
+ path = (Path *) create_append_path(result_rel, pathlist, NULL, 0, NIL);
/* We have to manually jam the right tlist into the path; ick */
path->pathtarget = create_pathtarget(root, tlist);
@@ -1364,6 +1364,9 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
List *inhOIDs;
List *appinfos;
ListCell *l;
+ bool need_append;
+ PartitionedChildRelInfo *pcinfo;
+ List *partitioned_child_rels = NIL;
/* Does RT entry allow inheritance? */
if (!rte->inh)
@@ -1435,6 +1438,7 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
/* Scan the inheritance set and expand it */
appinfos = NIL;
+ need_append = false;
foreach(l, inhOIDs)
{
Oid childOID = lfirst_oid(l);
@@ -1483,36 +1487,46 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
childRTindex = list_length(parse->rtable);
/*
- * Build an AppendRelInfo for this parent and child.
+ * Build an AppendRelInfo for this parent and child, unless the child
+ * is a partitioned table.
*/
- appinfo = makeNode(AppendRelInfo);
- appinfo->parent_relid = rti;
- appinfo->child_relid = childRTindex;
- appinfo->parent_reltype = oldrelation->rd_rel->reltype;
- appinfo->child_reltype = newrelation->rd_rel->reltype;
- make_inh_translation_list(oldrelation, newrelation, childRTindex,
- &appinfo->translated_vars);
- appinfo->parent_reloid = parentOID;
- appinfos = lappend(appinfos, appinfo);
-
- /*
- * Translate the column permissions bitmaps to the child's attnums (we
- * have to build the translated_vars list before we can do this). But
- * if this is the parent table, leave copyObject's result alone.
- *
- * Note: we need to do this even though the executor won't run any
- * permissions checks on the child RTE. The insertedCols/updatedCols
- * bitmaps may be examined for trigger-firing purposes.
- */
- if (childOID != parentOID)
+ if (childrte->relkind != RELKIND_PARTITIONED_TABLE)
{
- childrte->selectedCols = translate_col_privs(rte->selectedCols,
+ need_append = true;
+ appinfo = makeNode(AppendRelInfo);
+ appinfo->parent_relid = rti;
+ appinfo->child_relid = childRTindex;
+ appinfo->parent_reltype = oldrelation->rd_rel->reltype;
+ appinfo->child_reltype = newrelation->rd_rel->reltype;
+ make_inh_translation_list(oldrelation, newrelation, childRTindex,
+ &appinfo->translated_vars);
+ appinfo->parent_reloid = parentOID;
+ appinfos = lappend(appinfos, appinfo);
+
+ /*
+ * Translate the column permissions bitmaps to the child's attnums
+ * (we have to build the translated_vars list before we can do
+ * this). But if this is the parent table, leave copyObject's
+ * result alone.
+ *
+ * Note: we need to do this even though the executor won't run any
+ * permissions checks on the child RTE. The
+ * insertedCols/updatedCols bitmaps may be examined for
+ * trigger-firing purposes.
+ */
+ if (childOID != parentOID)
+ {
+ childrte->selectedCols = translate_col_privs(rte->selectedCols,
appinfo->translated_vars);
- childrte->insertedCols = translate_col_privs(rte->insertedCols,
+ childrte->insertedCols = translate_col_privs(rte->insertedCols,
appinfo->translated_vars);
- childrte->updatedCols = translate_col_privs(rte->updatedCols,
+ childrte->updatedCols = translate_col_privs(rte->updatedCols,
appinfo->translated_vars);
+ }
}
+ else
+ partitioned_child_rels = lappend_int(partitioned_child_rels,
+ childRTindex);
/*
* Build a PlanRowMark if parent is marked FOR UPDATE/SHARE.
@@ -1529,7 +1543,13 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
newrc->allMarkTypes = (1 << newrc->markType);
newrc->strength = oldrc->strength;
newrc->waitPolicy = oldrc->waitPolicy;
- newrc->isParent = false;
+
+ /*
+ * We mark RowMarks for partitioned child tables as parent RowMarks
+ * so that the executor ignores them (except their existence means
+ * that the child tables be locked using appropriate mode).
+ */
+ newrc->isParent = (childrte->relkind == RELKIND_PARTITIONED_TABLE);
/* Include child's rowmark type in parent's allMarkTypes */
oldrc->allMarkTypes |= newrc->allMarkTypes;
@@ -1545,18 +1565,37 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
heap_close(oldrelation, NoLock);
/*
- * If all the children were temp tables, pretend it's a non-inheritance
- * situation. The duplicate RTE we added for the parent table is
- * harmless, so we don't bother to get rid of it; ditto for the useless
- * PlanRowMark node.
+ * If all the children were temp tables or a partitioned parent did not
+ * have any leaf partitions, pretend it's a non-inheritance situation; we
+ * don't need Append node in that case. The duplicate RTE we added for
+ * the parent table is harmless, so we don't bother to get rid of it;
+ * ditto for the useless PlanRowMark node.
*/
- if (list_length(appinfos) < 2)
+ if (!need_append)
{
/* Clear flag before returning */
rte->inh = false;
return;
}
+ /*
+ * We keep a list of objects in root, each of which maps a partitioned
+ * parent RT index to the list of RT indexes of its partitioned child
+ * tables. When creating an Append or a ModifyTable path for the parent,
+ * we copy the child RT index list verbatim to the path so that it could
+ * be carried over to the executor so that the latter could identify
+ * the partitioned child tables.
+ */
+ if (partitioned_child_rels != NIL)
+ {
+ pcinfo = makeNode(PartitionedChildRelInfo);
+
+ Assert(rte->relkind == RELKIND_PARTITIONED_TABLE);
+ pcinfo->parent_relid = rti;
+ pcinfo->child_rels = partitioned_child_rels;
+ root->pcinfo_list = lappend(root->pcinfo_list, pcinfo);
+ }
+
/* Otherwise, OK to add to root->append_rel_list */
root->append_rel_list = list_concat(root->append_rel_list, appinfos);
}
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 8ce772d274..fca96eb001 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -1201,7 +1201,7 @@ create_tidscan_path(PlannerInfo *root, RelOptInfo *rel, List *tidquals,
*/
AppendPath *
create_append_path(RelOptInfo *rel, List *subpaths, Relids required_outer,
- int parallel_workers)
+ int parallel_workers, List *partitioned_rels)
{
AppendPath *pathnode = makeNode(AppendPath);
ListCell *l;
@@ -1216,6 +1216,7 @@ create_append_path(RelOptInfo *rel, List *subpaths, Relids required_outer,
pathnode->path.parallel_workers = parallel_workers;
pathnode->path.pathkeys = NIL; /* result is always considered
* unsorted */
+ pathnode->partitioned_rels = partitioned_rels;
pathnode->subpaths = subpaths;
/*
@@ -1258,7 +1259,8 @@ create_merge_append_path(PlannerInfo *root,
RelOptInfo *rel,
List *subpaths,
List *pathkeys,
- Relids required_outer)
+ Relids required_outer,
+ List *partitioned_rels)
{
MergeAppendPath *pathnode = makeNode(MergeAppendPath);
Cost input_startup_cost;
@@ -1274,6 +1276,7 @@ create_merge_append_path(PlannerInfo *root,
pathnode->path.parallel_safe = rel->consider_parallel;
pathnode->path.parallel_workers = 0;
pathnode->path.pathkeys = pathkeys;
+ pathnode->partitioned_rels = partitioned_rels;
pathnode->subpaths = subpaths;
/*
@@ -3105,7 +3108,7 @@ create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
ModifyTablePath *
create_modifytable_path(PlannerInfo *root, RelOptInfo *rel,
CmdType operation, bool canSetTag,
- Index nominalRelation,
+ Index nominalRelation, List *partitioned_rels,
List *resultRelations, List *subpaths,
List *subroots,
List *withCheckOptionLists, List *returningLists,
@@ -3172,6 +3175,7 @@ create_modifytable_path(PlannerInfo *root, RelOptInfo *rel,
pathnode->operation = operation;
pathnode->canSetTag = canSetTag;
pathnode->nominalRelation = nominalRelation;
+ pathnode->partitioned_rels = partitioned_rels;
pathnode->resultRelations = resultRelations;
pathnode->subpaths = subpaths;
pathnode->subroots = subroots;
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index fa02374811..d284ab7d3d 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -1514,7 +1514,8 @@ AcquireExecutorLocks(List *stmt_list, bool acquire)
* fail if it's been dropped entirely --- we'll just transiently
* acquire a non-conflicting lock.
*/
- if (list_member_int(plannedstmt->resultRelations, rt_index))
+ if (list_member_int(plannedstmt->resultRelations, rt_index) ||
+ list_member_int(plannedstmt->nonleafResultRelations, rt_index))
lockmode = RowExclusiveLock;
else if ((rc = get_plan_rowmark(plannedstmt->rowMarks, rt_index)) != NULL &&
RowMarkRequiresRowShareLock(rc->markType))
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 02dbe7b228..e64d6fb93f 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -375,6 +375,7 @@ extern void RegisterExprContextCallback(ExprContext *econtext,
extern void UnregisterExprContextCallback(ExprContext *econtext,
ExprContextCallbackFunction function,
Datum arg);
+extern void ExecLockNonLeafAppendTables(List *partitioned_rels, EState *estate);
/*
* prototypes from functions in execIndexing.c
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 2bc7a5df11..2cbd6d77b8 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -275,6 +275,7 @@ typedef enum NodeTag
T_PlaceHolderVar,
T_SpecialJoinInfo,
T_AppendRelInfo,
+ T_PartitionedChildRelInfo,
T_PlaceHolderInfo,
T_MinMaxAggInfo,
T_PlannerParamItem,
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index b880dc16cf..4a95e16b69 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -65,6 +65,9 @@ typedef struct PlannedStmt
/* rtable indexes of target relations for INSERT/UPDATE/DELETE */
List *resultRelations; /* integer list of RT indexes, or NIL */
+ /* rtable indexes of non-leaf target relations for INSERT/UPDATE/DELETE */
+ List *nonleafResultRelations;
+
List *subplans; /* Plan trees for SubPlan expressions */
Bitmapset *rewindPlanIDs; /* indices of subplans that require REWIND */
@@ -202,6 +205,8 @@ typedef struct ModifyTable
CmdType operation; /* INSERT, UPDATE, or DELETE */
bool canSetTag; /* do we set the command tag/es_processed? */
Index nominalRelation; /* Parent RT index for use of EXPLAIN */
+ /* RT indexes of non-leaf tables in a partition tree */
+ List *partitioned_rels;
List *resultRelations; /* integer list of RT indexes */
int resultRelIndex; /* index of first resultRel in plan's list */
List *plans; /* plan(s) producing source data */
@@ -227,6 +232,8 @@ typedef struct ModifyTable
typedef struct Append
{
Plan plan;
+ /* RT indexes of non-leaf tables in a partition tree */
+ List *partitioned_rels;
List *appendplans;
} Append;
@@ -238,6 +245,8 @@ typedef struct Append
typedef struct MergeAppend
{
Plan plan;
+ /* RT indexes of non-leaf tables in a partition tree */
+ List *partitioned_rels;
List *mergeplans;
/* remaining fields are just like the sort-key info in struct Sort */
int numCols; /* number of sort-key columns */
@@ -937,11 +946,12 @@ typedef enum RowMarkType
* When the planner discovers that a relation is the root of an inheritance
* tree, it sets isParent true, and adds an additional PlanRowMark to the
* list for each child relation (including the target rel itself in its role
- * as a child). The child entries have rti == child rel's RT index and
- * prti == parent's RT index, and can therefore be recognized as children by
- * the fact that prti != rti. The parent's allMarkTypes field gets the OR
- * of (1<<markType) across all its children (this definition allows children
- * to use different markTypes).
+ * as a child). isParent is also set to true for the partitioned child
+ * relations, which are not scanned just like the root parent. The child
+ * entries have rti == child rel's RT index and prti == parent's RT index,
+ * and can therefore be recognized as children by the fact that prti != rti.
+ * The parent's allMarkTypes field gets the OR of (1<<markType) across all
+ * its children (this definition allows children to use different markTypes).
*
* The planner also adds resjunk output columns to the plan that carry
* information sufficient to identify the locked or fetched rows. When
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index 05d6f07aea..1c88a79a21 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -107,6 +107,8 @@ typedef struct PlannerGlobal
List *resultRelations; /* "flat" list of integer RT indexes */
+ List *nonleafResultRelations; /* "flat" list of integer RT indexes */
+
List *relationOids; /* OIDs of relations the plan depends on */
List *invalItems; /* other dependencies, as PlanInvalItems */
@@ -248,6 +250,8 @@ typedef struct PlannerInfo
List *append_rel_list; /* list of AppendRelInfos */
+ List *pcinfo_list; /* list of PartitionedChildRelInfos */
+
List *rowMarks; /* list of PlanRowMarks */
List *placeholder_list; /* list of PlaceHolderInfos */
@@ -1116,6 +1120,8 @@ typedef struct CustomPath
typedef struct AppendPath
{
Path path;
+ /* RT indexes of non-leaf tables in a partition tree */
+ List *partitioned_rels;
List *subpaths; /* list of component Paths */
} AppendPath;
@@ -1134,6 +1140,8 @@ typedef struct AppendPath
typedef struct MergeAppendPath
{
Path path;
+ /* RT indexes of non-leaf tables in a partition tree */
+ List *partitioned_rels;
List *subpaths; /* list of component Paths */
double limit_tuples; /* hard limit on output tuples, or -1 */
} MergeAppendPath;
@@ -1482,6 +1490,8 @@ typedef struct ModifyTablePath
CmdType operation; /* INSERT, UPDATE, or DELETE */
bool canSetTag; /* do we set the command tag/es_processed? */
Index nominalRelation; /* Parent RT index for use of EXPLAIN */
+ /* RT indexes of non-leaf tables in a partition tree */
+ List *partitioned_rels;
List *resultRelations; /* integer list of RT indexes */
List *subpaths; /* Path(s) producing source data */
List *subroots; /* per-target-table PlannerInfos */
@@ -1836,10 +1846,10 @@ typedef struct SpecialJoinInfo
*
* When we expand an inheritable table or a UNION-ALL subselect into an
* "append relation" (essentially, a list of child RTEs), we build an
- * AppendRelInfo for each child RTE. The list of AppendRelInfos indicates
- * which child RTEs must be included when expanding the parent, and each
- * node carries information needed to translate Vars referencing the parent
- * into Vars referencing that child.
+ * AppendRelInfo for each non-partitioned child RTE. The list of
+ * AppendRelInfos indicates which child RTEs must be included when expanding
+ * the parent, and each node carries information needed to translate Vars
+ * referencing the parent into Vars referencing that child.
*
* These structs are kept in the PlannerInfo node's append_rel_list.
* Note that we just throw all the structs into one list, and scan the
@@ -1914,6 +1924,25 @@ typedef struct AppendRelInfo
} AppendRelInfo;
/*
+ * For a partitioned table, this maps its RT index to the list of RT indexes
+ * of the partitioned child tables in the partition tree. We need to
+ * separately store this information, because we do not create AppendRelInfos
+ * for the partitioned child tables of a parent table, since AppendRelInfos
+ * contain information that is unnecessary for the partitioned child tables.
+ * The child_rels list must contain at least one element, because the parent
+ * partitioned table is itself counted as a child.
+ *
+ * These structs are kept in the PlannerInfo node's pcinfo_list.
+ */
+typedef struct PartitionedChildRelInfo
+{
+ NodeTag type;
+
+ Index parent_relid;
+ List *child_rels;
+} PartitionedChildRelInfo;
+
+/*
* For each distinct placeholder expression generated during planning, we
* store a PlaceHolderInfo node in the PlannerInfo node's placeholder_list.
* This stores info that is needed centrally rather than in each copy of the
diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h
index 373c7221a8..81640de7ab 100644
--- a/src/include/optimizer/pathnode.h
+++ b/src/include/optimizer/pathnode.h
@@ -64,12 +64,14 @@ extern BitmapOrPath *create_bitmap_or_path(PlannerInfo *root,
extern TidPath *create_tidscan_path(PlannerInfo *root, RelOptInfo *rel,
List *tidquals, Relids required_outer);
extern AppendPath *create_append_path(RelOptInfo *rel, List *subpaths,
- Relids required_outer, int parallel_workers);
+ Relids required_outer, int parallel_workers,
+ List *partitioned_rels);
extern MergeAppendPath *create_merge_append_path(PlannerInfo *root,
RelOptInfo *rel,
List *subpaths,
List *pathkeys,
- Relids required_outer);
+ Relids required_outer,
+ List *partitioned_rels);
extern ResultPath *create_result_path(PlannerInfo *root, RelOptInfo *rel,
PathTarget *target, List *resconstantqual);
extern MaterialPath *create_material_path(RelOptInfo *rel, Path *subpath);
@@ -232,7 +234,7 @@ extern LockRowsPath *create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
extern ModifyTablePath *create_modifytable_path(PlannerInfo *root,
RelOptInfo *rel,
CmdType operation, bool canSetTag,
- Index nominalRelation,
+ Index nominalRelation, List *partitioned_rels,
List *resultRelations, List *subpaths,
List *subroots,
List *withCheckOptionLists, List *returningLists,
diff --git a/src/include/optimizer/planner.h b/src/include/optimizer/planner.h
index 6922933e36..f3aaa23975 100644
--- a/src/include/optimizer/planner.h
+++ b/src/include/optimizer/planner.h
@@ -57,4 +57,6 @@ extern Expr *preprocess_phv_expression(PlannerInfo *root, Expr *expr);
extern bool plan_cluster_use_sort(Oid tableOid, Oid indexOid);
+extern List *get_partitioned_child_rels(PlannerInfo *root, Index rti);
+
#endif /* PLANNER_H */
diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out
index 6494b205c4..6163ed8117 100644
--- a/src/test/regress/expected/inherit.out
+++ b/src/test/regress/expected/inherit.out
@@ -588,6 +588,45 @@ select tableoid::regclass::text as relname, bar.* from bar order by 1,2;
bar2 | 4 | 104
(8 rows)
+-- Check UPDATE with *partitioned* inherited target and an appendrel subquery
+create table some_tab (a int);
+insert into some_tab values (0);
+create table some_tab_child () inherits (some_tab);
+insert into some_tab_child values (1);
+create table parted_tab (a int, b char) partition by list (a);
+create table parted_tab_part1 partition of parted_tab for values in (1);
+create table parted_tab_part2 partition of parted_tab for values in (2);
+create table parted_tab_part3 partition of parted_tab for values in (3);
+insert into parted_tab values (1, 'a'), (2, 'a'), (3, 'a');
+update parted_tab set b = 'b'
+from
+ (select a from some_tab union all select a+1 from some_tab) ss (a)
+where parted_tab.a = ss.a;
+select tableoid::regclass::text as relname, parted_tab.* from parted_tab order by 1,2;
+ relname | a | b
+------------------+---+---
+ parted_tab_part1 | 1 | b
+ parted_tab_part2 | 2 | b
+ parted_tab_part3 | 3 | a
+(3 rows)
+
+truncate parted_tab;
+insert into parted_tab values (1, 'a'), (2, 'a'), (3, 'a');
+update parted_tab set b = 'b'
+from
+ (select 0 from parted_tab union all select 1 from parted_tab) ss (a)
+where parted_tab.a = ss.a;
+select tableoid::regclass::text as relname, parted_tab.* from parted_tab order by 1,2;
+ relname | a | b
+------------------+---+---
+ parted_tab_part1 | 1 | b
+ parted_tab_part2 | 2 | a
+ parted_tab_part3 | 3 | a
+(3 rows)
+
+drop table parted_tab;
+drop table some_tab cascade;
+NOTICE: drop cascades to table some_tab_child
/* Test multiple inheritance of column defaults */
CREATE TABLE firstparent (tomorrow date default now()::date + 1);
CREATE TABLE secondparent (tomorrow date default now() :: date + 1);
@@ -1611,71 +1650,60 @@ explain (costs off) select * from list_parted;
QUERY PLAN
--------------------------------
Append
- -> Seq Scan on list_parted
-> Seq Scan on part_ab_cd
-> Seq Scan on part_ef_gh
-> Seq Scan on part_null_xy
-(5 rows)
+(4 rows)
explain (costs off) select * from list_parted where a is null;
QUERY PLAN
--------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (a IS NULL)
-> Seq Scan on part_null_xy
Filter: (a IS NULL)
-(5 rows)
+(3 rows)
explain (costs off) select * from list_parted where a is not null;
QUERY PLAN
---------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (a IS NOT NULL)
-> Seq Scan on part_ab_cd
Filter: (a IS NOT NULL)
-> Seq Scan on part_ef_gh
Filter: (a IS NOT NULL)
-> Seq Scan on part_null_xy
Filter: (a IS NOT NULL)
-(9 rows)
+(7 rows)
explain (costs off) select * from list_parted where a in ('ab', 'cd', 'ef');
QUERY PLAN
----------------------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-> Seq Scan on part_ab_cd
Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-> Seq Scan on part_ef_gh
Filter: ((a)::text = ANY ('{ab,cd,ef}'::text[]))
-(7 rows)
+(5 rows)
explain (costs off) select * from list_parted where a = 'ab' or a in (null, 'cd');
QUERY PLAN
---------------------------------------------------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_ab_cd
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_ef_gh
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-> Seq Scan on part_null_xy
Filter: (((a)::text = 'ab'::text) OR ((a)::text = ANY ('{NULL,cd}'::text[])))
-(9 rows)
+(7 rows)
explain (costs off) select * from list_parted where a = 'ab';
QUERY PLAN
------------------------------------------
Append
- -> Seq Scan on list_parted
- Filter: ((a)::text = 'ab'::text)
-> Seq Scan on part_ab_cd
Filter: ((a)::text = 'ab'::text)
-(5 rows)
+(3 rows)
create table range_list_parted (
a int,
@@ -1695,14 +1723,9 @@ create table part_40_inf_ab partition of part_40_inf for values in ('ab');
create table part_40_inf_cd partition of part_40_inf for values in ('cd');
create table part_40_inf_null partition of part_40_inf for values in (null);
explain (costs off) select * from range_list_parted;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- -> Seq Scan on part_1_10
- -> Seq Scan on part_10_20
- -> Seq Scan on part_21_30
- -> Seq Scan on part_40_inf
-> Seq Scan on part_1_10_ab
-> Seq Scan on part_1_10_cd
-> Seq Scan on part_10_20_ab
@@ -1712,36 +1735,22 @@ explain (costs off) select * from range_list_parted;
-> Seq Scan on part_40_inf_ab
-> Seq Scan on part_40_inf_cd
-> Seq Scan on part_40_inf_null
-(15 rows)
+(10 rows)
explain (costs off) select * from range_list_parted where a = 5;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+--------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (a = 5)
- -> Seq Scan on part_1_10
- Filter: (a = 5)
-> Seq Scan on part_1_10_ab
Filter: (a = 5)
-> Seq Scan on part_1_10_cd
Filter: (a = 5)
-(9 rows)
+(5 rows)
explain (costs off) select * from range_list_parted where b = 'ab';
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_1_10
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_10_20
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_21_30
- Filter: (b = 'ab'::bpchar)
- -> Seq Scan on part_40_inf
- Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_1_10_ab
Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_10_20_ab
@@ -1750,27 +1759,19 @@ explain (costs off) select * from range_list_parted where b = 'ab';
Filter: (b = 'ab'::bpchar)
-> Seq Scan on part_40_inf_ab
Filter: (b = 'ab'::bpchar)
-(19 rows)
+(9 rows)
explain (costs off) select * from range_list_parted where a between 3 and 23 and b in ('ab');
QUERY PLAN
-----------------------------------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_1_10
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_10_20
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
- -> Seq Scan on part_21_30
- Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_1_10_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_10_20_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-> Seq Scan on part_21_30_ab
Filter: ((a >= 3) AND (a <= 23) AND (b = 'ab'::bpchar))
-(15 rows)
+(7 rows)
/* Should select no rows because range partition key cannot be null */
explain (costs off) select * from range_list_parted where a is null;
@@ -1782,37 +1783,17 @@ explain (costs off) select * from range_list_parted where a is null;
/* Should only select rows from the null-accepting partition */
explain (costs off) select * from range_list_parted where b is null;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (b IS NULL)
- -> Seq Scan on part_1_10
- Filter: (b IS NULL)
- -> Seq Scan on part_10_20
- Filter: (b IS NULL)
- -> Seq Scan on part_21_30
- Filter: (b IS NULL)
- -> Seq Scan on part_40_inf
- Filter: (b IS NULL)
-> Seq Scan on part_40_inf_null
Filter: (b IS NULL)
-(13 rows)
+(3 rows)
explain (costs off) select * from range_list_parted where a is not null and a < 67;
QUERY PLAN
------------------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_1_10
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_10_20
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_21_30
- Filter: ((a IS NOT NULL) AND (a < 67))
- -> Seq Scan on part_40_inf
- Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_1_10_ab
Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_1_10_cd
@@ -1831,23 +1812,19 @@ explain (costs off) select * from range_list_parted where a is not null and a <
Filter: ((a IS NOT NULL) AND (a < 67))
-> Seq Scan on part_40_inf_null
Filter: ((a IS NOT NULL) AND (a < 67))
-(29 rows)
+(19 rows)
explain (costs off) select * from range_list_parted where a >= 30;
- QUERY PLAN
--------------------------------------
+ QUERY PLAN
+------------------------------------
Append
- -> Seq Scan on range_list_parted
- Filter: (a >= 30)
- -> Seq Scan on part_40_inf
- Filter: (a >= 30)
-> Seq Scan on part_40_inf_ab
Filter: (a >= 30)
-> Seq Scan on part_40_inf_cd
Filter: (a >= 30)
-> Seq Scan on part_40_inf_null
Filter: (a >= 30)
-(11 rows)
+(7 rows)
drop table list_parted;
drop table range_list_parted;
diff --git a/src/test/regress/expected/tablesample.out b/src/test/regress/expected/tablesample.out
index b18e420e9b..d3794140fb 100644
--- a/src/test/regress/expected/tablesample.out
+++ b/src/test/regress/expected/tablesample.out
@@ -322,12 +322,10 @@ explain (costs off)
QUERY PLAN
-------------------------------------------
Append
- -> Sample Scan on parted_sample
- Sampling: bernoulli ('100'::real)
-> Sample Scan on parted_sample_1
Sampling: bernoulli ('100'::real)
-> Sample Scan on parted_sample_2
Sampling: bernoulli ('100'::real)
-(7 rows)
+(5 rows)
drop table parted_sample, parted_sample_1, parted_sample_2;
diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql
index e3e9e34895..d43b75c4a7 100644
--- a/src/test/regress/sql/inherit.sql
+++ b/src/test/regress/sql/inherit.sql
@@ -128,6 +128,34 @@ where bar.f1 = ss.f1;
select tableoid::regclass::text as relname, bar.* from bar order by 1,2;
+-- Check UPDATE with *partitioned* inherited target and an appendrel subquery
+create table some_tab (a int);
+insert into some_tab values (0);
+create table some_tab_child () inherits (some_tab);
+insert into some_tab_child values (1);
+create table parted_tab (a int, b char) partition by list (a);
+create table parted_tab_part1 partition of parted_tab for values in (1);
+create table parted_tab_part2 partition of parted_tab for values in (2);
+create table parted_tab_part3 partition of parted_tab for values in (3);
+insert into parted_tab values (1, 'a'), (2, 'a'), (3, 'a');
+
+update parted_tab set b = 'b'
+from
+ (select a from some_tab union all select a+1 from some_tab) ss (a)
+where parted_tab.a = ss.a;
+select tableoid::regclass::text as relname, parted_tab.* from parted_tab order by 1,2;
+
+truncate parted_tab;
+insert into parted_tab values (1, 'a'), (2, 'a'), (3, 'a');
+update parted_tab set b = 'b'
+from
+ (select 0 from parted_tab union all select 1 from parted_tab) ss (a)
+where parted_tab.a = ss.a;
+select tableoid::regclass::text as relname, parted_tab.* from parted_tab order by 1,2;
+
+drop table parted_tab;
+drop table some_tab cascade;
+
/* Test multiple inheritance of column defaults */
CREATE TABLE firstparent (tomorrow date default now()::date + 1);
--
2.11.0
[text/x-diff] 0002-Do-not-allocate-storage-for-partitioned-tables.patch (3.1K, ../../6837c359-45c4-8044-34d1-736756335a15@lab.ntt.co.jp/3-0002-Do-not-allocate-storage-for-partitioned-tables.patch)
download | inline diff:
From eb6bc35a29ab6f2111442549c5bf4a6aa282553a Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Tue, 24 Jan 2017 14:22:34 +0900
Subject: [PATCH 2/2] Do not allocate storage for partitioned tables.
Currently, it is not possible to insert any data into a partitioned
table. So, they're empty at all times, which means it is wasteful to
allocate relfilenode and related storage objects.
---
src/backend/access/common/reloptions.c | 3 +--
src/backend/catalog/heap.c | 17 ++++++++++-------
2 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 72e12532ab..d3b847e2e5 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -967,7 +967,6 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
case RELKIND_RELATION:
case RELKIND_TOASTVALUE:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
options = heap_reloptions(classForm->relkind, datum, false);
break;
case RELKIND_VIEW:
@@ -977,6 +976,7 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
options = index_reloptions(amoptions, datum, false);
break;
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
options = NULL;
break;
default:
@@ -1418,7 +1418,6 @@ heap_reloptions(char relkind, Datum reloptions, bool validate)
return (bytea *) rdopts;
case RELKIND_RELATION:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
default:
/* other relkinds are not supported */
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 41c0056556..2f5090b183 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -291,6 +291,7 @@ heap_create(const char *relname,
case RELKIND_VIEW:
case RELKIND_COMPOSITE_TYPE:
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
create_storage = false;
/*
@@ -1345,14 +1346,13 @@ heap_create_with_catalog(const char *relname,
if (oncommit != ONCOMMIT_NOOP)
register_on_commit_action(relid, oncommit);
- if (relpersistence == RELPERSISTENCE_UNLOGGED)
- {
- Assert(relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW ||
- relkind == RELKIND_TOASTVALUE ||
- relkind == RELKIND_PARTITIONED_TABLE);
-
+ /*
+ * We do not want to create any storage objects for a partitioned
+ * table, including the init fork.
+ */
+ if (relpersistence == RELPERSISTENCE_UNLOGGED &&
+ relkind != RELKIND_PARTITIONED_TABLE)
heap_create_init_fork(new_rel_desc);
- }
/*
* ok, the relation has been cataloged, so close our relations and return
@@ -1376,6 +1376,9 @@ heap_create_with_catalog(const char *relname,
void
heap_create_init_fork(Relation rel)
{
+ Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
+ rel->rd_rel->relkind == RELKIND_MATVIEW ||
+ rel->rd_rel->relkind == RELKIND_TOASTVALUE);
RelationOpenSmgr(rel);
smgrcreate(rel->rd_smgr, INIT_FORKNUM, false);
log_smgrcreate(&rel->rd_smgr->smgr_rnode.node, INIT_FORKNUM);
--
2.11.0
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-20 16:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-21 09:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-03-21 13:49 ` Robert Haas <robertmhaas@gmail.com>
2017-03-22 13:39 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
0 siblings, 1 reply; 96+ messages in thread
From: Robert Haas @ 2017-03-21 13:49 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; Michael Paquier <michael.paquier@gmail.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On Tue, Mar 21, 2017 at 5:05 AM, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
> Attached updated patches.
Committed 0001 after removing a comma.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-20 16:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-21 09:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 13:49 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
@ 2017-03-22 13:39 ` Robert Haas <robertmhaas@gmail.com>
2017-03-23 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
0 siblings, 1 reply; 96+ messages in thread
From: Robert Haas @ 2017-03-22 13:39 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; pgsql-hackers
Off-list by accident. Re-adding the list.
On Tue, Mar 21, 2017 at 10:37 AM, Robert Haas <robertmhaas@gmail.com> wrote:
> On Tue, Mar 21, 2017 at 9:49 AM, Robert Haas <robertmhaas@gmail.com> wrote:
>> On Tue, Mar 21, 2017 at 5:05 AM, Amit Langote
>> <Langote_Amit_f8@lab.ntt.co.jp> wrote:
>>> Attached updated patches.
>>
>> Committed 0001 after removing a comma.
>
> Regarding 0002, I notice this surprising behavior:
>
> rhaas=# create table foo (a int, b text) partition by list (a);
> CREATE TABLE
> rhaas=# select relfilenode from pg_class where oid = 'foo'::regclass;
> relfilenode
> -------------
> 16385
> (1 row)
>
> Why do we end up with a relfilenode if there's no storage? I would
> have expected to see 0 there.
>
> Other than that, there's not much to see here. I'm a little worried
> that you might have missed some case that can result in an access to
> the file, but I can't find one. Stuff I tried:
>
> VACUUM
> VACUUM FULL
> CLUSTER
> ANALYZE
> CREATE INDEX
> ALTER TABLE .. ALTER COLUMN .. TYPE
> TRUNCATE
>
> It would be good to go through and make sure all of those - and any
> others you can think of - are represented in the regression tests.
>
> Also, a documentation update is probably in order to explain that
> we're not going to accept heap_reloptions on the parent because the
> parent has no storage; such options must be set on the child in order
> to have effect.
>
> --
> Robert Haas
> EnterpriseDB: http://www.enterprisedb.com
> The Enterprise PostgreSQL Company
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-20 16:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-21 09:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 13:49 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-22 13:39 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
@ 2017-03-23 01:02 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-23 14:27 ` Re: Partitioned tables and relfilenode Maksim Milyutin <m.milyutin@postgrespro.ru>
0 siblings, 1 reply; 96+ messages in thread
From: Amit Langote @ 2017-03-23 01:02 UTC (permalink / raw)
To: Robert Haas <robertmhaas@gmail.com>; pgsql-hackers
> On Tue, Mar 21, 2017 at 10:37 AM, Robert Haas <robertmhaas@gmail.com> wrote:
>> On Tue, Mar 21, 2017 at 9:49 AM, Robert Haas <robertmhaas@gmail.com> wrote:
>>> On Tue, Mar 21, 2017 at 5:05 AM, Amit Langote
>>> <Langote_Amit_f8@lab.ntt.co.jp> wrote:
>>>> Attached updated patches.
>>>
>>> Committed 0001 after removing a comma.
>>
>> Regarding 0002,
Thanks for the review.
>> I notice this surprising behavior:
>>
>> rhaas=# create table foo (a int, b text) partition by list (a);
>> CREATE TABLE
>> rhaas=# select relfilenode from pg_class where oid = 'foo'::regclass;
>> relfilenode
>> -------------
>> 16385
>> (1 row)
>>
>> Why do we end up with a relfilenode if there's no storage? I would
>> have expected to see 0 there.
Hmm, I see that happening even with views (and other relkinds that do not
have storage):
create table foo (a int);
create view foov as select * from foo;
select relfilenode from pg_class where relname = 'foov';
-[ RECORD 1 ]------
relfilenode | 24606
create type typ as (a int);
select relfilenode from pg_class where relname = 'typ';
-[ RECORD 1 ]------
relfilenode | 24610
After staring at the relevant code, fixing things so that relfilenode is 0
for relations without storage seems to be slightly involved. In the header
comment of relmapper.c, there is a line:
Mapped catalogs have zero in their pg_class.relfilenode entries.
which is kind of significant for the relcache initialization code.
RelationInitPhysicalAddr() called when building a relcache entry
initializes the rd_rel.relfilenode from pg_class.relfilenode if it's valid
and from relation mapper if invalid (i.e. 0). So when relcache entries
for the mapped catalogs are being built, pg_class.relfilenode being
InvalidOid is a signal to get the same from the relmapper. Since the same
code path is exercised in other cases, all relations supposedly without
storage would wrongly be looked up in the relmapper. It may be possible
to fix that, but will require non-trivial rearrangement of relevant code.
>> Other than that, there's not much to see here. I'm a little worried
>> that you might have missed some case that can result in an access to
>> the file, but I can't find one. Stuff I tried:
>>
>> VACUUM
>> VACUUM FULL
>> CLUSTER
>> ANALYZE
>> CREATE INDEX
>> ALTER TABLE .. ALTER COLUMN .. TYPE
>> TRUNCATE
>>
>> It would be good to go through and make sure all of those - and any
>> others you can think of - are represented in the regression tests.
We now have tests that cover commands that previously would try to access
file for partitioned tables (most of those your listed above). The commit
yesterday to eliminate scan nodes is also covered by tests.
Speaking of - do you think the following error message is reasonable when
a a partitioned table is passed to pg_prewarm():
select pg_prewarm('p');
ERROR: fork "main" does not exist for this relation
It's the same if a view name is passed.
>> Also, a documentation update is probably in order to explain that
>> we're not going to accept heap_reloptions on the parent because the
>> parent has no storage; such options must be set on the child in order
>> to have effect.
Hmm, actually I am no longer sure if we should completely get rid of the
reloptions. Some options like fillfactor don't make sense, but we might
want to use the values for autovacuum_* options when we will improve
autovacuum's handling of partitioned tables. Maybe even parallel_workers
could be useful to specify for parent tables. So, I took out reloptions.c
changes from the patch for now and documented that specifying the storage
options for partitioned parents is ineffective currently. Does that make
sense?
Thanks,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Attachments:
[text/x-diff] 0001-Do-not-allocate-storage-for-partitioned-tables.patch (2.7K, ../../d937752c-bf74-5560-6b7c-a315efc1da77@lab.ntt.co.jp/2-0001-Do-not-allocate-storage-for-partitioned-tables.patch)
download | inline diff:
From aed0685b6bfb99a301e674221fb393cc4e660461 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Tue, 24 Jan 2017 14:22:34 +0900
Subject: [PATCH] Do not allocate storage for partitioned tables.
Currently, it is not possible to insert any data into a partitioned
table. So they're empty at all times, which means it is wasteful to
allocate relfilenode and related storage objects.
Also documented the fact that specifying storage options for partitioned
tables is ineffective at the moment.
---
doc/src/sgml/ref/create_table.sgml | 6 ++++++
src/backend/catalog/heap.c | 17 ++++++++++-------
2 files changed, 16 insertions(+), 7 deletions(-)
diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml
index 9ed25c05da..7ac55b17fa 100644
--- a/doc/src/sgml/ref/create_table.sgml
+++ b/doc/src/sgml/ref/create_table.sgml
@@ -1040,6 +1040,12 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
will use the table's parameter value.
</para>
+ <para>
+ Note that specifying the following parameters for partitioned tables has
+ no effect at the moment. You must specify them for individual leaf
+ partitions if necessary.
+ </para>
+
<variablelist>
<varlistentry>
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 41c0056556..2f5090b183 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -291,6 +291,7 @@ heap_create(const char *relname,
case RELKIND_VIEW:
case RELKIND_COMPOSITE_TYPE:
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
create_storage = false;
/*
@@ -1345,14 +1346,13 @@ heap_create_with_catalog(const char *relname,
if (oncommit != ONCOMMIT_NOOP)
register_on_commit_action(relid, oncommit);
- if (relpersistence == RELPERSISTENCE_UNLOGGED)
- {
- Assert(relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW ||
- relkind == RELKIND_TOASTVALUE ||
- relkind == RELKIND_PARTITIONED_TABLE);
-
+ /*
+ * We do not want to create any storage objects for a partitioned
+ * table, including the init fork.
+ */
+ if (relpersistence == RELPERSISTENCE_UNLOGGED &&
+ relkind != RELKIND_PARTITIONED_TABLE)
heap_create_init_fork(new_rel_desc);
- }
/*
* ok, the relation has been cataloged, so close our relations and return
@@ -1376,6 +1376,9 @@ heap_create_with_catalog(const char *relname,
void
heap_create_init_fork(Relation rel)
{
+ Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
+ rel->rd_rel->relkind == RELKIND_MATVIEW ||
+ rel->rd_rel->relkind == RELKIND_TOASTVALUE);
RelationOpenSmgr(rel);
smgrcreate(rel->rd_smgr, INIT_FORKNUM, false);
log_smgrcreate(&rel->rd_smgr->smgr_rnode.node, INIT_FORKNUM);
--
2.11.0
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-20 16:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-21 09:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 13:49 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-22 13:39 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-23 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-03-23 14:27 ` Maksim Milyutin <m.milyutin@postgrespro.ru>
2017-03-23 14:47 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
0 siblings, 1 reply; 96+ messages in thread
From: Maksim Milyutin @ 2017-03-23 14:27 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; Robert Haas <robertmhaas@gmail.com>; pgsql-hackers
Hi!
I have noticed that there is scheduled unlinking of nonexistent physical
storage under partitioned table when we execute DROP TABLE statement on
this partitioned table. Though this action doesn't generate any error
under typical behavior of postgres because the error of storage's lack
is caught through if-statement [1] I think it is not safe.
My patch fixes this issue.
1. src/backend/storage/smgr/md.c:1385
--
Maksim Milyutin
Postgres Professional: http://www.postgrespro.com
Russian Postgres Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Attachments:
[text/x-patch] exclude_unlinking_storage_for_partitioned_table.patch (518B, ../../5c1adf61-3293-1365-e31c-b6f672446c73@postgrespro.ru/2-exclude_unlinking_storage_for_partitioned_table.patch)
download | inline diff:
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 3999e6e..36917c8 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -1823,7 +1823,8 @@ heap_drop_with_catalog(Oid relid)
*/
if (rel->rd_rel->relkind != RELKIND_VIEW &&
rel->rd_rel->relkind != RELKIND_COMPOSITE_TYPE &&
- rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE)
+ rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
+ rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
{
RelationDropStorage(rel);
}
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-20 16:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-21 09:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 13:49 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-22 13:39 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-23 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-23 14:27 ` Re: Partitioned tables and relfilenode Maksim Milyutin <m.milyutin@postgrespro.ru>
@ 2017-03-23 14:47 ` Amit Langote <amitlangote09@gmail.com>
2017-03-24 00:54 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
0 siblings, 1 reply; 96+ messages in thread
From: Amit Langote @ 2017-03-23 14:47 UTC (permalink / raw)
To: Maksim Milyutin <m.milyutin@postgrespro.ru>; +Cc: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; Robert Haas <robertmhaas@gmail.com>; pgsql-hackers
Hi,
On Thu, Mar 23, 2017 at 11:27 PM, Maksim Milyutin
<m.milyutin@postgrespro.ru> wrote:
> Hi!
>
> I have noticed that there is scheduled unlinking of nonexistent physical
> storage under partitioned table when we execute DROP TABLE statement on this
> partitioned table. Though this action doesn't generate any error under
> typical behavior of postgres because the error of storage's lack is caught
> through if-statement [1] I think it is not safe.
>
> My patch fixes this issue.
>
> 1. src/backend/storage/smgr/md.c:1385
Good catch, will incorporate that in the main patch.
Thanks,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-20 16:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-21 09:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 13:49 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-22 13:39 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-23 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-23 14:27 ` Re: Partitioned tables and relfilenode Maksim Milyutin <m.milyutin@postgrespro.ru>
2017-03-23 14:47 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
@ 2017-03-24 00:54 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-27 14:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-27 15:13 ` Re: Partitioned tables and relfilenode Maksim Milyutin <m.milyutin@postgrespro.ru>
0 siblings, 2 replies; 96+ messages in thread
From: Amit Langote @ 2017-03-24 00:54 UTC (permalink / raw)
To: Amit Langote <amitlangote09@gmail.com>; Maksim Milyutin <m.milyutin@postgrespro.ru>; +Cc: Robert Haas <robertmhaas@gmail.com>; pgsql-hackers
On 2017/03/23 23:47, Amit Langote wrote:
> On Thu, Mar 23, 2017 at 11:27 PM, Maksim Milyutin
> <m.milyutin@postgrespro.ru> wrote:
>> Hi!
>>
>> I have noticed that there is scheduled unlinking of nonexistent physical
>> storage under partitioned table when we execute DROP TABLE statement on this
>> partitioned table. Though this action doesn't generate any error under
>> typical behavior of postgres because the error of storage's lack is caught
>> through if-statement [1] I think it is not safe.
>>
>> My patch fixes this issue.
>>
>> 1. src/backend/storage/smgr/md.c:1385
>
> Good catch, will incorporate that in the main patch.
And here is the updated patch.
Thanks,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Attachments:
[text/x-diff] 0001-Do-not-allocate-storage-for-partitioned-tables.patch (2.7K, ../../e57c3a1d-f0c6-fc95-f405-0a109fecf214@lab.ntt.co.jp/2-0001-Do-not-allocate-storage-for-partitioned-tables.patch)
download | inline diff:
From aed0685b6bfb99a301e674221fb393cc4e660461 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Tue, 24 Jan 2017 14:22:34 +0900
Subject: [PATCH] Do not allocate storage for partitioned tables.
Currently, it is not possible to insert any data into a partitioned
table. So they're empty at all times, which means it is wasteful to
allocate relfilenode and related storage objects.
Also documented the fact that specifying storage options for partitioned
tables is ineffective at the moment.
---
doc/src/sgml/ref/create_table.sgml | 6 ++++++
src/backend/catalog/heap.c | 17 ++++++++++-------
2 files changed, 16 insertions(+), 7 deletions(-)
diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml
index 9ed25c05da..7ac55b17fa 100644
--- a/doc/src/sgml/ref/create_table.sgml
+++ b/doc/src/sgml/ref/create_table.sgml
@@ -1040,6 +1040,12 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
will use the table's parameter value.
</para>
+ <para>
+ Note that specifying the following parameters for partitioned tables has
+ no effect at the moment. You must specify them for individual leaf
+ partitions if necessary.
+ </para>
+
<variablelist>
<varlistentry>
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 41c0056556..2f5090b183 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -291,6 +291,7 @@ heap_create(const char *relname,
case RELKIND_VIEW:
case RELKIND_COMPOSITE_TYPE:
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
create_storage = false;
/*
@@ -1345,14 +1346,13 @@ heap_create_with_catalog(const char *relname,
if (oncommit != ONCOMMIT_NOOP)
register_on_commit_action(relid, oncommit);
- if (relpersistence == RELPERSISTENCE_UNLOGGED)
- {
- Assert(relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW ||
- relkind == RELKIND_TOASTVALUE ||
- relkind == RELKIND_PARTITIONED_TABLE);
-
+ /*
+ * We do not want to create any storage objects for a partitioned
+ * table, including the init fork.
+ */
+ if (relpersistence == RELPERSISTENCE_UNLOGGED &&
+ relkind != RELKIND_PARTITIONED_TABLE)
heap_create_init_fork(new_rel_desc);
- }
/*
* ok, the relation has been cataloged, so close our relations and return
@@ -1376,6 +1376,9 @@ heap_create_with_catalog(const char *relname,
void
heap_create_init_fork(Relation rel)
{
+ Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
+ rel->rd_rel->relkind == RELKIND_MATVIEW ||
+ rel->rd_rel->relkind == RELKIND_TOASTVALUE);
RelationOpenSmgr(rel);
smgrcreate(rel->rd_smgr, INIT_FORKNUM, false);
log_smgrcreate(&rel->rd_smgr->smgr_rnode.node, INIT_FORKNUM);
--
2.11.0
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-20 16:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-21 09:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 13:49 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-22 13:39 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-23 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-23 14:27 ` Re: Partitioned tables and relfilenode Maksim Milyutin <m.milyutin@postgrespro.ru>
2017-03-23 14:47 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-24 00:54 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-03-27 14:27 ` Robert Haas <robertmhaas@gmail.com>
2017-03-29 06:40 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
1 sibling, 1 reply; 96+ messages in thread
From: Robert Haas @ 2017-03-27 14:27 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: Amit Langote <amitlangote09@gmail.com>; Maksim Milyutin <m.milyutin@postgrespro.ru>; pgsql-hackers
On Thu, Mar 23, 2017 at 8:54 PM, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
> On 2017/03/23 23:47, Amit Langote wrote:
>> On Thu, Mar 23, 2017 at 11:27 PM, Maksim Milyutin
>> <m.milyutin@postgrespro.ru> wrote:
>>> Hi!
>>>
>>> I have noticed that there is scheduled unlinking of nonexistent physical
>>> storage under partitioned table when we execute DROP TABLE statement on this
>>> partitioned table. Though this action doesn't generate any error under
>>> typical behavior of postgres because the error of storage's lack is caught
>>> through if-statement [1] I think it is not safe.
>>>
>>> My patch fixes this issue.
>>>
>>> 1. src/backend/storage/smgr/md.c:1385
>>
>> Good catch, will incorporate that in the main patch.
>
> And here is the updated patch.
I think you should go back to the earlier strategy of disallowing heap
reloptions to be set on the partitioned table. The thing is, we don't
really know which way we're going to want to go in the future. Maybe
we'll come up with a system where you can set options on the
partitioned table, and those options will cascade to the children. Or
maybe we'll come up with a system where partitioned tables have a
completely different set of options to control behaviors specific to
partitioned tables. If we do the latter, then we don't want to also
have to support useless heap reloptions for forward compatibility, nor
do we want to break backward-compatibility to remove support. If we
do the former, then it's better if we allow it in the same release
where it starts working.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-20 16:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-21 09:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 13:49 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-22 13:39 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-23 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-23 14:27 ` Re: Partitioned tables and relfilenode Maksim Milyutin <m.milyutin@postgrespro.ru>
2017-03-23 14:47 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-24 00:54 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-27 14:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
@ 2017-03-29 06:40 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 07:49 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
0 siblings, 1 reply; 96+ messages in thread
From: Amit Langote @ 2017-03-29 06:40 UTC (permalink / raw)
To: Robert Haas <robertmhaas@gmail.com>; +Cc: Amit Langote <amitlangote09@gmail.com>; Maksim Milyutin <m.milyutin@postgrespro.ru>; pgsql-hackers
On 2017/03/27 23:27, Robert Haas wrote:
> On Thu, Mar 23, 2017 at 8:54 PM, Amit Langote
> <Langote_Amit_f8@lab.ntt.co.jp> wrote:
>> On 2017/03/23 23:47, Amit Langote wrote:
>>> On Thu, Mar 23, 2017 at 11:27 PM, Maksim Milyutin
>>> <m.milyutin@postgrespro.ru> wrote:
>>>> Hi!
>>>>
>>>> I have noticed that there is scheduled unlinking of nonexistent physical
>>>> storage under partitioned table when we execute DROP TABLE statement on this
>>>> partitioned table. Though this action doesn't generate any error under
>>>> typical behavior of postgres because the error of storage's lack is caught
>>>> through if-statement [1] I think it is not safe.
>>>>
>>>> My patch fixes this issue.
>>>>
>>>> 1. src/backend/storage/smgr/md.c:1385
>>>
>>> Good catch, will incorporate that in the main patch.
>>
>> And here is the updated patch.
>
> I think you should go back to the earlier strategy of disallowing heap
> reloptions to be set on the partitioned table. The thing is, we don't
> really know which way we're going to want to go in the future. Maybe
> we'll come up with a system where you can set options on the
> partitioned table, and those options will cascade to the children. Or
> maybe we'll come up with a system where partitioned tables have a
> completely different set of options to control behaviors specific to
> partitioned tables. If we do the latter, then we don't want to also
> have to support useless heap reloptions for forward compatibility, nor
> do we want to break backward-compatibility to remove support. If we
> do the former, then it's better if we allow it in the same release
> where it starts working.
You're right, modified the patch accordingly.
By the way, the previous version of the patch didn't really "disallow"
specifying heap reloptions though. What I'd imagine that should entail is
CREATE TABLE or ALTER TABLE raising error if one of those reloptions is
specified, which didn't really occur with the patch. The options were
silently accepted and stored into pg_class, but their values were never
used. I modified the patch so that an error occurs instead of silently
accepting the user input.
create table p (a int) partition by list (a) with (fillfactor = 10);
ERROR: unrecognized parameter "fillfactor" for a partitioned table
Thanks,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Attachments:
[text/x-diff] 0001-Do-not-allocate-storage-for-partitioned-tables.patch (9.0K, ../../c4d71df2-9e0e-3912-dc81-9a72e080c238@lab.ntt.co.jp/2-0001-Do-not-allocate-storage-for-partitioned-tables.patch)
download | inline diff:
From da33f808c022f763aa7395f965d48e07f17339de Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Tue, 24 Jan 2017 14:22:34 +0900
Subject: [PATCH] Do not allocate storage for partitioned tables.
Currently, it is not possible to insert any data into a partitioned
table. So they're empty at all times, which means it is wasteful to
allocate relfilenode and related storage objects.
Also, because there is no storage, it doesn't make sense to allow
specifying storage parameters such as fillfactor, etc.
Patch by: Amit Langote & Maksim Milyutin
---
doc/src/sgml/ref/create_table.sgml | 6 ++++
src/backend/access/common/reloptions.c | 3 +-
src/backend/catalog/heap.c | 20 +++++++------
src/backend/commands/tablecmds.c | 45 ++++++++++++++++++++++++++++++
src/test/regress/expected/alter_table.out | 6 ++++
src/test/regress/expected/create_table.out | 3 ++
src/test/regress/sql/alter_table.sql | 5 ++++
src/test/regress/sql/create_table.sql | 3 ++
8 files changed, 81 insertions(+), 10 deletions(-)
diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml
index 283d53e203..5f13f240f5 100644
--- a/doc/src/sgml/ref/create_table.sgml
+++ b/doc/src/sgml/ref/create_table.sgml
@@ -1040,6 +1040,12 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
will use the table's parameter value.
</para>
+ <para>
+ Note that specifying the following parameters for partitioned tables is
+ not supported. You must specify them for individual leaf partitions if
+ necessary.
+ </para>
+
<variablelist>
<varlistentry>
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 72e12532ab..d9ea89db12 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -967,7 +967,6 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
case RELKIND_RELATION:
case RELKIND_TOASTVALUE:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
options = heap_reloptions(classForm->relkind, datum, false);
break;
case RELKIND_VIEW:
@@ -976,6 +975,7 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
case RELKIND_INDEX:
options = index_reloptions(amoptions, datum, false);
break;
+ case RELKIND_PARTITIONED_TABLE:
case RELKIND_FOREIGN_TABLE:
options = NULL;
break;
@@ -1418,7 +1418,6 @@ heap_reloptions(char relkind, Datum reloptions, bool validate)
return (bytea *) rdopts;
case RELKIND_RELATION:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
default:
/* other relkinds are not supported */
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index eee5e2f6ca..ff2f2e8efb 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -293,6 +293,7 @@ heap_create(const char *relname,
case RELKIND_VIEW:
case RELKIND_COMPOSITE_TYPE:
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
create_storage = false;
/*
@@ -1347,14 +1348,13 @@ heap_create_with_catalog(const char *relname,
if (oncommit != ONCOMMIT_NOOP)
register_on_commit_action(relid, oncommit);
- if (relpersistence == RELPERSISTENCE_UNLOGGED)
- {
- Assert(relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW ||
- relkind == RELKIND_TOASTVALUE ||
- relkind == RELKIND_PARTITIONED_TABLE);
-
+ /*
+ * We do not want to create any storage objects for a partitioned
+ * table, including the init fork.
+ */
+ if (relpersistence == RELPERSISTENCE_UNLOGGED &&
+ relkind != RELKIND_PARTITIONED_TABLE)
heap_create_init_fork(new_rel_desc);
- }
/*
* ok, the relation has been cataloged, so close our relations and return
@@ -1378,6 +1378,9 @@ heap_create_with_catalog(const char *relname,
void
heap_create_init_fork(Relation rel)
{
+ Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
+ rel->rd_rel->relkind == RELKIND_MATVIEW ||
+ rel->rd_rel->relkind == RELKIND_TOASTVALUE);
RelationOpenSmgr(rel);
smgrcreate(rel->rd_smgr, INIT_FORKNUM, false);
log_smgrcreate(&rel->rd_smgr->smgr_rnode.node, INIT_FORKNUM);
@@ -1824,7 +1827,8 @@ heap_drop_with_catalog(Oid relid)
*/
if (rel->rd_rel->relkind != RELKIND_VIEW &&
rel->rd_rel->relkind != RELKIND_COMPOSITE_TYPE &&
- rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE)
+ rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
+ rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
{
RelationDropStorage(rel);
}
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 4cf2efb2ad..6f1f16e2e7 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -583,6 +583,29 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
ownerId = GetUserId();
/*
+ * We haven't invented special storage options for partitioned tables,
+ * nor do "heap" storage options (or any other for that matter) make sense
+ * in their case. So disallow anything but "oids" in the WITH option
+ * list.
+ */
+ if (relkind == RELKIND_PARTITIONED_TABLE && stmt->options != NIL)
+ {
+ ListCell *cell;
+
+ foreach(cell, stmt->options)
+ {
+ DefElem *def = (DefElem *) lfirst(cell);
+
+ if (def->defnamespace == NULL &&
+ pg_strcasecmp(def->defname, "oids") != 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("unrecognized parameter \"%s\" for a partitioned table",
+ def->defname)));
+ }
+ }
+
+ /*
* Parse and validate reloptions, if any.
*/
reloptions = transformRelOptions((Datum) 0, stmt->options, NULL, validnsps,
@@ -9953,6 +9976,28 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
&isnull);
}
+ /*
+ * We haven't invented special storage options for partitioned tables,
+ * nor do "heap" storage options (or any other for that matter) make sense
+ * in their case. So disallow anything but "oids" to set/reset.
+ */
+ if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE && defList != NIL)
+ {
+ ListCell *cell;
+
+ foreach(cell, defList)
+ {
+ DefElem *def = (DefElem *) lfirst(cell);
+
+ if (def->defnamespace == NULL &&
+ pg_strcasecmp(def->defname, "oids") != 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("unrecognized parameter \"%s\" for a partitioned table",
+ def->defname)));
+ }
+ }
+
/* Generate new proposed reloptions (text array) */
newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
defList, NULL, validnsps, false,
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index 2227f2d977..2aedd620ca 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -3372,3 +3372,9 @@ ERROR: partition constraint is violated by some row
-- cleanup
drop table p;
drop table p1;
+-- partitioned tables accept no options other than "oids" in the WITH list
+create table parted_with_test (a int) partition by list (a) with (oids = true);
+alter table parted_with_test set (fillfactor = 90);
+ERROR: unrecognized parameter "fillfactor" for a partitioned table
+alter table parted_with_test reset (fillfactor);
+ERROR: unrecognized parameter "fillfactor" for a partitioned table
diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out
index 6f8645ddbd..0cf600383c 100644
--- a/src/test/regress/expected/create_table.out
+++ b/src/test/regress/expected/create_table.out
@@ -669,3 +669,6 @@ Number of partitions: 3 (Use \d+ to list them.)
-- cleanup
DROP TABLE parted, list_parted, range_parted, list_parted2, range_parted2, range_parted3;
+-- partitioned tables accept no options other than "oids" in the WITH list
+create table parted_with_test (a int) partition by list (a) with (fillfactor = 10);
+ERROR: unrecognized parameter "fillfactor" for a partitioned table
diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql
index 8cd6786a90..9825165d4c 100644
--- a/src/test/regress/sql/alter_table.sql
+++ b/src/test/regress/sql/alter_table.sql
@@ -2228,3 +2228,8 @@ alter table p attach partition p1 for values from (1, 2) to (1, 10);
-- cleanup
drop table p;
drop table p1;
+
+-- partitioned tables accept no options other than "oids" in the WITH list
+create table parted_with_test (a int) partition by list (a) with (oids = true);
+alter table parted_with_test set (fillfactor = 90);
+alter table parted_with_test reset (fillfactor);
diff --git a/src/test/regress/sql/create_table.sql b/src/test/regress/sql/create_table.sql
index 1f0fa8e16d..537d747d55 100644
--- a/src/test/regress/sql/create_table.sql
+++ b/src/test/regress/sql/create_table.sql
@@ -597,3 +597,6 @@ CREATE TABLE part_c_1_10 PARTITION OF part_c FOR VALUES FROM (1) TO (10);
-- cleanup
DROP TABLE parted, list_parted, range_parted, list_parted2, range_parted2, range_parted3;
+
+-- partitioned tables accept no options other than "oids" in the WITH list
+create table parted_with_test (a int) partition by list (a) with (fillfactor = 10);
--
2.11.0
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-20 16:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-21 09:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 13:49 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-22 13:39 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-23 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-23 14:27 ` Re: Partitioned tables and relfilenode Maksim Milyutin <m.milyutin@postgrespro.ru>
2017-03-23 14:47 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-24 00:54 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-27 14:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-29 06:40 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-03-29 07:49 ` Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-29 08:21 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
0 siblings, 1 reply; 96+ messages in thread
From: Kyotaro HORIGUCHI @ 2017-03-29 07:49 UTC (permalink / raw)
To: Langote_Amit_f8@lab.ntt.co.jp; +Cc: robertmhaas@gmail.com; amitlangote09@gmail.com; m.milyutin@postgrespro.ru; pgsql-hackers
Hello,
At Wed, 29 Mar 2017 15:40:20 +0900, Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> wrote in <c4d71df2-9e0e-3912-dc81-9a72e080c238@lab.ntt.co.jp>
> On 2017/03/27 23:27, Robert Haas wrote:
> > On Thu, Mar 23, 2017 at 8:54 PM, Amit Langote
> > <Langote_Amit_f8@lab.ntt.co.jp> wrote:
> >> On 2017/03/23 23:47, Amit Langote wrote:
> >>> On Thu, Mar 23, 2017 at 11:27 PM, Maksim Milyutin
> >>> <m.milyutin@postgrespro.ru> wrote:
> >>>> Hi!
> >>>>
> >>>> I have noticed that there is scheduled unlinking of nonexistent physical
> >>>> storage under partitioned table when we execute DROP TABLE statement on this
> >>>> partitioned table. Though this action doesn't generate any error under
> >>>> typical behavior of postgres because the error of storage's lack is caught
> >>>> through if-statement [1] I think it is not safe.
> >>>>
> >>>> My patch fixes this issue.
> >>>>
> >>>> 1. src/backend/storage/smgr/md.c:1385
> >>>
> >>> Good catch, will incorporate that in the main patch.
> >>
> >> And here is the updated patch.
> >
> > I think you should go back to the earlier strategy of disallowing heap
> > reloptions to be set on the partitioned table. The thing is, we don't
> > really know which way we're going to want to go in the future. Maybe
> > we'll come up with a system where you can set options on the
> > partitioned table, and those options will cascade to the children. Or
> > maybe we'll come up with a system where partitioned tables have a
> > completely different set of options to control behaviors specific to
> > partitioned tables. If we do the latter, then we don't want to also
> > have to support useless heap reloptions for forward compatibility, nor
> > do we want to break backward-compatibility to remove support. If we
> > do the former, then it's better if we allow it in the same release
> > where it starts working.
>
> You're right, modified the patch accordingly.
>
> By the way, the previous version of the patch didn't really "disallow"
> specifying heap reloptions though. What I'd imagine that should entail is
> CREATE TABLE or ALTER TABLE raising error if one of those reloptions is
> specified, which didn't really occur with the patch. The options were
> silently accepted and stored into pg_class, but their values were never
> used. I modified the patch so that an error occurs instead of silently
> accepting the user input.
>
> create table p (a int) partition by list (a) with (fillfactor = 10);
> ERROR: unrecognized parameter "fillfactor" for a partitioned table
The following attracted my eyes.
+ if (def->defnamespace == NULL &&
+ pg_strcasecmp(def->defname, "oids") != 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("unrecognized parameter \"%s\" for a partitioned table",
This works since defnamespace is always NULL here, but if I
understand correctly what we should do here is "reject any option
other than "(default).OID"". So I think that the condition should
be like the following.
+ if (def->defnamespace != NULL ||
+ pg_strcasecmp(def->defname, "oids") != 0)
regards,
--
Kyotaro Horiguchi
NTT Open Source Software Center
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-20 16:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-21 09:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 13:49 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-22 13:39 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-23 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-23 14:27 ` Re: Partitioned tables and relfilenode Maksim Milyutin <m.milyutin@postgrespro.ru>
2017-03-23 14:47 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-24 00:54 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-27 14:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-29 06:40 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 07:49 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
@ 2017-03-29 08:21 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 08:40 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-29 14:58 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
0 siblings, 2 replies; 96+ messages in thread
From: Amit Langote @ 2017-03-29 08:21 UTC (permalink / raw)
To: Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>; +Cc: robertmhaas@gmail.com; amitlangote09@gmail.com; m.milyutin@postgrespro.ru; pgsql-hackers
Horiguchi-san,
Thanks for taking a look.
On 2017/03/29 16:49, Kyotaro HORIGUCHI wrote:
> At Wed, 29 Mar 2017 15:40:20 +0900, Amit Langote wrote:
>> On 2017/03/27 23:27, Robert Haas wrote:
>>>> And here is the updated patch.
>>>
>>> I think you should go back to the earlier strategy of disallowing heap
>>> reloptions to be set on the partitioned table. The thing is, we don't
>>> really know which way we're going to want to go in the future. Maybe
>>> we'll come up with a system where you can set options on the
>>> partitioned table, and those options will cascade to the children. Or
>>> maybe we'll come up with a system where partitioned tables have a
>>> completely different set of options to control behaviors specific to
>>> partitioned tables. If we do the latter, then we don't want to also
>>> have to support useless heap reloptions for forward compatibility, nor
>>> do we want to break backward-compatibility to remove support. If we
>>> do the former, then it's better if we allow it in the same release
>>> where it starts working.
>>
>> You're right, modified the patch accordingly.
>>
>> By the way, the previous version of the patch didn't really "disallow"
>> specifying heap reloptions though. What I'd imagine that should entail is
>> CREATE TABLE or ALTER TABLE raising error if one of those reloptions is
>> specified, which didn't really occur with the patch. The options were
>> silently accepted and stored into pg_class, but their values were never
>> used. I modified the patch so that an error occurs instead of silently
>> accepting the user input.
>>
>> create table p (a int) partition by list (a) with (fillfactor = 10);
>> ERROR: unrecognized parameter "fillfactor" for a partitioned table
>
> The following attracted my eyes.
>
> + if (def->defnamespace == NULL &&
> + pg_strcasecmp(def->defname, "oids") != 0)
> + ereport(ERROR,
> + (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
> + errmsg("unrecognized parameter \"%s\" for a partitioned table",
>
> This works since defnamespace is always NULL here, but if I
> understand correctly what we should do here is "reject any option
> other than "(default).OID"". So I think that the condition should
> be like the following.
You're right. The following *wrongly* succeeds:
create table p (a int) partition by list (a) with
(toast.autovacuum_enabled = true);
CREATE TABLE
> + if (def->defnamespace != NULL ||
> + pg_strcasecmp(def->defname, "oids") != 0)
Looks correct, so incorporated in the attached updated patch. Thanks.
Regards,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Attachments:
[text/x-diff] 0001-Do-not-allocate-storage-for-partitioned-tables.patch (9.7K, ../../b1234f04-53e0-011d-9f02-2437b909cce4@lab.ntt.co.jp/2-0001-Do-not-allocate-storage-for-partitioned-tables.patch)
download | inline diff:
From 90a007dbf0eced97bb949da9a79df07b52486a60 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Tue, 24 Jan 2017 14:22:34 +0900
Subject: [PATCH] Do not allocate storage for partitioned tables.
Currently, it is not possible to insert any data into a partitioned
table. So they're empty at all times, which means it is wasteful to
allocate relfilenode and related storage objects.
Also, because there is no storage, it doesn't make sense to allow
specifying storage parameters such as fillfactor, etc.
Patch by: Amit Langote & Maksim Milyutin
Reviwed by: Kyotaro Horiguchi
---
doc/src/sgml/ref/create_table.sgml | 6 ++++
src/backend/access/common/reloptions.c | 3 +-
src/backend/catalog/heap.c | 20 +++++++------
src/backend/commands/tablecmds.c | 45 ++++++++++++++++++++++++++++++
src/test/regress/expected/alter_table.out | 9 ++++++
src/test/regress/expected/create_table.out | 5 ++++
src/test/regress/sql/alter_table.sql | 7 +++++
src/test/regress/sql/create_table.sql | 4 +++
8 files changed, 89 insertions(+), 10 deletions(-)
diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml
index 283d53e203..5f13f240f5 100644
--- a/doc/src/sgml/ref/create_table.sgml
+++ b/doc/src/sgml/ref/create_table.sgml
@@ -1040,6 +1040,12 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
will use the table's parameter value.
</para>
+ <para>
+ Note that specifying the following parameters for partitioned tables is
+ not supported. You must specify them for individual leaf partitions if
+ necessary.
+ </para>
+
<variablelist>
<varlistentry>
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 72e12532ab..d9ea89db12 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -967,7 +967,6 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
case RELKIND_RELATION:
case RELKIND_TOASTVALUE:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
options = heap_reloptions(classForm->relkind, datum, false);
break;
case RELKIND_VIEW:
@@ -976,6 +975,7 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
case RELKIND_INDEX:
options = index_reloptions(amoptions, datum, false);
break;
+ case RELKIND_PARTITIONED_TABLE:
case RELKIND_FOREIGN_TABLE:
options = NULL;
break;
@@ -1418,7 +1418,6 @@ heap_reloptions(char relkind, Datum reloptions, bool validate)
return (bytea *) rdopts;
case RELKIND_RELATION:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
default:
/* other relkinds are not supported */
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index eee5e2f6ca..ff2f2e8efb 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -293,6 +293,7 @@ heap_create(const char *relname,
case RELKIND_VIEW:
case RELKIND_COMPOSITE_TYPE:
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
create_storage = false;
/*
@@ -1347,14 +1348,13 @@ heap_create_with_catalog(const char *relname,
if (oncommit != ONCOMMIT_NOOP)
register_on_commit_action(relid, oncommit);
- if (relpersistence == RELPERSISTENCE_UNLOGGED)
- {
- Assert(relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW ||
- relkind == RELKIND_TOASTVALUE ||
- relkind == RELKIND_PARTITIONED_TABLE);
-
+ /*
+ * We do not want to create any storage objects for a partitioned
+ * table, including the init fork.
+ */
+ if (relpersistence == RELPERSISTENCE_UNLOGGED &&
+ relkind != RELKIND_PARTITIONED_TABLE)
heap_create_init_fork(new_rel_desc);
- }
/*
* ok, the relation has been cataloged, so close our relations and return
@@ -1378,6 +1378,9 @@ heap_create_with_catalog(const char *relname,
void
heap_create_init_fork(Relation rel)
{
+ Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
+ rel->rd_rel->relkind == RELKIND_MATVIEW ||
+ rel->rd_rel->relkind == RELKIND_TOASTVALUE);
RelationOpenSmgr(rel);
smgrcreate(rel->rd_smgr, INIT_FORKNUM, false);
log_smgrcreate(&rel->rd_smgr->smgr_rnode.node, INIT_FORKNUM);
@@ -1824,7 +1827,8 @@ heap_drop_with_catalog(Oid relid)
*/
if (rel->rd_rel->relkind != RELKIND_VIEW &&
rel->rd_rel->relkind != RELKIND_COMPOSITE_TYPE &&
- rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE)
+ rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
+ rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
{
RelationDropStorage(rel);
}
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 4cf2efb2ad..55ab18dee6 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -583,6 +583,29 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
ownerId = GetUserId();
/*
+ * We haven't invented special storage options for partitioned tables yet,
+ * nor do "heap" storage options (or any other for that matter) make sense
+ * in their case. So disallow anything but "oids" in the WITH option
+ * list.
+ */
+ if (relkind == RELKIND_PARTITIONED_TABLE && stmt->options != NIL)
+ {
+ ListCell *cell;
+
+ foreach(cell, stmt->options)
+ {
+ DefElem *def = (DefElem *) lfirst(cell);
+
+ if (def->defnamespace != NULL ||
+ pg_strcasecmp(def->defname, "oids") != 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("unrecognized parameter \"%s\" for a partitioned table",
+ def->defname)));
+ }
+ }
+
+ /*
* Parse and validate reloptions, if any.
*/
reloptions = transformRelOptions((Datum) 0, stmt->options, NULL, validnsps,
@@ -9953,6 +9976,28 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
&isnull);
}
+ /*
+ * We haven't invented special storage options for partitioned tables,
+ * nor do "heap" storage options (or any other for that matter) make sense
+ * in their case. So disallow anything but "oids" to set/reset.
+ */
+ if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE && defList != NIL)
+ {
+ ListCell *cell;
+
+ foreach(cell, defList)
+ {
+ DefElem *def = (DefElem *) lfirst(cell);
+
+ if (def->defnamespace != NULL ||
+ pg_strcasecmp(def->defname, "oids") != 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("unrecognized parameter \"%s\" for a partitioned table",
+ def->defname)));
+ }
+ }
+
/* Generate new proposed reloptions (text array) */
newOptions = transformRelOptions(isnull ? (Datum) 0 : datum,
defList, NULL, validnsps, false,
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index 2227f2d977..c0438a68b8 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -3372,3 +3372,12 @@ ERROR: partition constraint is violated by some row
-- cleanup
drop table p;
drop table p1;
+-- partitioned tables accept no options other than "oids" in the WITH list
+create table parted_withopt_test (a int) partition by list (a) with (oids = true);
+alter table parted_withopt_test set (fillfactor = 90);
+ERROR: unrecognized parameter "fillfactor" for a partitioned table
+alter table parted_withopt_test reset (fillfactor);
+ERROR: unrecognized parameter "fillfactor" for a partitioned table
+alter table parted_withopt_test set (toast.autvacuum_enabled = true);
+ERROR: unrecognized parameter "autvacuum_enabled" for a partitioned table
+drop table parted_withopt_test;
diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out
index 6f8645ddbd..6b223ccedb 100644
--- a/src/test/regress/expected/create_table.out
+++ b/src/test/regress/expected/create_table.out
@@ -669,3 +669,8 @@ Number of partitions: 3 (Use \d+ to list them.)
-- cleanup
DROP TABLE parted, list_parted, range_parted, list_parted2, range_parted2, range_parted3;
+-- partitioned tables accept no options other than "oids" in the WITH list
+create table parted_withop_test (a int) partition by list (a) with (fillfactor = 10);
+ERROR: unrecognized parameter "fillfactor" for a partitioned table
+create table parted_withop_test (a int) partition by list (a) with (toast.autvacuum_enabled = true);
+ERROR: unrecognized parameter "autvacuum_enabled" for a partitioned table
diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql
index 8cd6786a90..bac1809ae2 100644
--- a/src/test/regress/sql/alter_table.sql
+++ b/src/test/regress/sql/alter_table.sql
@@ -2228,3 +2228,10 @@ alter table p attach partition p1 for values from (1, 2) to (1, 10);
-- cleanup
drop table p;
drop table p1;
+
+-- partitioned tables accept no options other than "oids" in the WITH list
+create table parted_withopt_test (a int) partition by list (a) with (oids = true);
+alter table parted_withopt_test set (fillfactor = 90);
+alter table parted_withopt_test reset (fillfactor);
+alter table parted_withopt_test set (toast.autvacuum_enabled = true);
+drop table parted_withopt_test;
diff --git a/src/test/regress/sql/create_table.sql b/src/test/regress/sql/create_table.sql
index 1f0fa8e16d..68e785915c 100644
--- a/src/test/regress/sql/create_table.sql
+++ b/src/test/regress/sql/create_table.sql
@@ -597,3 +597,7 @@ CREATE TABLE part_c_1_10 PARTITION OF part_c FOR VALUES FROM (1) TO (10);
-- cleanup
DROP TABLE parted, list_parted, range_parted, list_parted2, range_parted2, range_parted3;
+
+-- partitioned tables accept no options other than "oids" in the WITH list
+create table parted_withop_test (a int) partition by list (a) with (fillfactor = 10);
+create table parted_withop_test (a int) partition by list (a) with (toast.autvacuum_enabled = true);
--
2.11.0
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-20 16:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-21 09:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 13:49 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-22 13:39 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-23 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-23 14:27 ` Re: Partitioned tables and relfilenode Maksim Milyutin <m.milyutin@postgrespro.ru>
2017-03-23 14:47 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-24 00:54 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-27 14:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-29 06:40 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 07:49 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-29 08:21 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-03-29 08:40 ` Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
1 sibling, 0 replies; 96+ messages in thread
From: Kyotaro HORIGUCHI @ 2017-03-29 08:40 UTC (permalink / raw)
To: Langote_Amit_f8@lab.ntt.co.jp; +Cc: robertmhaas@gmail.com; amitlangote09@gmail.com; m.milyutin@postgrespro.ru; pgsql-hackers
At Wed, 29 Mar 2017 17:21:26 +0900, Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> wrote in <b1234f04-53e0-011d-9f02-2437b909cce4@lab.ntt.co.jp>
> > Thanks for taking a look.
This patch is small enough to look at in a short time:p
> > The following attracted my eyes.
> >
> > + if (def->defnamespace == NULL &&
> > + pg_strcasecmp(def->defname, "oids") != 0)
> > + ereport(ERROR,
> > + (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
> > + errmsg("unrecognized parameter \"%s\" for a partitioned table",
> >
> > This works since defnamespace is always NULL here, but if I
> > understand correctly what we should do here is "reject any option
> > other than "(default).OID"". So I think that the condition should
> > be like the following.
>
> You're right. The following *wrongly* succeeds:
Ouch! I briefly checked that by "hoge.oids" without confirming
around.
> create table p (a int) partition by list (a) with
> (toast.autovacuum_enabled = true);
> CREATE TABLE
>
> > + if (def->defnamespace != NULL ||
> > + pg_strcasecmp(def->defname, "oids") != 0)
>
> Looks correct, so incorporated in the attached updated patch. Thanks.
--
Kyotaro Horiguchi
NTT Open Source Software Center
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-20 16:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-21 09:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 13:49 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-22 13:39 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-23 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-23 14:27 ` Re: Partitioned tables and relfilenode Maksim Milyutin <m.milyutin@postgrespro.ru>
2017-03-23 14:47 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-24 00:54 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-27 14:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-29 06:40 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 07:49 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-29 08:21 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-03-29 14:58 ` Robert Haas <robertmhaas@gmail.com>
2017-03-30 09:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
1 sibling, 1 reply; 96+ messages in thread
From: Robert Haas @ 2017-03-29 14:58 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>; Amit Langote <amitlangote09@gmail.com>; Maksim Milyutin <m.milyutin@postgrespro.ru>; pgsql-hackers
On Wed, Mar 29, 2017 at 4:21 AM, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
> Looks correct, so incorporated in the attached updated patch. Thanks.
This seems like a hacky way to limit the reloptions to just OIDs.
Shouldn't we instead have a new RELOPT_KIND_PARTITIONED or something
like that?
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-20 16:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-21 09:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 13:49 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-22 13:39 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-23 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-23 14:27 ` Re: Partitioned tables and relfilenode Maksim Milyutin <m.milyutin@postgrespro.ru>
2017-03-23 14:47 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-24 00:54 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-27 14:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-29 06:40 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 07:49 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-29 08:21 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 14:58 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
@ 2017-03-30 09:24 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-30 10:37 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
0 siblings, 1 reply; 96+ messages in thread
From: Amit Langote @ 2017-03-30 09:24 UTC (permalink / raw)
To: Robert Haas <robertmhaas@gmail.com>; +Cc: Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>; Amit Langote <amitlangote09@gmail.com>; Maksim Milyutin <m.milyutin@postgrespro.ru>; pgsql-hackers
On 2017/03/29 23:58, Robert Haas wrote:
> On Wed, Mar 29, 2017 at 4:21 AM, Amit Langote
> <Langote_Amit_f8@lab.ntt.co.jp> wrote:
>> Looks correct, so incorporated in the attached updated patch. Thanks.
>
> This seems like a hacky way to limit the reloptions to just OIDs.
> Shouldn't we instead have a new RELOPT_KIND_PARTITIONED or something
> like that?
OK, I tried that in the updated patch.
DefineRelation() and ATExecSetRelOptions() still calls heap_reloptions(),
but passes the new relopt_kind. None of the options listed in
reloptions.c are of this kind as of now, so parseRelOptions() simply
outputs the "unrecognized parameter %s" in the case of partitioned tables
(except in some cases described below, but not because of the limitations
of this patch). If and when partitioned tables start supporting the
existing parameters, we'll update the relopt_gen.kinds bitmask of those
parameters to allow them to be specified for partitioned tables.
With the patch:
create table parted (a int) partition by list (a) with (fillfactor = 10);
ERROR: unrecognized parameter "fillfactor"
create table parted (a int) partition by list (a) with (toast.fillfactor =
10);
ERROR: unrecognized parameter "fillfactor"
and:
create table parted (a int) partition by list (a) with (oids = true);
alter table parted set (fillfactor = 90);
ERROR: unrecognized parameter "fillfactor"
but:
-- appears to succeed, whereas an error should have been reported (I think)
alter table parted set (toast.fillfactor = 10);
ALTER TABLE
-- even with views
create table foo (a int);
create view foov with (toast.fillfactor = 10) as select * from foo;
CREATE VIEW
alter view foov set (toast.fillfactor = 20);
ALTER VIEW
Nothing is stored in pg_class.reloptions really, but the validation that
should have occurred in parseRelOptions() doesn't. This happens because
of the way transformRelOptions() works. It will ignore the DefElem's that
don't apply to the specified relation based on the value of the namspace
parameter ("toast" or NULL). That means it won't be included in the array
of options later received by parseRelOptions(), which is where the
validation occurs.
Also, alter table reset (xxx) never validates anything:
alter table foo reset (foo);
ALTER TABLE
alter table foo reset (foo.bar);
ALTER TABLE
Again, no pg_class.reloptions update occurs in this case. The reason this
happens is because transformRelOptions() never includes the options to be
reset in the array of options received by parseRelOptions(), so no
validation occurs.
But since both are existing behaviors, perhaps we can worry about it some
other time.
Thanks,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Attachments:
[text/x-diff] 0001-Do-not-allocate-storage-for-partitioned-tables.patch (8.5K, ../../ee5f1cd4-4783-42e8-0263-648ae9c11264@lab.ntt.co.jp/2-0001-Do-not-allocate-storage-for-partitioned-tables.patch)
download | inline diff:
From f150dec562985642b1af83236b65a42f7350033e Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Tue, 24 Jan 2017 14:22:34 +0900
Subject: [PATCH] Do not allocate storage for partitioned tables.
Currently, it is not possible to insert any data into a partitioned
table. So they're empty at all times, which means it is wasteful to
allocate relfilenode and related storage objects.
Also, because there is no storage, it doesn't make sense to allow
specifying storage parameters such as fillfactor, etc.
Patch by: Amit Langote & Maksim Milyutin
Reviwed by: Kyotaro Horiguchi
---
doc/src/sgml/ref/create_table.sgml | 6 ++++++
src/backend/access/common/reloptions.c | 33 ++++++++++++++++++++++--------
src/backend/catalog/heap.c | 20 ++++++++++--------
src/include/access/reloptions.h | 3 ++-
src/test/regress/expected/alter_table.out | 5 +++++
src/test/regress/expected/create_table.out | 5 +++++
src/test/regress/sql/alter_table.sql | 5 +++++
src/test/regress/sql/create_table.sql | 4 ++++
8 files changed, 63 insertions(+), 18 deletions(-)
diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml
index 283d53e203..5f13f240f5 100644
--- a/doc/src/sgml/ref/create_table.sgml
+++ b/doc/src/sgml/ref/create_table.sgml
@@ -1040,6 +1040,12 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
will use the table's parameter value.
</para>
+ <para>
+ Note that specifying the following parameters for partitioned tables is
+ not supported. You must specify them for individual leaf partitions if
+ necessary.
+ </para>
+
<variablelist>
<varlistentry>
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 72e12532ab..f3f5ade38f 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -1024,21 +1024,28 @@ parseRelOptions(Datum options, bool validate, relopt_kind kind,
if (relOpts[i]->kinds & kind)
numoptions++;
- if (numoptions == 0)
+ /*
+ * Even if we found no options of kind, it's better to raise the
+ * "unrecognized parameter %s" error here, instead of at the caller.
+ */
+ if (numoptions == 0 && !validate)
{
*numrelopts = 0;
return NULL;
}
- reloptions = palloc(numoptions * sizeof(relopt_value));
-
- for (i = 0, j = 0; relOpts[i]; i++)
+ if (numoptions > 0)
{
- if (relOpts[i]->kinds & kind)
+ reloptions = palloc(numoptions * sizeof(relopt_value));
+
+ for (i = 0, j = 0; relOpts[i]; i++)
{
- reloptions[j].gen = relOpts[i];
- reloptions[j].isset = false;
- j++;
+ if (relOpts[i]->kinds & kind)
+ {
+ reloptions[j].gen = relOpts[i];
+ reloptions[j].isset = false;
+ j++;
+ }
}
}
@@ -1418,8 +1425,16 @@ heap_reloptions(char relkind, Datum reloptions, bool validate)
return (bytea *) rdopts;
case RELKIND_RELATION:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
+
+ /*
+ * There aren't any partitioned table options yet really, so the
+ * following simply serves to reject whatever's specified as being
+ * "unrecognized storage parameter" if validate is true.
+ */
+ case RELKIND_PARTITIONED_TABLE:
+ return default_reloptions(reloptions, validate,
+ RELOPT_KIND_PARTITIONED);
default:
/* other relkinds are not supported */
return NULL;
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index eee5e2f6ca..ff2f2e8efb 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -293,6 +293,7 @@ heap_create(const char *relname,
case RELKIND_VIEW:
case RELKIND_COMPOSITE_TYPE:
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
create_storage = false;
/*
@@ -1347,14 +1348,13 @@ heap_create_with_catalog(const char *relname,
if (oncommit != ONCOMMIT_NOOP)
register_on_commit_action(relid, oncommit);
- if (relpersistence == RELPERSISTENCE_UNLOGGED)
- {
- Assert(relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW ||
- relkind == RELKIND_TOASTVALUE ||
- relkind == RELKIND_PARTITIONED_TABLE);
-
+ /*
+ * We do not want to create any storage objects for a partitioned
+ * table, including the init fork.
+ */
+ if (relpersistence == RELPERSISTENCE_UNLOGGED &&
+ relkind != RELKIND_PARTITIONED_TABLE)
heap_create_init_fork(new_rel_desc);
- }
/*
* ok, the relation has been cataloged, so close our relations and return
@@ -1378,6 +1378,9 @@ heap_create_with_catalog(const char *relname,
void
heap_create_init_fork(Relation rel)
{
+ Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
+ rel->rd_rel->relkind == RELKIND_MATVIEW ||
+ rel->rd_rel->relkind == RELKIND_TOASTVALUE);
RelationOpenSmgr(rel);
smgrcreate(rel->rd_smgr, INIT_FORKNUM, false);
log_smgrcreate(&rel->rd_smgr->smgr_rnode.node, INIT_FORKNUM);
@@ -1824,7 +1827,8 @@ heap_drop_with_catalog(Oid relid)
*/
if (rel->rd_rel->relkind != RELKIND_VIEW &&
rel->rd_rel->relkind != RELKIND_COMPOSITE_TYPE &&
- rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE)
+ rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
+ rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
{
RelationDropStorage(rel);
}
diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h
index 861977a608..91b2cd7bb2 100644
--- a/src/include/access/reloptions.h
+++ b/src/include/access/reloptions.h
@@ -48,8 +48,9 @@ typedef enum relopt_kind
RELOPT_KIND_SPGIST = (1 << 8),
RELOPT_KIND_VIEW = (1 << 9),
RELOPT_KIND_BRIN = (1 << 10),
+ RELOPT_KIND_PARTITIONED = (1 << 11),
/* if you add a new kind, make sure you update "last_default" too */
- RELOPT_KIND_LAST_DEFAULT = RELOPT_KIND_BRIN,
+ RELOPT_KIND_LAST_DEFAULT = RELOPT_KIND_PARTITIONED,
/* some compilers treat enums as signed ints, so we can't use 1 << 31 */
RELOPT_KIND_MAX = (1 << 30)
} relopt_kind;
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index 2227f2d977..1230ad776d 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -3372,3 +3372,8 @@ ERROR: partition constraint is violated by some row
-- cleanup
drop table p;
drop table p1;
+-- partitioned tables accept no options other than "oids" in the WITH list
+create table parted_withopt_test (a int) partition by list (a) with (oids = true);
+alter table parted_withopt_test set (fillfactor = 90);
+ERROR: unrecognized parameter "fillfactor"
+drop table parted_withopt_test;
diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out
index 6f8645ddbd..6294a160fa 100644
--- a/src/test/regress/expected/create_table.out
+++ b/src/test/regress/expected/create_table.out
@@ -669,3 +669,8 @@ Number of partitions: 3 (Use \d+ to list them.)
-- cleanup
DROP TABLE parted, list_parted, range_parted, list_parted2, range_parted2, range_parted3;
+-- partitioned tables accept no options other than "oids" in the WITH list
+create table parted_withopt_test (a int) partition by list (a) with (fillfactor = 10);
+ERROR: unrecognized parameter "fillfactor"
+create table parted_withopt_test (a int) partition by list (a) with (toast.autvacuum_enabled = true);
+ERROR: unrecognized parameter "autvacuum_enabled"
diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql
index 8cd6786a90..e50f408b59 100644
--- a/src/test/regress/sql/alter_table.sql
+++ b/src/test/regress/sql/alter_table.sql
@@ -2228,3 +2228,8 @@ alter table p attach partition p1 for values from (1, 2) to (1, 10);
-- cleanup
drop table p;
drop table p1;
+
+-- partitioned tables accept no options other than "oids" in the WITH list
+create table parted_withopt_test (a int) partition by list (a) with (oids = true);
+alter table parted_withopt_test set (fillfactor = 90);
+drop table parted_withopt_test;
diff --git a/src/test/regress/sql/create_table.sql b/src/test/regress/sql/create_table.sql
index 1f0fa8e16d..0c8cae001f 100644
--- a/src/test/regress/sql/create_table.sql
+++ b/src/test/regress/sql/create_table.sql
@@ -597,3 +597,7 @@ CREATE TABLE part_c_1_10 PARTITION OF part_c FOR VALUES FROM (1) TO (10);
-- cleanup
DROP TABLE parted, list_parted, range_parted, list_parted2, range_parted2, range_parted3;
+
+-- partitioned tables accept no options other than "oids" in the WITH list
+create table parted_withopt_test (a int) partition by list (a) with (fillfactor = 10);
+create table parted_withopt_test (a int) partition by list (a) with (toast.autvacuum_enabled = true);
--
2.11.0
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-20 16:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-21 09:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 13:49 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-22 13:39 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-23 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-23 14:27 ` Re: Partitioned tables and relfilenode Maksim Milyutin <m.milyutin@postgrespro.ru>
2017-03-23 14:47 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-24 00:54 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-27 14:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-29 06:40 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 07:49 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-29 08:21 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 14:58 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-30 09:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-03-30 10:37 ` Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-30 11:58 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
0 siblings, 1 reply; 96+ messages in thread
From: Kyotaro HORIGUCHI @ 2017-03-30 10:37 UTC (permalink / raw)
To: Langote_Amit_f8@lab.ntt.co.jp; +Cc: robertmhaas@gmail.com; amitlangote09@gmail.com; m.milyutin@postgrespro.ru; pgsql-hackers
Hello,
At Thu, 30 Mar 2017 18:24:16 +0900, Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> wrote in <ee5f1cd4-4783-42e8-0263-648ae9c11264@lab.ntt.co.jp>
> On 2017/03/29 23:58, Robert Haas wrote:
> > On Wed, Mar 29, 2017 at 4:21 AM, Amit Langote
> > <Langote_Amit_f8@lab.ntt.co.jp> wrote:
> >> Looks correct, so incorporated in the attached updated patch. Thanks.
> >
> > This seems like a hacky way to limit the reloptions to just OIDs.
> > Shouldn't we instead have a new RELOPT_KIND_PARTITIONED or something
> > like that?
>
> OK, I tried that in the updated patch.
The name RELOPT_KIND_PARTITIONED looks somewhat odd. RELKIND for
partitioned tables is RELKIND_PARTITIONED_TABLE, so is this
better to be _TABLE, even if a bit longer?
parseRelOptions seems to return garbage pointer if no option of
the kind is available.
> DefineRelation() and ATExecSetRelOptions() still calls heap_reloptions(),
> but passes the new relopt_kind. None of the options listed in
> reloptions.c are of this kind as of now, so parseRelOptions() simply
> outputs the "unrecognized parameter %s" in the case of partitioned tables
> (except in some cases described below, but not because of the limitations
> of this patch). If and when partitioned tables start supporting the
> existing parameters, we'll update the relopt_gen.kinds bitmask of those
> parameters to allow them to be specified for partitioned tables.
>
> With the patch:
>
> create table parted (a int) partition by list (a) with (fillfactor = 10);
> ERROR: unrecognized parameter "fillfactor"
>
> create table parted (a int) partition by list (a) with (toast.fillfactor =
> 10);
> ERROR: unrecognized parameter "fillfactor"
>
> and:
>
> create table parted (a int) partition by list (a) with (oids = true);
> alter table parted set (fillfactor = 90);
> ERROR: unrecognized parameter "fillfactor"
>
> but:
>
> -- appears to succeed, whereas an error should have been reported (I think)
> alter table parted set (toast.fillfactor = 10);
> ALTER TABLE
>
> -- even with views
> create table foo (a int);
> create view foov with (toast.fillfactor = 10) as select * from foo;
> CREATE VIEW
> alter view foov set (toast.fillfactor = 20);
> ALTER VIEW
>
> Nothing is stored in pg_class.reloptions really, but the validation that
> should have occurred in parseRelOptions() doesn't. This happens because
> of the way transformRelOptions() works. It will ignore the DefElem's that
> don't apply to the specified relation based on the value of the namspace
> parameter ("toast" or NULL). That means it won't be included in the array
> of options later received by parseRelOptions(), which is where the
> validation occurs.
>
> Also, alter table reset (xxx) never validates anything:
>
> alter table foo reset (foo);
> ALTER TABLE
> alter table foo reset (foo.bar);
> ALTER TABLE
>
> Again, no pg_class.reloptions update occurs in this case. The reason this
> happens is because transformRelOptions() never includes the options to be
> reset in the array of options received by parseRelOptions(), so no
> validation occurs.
>
> But since both are existing behaviors, perhaps we can worry about it some
> other time.
--
Kyotaro Horiguchi
NTT Open Source Software Center
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-20 16:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-21 09:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 13:49 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-22 13:39 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-23 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-23 14:27 ` Re: Partitioned tables and relfilenode Maksim Milyutin <m.milyutin@postgrespro.ru>
2017-03-23 14:47 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-24 00:54 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-27 14:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-29 06:40 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 07:49 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-29 08:21 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 14:58 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-30 09:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-30 10:37 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
@ 2017-03-30 11:58 ` Amit Langote <amitlangote09@gmail.com>
2017-03-31 06:50 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
0 siblings, 1 reply; 96+ messages in thread
From: Amit Langote @ 2017-03-30 11:58 UTC (permalink / raw)
To: Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>; +Cc: Langote_Amit_f8@lab.ntt.co.jp <Langote_Amit_f8@lab.ntt.co.jp>; Robert Haas <robertmhaas@gmail.com>; Maksim Milyutin <m.milyutin@postgrespro.ru>; pgsql-hackers
Thanks for the review.
On Thu, Mar 30, 2017 at 7:37 PM, Kyotaro HORIGUCHI wrote:
> At Thu, 30 Mar 2017 18:24:16 +0900, Amit Langote wrote:
>> On 2017/03/29 23:58, Robert Haas wrote:
>> > On Wed, Mar 29, 2017 at 4:21 AM, Amit Langote
>> > <Langote_Amit_f8@lab.ntt.co.jp> wrote:
>> >> Looks correct, so incorporated in the attached updated patch. Thanks.
>> >
>> > This seems like a hacky way to limit the reloptions to just OIDs.
>> > Shouldn't we instead have a new RELOPT_KIND_PARTITIONED or something
>> > like that?
>>
>> OK, I tried that in the updated patch.
>
> The name RELOPT_KIND_PARTITIONED looks somewhat odd. RELKIND for
> partitioned tables is RELKIND_PARTITIONED_TABLE, so is this
> better to be _TABLE, even if a bit longer?
Hm, OK. Done.
> parseRelOptions seems to return garbage pointer if no option of
> the kind is available.
Oops, fixed that too.
Updated patch attached.
Thanks,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Attachments:
[application/octet-stream] 0001-Do-not-allocate-storage-for-partitioned-tables.patch (8.7K, ../../CA+HiwqFmrJGe4eid2EaqnCjjQxrAYR5hJfzc5Cz929WA9p=A+w@mail.gmail.com/2-0001-Do-not-allocate-storage-for-partitioned-tables.patch)
download | inline diff:
From 9212004b62d96917d29e36b529c2c80994137bf9 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Tue, 24 Jan 2017 14:22:34 +0900
Subject: [PATCH] Do not allocate storage for partitioned tables.
Currently, it is not possible to insert any data into a partitioned
table. So they're empty at all times, which means it is wasteful to
allocate relfilenode and related storage objects.
Also, because there is no storage, it doesn't make sense to allow
specifying storage parameters such as fillfactor, etc. for partitioned
tables.
Patch by: Amit Langote & Maksim Milyutin
Reviwed by: Kyotaro Horiguchi
---
doc/src/sgml/ref/create_table.sgml | 6 +++++
src/backend/access/common/reloptions.c | 35 +++++++++++++++++++++---------
src/backend/catalog/heap.c | 20 ++++++++++-------
src/include/access/reloptions.h | 3 ++-
src/test/regress/expected/alter_table.out | 5 +++++
src/test/regress/expected/create_table.out | 5 +++++
src/test/regress/sql/alter_table.sql | 5 +++++
src/test/regress/sql/create_table.sql | 4 ++++
8 files changed, 64 insertions(+), 19 deletions(-)
diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml
index 283d53e..5f13f24 100644
--- a/doc/src/sgml/ref/create_table.sgml
+++ b/doc/src/sgml/ref/create_table.sgml
@@ -1040,6 +1040,12 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
will use the table's parameter value.
</para>
+ <para>
+ Note that specifying the following parameters for partitioned tables is
+ not supported. You must specify them for individual leaf partitions if
+ necessary.
+ </para>
+
<variablelist>
<varlistentry>
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 72e1253..d3f1e7b 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -1010,7 +1010,7 @@ relopt_value *
parseRelOptions(Datum options, bool validate, relopt_kind kind,
int *numrelopts)
{
- relopt_value *reloptions;
+ relopt_value *reloptions = NULL;
int numoptions = 0;
int i;
int j;
@@ -1024,21 +1024,28 @@ parseRelOptions(Datum options, bool validate, relopt_kind kind,
if (relOpts[i]->kinds & kind)
numoptions++;
- if (numoptions == 0)
+ /*
+ * Even if we found no options of kind, it's better to raise the
+ * "unrecognized parameter %s" error here, instead of at the caller.
+ */
+ if (numoptions == 0 && !validate)
{
*numrelopts = 0;
return NULL;
}
- reloptions = palloc(numoptions * sizeof(relopt_value));
-
- for (i = 0, j = 0; relOpts[i]; i++)
+ if (numoptions > 0)
{
- if (relOpts[i]->kinds & kind)
+ reloptions = palloc(numoptions * sizeof(relopt_value));
+
+ for (i = 0, j = 0; relOpts[i]; i++)
{
- reloptions[j].gen = relOpts[i];
- reloptions[j].isset = false;
- j++;
+ if (relOpts[i]->kinds & kind)
+ {
+ reloptions[j].gen = relOpts[i];
+ reloptions[j].isset = false;
+ j++;
+ }
}
}
@@ -1418,8 +1425,16 @@ heap_reloptions(char relkind, Datum reloptions, bool validate)
return (bytea *) rdopts;
case RELKIND_RELATION:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
+
+ /*
+ * There aren't any partitioned table options yet really, so the
+ * following simply serves to reject whatever's specified as being
+ * "unrecognized storage parameter" if validate is true.
+ */
+ case RELKIND_PARTITIONED_TABLE:
+ return default_reloptions(reloptions, validate,
+ RELOPT_KIND_PARTITIONED_TABLE);
default:
/* other relkinds are not supported */
return NULL;
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index eee5e2f..ff2f2e8 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -293,6 +293,7 @@ heap_create(const char *relname,
case RELKIND_VIEW:
case RELKIND_COMPOSITE_TYPE:
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
create_storage = false;
/*
@@ -1347,14 +1348,13 @@ heap_create_with_catalog(const char *relname,
if (oncommit != ONCOMMIT_NOOP)
register_on_commit_action(relid, oncommit);
- if (relpersistence == RELPERSISTENCE_UNLOGGED)
- {
- Assert(relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW ||
- relkind == RELKIND_TOASTVALUE ||
- relkind == RELKIND_PARTITIONED_TABLE);
-
+ /*
+ * We do not want to create any storage objects for a partitioned
+ * table, including the init fork.
+ */
+ if (relpersistence == RELPERSISTENCE_UNLOGGED &&
+ relkind != RELKIND_PARTITIONED_TABLE)
heap_create_init_fork(new_rel_desc);
- }
/*
* ok, the relation has been cataloged, so close our relations and return
@@ -1378,6 +1378,9 @@ heap_create_with_catalog(const char *relname,
void
heap_create_init_fork(Relation rel)
{
+ Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
+ rel->rd_rel->relkind == RELKIND_MATVIEW ||
+ rel->rd_rel->relkind == RELKIND_TOASTVALUE);
RelationOpenSmgr(rel);
smgrcreate(rel->rd_smgr, INIT_FORKNUM, false);
log_smgrcreate(&rel->rd_smgr->smgr_rnode.node, INIT_FORKNUM);
@@ -1824,7 +1827,8 @@ heap_drop_with_catalog(Oid relid)
*/
if (rel->rd_rel->relkind != RELKIND_VIEW &&
rel->rd_rel->relkind != RELKIND_COMPOSITE_TYPE &&
- rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE)
+ rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
+ rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
{
RelationDropStorage(rel);
}
diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h
index 861977a..4b78d77 100644
--- a/src/include/access/reloptions.h
+++ b/src/include/access/reloptions.h
@@ -48,8 +48,9 @@ typedef enum relopt_kind
RELOPT_KIND_SPGIST = (1 << 8),
RELOPT_KIND_VIEW = (1 << 9),
RELOPT_KIND_BRIN = (1 << 10),
+ RELOPT_KIND_PARTITIONED_TABLE = (1 << 11),
/* if you add a new kind, make sure you update "last_default" too */
- RELOPT_KIND_LAST_DEFAULT = RELOPT_KIND_BRIN,
+ RELOPT_KIND_LAST_DEFAULT = RELOPT_KIND_PARTITIONED_TABLE,
/* some compilers treat enums as signed ints, so we can't use 1 << 31 */
RELOPT_KIND_MAX = (1 << 30)
} relopt_kind;
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index 2227f2d..1230ad7 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -3372,3 +3372,8 @@ ERROR: partition constraint is violated by some row
-- cleanup
drop table p;
drop table p1;
+-- partitioned tables accept no options other than "oids" in the WITH list
+create table parted_withopt_test (a int) partition by list (a) with (oids = true);
+alter table parted_withopt_test set (fillfactor = 90);
+ERROR: unrecognized parameter "fillfactor"
+drop table parted_withopt_test;
diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out
index 6f8645d..6294a16 100644
--- a/src/test/regress/expected/create_table.out
+++ b/src/test/regress/expected/create_table.out
@@ -669,3 +669,8 @@ Number of partitions: 3 (Use \d+ to list them.)
-- cleanup
DROP TABLE parted, list_parted, range_parted, list_parted2, range_parted2, range_parted3;
+-- partitioned tables accept no options other than "oids" in the WITH list
+create table parted_withopt_test (a int) partition by list (a) with (fillfactor = 10);
+ERROR: unrecognized parameter "fillfactor"
+create table parted_withopt_test (a int) partition by list (a) with (toast.autvacuum_enabled = true);
+ERROR: unrecognized parameter "autvacuum_enabled"
diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql
index 8cd6786..e50f408 100644
--- a/src/test/regress/sql/alter_table.sql
+++ b/src/test/regress/sql/alter_table.sql
@@ -2228,3 +2228,8 @@ alter table p attach partition p1 for values from (1, 2) to (1, 10);
-- cleanup
drop table p;
drop table p1;
+
+-- partitioned tables accept no options other than "oids" in the WITH list
+create table parted_withopt_test (a int) partition by list (a) with (oids = true);
+alter table parted_withopt_test set (fillfactor = 90);
+drop table parted_withopt_test;
diff --git a/src/test/regress/sql/create_table.sql b/src/test/regress/sql/create_table.sql
index 1f0fa8e..0c8cae0 100644
--- a/src/test/regress/sql/create_table.sql
+++ b/src/test/regress/sql/create_table.sql
@@ -597,3 +597,7 @@ CREATE TABLE part_c_1_10 PARTITION OF part_c FOR VALUES FROM (1) TO (10);
-- cleanup
DROP TABLE parted, list_parted, range_parted, list_parted2, range_parted2, range_parted3;
+
+-- partitioned tables accept no options other than "oids" in the WITH list
+create table parted_withopt_test (a int) partition by list (a) with (fillfactor = 10);
+create table parted_withopt_test (a int) partition by list (a) with (toast.autvacuum_enabled = true);
--
2.3.2 (Apple Git-55)
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-20 16:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-21 09:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 13:49 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-22 13:39 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-23 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-23 14:27 ` Re: Partitioned tables and relfilenode Maksim Milyutin <m.milyutin@postgrespro.ru>
2017-03-23 14:47 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-24 00:54 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-27 14:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-29 06:40 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 07:49 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-29 08:21 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 14:58 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-30 09:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-30 10:37 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-30 11:58 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
@ 2017-03-31 06:50 ` Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-31 07:17 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
0 siblings, 1 reply; 96+ messages in thread
From: Kyotaro HORIGUCHI @ 2017-03-31 06:50 UTC (permalink / raw)
To: amitlangote09@gmail.com; +Cc: Langote_Amit_f8@lab.ntt.co.jp; robertmhaas@gmail.com; m.milyutin@postgrespro.ru; pgsql-hackers
At Thu, 30 Mar 2017 20:58:35 +0900, Amit Langote <amitlangote09@gmail.com> wrote in <CA+HiwqFmrJGe4eid2EaqnCjjQxrAYR5hJfzc5Cz929WA9p=A+w@mail.gmail.com>
> Thanks for the review.
>
> On Thu, Mar 30, 2017 at 7:37 PM, Kyotaro HORIGUCHI wrote:
> > At Thu, 30 Mar 2017 18:24:16 +0900, Amit Langote wrote:
> >> On 2017/03/29 23:58, Robert Haas wrote:
> >> > On Wed, Mar 29, 2017 at 4:21 AM, Amit Langote
> >> > <Langote_Amit_f8@lab.ntt.co.jp> wrote:
> >> >> Looks correct, so incorporated in the attached updated patch. Thanks.
> >> >
> >> > This seems like a hacky way to limit the reloptions to just OIDs.
> >> > Shouldn't we instead have a new RELOPT_KIND_PARTITIONED or something
> >> > like that?
> >>
> >> OK, I tried that in the updated patch.
> >
> > The name RELOPT_KIND_PARTITIONED looks somewhat odd. RELKIND for
> > partitioned tables is RELKIND_PARTITIONED_TABLE, so is this
> > better to be _TABLE, even if a bit longer?
>
> Hm, OK. Done.
>
> > parseRelOptions seems to return garbage pointer if no option of
> > the kind is available.
>
> Oops, fixed that too.
>
> Updated patch attached.
Thank you.
- Applies cleanly on master (f90d23d)
- Compiled without error
- Code seems fine.
- Documentaion seems fine.. for me.
- Passes regression test.
- Leaving the ALTER-on-toast.* problem is fine for me.
The regression contains the tests to fail with several reloptions
only for partitioned tables. Are they still required even though
it is now in the same framework with other kind of reloptions?
regards,
--
Kyotaro Horiguchi
NTT Open Source Software Center
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-20 16:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-21 09:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 13:49 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-22 13:39 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-23 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-23 14:27 ` Re: Partitioned tables and relfilenode Maksim Milyutin <m.milyutin@postgrespro.ru>
2017-03-23 14:47 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-24 00:54 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-27 14:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-29 06:40 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 07:49 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-29 08:21 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 14:58 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-30 09:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-30 10:37 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-30 11:58 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-31 06:50 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
@ 2017-03-31 07:17 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-31 08:33 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
0 siblings, 1 reply; 96+ messages in thread
From: Amit Langote @ 2017-03-31 07:17 UTC (permalink / raw)
To: Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>; amitlangote09@gmail.com; +Cc: robertmhaas@gmail.com; m.milyutin@postgrespro.ru; pgsql-hackers
Horiguchi-san,
On 2017/03/31 15:50, Kyotaro HORIGUCHI wrote:
> At Thu, 30 Mar 2017 20:58:35 +0900, Amit Langote wrote:
>> Updated patch attached.
>
> Thank you.
>
> - Applies cleanly on master (f90d23d)
> - Compiled without error
> - Code seems fine.
> - Documentaion seems fine.. for me.
> - Passes regression test.
> - Leaving the ALTER-on-toast.* problem is fine for me.
Thanks for the review.
> The regression contains the tests to fail with several reloptions
> only for partitioned tables. Are they still required even though
> it is now in the same framework with other kind of reloptions?
Hmm, maybe we don't really need those tests, so removed.
Thanks,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Attachments:
[text/x-diff] 0001-Do-not-allocate-storage-for-partitioned-tables.patch (5.6K, ../../2dec1acb-6e2f-5aa5-0e26-fcc172ce9359@lab.ntt.co.jp/2-0001-Do-not-allocate-storage-for-partitioned-tables.patch)
download | inline diff:
From bc80db31f218d299ad4ccfa5140088382ac947db Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Tue, 24 Jan 2017 14:22:34 +0900
Subject: [PATCH] Do not allocate storage for partitioned tables.
Currently, it is not possible to insert any data into a partitioned
table. So they're empty at all times, which means it is wasteful to
allocate relfilenode and related storage objects.
Also, because there is no storage, it doesn't make sense to allow
specifying storage parameters such as fillfactor, etc.
Patch by: Amit Langote & Maksim Milyutin
Reviewed by: Kyotaro Horiguchi
---
doc/src/sgml/ref/create_table.sgml | 6 ++++++
src/backend/access/common/reloptions.c | 33 ++++++++++++++++++++++++---------
src/backend/catalog/heap.c | 20 ++++++++++++--------
src/include/access/reloptions.h | 3 ++-
4 files changed, 44 insertions(+), 18 deletions(-)
diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml
index 283d53e203..5f13f240f5 100644
--- a/doc/src/sgml/ref/create_table.sgml
+++ b/doc/src/sgml/ref/create_table.sgml
@@ -1040,6 +1040,12 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
will use the table's parameter value.
</para>
+ <para>
+ Note that specifying the following parameters for partitioned tables is
+ not supported. You must specify them for individual leaf partitions if
+ necessary.
+ </para>
+
<variablelist>
<varlistentry>
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 72e12532ab..f3f5ade38f 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -1024,21 +1024,28 @@ parseRelOptions(Datum options, bool validate, relopt_kind kind,
if (relOpts[i]->kinds & kind)
numoptions++;
- if (numoptions == 0)
+ /*
+ * Even if we found no options of kind, it's better to raise the
+ * "unrecognized parameter %s" error here, instead of at the caller.
+ */
+ if (numoptions == 0 && !validate)
{
*numrelopts = 0;
return NULL;
}
- reloptions = palloc(numoptions * sizeof(relopt_value));
-
- for (i = 0, j = 0; relOpts[i]; i++)
+ if (numoptions > 0)
{
- if (relOpts[i]->kinds & kind)
+ reloptions = palloc(numoptions * sizeof(relopt_value));
+
+ for (i = 0, j = 0; relOpts[i]; i++)
{
- reloptions[j].gen = relOpts[i];
- reloptions[j].isset = false;
- j++;
+ if (relOpts[i]->kinds & kind)
+ {
+ reloptions[j].gen = relOpts[i];
+ reloptions[j].isset = false;
+ j++;
+ }
}
}
@@ -1418,8 +1425,16 @@ heap_reloptions(char relkind, Datum reloptions, bool validate)
return (bytea *) rdopts;
case RELKIND_RELATION:
case RELKIND_MATVIEW:
- case RELKIND_PARTITIONED_TABLE:
return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
+
+ /*
+ * There aren't any partitioned table options yet really, so the
+ * following simply serves to reject whatever's specified as being
+ * "unrecognized storage parameter" if validate is true.
+ */
+ case RELKIND_PARTITIONED_TABLE:
+ return default_reloptions(reloptions, validate,
+ RELOPT_KIND_PARTITIONED);
default:
/* other relkinds are not supported */
return NULL;
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index eee5e2f6ca..ff2f2e8efb 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -293,6 +293,7 @@ heap_create(const char *relname,
case RELKIND_VIEW:
case RELKIND_COMPOSITE_TYPE:
case RELKIND_FOREIGN_TABLE:
+ case RELKIND_PARTITIONED_TABLE:
create_storage = false;
/*
@@ -1347,14 +1348,13 @@ heap_create_with_catalog(const char *relname,
if (oncommit != ONCOMMIT_NOOP)
register_on_commit_action(relid, oncommit);
- if (relpersistence == RELPERSISTENCE_UNLOGGED)
- {
- Assert(relkind == RELKIND_RELATION || relkind == RELKIND_MATVIEW ||
- relkind == RELKIND_TOASTVALUE ||
- relkind == RELKIND_PARTITIONED_TABLE);
-
+ /*
+ * We do not want to create any storage objects for a partitioned
+ * table, including the init fork.
+ */
+ if (relpersistence == RELPERSISTENCE_UNLOGGED &&
+ relkind != RELKIND_PARTITIONED_TABLE)
heap_create_init_fork(new_rel_desc);
- }
/*
* ok, the relation has been cataloged, so close our relations and return
@@ -1378,6 +1378,9 @@ heap_create_with_catalog(const char *relname,
void
heap_create_init_fork(Relation rel)
{
+ Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
+ rel->rd_rel->relkind == RELKIND_MATVIEW ||
+ rel->rd_rel->relkind == RELKIND_TOASTVALUE);
RelationOpenSmgr(rel);
smgrcreate(rel->rd_smgr, INIT_FORKNUM, false);
log_smgrcreate(&rel->rd_smgr->smgr_rnode.node, INIT_FORKNUM);
@@ -1824,7 +1827,8 @@ heap_drop_with_catalog(Oid relid)
*/
if (rel->rd_rel->relkind != RELKIND_VIEW &&
rel->rd_rel->relkind != RELKIND_COMPOSITE_TYPE &&
- rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE)
+ rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
+ rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
{
RelationDropStorage(rel);
}
diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h
index 861977a608..91b2cd7bb2 100644
--- a/src/include/access/reloptions.h
+++ b/src/include/access/reloptions.h
@@ -48,8 +48,9 @@ typedef enum relopt_kind
RELOPT_KIND_SPGIST = (1 << 8),
RELOPT_KIND_VIEW = (1 << 9),
RELOPT_KIND_BRIN = (1 << 10),
+ RELOPT_KIND_PARTITIONED = (1 << 11),
/* if you add a new kind, make sure you update "last_default" too */
- RELOPT_KIND_LAST_DEFAULT = RELOPT_KIND_BRIN,
+ RELOPT_KIND_LAST_DEFAULT = RELOPT_KIND_PARTITIONED,
/* some compilers treat enums as signed ints, so we can't use 1 << 31 */
RELOPT_KIND_MAX = (1 << 30)
} relopt_kind;
--
2.11.0
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-20 16:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-21 09:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 13:49 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-22 13:39 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-23 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-23 14:27 ` Re: Partitioned tables and relfilenode Maksim Milyutin <m.milyutin@postgrespro.ru>
2017-03-23 14:47 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-24 00:54 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-27 14:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-29 06:40 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 07:49 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-29 08:21 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 14:58 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-30 09:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-30 10:37 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-30 11:58 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-31 06:50 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-31 07:17 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-03-31 08:33 ` Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-31 20:29 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
0 siblings, 1 reply; 96+ messages in thread
From: Kyotaro HORIGUCHI @ 2017-03-31 08:33 UTC (permalink / raw)
To: Langote_Amit_f8@lab.ntt.co.jp; +Cc: amitlangote09@gmail.com; robertmhaas@gmail.com; m.milyutin@postgrespro.ru; pgsql-hackers
At Fri, 31 Mar 2017 16:17:05 +0900, Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> wrote in <2dec1acb-6e2f-5aa5-0e26-fcc172ce9359@lab.ntt.co.jp>
> Horiguchi-san,
>
> On 2017/03/31 15:50, Kyotaro HORIGUCHI wrote:
> > At Thu, 30 Mar 2017 20:58:35 +0900, Amit Langote wrote:
> >> Updated patch attached.
> >
> > Thank you.
> >
> > - Applies cleanly on master (f90d23d)
> > - Compiled without error
> > - Code seems fine.
> > - Documentaion seems fine.. for me.
> > - Passes regression test.
> > - Leaving the ALTER-on-toast.* problem is fine for me.
>
> Thanks for the review.
>
> > The regression contains the tests to fail with several reloptions
> > only for partitioned tables. Are they still required even though
> > it is now in the same framework with other kind of reloptions?
>
> Hmm, maybe we don't really need those tests, so removed.
I have no more comment on this. Thank you.
regards,
--
Kyotaro Horiguchi
NTT Open Source Software Center
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-20 16:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-21 09:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 13:49 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-22 13:39 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-23 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-23 14:27 ` Re: Partitioned tables and relfilenode Maksim Milyutin <m.milyutin@postgrespro.ru>
2017-03-23 14:47 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-24 00:54 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-27 14:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-29 06:40 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 07:49 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-29 08:21 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 14:58 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-30 09:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-30 10:37 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-30 11:58 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-31 06:50 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-31 07:17 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-31 08:33 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
@ 2017-03-31 20:29 ` Robert Haas <robertmhaas@gmail.com>
2017-04-03 02:39 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
0 siblings, 1 reply; 96+ messages in thread
From: Robert Haas @ 2017-03-31 20:29 UTC (permalink / raw)
To: Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>; +Cc: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; Amit Langote <amitlangote09@gmail.com>; Maksim Milyutin <m.milyutin@postgrespro.ru>; pgsql-hackers
On Fri, Mar 31, 2017 at 4:33 AM, Kyotaro HORIGUCHI
<horiguchi.kyotaro@lab.ntt.co.jp> wrote:
> I have no more comment on this. Thank you.
I committed this with a few tweaks. I simplified the wording in the
documentation a bit, removed or adjusted a couple of comments, and
slightly changed the way the logic works in parseRelOptions in a way
that I think is simpler.
Thanks for reviewing, and thanks to Maksim as well, and thanks to Amit
for writing the patch.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-20 16:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-21 09:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 13:49 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-22 13:39 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-23 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-23 14:27 ` Re: Partitioned tables and relfilenode Maksim Milyutin <m.milyutin@postgrespro.ru>
2017-03-23 14:47 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-24 00:54 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-27 14:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-29 06:40 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 07:49 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-29 08:21 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 14:58 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-30 09:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-30 10:37 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-30 11:58 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-31 06:50 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-31 07:17 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-31 08:33 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-31 20:29 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
@ 2017-04-03 02:39 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-04-11 09:16 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
0 siblings, 1 reply; 96+ messages in thread
From: Amit Langote @ 2017-04-03 02:39 UTC (permalink / raw)
To: Robert Haas <robertmhaas@gmail.com>; Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>; +Cc: Amit Langote <amitlangote09@gmail.com>; Maksim Milyutin <m.milyutin@postgrespro.ru>; pgsql-hackers
On 2017/04/01 5:29, Robert Haas wrote:
> On Fri, Mar 31, 2017 at 4:33 AM, Kyotaro HORIGUCHI
> <horiguchi.kyotaro@lab.ntt.co.jp> wrote:
>> I have no more comment on this. Thank you.
>
> I committed this with a few tweaks. I simplified the wording in the
> documentation a bit, removed or adjusted a couple of comments, and
> slightly changed the way the logic works in parseRelOptions in a way
> that I think is simpler.
Looks good.
> Thanks for reviewing, and thanks to Maksim as well, and thanks to Amit
> for writing the patch.
Thanks for committing. :)
Regards,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-20 16:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-21 09:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 13:49 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-22 13:39 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-23 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-23 14:27 ` Re: Partitioned tables and relfilenode Maksim Milyutin <m.milyutin@postgrespro.ru>
2017-03-23 14:47 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-24 00:54 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-27 14:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-29 06:40 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 07:49 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-29 08:21 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 14:58 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-30 09:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-30 10:37 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-30 11:58 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-31 06:50 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-31 07:17 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-31 08:33 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-31 20:29 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-04-03 02:39 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-04-11 09:16 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-04-11 12:59 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-04-11 13:45 ` Re: Partitioned tables and relfilenode Tom Lane <tgl@sss.pgh.pa.us>
0 siblings, 2 replies; 96+ messages in thread
From: Amit Langote @ 2017-04-11 09:16 UTC (permalink / raw)
To: Robert Haas <robertmhaas@gmail.com>; Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>; +Cc: Amit Langote <amitlangote09@gmail.com>; Maksim Milyutin <m.milyutin@postgrespro.ru>; pgsql-hackers
On 2017/04/03 11:39, Amit Langote wrote:
> On 2017/04/01 5:29, Robert Haas wrote:
>> Thanks for reviewing, and thanks to Maksim as well, and thanks to Amit
>> for writing the patch.
>
> Thanks for committing. :)
I noticed that I had missed a couple of places that would try to scan
partitioned tables, resulting in file access.
1. In validateCheckConstraint(), along with foreign tables, must ignore
partitioned tables.
2. DefineQueryRewrite() may try to scan a partitioned table in the case of
converting a table to view, where we must make sure that the table being
converted is empty. It's checked by scanning the heap, which we should
not do for a partitioned table. Nor should we try to drop the storage
once ready to make the table into a REKIND_VIEW relation (because all
other checks passed okaying the conversion).
Tests are added for both the cases.
Thanks,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Attachments:
[text/x-diff] 0001-Fix-few-places-still-scanning-partitioned-tables.patch (7.6K, ../../062ab583-767d-9d08-5c7c-16b674a4c279@lab.ntt.co.jp/2-0001-Fix-few-places-still-scanning-partitioned-tables.patch)
download | inline diff:
From e0e0d792dedf855e01d82f2f608ee02b9cded039 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Tue, 11 Apr 2017 16:04:50 +0900
Subject: [PATCH] Fix few places still scanning partitioned tables
Commit c94e6942ce missed the following instances:
- validateCheckConstraint
- DefineQueryRewrite
---
src/backend/commands/tablecmds.c | 8 ++++++--
src/backend/rewrite/rewriteDefine.c | 32 +++++++++++++++++++++----------
src/test/regress/expected/alter_table.out | 6 ++++++
src/test/regress/expected/rules.out | 29 ++++++++++++++++++++++++++++
src/test/regress/sql/alter_table.sql | 7 +++++++
src/test/regress/sql/rules.sql | 22 +++++++++++++++++++++
6 files changed, 92 insertions(+), 12 deletions(-)
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index abb262b851..4438a7b95c 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -8090,8 +8090,12 @@ validateCheckConstraint(Relation rel, HeapTuple constrtup)
bool isnull;
Snapshot snapshot;
- /* VALIDATE CONSTRAINT is a no-op for foreign tables */
- if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+ /*
+ * VALIDATE CONSTRAINT is a no-op for foreign tables and partitioned
+ * tables.
+ */
+ if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
+ rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
return;
constrForm = (Form_pg_constraint) GETSTRUCT(constrtup);
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index 86d588bba5..407c92d1f9 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -419,18 +419,26 @@ DefineQueryRewrite(char *rulename,
if (event_relation->rd_rel->relkind != RELKIND_VIEW &&
event_relation->rd_rel->relkind != RELKIND_MATVIEW)
{
- HeapScanDesc scanDesc;
- Snapshot snapshot;
+ /*
+ * Must not try to scan a partitioned table; if there is any data,
+ * it would be in partitions (child tables), which if there are
+ * any, we will throw an error below.
+ */
+ if (event_relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
+ {
+ HeapScanDesc scanDesc;
+ Snapshot snapshot;
- snapshot = RegisterSnapshot(GetLatestSnapshot());
- scanDesc = heap_beginscan(event_relation, snapshot, 0, NULL);
- if (heap_getnext(scanDesc, ForwardScanDirection) != NULL)
- ereport(ERROR,
+ snapshot = RegisterSnapshot(GetLatestSnapshot());
+ scanDesc = heap_beginscan(event_relation, snapshot, 0, NULL);
+ if (heap_getnext(scanDesc, ForwardScanDirection) != NULL)
+ ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("could not convert table \"%s\" to a view because it is not empty",
RelationGetRelationName(event_relation))));
- heap_endscan(scanDesc);
- UnregisterSnapshot(snapshot);
+ heap_endscan(scanDesc);
+ UnregisterSnapshot(snapshot);
+ }
if (event_relation->rd_rel->relhastriggers)
ereport(ERROR,
@@ -551,8 +559,12 @@ DefineQueryRewrite(char *rulename,
relationRelation = heap_open(RelationRelationId, RowExclusiveLock);
toastrelid = event_relation->rd_rel->reltoastrelid;
- /* drop storage while table still looks like a table */
- RelationDropStorage(event_relation);
+ /*
+ * Drop storage while table still looks like a table; must not try
+ * if it's a partitioned table.
+ */
+ if (event_relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
+ RelationDropStorage(event_relation);
DeleteSystemAttributeTuples(event_relid);
/*
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index 2227f2d977..883a5c9864 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -3372,3 +3372,9 @@ ERROR: partition constraint is violated by some row
-- cleanup
drop table p;
drop table p1;
+-- validate constraint on partitioned tables should only scan leaf partitions
+create table parted_validate_test (a int) partition by list (a);
+create table parted_validate_test_1 partition of parted_validate_test for values in (0, 1);
+alter table parted_validate_test add constraint parted_validate_test_chka check (a > 0) not valid;
+alter table parted_validate_test validate constraint parted_validate_test_chka;
+drop table parted_validate_test;
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index cba82bb114..4d794ac4ba 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -2574,6 +2574,35 @@ select reltoastrelid, relkind, relfrozenxid
(1 row)
drop view fooview;
+-- check the same for a partitioned table
+create table partedfooview (x int, y text) partition by list (x);
+create table partedfooview_part partition of partedfooview for values in (1);
+-- nope, cannot convert if there exists a child table
+create rule "_RETURN" as on select to partedfooview do instead
+ select 1 as x, 'aaa'::text as y;
+ERROR: could not convert table "partedfooview" to a view because it has child tables
+drop table partedfooview_part;
+analyze partedfooview; -- reset relhassubclass
+create rule "_RETURN" as on select to partedfooview do instead
+ select 1 as x, 'aaa'::text as y;
+select * from partedfooview;
+ x | y
+---+-----
+ 1 | aaa
+(1 row)
+
+select xmin, * from partedfooview; -- fail, views don't have such a column
+ERROR: column "xmin" does not exist
+LINE 1: select xmin, * from partedfooview;
+ ^
+select reltoastrelid, relkind, relfrozenxid
+ from pg_class where oid = 'partedfooview'::regclass;
+ reltoastrelid | relkind | relfrozenxid
+---------------+---------+--------------
+ 0 | v | 0
+(1 row)
+
+drop view partedfooview;
--
-- check for planner problems with complex inherited UPDATES
--
diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql
index 8cd6786a90..eb1b4b536f 100644
--- a/src/test/regress/sql/alter_table.sql
+++ b/src/test/regress/sql/alter_table.sql
@@ -2228,3 +2228,10 @@ alter table p attach partition p1 for values from (1, 2) to (1, 10);
-- cleanup
drop table p;
drop table p1;
+
+-- validate constraint on partitioned tables should only scan leaf partitions
+create table parted_validate_test (a int) partition by list (a);
+create table parted_validate_test_1 partition of parted_validate_test for values in (0, 1);
+alter table parted_validate_test add constraint parted_validate_test_chka check (a > 0) not valid;
+alter table parted_validate_test validate constraint parted_validate_test_chka;
+drop table parted_validate_test;
diff --git a/src/test/regress/sql/rules.sql b/src/test/regress/sql/rules.sql
index dcff0de2a5..c86ea83837 100644
--- a/src/test/regress/sql/rules.sql
+++ b/src/test/regress/sql/rules.sql
@@ -898,6 +898,28 @@ select reltoastrelid, relkind, relfrozenxid
drop view fooview;
+-- check the same for a partitioned table
+create table partedfooview (x int, y text) partition by list (x);
+create table partedfooview_part partition of partedfooview for values in (1);
+
+-- nope, cannot convert if there exists a child table
+create rule "_RETURN" as on select to partedfooview do instead
+ select 1 as x, 'aaa'::text as y;
+
+drop table partedfooview_part;
+analyze partedfooview; -- reset relhassubclass
+
+create rule "_RETURN" as on select to partedfooview do instead
+ select 1 as x, 'aaa'::text as y;
+
+select * from partedfooview;
+select xmin, * from partedfooview; -- fail, views don't have such a column
+
+select reltoastrelid, relkind, relfrozenxid
+ from pg_class where oid = 'partedfooview'::regclass;
+
+drop view partedfooview;
+
--
-- check for planner problems with complex inherited UPDATES
--
--
2.11.0
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-20 16:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-21 09:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 13:49 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-22 13:39 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-23 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-23 14:27 ` Re: Partitioned tables and relfilenode Maksim Milyutin <m.milyutin@postgrespro.ru>
2017-03-23 14:47 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-24 00:54 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-27 14:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-29 06:40 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 07:49 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-29 08:21 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 14:58 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-30 09:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-30 10:37 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-30 11:58 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-31 06:50 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-31 07:17 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-31 08:33 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-31 20:29 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-04-03 02:39 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-04-11 09:16 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-04-11 12:59 ` Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
1 sibling, 0 replies; 96+ messages in thread
From: Ashutosh Bapat @ 2017-04-11 12:59 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: Robert Haas <robertmhaas@gmail.com>; Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>; Amit Langote <amitlangote09@gmail.com>; Maksim Milyutin <m.milyutin@postgrespro.ru>; pgsql-hackers
Looking at the number of issues where we have to fix tests based on
the relkind checks, I think, we have to consider creating macros as
described in my reply to thread with subject " Allowing extended stats
on foreign and partitioned tables".
On Tue, Apr 11, 2017 at 2:46 PM, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
> On 2017/04/03 11:39, Amit Langote wrote:
>> On 2017/04/01 5:29, Robert Haas wrote:
>>> Thanks for reviewing, and thanks to Maksim as well, and thanks to Amit
>>> for writing the patch.
>>
>> Thanks for committing. :)
>
> I noticed that I had missed a couple of places that would try to scan
> partitioned tables, resulting in file access.
>
> 1. In validateCheckConstraint(), along with foreign tables, must ignore
> partitioned tables.
>
> 2. DefineQueryRewrite() may try to scan a partitioned table in the case of
> converting a table to view, where we must make sure that the table being
> converted is empty. It's checked by scanning the heap, which we should
> not do for a partitioned table. Nor should we try to drop the storage
> once ready to make the table into a REKIND_VIEW relation (because all
> other checks passed okaying the conversion).
>
> Tests are added for both the cases.
>
> Thanks,
> Amit
>
>
> --
> Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
> To make changes to your subscription:
> http://www.postgresql.org/mailpref/pgsql-hackers
>
--
Best Wishes,
Ashutosh Bapat
EnterpriseDB Corporation
The Postgres Database Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-20 16:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-21 09:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 13:49 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-22 13:39 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-23 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-23 14:27 ` Re: Partitioned tables and relfilenode Maksim Milyutin <m.milyutin@postgrespro.ru>
2017-03-23 14:47 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-24 00:54 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-27 14:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-29 06:40 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 07:49 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-29 08:21 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 14:58 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-30 09:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-30 10:37 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-30 11:58 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-31 06:50 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-31 07:17 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-31 08:33 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-31 20:29 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-04-03 02:39 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-04-11 09:16 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-04-11 13:45 ` Tom Lane <tgl@sss.pgh.pa.us>
2017-04-11 17:41 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
1 sibling, 1 reply; 96+ messages in thread
From: Tom Lane @ 2017-04-11 13:45 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: Robert Haas <robertmhaas@gmail.com>; Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>; Amit Langote <amitlangote09@gmail.com>; Maksim Milyutin <m.milyutin@postgrespro.ru>; pgsql-hackers
Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> writes:
> 2. DefineQueryRewrite() may try to scan a partitioned table in the case of
> converting a table to view, where we must make sure that the table being
> converted is empty. It's checked by scanning the heap, which we should
> not do for a partitioned table. Nor should we try to drop the storage
> once ready to make the table into a REKIND_VIEW relation (because all
> other checks passed okaying the conversion).
It looks like this patch intends to allow converting a partitioned table
to a view. I would lobby for refusing the command, instead. There is
no good reason to allow it, and it might well be a user error.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-20 16:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-21 09:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 13:49 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-22 13:39 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-23 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-23 14:27 ` Re: Partitioned tables and relfilenode Maksim Milyutin <m.milyutin@postgrespro.ru>
2017-03-23 14:47 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-24 00:54 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-27 14:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-29 06:40 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 07:49 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-29 08:21 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 14:58 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-30 09:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-30 10:37 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-30 11:58 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-31 06:50 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-31 07:17 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-31 08:33 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-31 20:29 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-04-03 02:39 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-04-11 09:16 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-04-11 13:45 ` Re: Partitioned tables and relfilenode Tom Lane <tgl@sss.pgh.pa.us>
@ 2017-04-11 17:41 ` Robert Haas <robertmhaas@gmail.com>
2017-04-12 02:15 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
0 siblings, 1 reply; 96+ messages in thread
From: Robert Haas @ 2017-04-11 17:41 UTC (permalink / raw)
To: Tom Lane <tgl@sss.pgh.pa.us>; +Cc: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>; Amit Langote <amitlangote09@gmail.com>; Maksim Milyutin <m.milyutin@postgrespro.ru>; pgsql-hackers
On Tue, Apr 11, 2017 at 9:45 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> writes:
>> 2. DefineQueryRewrite() may try to scan a partitioned table in the case of
>> converting a table to view, where we must make sure that the table being
>> converted is empty. It's checked by scanning the heap, which we should
>> not do for a partitioned table. Nor should we try to drop the storage
>> once ready to make the table into a REKIND_VIEW relation (because all
>> other checks passed okaying the conversion).
>
> It looks like this patch intends to allow converting a partitioned table
> to a view. I would lobby for refusing the command, instead. There is
> no good reason to allow it, and it might well be a user error.
Yeah, I agree.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-20 16:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-21 09:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 13:49 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-22 13:39 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-23 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-23 14:27 ` Re: Partitioned tables and relfilenode Maksim Milyutin <m.milyutin@postgrespro.ru>
2017-03-23 14:47 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-24 00:54 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-27 14:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-29 06:40 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 07:49 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-29 08:21 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 14:58 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-30 09:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-30 10:37 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-30 11:58 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-31 06:50 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-31 07:17 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-31 08:33 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-31 20:29 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-04-03 02:39 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-04-11 09:16 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-04-11 13:45 ` Re: Partitioned tables and relfilenode Tom Lane <tgl@sss.pgh.pa.us>
2017-04-11 17:41 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
@ 2017-04-12 02:15 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-04-12 15:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
0 siblings, 1 reply; 96+ messages in thread
From: Amit Langote @ 2017-04-12 02:15 UTC (permalink / raw)
To: Robert Haas <robertmhaas@gmail.com>; Tom Lane <tgl@sss.pgh.pa.us>; +Cc: Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>; Amit Langote <amitlangote09@gmail.com>; Maksim Milyutin <m.milyutin@postgrespro.ru>; pgsql-hackers
On 2017/04/12 2:41, Robert Haas wrote:
> On Tue, Apr 11, 2017 at 9:45 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>> Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> writes:
>>> 2. DefineQueryRewrite() may try to scan a partitioned table in the case of
>>> converting a table to view, where we must make sure that the table being
>>> converted is empty. It's checked by scanning the heap, which we should
>>> not do for a partitioned table. Nor should we try to drop the storage
>>> once ready to make the table into a REKIND_VIEW relation (because all
>>> other checks passed okaying the conversion).
>>
>> It looks like this patch intends to allow converting a partitioned table
>> to a view. I would lobby for refusing the command, instead. There is
>> no good reason to allow it, and it might well be a user error.
>
> Yeah, I agree.
Alright. So I made it into two patches instead: 0001 fixes the bug that
validateCheckConstraint() tries to scan partitioned tables and 0002 makes
trying to convert a partitioned table to a view a user error.
Thanks,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Attachments:
[text/x-diff] 0001-Fix-a-few-places-still-scanning-partitioned-tables.patch (2.7K, ../../e5c3cbd3-1551-d6f8-c9e2-51777d632fd2@lab.ntt.co.jp/2-0001-Fix-a-few-places-still-scanning-partitioned-tables.patch)
download | inline diff:
From a71b2d8c38c1ca2ca3430bdc3f4f850d66e486d6 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Tue, 11 Apr 2017 16:04:50 +0900
Subject: [PATCH 1/2] Fix a few places still scanning partitioned tables
Commit c94e6942ce missed validateCheckConstraint.
---
src/backend/commands/tablecmds.c | 8 ++++++--
src/test/regress/expected/alter_table.out | 6 ++++++
src/test/regress/sql/alter_table.sql | 7 +++++++
3 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index a6a9f54b13..a02904c85c 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -8120,8 +8120,12 @@ validateCheckConstraint(Relation rel, HeapTuple constrtup)
bool isnull;
Snapshot snapshot;
- /* VALIDATE CONSTRAINT is a no-op for foreign tables */
- if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+ /*
+ * VALIDATE CONSTRAINT is a no-op for foreign tables and partitioned
+ * tables.
+ */
+ if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
+ rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
return;
constrForm = (Form_pg_constraint) GETSTRUCT(constrtup);
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index 2227f2d977..883a5c9864 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -3372,3 +3372,9 @@ ERROR: partition constraint is violated by some row
-- cleanup
drop table p;
drop table p1;
+-- validate constraint on partitioned tables should only scan leaf partitions
+create table parted_validate_test (a int) partition by list (a);
+create table parted_validate_test_1 partition of parted_validate_test for values in (0, 1);
+alter table parted_validate_test add constraint parted_validate_test_chka check (a > 0) not valid;
+alter table parted_validate_test validate constraint parted_validate_test_chka;
+drop table parted_validate_test;
diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql
index 8cd6786a90..eb1b4b536f 100644
--- a/src/test/regress/sql/alter_table.sql
+++ b/src/test/regress/sql/alter_table.sql
@@ -2228,3 +2228,10 @@ alter table p attach partition p1 for values from (1, 2) to (1, 10);
-- cleanup
drop table p;
drop table p1;
+
+-- validate constraint on partitioned tables should only scan leaf partitions
+create table parted_validate_test (a int) partition by list (a);
+create table parted_validate_test_1 partition of parted_validate_test for values in (0, 1);
+alter table parted_validate_test add constraint parted_validate_test_chka check (a > 0) not valid;
+alter table parted_validate_test validate constraint parted_validate_test_chka;
+drop table parted_validate_test;
--
2.11.0
[text/x-diff] 0002-Disallow-converting-partitioned-tables-to-a-view.patch (1.6K, ../../e5c3cbd3-1551-d6f8-c9e2-51777d632fd2@lab.ntt.co.jp/3-0002-Disallow-converting-partitioned-tables-to-a-view.patch)
download | inline diff:
From e788b5663db1e62ee4d6f6a7a9c111b049f25fbe Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Wed, 12 Apr 2017 11:12:11 +0900
Subject: [PATCH 2/2] Disallow converting partitioned tables to a view
---
src/backend/rewrite/rewriteDefine.c | 6 ++++++
src/test/regress/sql/rules.sql | 5 +++++
2 files changed, 11 insertions(+)
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index df32f2c3ae..eab3f6062d 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -422,6 +422,12 @@ DefineQueryRewrite(char *rulename,
HeapScanDesc scanDesc;
Snapshot snapshot;
+ if (event_relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("could not convert partitioned table \"%s\" to a view",
+ RelationGetRelationName(event_relation))));
+
snapshot = RegisterSnapshot(GetLatestSnapshot());
scanDesc = heap_beginscan(event_relation, snapshot, 0, NULL);
if (heap_getnext(scanDesc, ForwardScanDirection) != NULL)
diff --git a/src/test/regress/sql/rules.sql b/src/test/regress/sql/rules.sql
index d4a61813e4..4fff266216 100644
--- a/src/test/regress/sql/rules.sql
+++ b/src/test/regress/sql/rules.sql
@@ -898,6 +898,11 @@ select reltoastrelid, relkind, relfrozenxid
drop view fooview;
+-- trying to convert a partitioned table to view is not allowed
+create table fooview (x int, y text) partition by list (x);
+create rule "_RETURN" as on select to fooview do instead
+ select 1 as x, 'aaa'::text as y;
+
--
-- check for planner problems with complex inherited UPDATES
--
--
2.11.0
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-20 16:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-21 09:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 13:49 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-22 13:39 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-23 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-23 14:27 ` Re: Partitioned tables and relfilenode Maksim Milyutin <m.milyutin@postgrespro.ru>
2017-03-23 14:47 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-24 00:54 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-27 14:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-29 06:40 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 07:49 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-29 08:21 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 14:58 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-30 09:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-30 10:37 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-30 11:58 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-31 06:50 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-31 07:17 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-31 08:33 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-31 20:29 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-04-03 02:39 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-04-11 09:16 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-04-11 13:45 ` Re: Partitioned tables and relfilenode Tom Lane <tgl@sss.pgh.pa.us>
2017-04-11 17:41 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-04-12 02:15 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-04-12 15:36 ` Robert Haas <robertmhaas@gmail.com>
2017-04-13 00:35 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
0 siblings, 1 reply; 96+ messages in thread
From: Robert Haas @ 2017-04-12 15:36 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: Tom Lane <tgl@sss.pgh.pa.us>; Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>; Amit Langote <amitlangote09@gmail.com>; Maksim Milyutin <m.milyutin@postgrespro.ru>; pgsql-hackers
On Tue, Apr 11, 2017 at 10:15 PM, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
> Alright. So I made it into two patches instead: 0001 fixes the bug that
> validateCheckConstraint() tries to scan partitioned tables and 0002 makes
> trying to convert a partitioned table to a view a user error.
Committed together, after updating the regression test outputs to make
the tests pass. You forgot to update the expected output file in
0002.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-20 16:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-21 09:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 13:49 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-22 13:39 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-23 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-23 14:27 ` Re: Partitioned tables and relfilenode Maksim Milyutin <m.milyutin@postgrespro.ru>
2017-03-23 14:47 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-24 00:54 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-27 14:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-29 06:40 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 07:49 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-29 08:21 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 14:58 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-30 09:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-30 10:37 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-30 11:58 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-31 06:50 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-31 07:17 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-31 08:33 ` Re: Partitioned tables and relfilenode Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-31 20:29 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-04-03 02:39 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-04-11 09:16 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-04-11 13:45 ` Re: Partitioned tables and relfilenode Tom Lane <tgl@sss.pgh.pa.us>
2017-04-11 17:41 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-04-12 02:15 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-04-12 15:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
@ 2017-04-13 00:35 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
0 siblings, 0 replies; 96+ messages in thread
From: Amit Langote @ 2017-04-13 00:35 UTC (permalink / raw)
To: Robert Haas <robertmhaas@gmail.com>; +Cc: Tom Lane <tgl@sss.pgh.pa.us>; Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>; Amit Langote <amitlangote09@gmail.com>; Maksim Milyutin <m.milyutin@postgrespro.ru>; pgsql-hackers
On 2017/04/13 0:36, Robert Haas wrote:
> On Tue, Apr 11, 2017 at 10:15 PM, Amit Langote
> <Langote_Amit_f8@lab.ntt.co.jp> wrote:
>> Alright. So I made it into two patches instead: 0001 fixes the bug that
>> validateCheckConstraint() tries to scan partitioned tables and 0002 makes
>> trying to convert a partitioned table to a view a user error.
>
> Committed together, after updating the regression test outputs to make
> the tests pass. You forgot to update the expected output file in
> 0002.
Oops, sorry about that. Thanks for fixing and committing.
Regards,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-20 16:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-21 09:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 13:49 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-22 13:39 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-23 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-23 14:27 ` Re: Partitioned tables and relfilenode Maksim Milyutin <m.milyutin@postgrespro.ru>
2017-03-23 14:47 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-24 00:54 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-03-27 15:13 ` Maksim Milyutin <m.milyutin@postgrespro.ru>
2017-03-28 00:59 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
1 sibling, 1 reply; 96+ messages in thread
From: Maksim Milyutin @ 2017-03-27 15:13 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; Amit Langote <amitlangote09@gmail.com>; +Cc: Robert Haas <robertmhaas@gmail.com>; pgsql-hackers
On 24.03.2017 03:54, Amit Langote wrote:
>
> And here is the updated patch.
>
Perhaps you forgot my fix in the updated patch
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 3999e6e..36917c8 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -1823,7 +1823,8 @@ heap_drop_with_catalog(Oid relid)
*/
if (rel->rd_rel->relkind != RELKIND_VIEW &&
rel->rd_rel->relkind != RELKIND_COMPOSITE_TYPE &&
- rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE)
+ rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
+ rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
{
RelationDropStorage(rel);
}
--
Maksim Milyutin
Postgres Professional: http://www.postgrespro.com
Russian Postgres Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-20 16:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-21 09:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 13:49 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-22 13:39 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-23 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-23 14:27 ` Re: Partitioned tables and relfilenode Maksim Milyutin <m.milyutin@postgrespro.ru>
2017-03-23 14:47 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-24 00:54 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-27 15:13 ` Re: Partitioned tables and relfilenode Maksim Milyutin <m.milyutin@postgrespro.ru>
@ 2017-03-28 00:59 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 03:18 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
0 siblings, 1 reply; 96+ messages in thread
From: Amit Langote @ 2017-03-28 00:59 UTC (permalink / raw)
To: Maksim Milyutin <m.milyutin@postgrespro.ru>; Amit Langote <amitlangote09@gmail.com>; +Cc: Robert Haas <robertmhaas@gmail.com>; pgsql-hackers
Hi,
On 2017/03/28 0:13, Maksim Milyutin wrote:
> On 24.03.2017 03:54, Amit Langote wrote:
>>
>> And here is the updated patch.
>>
>
> Perhaps you forgot my fix in the updated patch
>
> diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
> index 3999e6e..36917c8 100644
> --- a/src/backend/catalog/heap.c
> +++ b/src/backend/catalog/heap.c
> @@ -1823,7 +1823,8 @@ heap_drop_with_catalog(Oid relid)
> */
> if (rel->rd_rel->relkind != RELKIND_VIEW &&
> rel->rd_rel->relkind != RELKIND_COMPOSITE_TYPE &&
> - rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE)
> + rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
> + rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
> {
> RelationDropStorage(rel);
> }
Oops, my bad. I will include it in the patch I'll send after addressing
Robert's comments. Thanks again!
Regards,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-20 16:16 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-21 09:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 13:49 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-22 13:39 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-23 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-23 14:27 ` Re: Partitioned tables and relfilenode Maksim Milyutin <m.milyutin@postgrespro.ru>
2017-03-23 14:47 ` Re: Partitioned tables and relfilenode Amit Langote <amitlangote09@gmail.com>
2017-03-24 00:54 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-27 15:13 ` Re: Partitioned tables and relfilenode Maksim Milyutin <m.milyutin@postgrespro.ru>
2017-03-28 00:59 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-03-29 03:18 ` Robert Haas <robertmhaas@gmail.com>
0 siblings, 0 replies; 96+ messages in thread
From: Robert Haas @ 2017-03-29 03:18 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: Maksim Milyutin <m.milyutin@postgrespro.ru>; Amit Langote <amitlangote09@gmail.com>; pgsql-hackers
On Mon, Mar 27, 2017 at 8:59 PM, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
> Oops, my bad. I will include it in the patch I'll send after addressing
> Robert's comments. Thanks again!
That patch coming soon?
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-03-21 16:19 ` Simon Riggs <simon@2ndquadrant.com>
2017-03-21 16:33 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
1 sibling, 1 reply; 96+ messages in thread
From: Simon Riggs @ 2017-03-21 16:19 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: Robert Haas <robertmhaas@gmail.com>; Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; Michael Paquier <michael.paquier@gmail.com>; pgsql-hackers
On 16 March 2017 at 10:03, Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> wrote:
> On 2017/03/15 7:09, Robert Haas wrote:
>> I think that eliding the Append node when there's only one child may
>> be unsafe in the case where the child's attribute numbers are
>> different from the parent's attribute numbers. I remember Tom making
>> some comment about this when I was working on MergeAppend, although I
>> no longer remember the specific details.
>
> Append node elision does not occur in the one-child case. With the patch:
...
> create table q1 partition of q for values in (1);
> explain select * from q;
> QUERY PLAN
> ------------------------------------------------------------
> Append (cost=0.00..35.50 rows=2550 width=4)
> -> Seq Scan on q1 (cost=0.00..35.50 rows=2550 width=4)
> (2 rows)
>
> Maybe that should be done, but this patch doesn't implement that.
Robert raises the possible problem that removing the Append wouldn't
work when the parent and child attribute numbers don't match. Surely
that never happens with partitions, by definition?
--
Simon Riggs http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 16:19 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
@ 2017-03-21 16:33 ` Robert Haas <robertmhaas@gmail.com>
2017-03-21 17:21 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
0 siblings, 1 reply; 96+ messages in thread
From: Robert Haas @ 2017-03-21 16:33 UTC (permalink / raw)
To: Simon Riggs <simon@2ndquadrant.com>; +Cc: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; Michael Paquier <michael.paquier@gmail.com>; pgsql-hackers
On Tue, Mar 21, 2017 at 12:19 PM, Simon Riggs <simon@2ndquadrant.com> wrote:
> On 16 March 2017 at 10:03, Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> wrote:
>> On 2017/03/15 7:09, Robert Haas wrote:
>
>>> I think that eliding the Append node when there's only one child may
>>> be unsafe in the case where the child's attribute numbers are
>>> different from the parent's attribute numbers. I remember Tom making
>>> some comment about this when I was working on MergeAppend, although I
>>> no longer remember the specific details.
>>
>> Append node elision does not occur in the one-child case. With the patch:
> ...
>> create table q1 partition of q for values in (1);
>> explain select * from q;
>> QUERY PLAN
>> ------------------------------------------------------------
>> Append (cost=0.00..35.50 rows=2550 width=4)
>> -> Seq Scan on q1 (cost=0.00..35.50 rows=2550 width=4)
>> (2 rows)
>>
>> Maybe that should be done, but this patch doesn't implement that.
>
> Robert raises the possible problem that removing the Append wouldn't
> work when the parent and child attribute numbers don't match. Surely
> that never happens with partitions, by definition?
No, the attribute numbers don't have to match. This decision was made
a long time ago, and there have been a whole bunch of followup commits
since the original partitioning patch that were dedicated to fixing up
cases where that wasn't working properly in the original commit. It
seems superficially attractive to require the attribute numbers to
match, but it creates some really unpleasant cases. For example,
suppose a user tries to creates a partitioned table, drops a column,
then creates a standalone table which matches the apparent column list
of the partitioned table, then tries to attach it as a partition.
ERROR: the columns you previously dropped from the parent that you
can't see and don't know about aren't the same as the ones dropped
from the standalone table you're trying to attach as a partition
DETAIL: Try recreating your proposed new partition with a
pass-by-value column of width 8 after the third column, and then
dropping that column before trying to attach it as a partition.
HINT: Abandon all hope, ye who enter here.
Not cool with that.
The decision not to require the attribute numbers to match doesn't
necessarily mean we can't get rid of the Append node, though. First
of all, in a lot of practical cases the attribute numbers will all
match. Second, if they don't, the most that would be required is a
projection step, which could usually be done without a separate node
because most nodes are projection-capable. And maybe not even that
much is needed; I'd have to go back and look at what Tom was worried
about the last time this came up. (Hmm, maybe the problem had to do
with varnos matching, rather then attribute numbers?)
Another and independent problem with eliding the Append node is that,
if we did that, we'd still have to guarantee that the parent relation
corresponding to the Append node got locked somehow. Otherwise, we'll
be accessing the tuple routing information for a table on which we
don't have a lock. That's probably a solvable problem, too, but it
hasn't been solved yet.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 16:19 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-03-21 16:33 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
@ 2017-03-21 17:21 ` Simon Riggs <simon@2ndquadrant.com>
2017-03-21 18:15 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
0 siblings, 1 reply; 96+ messages in thread
From: Simon Riggs @ 2017-03-21 17:21 UTC (permalink / raw)
To: Robert Haas <robertmhaas@gmail.com>; +Cc: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; Michael Paquier <michael.paquier@gmail.com>; pgsql-hackers
On 21 March 2017 at 16:33, Robert Haas <robertmhaas@gmail.com> wrote:
> On Tue, Mar 21, 2017 at 12:19 PM, Simon Riggs <simon@2ndquadrant.com> wrote:
>> On 16 March 2017 at 10:03, Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> wrote:
>>> On 2017/03/15 7:09, Robert Haas wrote:
>>
>>>> I think that eliding the Append node when there's only one child may
>>>> be unsafe in the case where the child's attribute numbers are
>>>> different from the parent's attribute numbers. I remember Tom making
>>>> some comment about this when I was working on MergeAppend, although I
>>>> no longer remember the specific details.
>>>
>>> Append node elision does not occur in the one-child case. With the patch:
>> ...
>>> create table q1 partition of q for values in (1);
>>> explain select * from q;
>>> QUERY PLAN
>>> ------------------------------------------------------------
>>> Append (cost=0.00..35.50 rows=2550 width=4)
>>> -> Seq Scan on q1 (cost=0.00..35.50 rows=2550 width=4)
>>> (2 rows)
>>>
>>> Maybe that should be done, but this patch doesn't implement that.
>>
>> Robert raises the possible problem that removing the Append wouldn't
>> work when the parent and child attribute numbers don't match. Surely
>> that never happens with partitions, by definition?
>
> No, the attribute numbers don't have to match. This decision was made
> a long time ago, and there have been a whole bunch of followup commits
> since the original partitioning patch that were dedicated to fixing up
> cases where that wasn't working properly in the original commit. It
> seems superficially attractive to require the attribute numbers to
> match, but it creates some really unpleasant cases. For example,
> suppose a user tries to creates a partitioned table, drops a column,
> then creates a standalone table which matches the apparent column list
> of the partitioned table, then tries to attach it as a partition.
>
> ERROR: the columns you previously dropped from the parent that you
> can't see and don't know about aren't the same as the ones dropped
> from the standalone table you're trying to attach as a partition
> DETAIL: Try recreating your proposed new partition with a
> pass-by-value column of width 8 after the third column, and then
> dropping that column before trying to attach it as a partition.
> HINT: Abandon all hope, ye who enter here.
>
> Not cool with that.
Thanks for the explanation.
> The decision not to require the attribute numbers to match doesn't
> necessarily mean we can't get rid of the Append node, though. First
> of all, in a lot of practical cases the attribute numbers will all
> match. Second, if they don't, the most that would be required is a
> projection step, which could usually be done without a separate node
> because most nodes are projection-capable. And maybe not even that
> much is needed; I'd have to go back and look at what Tom was worried
> about the last time this came up. (Hmm, maybe the problem had to do
> with varnos matching, rather then attribute numbers?)
There used to be some code there to fix them up, not sure where that went.
> Another and independent problem with eliding the Append node is that,
> if we did that, we'd still have to guarantee that the parent relation
> corresponding to the Append node got locked somehow. Otherwise, we'll
> be accessing the tuple routing information for a table on which we
> don't have a lock. That's probably a solvable problem, too, but it
> hasn't been solved yet.
Hmm, why would we need to access tuple routing information?
--
Simon Riggs http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-16 10:03 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 16:19 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-03-21 16:33 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-21 17:21 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
@ 2017-03-21 18:15 ` Robert Haas <robertmhaas@gmail.com>
0 siblings, 0 replies; 96+ messages in thread
From: Robert Haas @ 2017-03-21 18:15 UTC (permalink / raw)
To: Simon Riggs <simon@2ndquadrant.com>; +Cc: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; Michael Paquier <michael.paquier@gmail.com>; pgsql-hackers
On Tue, Mar 21, 2017 at 1:21 PM, Simon Riggs <simon@2ndquadrant.com> wrote:
>> The decision not to require the attribute numbers to match doesn't
>> necessarily mean we can't get rid of the Append node, though. First
>> of all, in a lot of practical cases the attribute numbers will all
>> match. Second, if they don't, the most that would be required is a
>> projection step, which could usually be done without a separate node
>> because most nodes are projection-capable. And maybe not even that
>> much is needed; I'd have to go back and look at what Tom was worried
>> about the last time this came up. (Hmm, maybe the problem had to do
>> with varnos matching, rather then attribute numbers?)
>
> There used to be some code there to fix them up, not sure where that went.
Me neither. To be clear in case I haven't been already, I'm totally
fine with somebody doing the work to get rid of the Append node; I
just think it'll take some investigation and work that hasn't been
done yet.
(I'm also a little skeptical about the value of the work. The Append
node doesn't cost much; what's expensive is that the planner isn't
smart about planning queries that involve Append nodes and so getting
rid of one can improve the whole plan shape. But I think the answer
to that problem is optimizations like partition-wise join and
partition-wise aggregate, which can handle cases where an Append has
any number of surviving children. Eliminating the Append only helps
when the number of surviving children is exactly one. Now, that's not
to say I'm going to fight a patch if somebody writes one, but I think
to some extent it's just a band-aid.)
>> Another and independent problem with eliding the Append node is that,
>> if we did that, we'd still have to guarantee that the parent relation
>> corresponding to the Append node got locked somehow. Otherwise, we'll
>> be accessing the tuple routing information for a table on which we
>> don't have a lock. That's probably a solvable problem, too, but it
>> hasn't been solved yet.
>
> Hmm, why would we need to access tuple routing information?
I didn't state that very well. It's not so much that we need access
to the tuple routing information as that we need to replan if it
changes, because if the tuple routing information changes then we
might need to include partitions that were previously being pruned.
If we haven't got some kind of a lock on the parent, I'm pretty sure
that's not going to work reliably. Synchronization of invalidation
traffic relies on DDL statements holding a lock that conflicts with
the lock held by the process using the table; if there is no such
lock, we might fail to notice that we need to replan.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Re: Partitioned tables and relfilenode Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:20 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-02-28 06:05 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Re: Partitioned tables and relfilenode Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-03-07 16:20 ` Robert Haas <robertmhaas@gmail.com>
1 sibling, 0 replies; 96+ messages in thread
From: Robert Haas @ 2017-03-07 16:20 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>; Simon Riggs <simon@2ndquadrant.com>; pgsql-hackers
On Thu, Mar 2, 2017 at 8:02 PM, Amit Langote
<Langote_Amit_f8@lab.ntt.co.jp> wrote:
> Thanks. I noticed that 'and' is duplicated in a line added by the commit
> to analyze.sgml. Attached 0001 fixes that. 0002 and 0003 same as the
> last version.
Oh, rats. Thanks for noticing. Committed 0001.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
@ 2017-02-19 20:31 ` Simon Riggs <simon@2ndquadrant.com>
2017-02-20 02:28 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
1 sibling, 1 reply; 96+ messages in thread
From: Simon Riggs @ 2017-02-19 20:31 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: pgsql-hackers
On 16 February 2017 at 11:32, Simon Riggs <simon@2ndquadrant.com> wrote:
> On 10 February 2017 at 06:19, Amit Langote
> <Langote_Amit_f8@lab.ntt.co.jp> wrote:
>
>> the "right thing" here being that the
>> command's code either throws an error or warning (in some cases) if the
>> specified table is a partitioned table or ignores any partitioned tables
>> when it reads the list of relations to process from pg_class.
>
> This is a massive assumption and deserves major discussion.
>
> My expectation is that "partitioned tables" are "tables". Anything
> else seems to fly in the face of both the SQL Standard and the POLA
> principle for users coming from other database systems.
>
> IMHO all the main actions should all "just work" not throw errors.
This included DROP TABLE, which I commented on before.
CASCADE should not be required.
--
Simon Riggs http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
2017-02-19 20:31 ` Re: Partitioned tables and relfilenode Simon Riggs <simon@2ndquadrant.com>
@ 2017-02-20 02:28 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
0 siblings, 0 replies; 96+ messages in thread
From: Amit Langote @ 2017-02-20 02:28 UTC (permalink / raw)
To: Simon Riggs <simon@2ndquadrant.com>; +Cc: pgsql-hackers
On 2017/02/20 5:31, Simon Riggs wrote:
> On 16 February 2017 at 11:32, Simon Riggs <simon@2ndquadrant.com> wrote:
>> On 10 February 2017 at 06:19, Amit Langote
>> <Langote_Amit_f8@lab.ntt.co.jp> wrote:
>>
>>> the "right thing" here being that the
>>> command's code either throws an error or warning (in some cases) if the
>>> specified table is a partitioned table or ignores any partitioned tables
>>> when it reads the list of relations to process from pg_class.
>>
>> This is a massive assumption and deserves major discussion.
>>
>> My expectation is that "partitioned tables" are "tables". Anything
>> else seems to fly in the face of both the SQL Standard and the POLA
>> principle for users coming from other database systems.
>>
>> IMHO all the main actions should all "just work" not throw errors.
>
> This included DROP TABLE, which I commented on before.
>
> CASCADE should not be required.
Yeah, it seemed like that is the consensus so I posted a patch [0], which
re-posted in a new thread titled "dropping partitioned tables without
CASCADE" [1].
Thanks,
Amit
[0] https://postgr.es/m/ca132b99-0d18-439a-fe65-024085449259%40lab.ntt.co.jp
[1] https://postgr.es/m/6c420206-45d7-3f56-8325-4bd7b76483ba%40lab.ntt.co.jp
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-02-27 18:54 ` Bruce Momjian <bruce@momjian.us>
2017-02-28 02:53 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
3 siblings, 1 reply; 96+ messages in thread
From: Bruce Momjian @ 2017-02-27 18:54 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: pgsql-hackers
On Fri, Feb 10, 2017 at 03:19:47PM +0900, Amit Langote wrote:
> The new partitioned tables do not contain any data by themselves. Any
> data inserted into a partitioned table is routed to and stored in one of
> its partitions. In fact, it is impossible to insert *any* data before a
> partition (to be precise, a leaf partition) is created. It seems wasteful
> then to allocate physical storage (files) for partitioned tables. If we
> do not allocate the storage, then we must make sure that the right thing
> happens when a command that is intended to manipulate a table's storage
> encounters a partitioned table, the "right thing" here being that the
> command's code either throws an error or warning (in some cases) if the
> specified table is a partitioned table or ignores any partitioned tables
> when it reads the list of relations to process from pg_class. Commands
> that need to be taught about this are vacuum, analyze, truncate, and alter
> table. Specifically:
>
> - In case of vacuum, specifying a partitioned table causes a warning
>
> - In case of analyze, we do not throw an error or warning but simply
> avoid calling do_analyze_rel() *non-recursively*. Further in
> acquire_inherited_sample_rows(), any partitioned tables in the list
> returned by find_all_inheritors() are skipped.
>
> - In case of truncate, only the part which manipulates table's physical
> storage is skipped for partitioned tables.
>
> - ATRewriteTables() skips on the AlteredTableInfo entries for partitioned
> tables, because there is nothing to be done.
>
> - Since we cannot create indexes on partitioned tables anyway, there is
> no need to handle cluster and reindex (they throw a meaningful error
> already due to the lack of indexes.)
I don't think we are doing this, but if the parent table doesn't have a
physical file pg_upgrade will need to be taught that. We have that case
now for unlogged tables on standby servers that we need to address.
--
Bruce Momjian <bruce@momjian.us> http://momjian.us
EnterpriseDB http://enterprisedb.com
+ As you are, so once was I. As I am, so you will be. +
+ Ancient Roman grave inscription +
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-27 18:54 ` Re: Partitioned tables and relfilenode Bruce Momjian <bruce@momjian.us>
@ 2017-02-28 02:53 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:23 ` Re: Partitioned tables and relfilenode Bruce Momjian <bruce@momjian.us>
0 siblings, 1 reply; 96+ messages in thread
From: Amit Langote @ 2017-02-28 02:53 UTC (permalink / raw)
To: Bruce Momjian <bruce@momjian.us>; +Cc: pgsql-hackers
On 2017/02/28 3:54, Bruce Momjian wrote:
> On Fri, Feb 10, 2017 at 03:19:47PM +0900, Amit Langote wrote:
>> The new partitioned tables do not contain any data by themselves. Any
>> data inserted into a partitioned table is routed to and stored in one of
>> its partitions. In fact, it is impossible to insert *any* data before a
>> partition (to be precise, a leaf partition) is created. It seems wasteful
>> then to allocate physical storage (files) for partitioned tables. If we
>> do not allocate the storage, then we must make sure that the right thing
>> happens when a command that is intended to manipulate a table's storage
>> encounters a partitioned table, the "right thing" here being that the
>> command's code either throws an error or warning (in some cases) if the
>> specified table is a partitioned table or ignores any partitioned tables
>> when it reads the list of relations to process from pg_class. Commands
>> that need to be taught about this are vacuum, analyze, truncate, and alter
>> table. Specifically:
>>
>> - In case of vacuum, specifying a partitioned table causes a warning
>>
>> - In case of analyze, we do not throw an error or warning but simply
>> avoid calling do_analyze_rel() *non-recursively*. Further in
>> acquire_inherited_sample_rows(), any partitioned tables in the list
>> returned by find_all_inheritors() are skipped.
>>
>> - In case of truncate, only the part which manipulates table's physical
>> storage is skipped for partitioned tables.
>>
>> - ATRewriteTables() skips on the AlteredTableInfo entries for partitioned
>> tables, because there is nothing to be done.
>>
>> - Since we cannot create indexes on partitioned tables anyway, there is
>> no need to handle cluster and reindex (they throw a meaningful error
>> already due to the lack of indexes.)
>
> I don't think we are doing this, but if the parent table doesn't have a
> physical file pg_upgrade will need to be taught that. We have that case
> now for unlogged tables on standby servers that we need to address.
Partitioned tables do have physical files as of now. This thread is to
discuss the proposal to get rid of the physical file for partitioned tables.
By the way, I just tried pg_upgrade on top of this patch, and it seems
partitioned tables without the physical file migrate just fine to the new
cluster. To test I did: created a partitioned table and few partitions,
inserted some data into it, pg_upgraded the cluster to find the
partitioned table intact with its data in the new cluster (to be clear,
the data is contained in partitions). Is there something that wouldn't
work that I should instead be testing?
Also, it seems that the partitioned tables (without physical files) won't
have the same issue on the standby servers as unlogged tables. It's just
that we route inserts into a partitioned table to its partitions and hence
the partitioned table itself does not contain because all the incoming
data is routed. Am I missing something?
Thanks,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-27 18:54 ` Re: Partitioned tables and relfilenode Bruce Momjian <bruce@momjian.us>
2017-02-28 02:53 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
@ 2017-02-28 03:23 ` Bruce Momjian <bruce@momjian.us>
2017-02-28 03:29 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
0 siblings, 1 reply; 96+ messages in thread
From: Bruce Momjian @ 2017-02-28 03:23 UTC (permalink / raw)
To: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; +Cc: pgsql-hackers
On Tue, Feb 28, 2017 at 11:53:16AM +0900, Amit Langote wrote:
> > I don't think we are doing this, but if the parent table doesn't have a
> > physical file pg_upgrade will need to be taught that. We have that case
> > now for unlogged tables on standby servers that we need to address.
>
> Partitioned tables do have physical files as of now. This thread is to
> discuss the proposal to get rid of the physical file for partitioned tables.
>
> By the way, I just tried pg_upgrade on top of this patch, and it seems
> partitioned tables without the physical file migrate just fine to the new
> cluster. To test I did: created a partitioned table and few partitions,
> inserted some data into it, pg_upgraded the cluster to find the
> partitioned table intact with its data in the new cluster (to be clear,
> the data is contained in partitions). Is there something that wouldn't
> work that I should instead be testing?
>
> Also, it seems that the partitioned tables (without physical files) won't
> have the same issue on the standby servers as unlogged tables. It's just
> that we route inserts into a partitioned table to its partitions and hence
> the partitioned table itself does not contain because all the incoming
> data is routed. Am I missing something?
I see why it works now. pg_upgrade only upgrades relations and
materialized views:
" WHERE relkind IN ('r', 'm') AND "
but partitions are defined as 'P':
#define RELKIND_PARTITIONED_TABLE 'P' /* partitioned table */
I am a little confused by the above. Is a partitioned table the parent
or the children? Reading the code it seems it is the parent, which
explains why it works. Can I clarify that?
--
Bruce Momjian <bruce@momjian.us> http://momjian.us
EnterpriseDB http://enterprisedb.com
+ As you are, so once was I. As I am, so you will be. +
+ Ancient Roman grave inscription +
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-27 18:54 ` Re: Partitioned tables and relfilenode Bruce Momjian <bruce@momjian.us>
2017-02-28 02:53 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:23 ` Re: Partitioned tables and relfilenode Bruce Momjian <bruce@momjian.us>
@ 2017-02-28 03:29 ` Michael Paquier <michael.paquier@gmail.com>
2017-02-28 04:08 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
0 siblings, 1 reply; 96+ messages in thread
From: Michael Paquier @ 2017-02-28 03:29 UTC (permalink / raw)
To: Bruce Momjian <bruce@momjian.us>; +Cc: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>; pgsql-hackers
On Tue, Feb 28, 2017 at 12:23 PM, Bruce Momjian <bruce@momjian.us> wrote:
> I am a little confused by the above. Is a partitioned table the parent
> or the children? Reading the code it seems it is the parent, which
> explains why it works. Can I clarify that?
As I understand things, a partitioned table is a parent relation that
exists only to link to its child portions, holding as well the
definitions linking to each partition.
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
* Re: Partitioned tables and relfilenode
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-27 18:54 ` Re: Partitioned tables and relfilenode Bruce Momjian <bruce@momjian.us>
2017-02-28 02:53 ` Re: Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:23 ` Re: Partitioned tables and relfilenode Bruce Momjian <bruce@momjian.us>
2017-02-28 03:29 ` Re: Partitioned tables and relfilenode Michael Paquier <michael.paquier@gmail.com>
@ 2017-02-28 04:08 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
0 siblings, 0 replies; 96+ messages in thread
From: Amit Langote @ 2017-02-28 04:08 UTC (permalink / raw)
To: Michael Paquier <michael.paquier@gmail.com>; Bruce Momjian <bruce@momjian.us>; +Cc: pgsql-hackers
On 2017/02/28 12:29, Michael Paquier wrote:
> On Tue, Feb 28, 2017 at 12:23 PM, Bruce Momjian <bruce@momjian.us> wrote:
>> I am a little confused by the above. Is a partitioned table the parent
>> or the children? Reading the code it seems it is the parent, which
>> explains why it works. Can I clarify that?
>
> As I understand things, a partitioned table is a parent relation that
> exists only to link to its child portions, holding as well the
> definitions linking to each partition.
Yes. As I mentioned in my previous email, data inserted into the
partitioned table is routed to its partitions. A partition may be itself
a partitioned table, so the routing continues until we find a leaf
partition. All the partitioned tables in this chain leading to the leaf
partition are RELKIND_PARTITIONED_TABLE ('P') relations and only the leaf
tables are RELKIND_RELATION tables.
Thanks,
Amit
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
^ permalink raw reply [nested|flat] 96+ messages in thread
end of thread, other threads:[~2017-04-13 00:35 UTC | newest]
Thread overview: 96+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2017-02-10 06:19 Partitioned tables and relfilenode Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-10 06:58 ` Simon Riggs <simon@2ndquadrant.com>
2017-02-10 07:15 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-15 07:14 ` Michael Paquier <michael.paquier@gmail.com>
2017-02-15 16:14 ` Robert Haas <robertmhaas@gmail.com>
2017-02-17 02:34 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-16 11:32 ` Simon Riggs <simon@2ndquadrant.com>
2017-02-16 14:40 ` Robert Haas <robertmhaas@gmail.com>
2017-02-17 07:42 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-19 09:53 ` Robert Haas <robertmhaas@gmail.com>
2017-02-20 10:30 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-21 13:21 ` Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-22 08:20 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-22 12:58 ` Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 05:49 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-23 06:44 ` Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 07:38 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-23 07:48 ` Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-23 08:08 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-23 08:49 ` Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-28 03:20 ` Robert Haas <robertmhaas@gmail.com>
2017-02-28 04:52 ` Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-02-28 05:03 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 06:05 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 09:36 ` Robert Haas <robertmhaas@gmail.com>
2017-03-02 10:22 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-02 12:48 ` Robert Haas <robertmhaas@gmail.com>
2017-03-03 01:02 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 06:41 ` Michael Paquier <michael.paquier@gmail.com>
2017-03-06 07:18 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 07:49 ` Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-06 07:56 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 08:01 ` Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-06 08:23 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-06 08:29 ` Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-06 08:22 ` Michael Paquier <michael.paquier@gmail.com>
2017-03-07 01:56 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-07 05:11 ` Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-07 17:27 ` Robert Haas <robertmhaas@gmail.com>
2017-03-08 10:36 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-08 13:36 ` Robert Haas <robertmhaas@gmail.com>
2017-03-10 08:57 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:24 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-13 10:30 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 08:18 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-14 22:09 ` Robert Haas <robertmhaas@gmail.com>
2017-03-15 04:38 ` Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-15 06:32 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 07:47 ` Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-03-16 10:03 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-16 13:16 ` Robert Haas <robertmhaas@gmail.com>
2017-03-17 08:57 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-20 16:16 ` Robert Haas <robertmhaas@gmail.com>
2017-03-21 09:05 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-21 13:49 ` Robert Haas <robertmhaas@gmail.com>
2017-03-22 13:39 ` Robert Haas <robertmhaas@gmail.com>
2017-03-23 01:02 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-23 14:27 ` Maksim Milyutin <m.milyutin@postgrespro.ru>
2017-03-23 14:47 ` Amit Langote <amitlangote09@gmail.com>
2017-03-24 00:54 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-27 14:27 ` Robert Haas <robertmhaas@gmail.com>
2017-03-29 06:40 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 07:49 ` Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-29 08:21 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 08:40 ` Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-29 14:58 ` Robert Haas <robertmhaas@gmail.com>
2017-03-30 09:24 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-30 10:37 ` Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-30 11:58 ` Amit Langote <amitlangote09@gmail.com>
2017-03-31 06:50 ` Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-31 07:17 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-31 08:33 ` Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>
2017-03-31 20:29 ` Robert Haas <robertmhaas@gmail.com>
2017-04-03 02:39 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-04-11 09:16 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-04-11 12:59 ` Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
2017-04-11 13:45 ` Tom Lane <tgl@sss.pgh.pa.us>
2017-04-11 17:41 ` Robert Haas <robertmhaas@gmail.com>
2017-04-12 02:15 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-04-12 15:36 ` Robert Haas <robertmhaas@gmail.com>
2017-04-13 00:35 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-27 15:13 ` Maksim Milyutin <m.milyutin@postgrespro.ru>
2017-03-28 00:59 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-03-29 03:18 ` Robert Haas <robertmhaas@gmail.com>
2017-03-21 16:19 ` Simon Riggs <simon@2ndquadrant.com>
2017-03-21 16:33 ` Robert Haas <robertmhaas@gmail.com>
2017-03-21 17:21 ` Simon Riggs <simon@2ndquadrant.com>
2017-03-21 18:15 ` Robert Haas <robertmhaas@gmail.com>
2017-03-07 16:20 ` Robert Haas <robertmhaas@gmail.com>
2017-02-19 20:31 ` Simon Riggs <simon@2ndquadrant.com>
2017-02-20 02:28 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-27 18:54 ` Bruce Momjian <bruce@momjian.us>
2017-02-28 02:53 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
2017-02-28 03:23 ` Bruce Momjian <bruce@momjian.us>
2017-02-28 03:29 ` Michael Paquier <michael.paquier@gmail.com>
2017-02-28 04:08 ` Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox