blob: b0a1d1be0de66fc6a92efc3924a9451404659688 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/*-------------------------------------------------------------------------
*
* cdbpathlocus.h
*
*
*
*-------------------------------------------------------------------------
*/
#ifndef CDBPATHLOCUS_H
#define CDBPATHLOCUS_H
#include "nodes/pg_list.h" /* List */
#include "nodes/bitmapset.h" /* Bitmapset */
struct Plan; /* defined in plannodes.h */
struct RelOptInfo; /* defined in relation.h */
struct PlannerInfo; /* defined in relation.h */
/*
* This flag controls the policy type returned from
* cdbpathlocus_from_baserel() for non-partitioned tables.
* It's a kludge put in to allow us to do
* distributed queries on catalog tables, like pg_class
* and pg_statistic.
* To use it, simply set it to true before running a catalog query, then set
* it back to false.
*/
extern bool cdbpathlocus_querysegmentcatalogs;
/*
* CdbLocusType
*/
typedef enum CdbLocusType
{
CdbLocusType_Null,
CdbLocusType_Entry, /* a single backend process on the entry db:
* usually the qDisp itself, but could be a
* qExec started by the entry postmaster.
*/
CdbLocusType_SingleQE, /* a single backend process on any db: the
* qDisp itself, or a qExec started by a
* segment postmaster or the entry postmaster.
*/
CdbLocusType_General, /* compatible with any locus (data is
* self-contained in the query plan or
* generally available in any qExec or qDisp) */
CdbLocusType_Replicated, /* replicated over all qExecs of an N-gang */
CdbLocusType_Hashed, /* hash partitioned over all qExecs of N-gang */
CdbLocusType_HashedOJ, /* result of hash partitioned outer join */
CdbLocusType_Strewn, /* partitioned on no known function */
CdbLocusType_End /* = last valid CdbLocusType + 1 */
} CdbLocusType;
#define CdbLocusType_IsValid(locustype) \
((locustype) > CdbLocusType_Null && \
(locustype) < CdbLocusType_End)
#define CdbLocusType_IsValidOrNull(locustype) \
((locustype) >= CdbLocusType_Null && \
(locustype) < CdbLocusType_End)
/*
* CdbPathLocus
*
* Specifies a distribution of tuples across processes.
*
* If the distribution is a hashed one (locustype == CdbLocusType_Hashed
* or CdbLocusType_HashedOJ), then the tuples are distributed based on
* values of a partitioning key.
*
* A tuple's partitioning key is an m-tuple of values (v1, v2, ..., vm)
* computed by evaluating an m-tuple of expressions (e1, e2, ..., em)
* on the columns of the tuple. Each expression 'ei' is drawn from
* the corresponding set of expressions Ei = {expr, expr, ... }
* in the i'th position of the m-List (E1, E2, ..., Em) that hangs
* from the 'partkey' field. (The data structure used to represent
* these sets depends upon the locustype, as described below.)
* The CdbPathLocus_Degree() macro returns 'm'.
*
* All choices of the 'ei' from the 'Ei' lead to an equivalent
* distribution of rows; thus the set of possible m-tuples of
* expressions (e1, e2, ..., em) forms an equivalence class
* with respect to the partitioning function.
*
* We use this information primarily to optimize joins for which we
* have an equijoin predicate on every column of the partitioning key.
* In such a join, a row in which any partitioning key column is NULL
* cannot join with other rows. So for our purposes here, equivalence
* with respect to partitioning pertains only to rows in which no
* partitioning key column is NULL. In particular, we can disregard
* the distribution of null-augmented rows generated by outer join.
*
* If locustype == CdbLocusType_Hashed:
* Rows are distributed on a hash function of the partitioning key.
* The 'partkey' field points to a pathkey list (see pathkeys.c).
* Each of the sets 'Ei' is represented as a pathkey: a List of
* PathKeyItems pointing to expressions that are constrained by
* equality predicates to be equal to one another.
*
* If locustype == CdbLocusType_HashedOJ:
* Rows are distributed on a hash function of the partitioning key,
* the same as CdbLocusType_Hashed. Each of the sets 'Ei' in the
* 'partkey' list is represented as a List of pathkeys, where again,
* a pathkey is a List of PathKeyItems. This case arises in the
* result of outer join.
*
* If locustype == CdbLocusType_Strewn:
* Rows are distributed according to a criterion that is unknown or
* may depend on inputs that are unknown or unavailable in the present
* context. The 'partkey' field is NIL and the CdbPathLocus_Degree()
* macro returns 0.
*
* If the distribution is not partitioned, then the 'partkey' field is NIL
* and the CdbPathLocus_Degree() macro returns 0.
*/
typedef struct CdbPathLocus
{
CdbLocusType locustype;
List *partkey;
} CdbPathLocus;
#define CdbPathLocus_Degree(locus) \
(list_length((locus).partkey))
/*
* CdbPathLocus_IsEqual
*
* Returns true if one CdbPathLocus is exactly the same as the other.
* To test for logical equivalence, use cdbpathlocus_compare() instead.
*/
#define CdbPathLocus_IsEqual(a, b) \
((a).locustype == (b).locustype && \
(a).partkey == (b).partkey) \
/*
* CdbPathLocus_IsBottleneck
*
* Returns true if the locus indicates confinement to a single process:
* either a singleton qExec (1-gang) on a segment db or the entry db, or
* the qDisp process.
*/
#define CdbPathLocus_IsBottleneck(locus) \
(CdbPathLocus_IsEntry(locus) || \
CdbPathLocus_IsSingleQE(locus))
/*
* CdbPathLocus_IsPartitioned
*
* Returns true if the locus indicates partitioning across an N-gang, such
* that each qExec has a disjoint subset of the rows.
*/
#define CdbPathLocus_IsPartitioned(locus) \
(CdbPathLocus_IsHashed(locus) || \
CdbPathLocus_IsHashedOJ(locus) || \
CdbPathLocus_IsStrewn(locus))
#define CdbPathLocus_IsNull(locus) \
((locus).locustype == CdbLocusType_Null)
#define CdbPathLocus_IsEntry(locus) \
((locus).locustype == CdbLocusType_Entry)
#define CdbPathLocus_IsSingleQE(locus) \
((locus).locustype == CdbLocusType_SingleQE)
#define CdbPathLocus_IsGeneral(locus) \
((locus).locustype == CdbLocusType_General)
#define CdbPathLocus_IsReplicated(locus) \
((locus).locustype == CdbLocusType_Replicated)
#define CdbPathLocus_IsHashed(locus) \
((locus).locustype == CdbLocusType_Hashed)
#define CdbPathLocus_IsHashedOJ(locus) \
((locus).locustype == CdbLocusType_HashedOJ)
#define CdbPathLocus_IsStrewn(locus) \
((locus).locustype == CdbLocusType_Strewn)
#define CdbPathLocus_Make(plocus, _locustype, _partkey) \
do { \
CdbPathLocus *_locus = (plocus); \
_locus->locustype = (_locustype); \
_locus->partkey = (_partkey); \
Assert(_locus->partkey == NULL || \
cdbpathlocus_is_valid(*_locus)); \
} while (0)
#define CdbPathLocus_MakeNull(plocus) \
CdbPathLocus_Make((plocus), CdbLocusType_Null, NIL)
#define CdbPathLocus_MakeEntry(plocus) \
CdbPathLocus_Make((plocus), CdbLocusType_Entry, NIL)
#define CdbPathLocus_MakeSingleQE(plocus) \
CdbPathLocus_Make((plocus), CdbLocusType_SingleQE, NIL)
#define CdbPathLocus_MakeGeneral(plocus) \
CdbPathLocus_Make((plocus), CdbLocusType_General, NIL)
#define CdbPathLocus_MakeReplicated(plocus) \
CdbPathLocus_Make((plocus), CdbLocusType_Replicated, NIL)
#define CdbPathLocus_MakeHashed(plocus, partkey) \
CdbPathLocus_Make((plocus), CdbLocusType_Hashed, (partkey))
#define CdbPathLocus_MakeHashedOJ(plocus, partkey) \
CdbPathLocus_Make((plocus), CdbLocusType_HashedOJ, (partkey))
#define CdbPathLocus_MakeStrewn(plocus) \
CdbPathLocus_Make((plocus), CdbLocusType_Strewn, NIL)
/************************************************************************/
typedef enum
{
CdbPathLocus_Comparison_Equal,
CdbPathLocus_Comparison_Contains
} CdbPathLocus_Comparison;
bool
cdbpathlocus_compare(CdbPathLocus_Comparison op,
CdbPathLocus a,
CdbPathLocus b);
/************************************************************************/
CdbPathLocus
cdbpathlocus_from_baserel(struct PlannerInfo *root,
struct RelOptInfo *rel);
CdbPathLocus
cdbpathlocus_from_exprs(struct PlannerInfo *root,
List *hash_on_exprs);
CdbPathLocus
cdbpathlocus_from_subquery(struct PlannerInfo *root,
struct Plan *subqplan,
Index subqrelid);
CdbPathLocus
cdbpathlocus_join(CdbPathLocus a, CdbPathLocus b);
/************************************************************************/
/*
* cdbpathlocus_get_partkey_exprs
*
* Returns a List with one Expr for each partkey column. Each item either is
* in the given targetlist, or has no Var nodes that are not in the targetlist;
* and uses only rels in the given set of relids. Returns NIL if the
* partkey cannot be expressed in terms of the given relids and targetlist.
*/
List *
cdbpathlocus_get_partkey_exprs(CdbPathLocus locus,
Bitmapset *relids,
List *targetlist);
/*
* cdbpathlocus_pull_above_projection
*
* Given a targetlist, and a locus evaluable before the projection is
* applied, returns an equivalent locus evaluable after the projection.
* Returns a strewn locus if the necessary inputs are not projected.
*
* 'relids' is the set of relids that may occur in the targetlist exprs.
* 'targetlist' specifies the projection. It is a List of TargetEntry
* or merely a List of Expr.
* 'newvarlist' is an optional List of Expr, in 1-1 correspondence with
* 'targetlist'. If specified, instead of creating a Var node to
* reference a targetlist item, we plug in a copy of the corresponding
* newvarlist item.
* 'newrelid' is the RTE index of the projected result, for finding or
* building Var nodes that reference the projected columns.
* Ignored if 'newvarlist' is specified.
*/
CdbPathLocus
cdbpathlocus_pull_above_projection(struct PlannerInfo *root,
CdbPathLocus locus,
Bitmapset *relids,
List *targetlist,
List *newvarlist,
Index newrelid);
/************************************************************************/
/*
* cdbpathlocus_is_hashed_on_exprs
*
* This function tests whether grouping on a given set of exprs can be done
* in place without motion.
*
* For a hashed locus, returns false if the partkey has a column whose
* equivalence class contains no expr belonging to the given list.
*/
bool
cdbpathlocus_is_hashed_on_exprs(CdbPathLocus locus, List *exprlist);
/*
* cdbpathlocus_is_hashed_on_relids
*
* Used when a subquery predicate (such as "x IN (SELECT ...)") has been
* flattened into a join with the tables of the current query. A row of
* the cross-product of the current query's tables might join with more
* than one row from the subquery and thus be duplicated. Removing such
* duplicates after the join is called deduping. If a row's duplicates
* might occur in more than one partition, a Motion operator will be
* needed to bring them together. This function tests whether the join
* result (whose locus is given) can be deduped in place without motion.
*
* For a hashed locus, returns false if the partkey has a column whose
* equivalence class contains no Var node belonging to the given set of
* relids. Caller should specify the relids of the non-subquery tables.
*/
bool
cdbpathlocus_is_hashed_on_relids(CdbPathLocus locus, Bitmapset *relids);
/*
* cdbpathlocus_is_valid
*
* Returns true if locus appears structurally valid.
*/
bool
cdbpathlocus_is_valid(CdbPathLocus locus);
#endif /* CDBPATHLOCUS_H */