#include "optimizer/tlist.h"
#include "parser/parse_coerce.h"
#include "parser/parsetree.h"
+#include "partitioning/partdir.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/selfuncs.h"
static void expand_partitioned_rtentry(PlannerInfo *root,
RangeTblEntry *parentrte,
Index parentRTindex, Relation parentrel,
- PlanRowMark *top_parentrc, LOCKMODE lockmode,
- List **appinfos);
+ PlanRowMark *top_parentrc, List **appinfos);
static void expand_single_inheritance_child(PlannerInfo *root,
RangeTblEntry *parentrte,
Index parentRTindex, Relation parentrel,
Oid parentOID;
PlanRowMark *oldrc;
Relation oldrelation;
- LOCKMODE lockmode;
List *inhOIDs;
ListCell *l;
}
/*
- * The rewriter should already have obtained an appropriate lock on each
- * relation named in the query. However, for each child relation we add
- * to the query, we must obtain an appropriate lock, because this will be
- * the first use of those relations in the parse/rewrite/plan pipeline.
- * Child rels should use the same lockmode as their parent.
- */
- lockmode = rte->rellockmode;
-
- /* Scan for all members of inheritance set, acquire needed locks */
- inhOIDs = find_all_inheritors(parentOID, lockmode, NULL);
-
- /*
- * 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.
- */
- if (list_length(inhOIDs) < 2)
- {
- /* Clear flag before returning */
- rte->inh = false;
- return;
- }
-
- /*
- * If parent relation is selected FOR UPDATE/SHARE, we need to mark its
- * PlanRowMark as isParent = true, and generate a new PlanRowMark for each
- * child.
+ * If parent relation is selected FOR UPDATE/SHARE, we will need to mark
+ * its PlanRowMark as isParent = true, and generate a new PlanRowMark for
+ * each child. expand_single_inheritance_child() will handle this, but we
+ * need to pass down the rowmark for the original parent to make it
+ * possible.
*/
oldrc = get_plan_rowmark(root->rowMarks, rti);
- if (oldrc)
- oldrc->isParent = true;
/*
* Must open the parent relation to examine its tupdesc. We need not lock
{
Assert(rte->relkind == RELKIND_PARTITIONED_TABLE);
+ if (root->partition_directory == NULL)
+ root->partition_directory = CreatePartitionDirectory(CurrentMemoryContext);
+
/*
* If this table has partitions, recursively expand them in the order
* in which they appear in the PartitionDesc. While at it, also
* extract the partition key columns of all the partitioned tables.
*/
expand_partitioned_rtentry(root, rte, rti, oldrelation, oldrc,
- lockmode, &root->append_rel_list);
+ &root->append_rel_list);
}
else
{
RangeTblEntry *childrte;
Index childRTindex;
+ /* Scan for all members of inheritance set, acquire needed locks */
+ inhOIDs = find_all_inheritors(parentOID, rte->rellockmode, NULL);
+
/*
- * This table has no partitions. Expand any plain inheritance
- * children in the order the OIDs were returned by
+ * This is not a partitioned table, but it has plain inheritance
+ * children. Expand them in the order that the OIDs were returned by
* find_all_inheritors.
*/
foreach(l, inhOIDs)
*/
if (childOID != parentOID && RELATION_IS_OTHER_TEMP(newrelation))
{
- heap_close(newrelation, lockmode);
+ heap_close(newrelation, rte->rellockmode);
continue;
}
}
/*
- * If all the children were temp tables, 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 all the children were temp tables, or there were none, 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)
rte->inh = false;
static void
expand_partitioned_rtentry(PlannerInfo *root, RangeTblEntry *parentrte,
Index parentRTindex, Relation parentrel,
- PlanRowMark *top_parentrc, LOCKMODE lockmode,
- List **appinfos)
+ PlanRowMark *top_parentrc, List **appinfos)
{
int i;
RangeTblEntry *childrte;
Index childRTindex;
- PartitionDesc partdesc = RelationGetPartitionDesc(parentrel);
+ PartitionDesc partdesc;
check_stack_depth();
+ partdesc = PartitionDirectoryLookup(root->partition_directory, parentrel);
+
/* A partitioned table should always have a partition descriptor. */
Assert(partdesc);
Oid childOID = partdesc->oids[i];
Relation childrel;
- /* Open rel; we already have required locks */
- childrel = heap_open(childOID, NoLock);
+ /* Open and lock child rel */
+ childrel = heap_open(childOID, parentrte->rellockmode);
/*
* Temporary partitions belonging to other sessions should have been
/* If this child is itself partitioned, recurse */
if (childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
expand_partitioned_rtentry(root, childrte, childRTindex,
- childrel, top_parentrc, lockmode,
- appinfos);
+ childrel, top_parentrc, appinfos);
/* Close child relation, but keep locks */
heap_close(childrel, NoLock);
/* Include child's rowmark type in top parent's allMarkTypes */
top_parentrc->allMarkTypes |= childrc->allMarkTypes;
+ /*
+ * If we create at least one child rowmark, isParent should be set
+ * on the original rowmark. That's very cheap, so just do it here
+ * unconditionally without worrying about whether it has been done
+ * previously.
+ */
+ top_parentrc->isParent = true;
+
root->rowMarks = lappend(root->rowMarks, childrc);
}
}