mirror of https://github.com/citusdata/citus.git
Add infrastructure for filtering restriction contexts based on the input query
In subquery pushdown, we first ensure that each relation is joined with at least on another relation on the partition keys. That's fine given that the decision is binary: pushdown the query at all or not. With recursive planning, we'd want to check whether any specific part of the query can be pushded down or not. Thus, we need the ability to understand which part(s) of the subquery is safe to pushdown. This commit adds the infrastructure for doing that.pull/1833/head
parent
26d9b58e9e
commit
05fb0dd020
|
@ -85,6 +85,17 @@ static DeferredErrorMessage * DeferErrorIfUnsupportedSubqueryPushdown(Query *
|
||||||
PlannerRestrictionContext
|
PlannerRestrictionContext
|
||||||
*
|
*
|
||||||
plannerRestrictionContext);
|
plannerRestrictionContext);
|
||||||
|
static RelationRestrictionContext * FilterRelationRestrictionContext(
|
||||||
|
RelationRestrictionContext *relationRestrictionContext,
|
||||||
|
Relids
|
||||||
|
queryRteIdentities);
|
||||||
|
static JoinRestrictionContext * FilterJoinRestrictionContext(
|
||||||
|
JoinRestrictionContext *joinRestrictionContext, Relids
|
||||||
|
queryRteIdentities);
|
||||||
|
static bool RangeTableArrayContainsAnyRTEIdentities(RangeTblEntry **rangeTableEntries, int
|
||||||
|
rangeTableArrayLength, Relids
|
||||||
|
queryRteIdentities);
|
||||||
|
static Relids QueryRteIdentities(Query *queryTree);
|
||||||
static DeferredErrorMessage * DeferErrorIfUnsupportedSublinkAndReferenceTable(
|
static DeferredErrorMessage * DeferErrorIfUnsupportedSublinkAndReferenceTable(
|
||||||
Query *queryTree);
|
Query *queryTree);
|
||||||
static DeferredErrorMessage * DeferErrorIfUnsupportedFilters(Query *subquery);
|
static DeferredErrorMessage * DeferErrorIfUnsupportedFilters(Query *subquery);
|
||||||
|
@ -704,6 +715,210 @@ DeferErrorIfUnsupportedSubqueryPushdown(Query *originalQuery,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FilterPlannerRestrictionForQuery gets a planner restriction context and
|
||||||
|
* set of rte identities. It returns the restrictions that that appear
|
||||||
|
* in the queryRteIdentities and returns a newly allocated
|
||||||
|
* PlannerRestrictionContext. The function also sets all the other fields of
|
||||||
|
* the PlannerRestrictionContext with respect to the filtered restrictions.
|
||||||
|
*/
|
||||||
|
PlannerRestrictionContext *
|
||||||
|
FilterPlannerRestrictionForQuery(PlannerRestrictionContext *plannerRestrictionContext,
|
||||||
|
Query *query)
|
||||||
|
{
|
||||||
|
PlannerRestrictionContext *filteredPlannerRestrictionContext = NULL;
|
||||||
|
int referenceRelationCount = 0;
|
||||||
|
int totalRelationCount = 0;
|
||||||
|
|
||||||
|
Relids queryRteIdentities = QueryRteIdentities(query);
|
||||||
|
|
||||||
|
RelationRestrictionContext *relationRestrictionContext =
|
||||||
|
plannerRestrictionContext->relationRestrictionContext;
|
||||||
|
JoinRestrictionContext *joinRestrictionContext =
|
||||||
|
plannerRestrictionContext->joinRestrictionContext;
|
||||||
|
|
||||||
|
RelationRestrictionContext *filteredRelationRestrictionContext =
|
||||||
|
FilterRelationRestrictionContext(relationRestrictionContext, queryRteIdentities);
|
||||||
|
|
||||||
|
JoinRestrictionContext *filtererdJoinRestrictionContext =
|
||||||
|
FilterJoinRestrictionContext(joinRestrictionContext, queryRteIdentities);
|
||||||
|
|
||||||
|
/* allocate the filtered planner restriction context and set all the fields */
|
||||||
|
filteredPlannerRestrictionContext = palloc0(sizeof(PlannerRestrictionContext));
|
||||||
|
|
||||||
|
filteredPlannerRestrictionContext->memoryContext =
|
||||||
|
plannerRestrictionContext->memoryContext;
|
||||||
|
|
||||||
|
totalRelationCount = list_length(
|
||||||
|
filteredRelationRestrictionContext->relationRestrictionList);
|
||||||
|
referenceRelationCount = ReferenceRelationCount(filteredRelationRestrictionContext);
|
||||||
|
|
||||||
|
filteredRelationRestrictionContext->allReferenceTables =
|
||||||
|
(totalRelationCount == referenceRelationCount);
|
||||||
|
|
||||||
|
/* we currently don't support local relations and we cannot come up to this point */
|
||||||
|
filteredRelationRestrictionContext->hasLocalRelation = false;
|
||||||
|
filteredRelationRestrictionContext->hasDistributedRelation = true;
|
||||||
|
|
||||||
|
/* finally set the relation and join restriction contexts */
|
||||||
|
filteredPlannerRestrictionContext->relationRestrictionContext =
|
||||||
|
filteredRelationRestrictionContext;
|
||||||
|
filteredPlannerRestrictionContext->joinRestrictionContext =
|
||||||
|
filtererdJoinRestrictionContext;
|
||||||
|
|
||||||
|
return filteredPlannerRestrictionContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FilterRelationRestrictionContext gets a relation restriction context and
|
||||||
|
* set of rte identities. It returns the relation restrictions that that appear
|
||||||
|
* in the queryRteIdentities and returns a newly allocated
|
||||||
|
* RelationRestrictionContext.
|
||||||
|
*/
|
||||||
|
static RelationRestrictionContext *
|
||||||
|
FilterRelationRestrictionContext(RelationRestrictionContext *relationRestrictionContext,
|
||||||
|
Relids queryRteIdentities)
|
||||||
|
{
|
||||||
|
RelationRestrictionContext *filteredRestrictionContext =
|
||||||
|
palloc0(sizeof(RelationRestrictionContext));
|
||||||
|
|
||||||
|
ListCell *relationRestrictionCell = NULL;
|
||||||
|
|
||||||
|
foreach(relationRestrictionCell, relationRestrictionContext->relationRestrictionList)
|
||||||
|
{
|
||||||
|
RelationRestriction *relationRestriction =
|
||||||
|
(RelationRestriction *) lfirst(relationRestrictionCell);
|
||||||
|
|
||||||
|
int rteIdentity = GetRTEIdentity(relationRestriction->rte);
|
||||||
|
|
||||||
|
if (bms_is_member(rteIdentity, queryRteIdentities))
|
||||||
|
{
|
||||||
|
filteredRestrictionContext->relationRestrictionList =
|
||||||
|
lappend(filteredRestrictionContext->relationRestrictionList,
|
||||||
|
relationRestriction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filteredRestrictionContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FilterJoinRestrictionContext gets a join restriction context and
|
||||||
|
* set of rte identities. It returns the join restrictions that that appear
|
||||||
|
* in the queryRteIdentities and returns a newly allocated
|
||||||
|
* JoinRestrictionContext.
|
||||||
|
*
|
||||||
|
* Note that the join restriction is added to the return context as soon as
|
||||||
|
* any range table entry that appear in the join belongs to queryRteIdentities.
|
||||||
|
*/
|
||||||
|
static JoinRestrictionContext *
|
||||||
|
FilterJoinRestrictionContext(JoinRestrictionContext *joinRestrictionContext, Relids
|
||||||
|
queryRteIdentities)
|
||||||
|
{
|
||||||
|
JoinRestrictionContext *filtererdJoinRestrictionContext =
|
||||||
|
palloc0(sizeof(JoinRestrictionContext));
|
||||||
|
|
||||||
|
ListCell *joinRestrictionCell = NULL;
|
||||||
|
|
||||||
|
foreach(joinRestrictionCell, joinRestrictionContext->joinRestrictionList)
|
||||||
|
{
|
||||||
|
JoinRestriction *joinRestriction =
|
||||||
|
(JoinRestriction *) lfirst(joinRestrictionCell);
|
||||||
|
RangeTblEntry **rangeTableEntries =
|
||||||
|
joinRestriction->plannerInfo->simple_rte_array;
|
||||||
|
int rangeTableArrayLength = joinRestriction->plannerInfo->simple_rel_array_size;
|
||||||
|
|
||||||
|
if (RangeTableArrayContainsAnyRTEIdentities(rangeTableEntries,
|
||||||
|
rangeTableArrayLength,
|
||||||
|
queryRteIdentities))
|
||||||
|
{
|
||||||
|
filtererdJoinRestrictionContext->joinRestrictionList = lappend(
|
||||||
|
filtererdJoinRestrictionContext->joinRestrictionList,
|
||||||
|
joinRestriction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filtererdJoinRestrictionContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RangeTableArrayContainsAnyRTEIdentities returns true if any of the range table entries
|
||||||
|
* int rangeTableEntries array is an range table relation specified in queryRteIdentities.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
RangeTableArrayContainsAnyRTEIdentities(RangeTblEntry **rangeTableEntries, int
|
||||||
|
rangeTableArrayLength, Relids queryRteIdentities)
|
||||||
|
{
|
||||||
|
int rteIndex = 0;
|
||||||
|
|
||||||
|
/* simple_rte_array starts from 1, see plannerInfo struct */
|
||||||
|
for (rteIndex = 1; rteIndex < rangeTableArrayLength; ++rteIndex)
|
||||||
|
{
|
||||||
|
RangeTblEntry *rangeTableEntry = rangeTableEntries[rteIndex];
|
||||||
|
List *rangeTableRelationList = NULL;
|
||||||
|
ListCell *rteRelationCell = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get list of all RTE_RELATIONs in the given range table entry
|
||||||
|
* (i.e.,rangeTableEntry could be a subquery where we're interested
|
||||||
|
* in relations).
|
||||||
|
*/
|
||||||
|
ExtractRangeTableRelationWalker((Node *) rangeTableEntry,
|
||||||
|
&rangeTableRelationList);
|
||||||
|
|
||||||
|
foreach(rteRelationCell, rangeTableRelationList)
|
||||||
|
{
|
||||||
|
RangeTblEntry *rteRelation = (RangeTblEntry *) lfirst(rteRelationCell);
|
||||||
|
int rteIdentity = 0;
|
||||||
|
|
||||||
|
Assert(rteRelation->rtekind == RTE_RELATION);
|
||||||
|
|
||||||
|
rteIdentity = GetRTEIdentity(rteRelation);
|
||||||
|
if (bms_is_member(rteIdentity, queryRteIdentities))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* QueryRteIdentities gets a queryTree, find get all the rte identities assigned by
|
||||||
|
* us.
|
||||||
|
*/
|
||||||
|
static Relids
|
||||||
|
QueryRteIdentities(Query *queryTree)
|
||||||
|
{
|
||||||
|
List *rangeTableList = NULL;
|
||||||
|
ListCell *rangeTableCell = NULL;
|
||||||
|
Relids queryRteIdentities = NULL;
|
||||||
|
|
||||||
|
/* extract range table entries for simple relations only */
|
||||||
|
ExtractRangeTableRelationWalker((Node *) queryTree, &rangeTableList);
|
||||||
|
|
||||||
|
foreach(rangeTableCell, rangeTableList)
|
||||||
|
{
|
||||||
|
RangeTblEntry *rangeTableEntry = (RangeTblEntry *) lfirst(rangeTableCell);
|
||||||
|
int rteIdentity = 0;
|
||||||
|
|
||||||
|
/* we're only interested in relations */
|
||||||
|
Assert(rangeTableEntry->rtekind == RTE_RELATION);
|
||||||
|
|
||||||
|
rteIdentity = GetRTEIdentity(rangeTableEntry);
|
||||||
|
|
||||||
|
queryRteIdentities = bms_add_member(queryRteIdentities, rteIdentity);
|
||||||
|
}
|
||||||
|
|
||||||
|
return queryRteIdentities;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DeferErrorIfUnsupportedSublinkAndReferenceTable returns a deferred error if the
|
* DeferErrorIfUnsupportedSublinkAndReferenceTable returns a deferred error if the
|
||||||
* given query is not suitable for subquery pushdown.
|
* given query is not suitable for subquery pushdown.
|
||||||
|
@ -3453,7 +3668,8 @@ ExtractRangeTableEntryWalker(Node *node, List **rangeTableList)
|
||||||
}
|
}
|
||||||
else if (IsA(node, Query))
|
else if (IsA(node, Query))
|
||||||
{
|
{
|
||||||
walkIsComplete = query_tree_walker((Query *) node, ExtractRangeTableEntryWalker,
|
walkIsComplete = query_tree_walker((Query *) node,
|
||||||
|
ExtractRangeTableEntryWalker,
|
||||||
rangeTableList, QTW_EXAMINE_RTES);
|
rangeTableList, QTW_EXAMINE_RTES);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -62,7 +62,6 @@ typedef struct AttributeEquivalenceClassMember
|
||||||
} AttributeEquivalenceClassMember;
|
} AttributeEquivalenceClassMember;
|
||||||
|
|
||||||
|
|
||||||
static uint32 ReferenceRelationCount(RelationRestrictionContext *restrictionContext);
|
|
||||||
static Var * FindTranslatedVar(List *appendRelList, Oid relationOid,
|
static Var * FindTranslatedVar(List *appendRelList, Oid relationOid,
|
||||||
Index relationRteIndex, Index *partitionKeyIndex);
|
Index relationRteIndex, Index *partitionKeyIndex);
|
||||||
static bool EquivalenceListContainsRelationsEquality(List *attributeEquivalenceList,
|
static bool EquivalenceListContainsRelationsEquality(List *attributeEquivalenceList,
|
||||||
|
@ -408,7 +407,7 @@ RestrictionEquivalenceForPartitionKeys(PlannerRestrictionContext *
|
||||||
* ReferenceRelationCount iterates over the relations and returns the reference table
|
* ReferenceRelationCount iterates over the relations and returns the reference table
|
||||||
* relation count.
|
* relation count.
|
||||||
*/
|
*/
|
||||||
static uint32
|
uint32
|
||||||
ReferenceRelationCount(RelationRestrictionContext *restrictionContext)
|
ReferenceRelationCount(RelationRestrictionContext *restrictionContext)
|
||||||
{
|
{
|
||||||
ListCell *relationRestrictionCell = NULL;
|
ListCell *relationRestrictionCell = NULL;
|
||||||
|
|
|
@ -187,6 +187,9 @@ extern MultiTreeRoot * MultiLogicalPlanCreate(Query *originalQuery, Query *query
|
||||||
PlannerRestrictionContext *
|
PlannerRestrictionContext *
|
||||||
plannerRestrictionContext,
|
plannerRestrictionContext,
|
||||||
ParamListInfo boundParams);
|
ParamListInfo boundParams);
|
||||||
|
extern PlannerRestrictionContext * FilterPlannerRestrictionForQuery(
|
||||||
|
PlannerRestrictionContext *plannerRestrictionContext,
|
||||||
|
Query *query);
|
||||||
extern bool SafeToPushdownWindowFunction(Query *query, StringInfo *errorDetail);
|
extern bool SafeToPushdownWindowFunction(Query *query, StringInfo *errorDetail);
|
||||||
extern bool TargetListOnPartitionColumn(Query *query, List *targetEntryList);
|
extern bool TargetListOnPartitionColumn(Query *query, List *targetEntryList);
|
||||||
extern bool NeedsDistributedPlanning(Query *queryTree);
|
extern bool NeedsDistributedPlanning(Query *queryTree);
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
extern bool ContainsUnionSubquery(Query *queryTree);
|
extern bool ContainsUnionSubquery(Query *queryTree);
|
||||||
extern bool RestrictionEquivalenceForPartitionKeys(PlannerRestrictionContext *
|
extern bool RestrictionEquivalenceForPartitionKeys(PlannerRestrictionContext *
|
||||||
plannerRestrictionContext);
|
plannerRestrictionContext);
|
||||||
|
extern uint32 ReferenceRelationCount(RelationRestrictionContext *restrictionContext);
|
||||||
extern bool SafeToPushdownUnionSubquery(RelationRestrictionContext *restrictionContext);
|
extern bool SafeToPushdownUnionSubquery(RelationRestrictionContext *restrictionContext);
|
||||||
extern List * RelationIdList(Query *query);
|
extern List * RelationIdList(Query *query);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue