*
* plannodes.h
* definitions for query plan nodes
*
*
* Portions Copyright (c) 2021, openGauss Contributors
* Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* src/include/nodes/plannodes.h
*
* -------------------------------------------------------------------------
*/
#ifndef PLANNODES_H
#define PLANNODES_H
#include "access/sdir.h"
#include "foreign/foreign.h"
#include "nodes/bitmapset.h"
#include "nodes/primnodes.h"
#include "utils/partitionmap.h"
#include "utils/partitionmap_gs.h"
#include "optimizer/pruning.h"
#include "pgxc/locator.h"
#include "pgxc/nodemgr.h"
#include "bulkload/dist_fdw.h"
#include "utils/bloom_filter.h"
#include "parsenodes_common.h"
#define MAX_SPECIAL_BUCKETMAP_NUM 20
#define BUCKETMAP_DEFAULT_INDEX_BIT (1 << 31)
* Determines the position where the RemoteQuery node will run.
*/
typedef enum { GATHER, PLAN_ROUTER, SCAN_GATHER } RemoteQueryType;
* @hdfs
* Determines the optimization mode base on informational constraint.
* Currently, join Scan and foreign scan about on HDFS foreign table
* would be optimized.
*/
typedef enum { INVALID_MODE, SCAN_OPTIMIZE_MODE, JOIN_OPTIMIZE_MODE } OptimizedMode;
* node definitions
* ----------------------------------------------------------------
*/
typedef struct NodeGroupQueryMem {
Oid ng_oid;
char nodegroup[NAMEDATALEN];
int query_mem[2];
} NodeGroupQueryMem;
* PlannedStmt node
*
* The output of the planner is a Plan tree headed by a PlannedStmt node.
* PlannedStmt holds the "one time" information needed by the executor.
* ----------------
*/
typedef struct PlannedStmt {
NodeTag type;
CmdType commandType;
uint64 queryId;
bool hasReturning;
bool hasModifyingCTE;
bool hasIgnore;
bool canSetTag;
bool transientPlan;
bool dependsOnRole;
bool is_flt_frame;
Plan* planTree;
List* rtable;
List* resultRelations;
Node* utilityStmt;
List* subplans;
Bitmapset* rewindPlanIDs;
List* rowMarks;
* Notice: be careful to use relationOids as it may contain non-table OID
* in some scenarios, e.g. assignment of relationOids in fix_expr_common.
*/
List* relationOids;
List* invalItems;
int nParamExec;
int num_streams;
int max_push_sql_num;
int gather_count;
int num_nodes;
NodeDefinition* nodesDefinition;
int instrument_option;
int num_plannodes;
int query_mem[2];
int assigned_query_mem[2];
bool is_dynmaic_smp;
int dynsmp_max_cpu;
int dynsmp_avail_cpu;
int dynsmp_cpu_util;
int dynsmp_active_statement;
double dynsmp_query_estimate_cpu_usge;
int dynsmp_plan_optimal_dop;
int dynsmp_plan_original_dop;
int dynsmp_dop_mem_limit;
int dynsmp_min_non_spill_dop;
int num_bucketmaps;
uint2* bucketMap[MAX_SPECIAL_BUCKETMAP_NUM];
int bucketCnt[MAX_SPECIAL_BUCKETMAP_NUM];
char* query_string;
List* subplan_ids;
List* initPlan;
* dataDestRelIndex is index into the range table. This variable
* will take effect on data redistribution state.
*/
Index dataDestRelIndex;
int MaxBloomFilterNum;
int query_dop;
double plannertime;
* the compute pool
*/
bool in_compute_pool;
* in plantree.
*/
bool has_obsrel;
List* plan_hint_warning;
List* noanalyze_rellist;
int ng_num;
NodeGroupQueryMem* ng_queryMem;
bool ng_use_planA;
bool isRowTriggerShippable;
bool is_stream_plan;
bool multi_node_hint;
uint64 uniqueSQLId;
uint32 cause_type;
#ifdef USE_SPQ
uint64 spq_session_id;
int current_id;
bool enable_adaptive_scan;
bool is_spq_optmized;
int write_node_index;
int numSlices;
struct PlanSlice *slices;
int *subplan_sliceIds;
#endif
} PlannedStmt;
typedef struct NodeGroupInfoContext {
Oid groupOids[MAX_SPECIAL_BUCKETMAP_NUM];
uint2* bucketMap[MAX_SPECIAL_BUCKETMAP_NUM];
int bucketCnt[MAX_SPECIAL_BUCKETMAP_NUM];
int num_bucketmaps;
} NodeGroupInfoContext;
* Determine if this plan step needs excution on current dn
* RestoreMode is always considered as 'have to' execute
*/
#define NeedExecute(plan) \
(isRestoreMode ? true \
: (plan->exec_nodes == NULL || plan->exec_nodes->nodeList == NULL || \
list_member_int((plan)->exec_nodes->nodeList, u_sess->pgxc_cxt.PGXCNodeId)))
#define exec_subplan_get_plan(plannedstmt, subplan) ((Plan*)list_nth((plannedstmt)->subplans, (subplan)->plan_id - 1))
* Plan node
*
* All plan nodes "derive" from the Plan structure by having the
* Plan structure as the first field. This ensures that everything works
* when nodes are cast to Plan's. (node pointers are frequently cast to Plan*
* when passed around generically in the executor)
*
* We never actually instantiate any Plan nodes; this is just the common
* abstract superclass for all Plan-type nodes.
* ----------------
*/
typedef struct Plan {
NodeTag type;
int plan_node_id;
int parent_node_id;
RemoteQueryExecType exec_type;
* estimated execution costs for plan (see costsize.c for more info)
*/
Cost startup_cost;
Cost total_cost;
* planner's estimate of result size of this plan step
*/
double plan_rows;
double multiple;
int plan_width;
int dop;
* machine learning model estimations
*/
double pred_rows;
double pred_startup_time;
double pred_total_time;
long pred_max_memory;
* MPPDB Recursive-Union Support
*
* - @recursive_union_plan_nodeid
* Pointing to its belonging RecursiveUnion's plan node id to indate if we are
* under RecursiveUnion
*
* - @recursive_union_controller
* Indicate if current Plan node is controller node in recursive-union steps
*
* - @control_plan_nodeid
* Normally, set on the top-plan node of a producer thread, to indicate which
* control-plan we need syn-up with
*
* - @is_sync_planode
* Indicate the current producer thread is the sync-up thread in recursive union,
* normally set on produer's top plan node
*
* Please note the above four variables is meaningless if a plan node is not under
* recursive-union's recursive part
*/
* plan node id of RecursiveUnion node where current plan node belongs to, 0 for
* not under recursive-union
*/
int recursive_union_plan_nodeid;
bool recursive_union_controller;
bool isinherit;
int control_plan_nodeid;
bool is_sync_plannode;
* Common structural data for all Plan types.
*/
List* targetlist;
List* qual;
struct Plan* lefttree;
struct Plan* righttree;
bool ispwj;
int paramno;
int subparamno;
List* initPlan;
* subselects) */
List* distributed_keys;
ExecNodes* exec_nodes;
* Information for management of parameter-change-driven rescanning
*
* extParam includes the paramIDs of all external PARAM_EXEC params
* affecting this plan node or its children. setParam params from the
* node's initPlans are not included, but their extParams are.
*
* allParam includes all the extParam paramIDs, plus the IDs of local
* params that affect the node (i.e., the setParams of its initplans).
* These are _all_ the PARAM_EXEC params that affect this node.
*/
Bitmapset* extParam;
Bitmapset* allParam;
bool vec_output;
* @hdfs
* Mark the foreign scan whether has unique results on one of its
* output columns.
*/
bool hasUniqueResults;
* Mark the plan whether includes delta table or not.
*/
bool isDeltaTable;
int operatorMemKB[2];
int operatorMaxMem;
bool parallel_enabled;
bool hasHashFilter;
List* var_list;
List* filterIndexList;
int** ng_operatorMemKBArray;
int ng_num;
double innerdistinct;
double outerdistinct;
List* flatList = NULL;
RightRefState* rightRefState;
bool ndp_pushdown_optimized;
* caution: ndp_pushdown_condition under Agg node is used for save ndp handled aggslot
* -> SeqScan save ndp condition
* -> Agg save ndp aggslot
* -> SeqScan->ndp_pushdown_condition save ndp condition
* */
Node* ndp_pushdown_condition;
#ifdef USE_SPQ
bool spq_scan_partial;
#endif
int cursor_expr_level;
int cursor_owner_node_id;
} Plan;
typedef struct NdpScanCondition {
NodeTag type;
uint16 tableId;
void* ctx;
Plan* plan;
} NdpScanCondition;
* these are defined to avoid confusion problems with "left"
* and "right" and "inner" and "outer". The convention is that
* the "left" plan is the "outer" plan and the "right" plan is
* the inner plan, but these make the code more readable.
* ----------------
*/
#define innerPlan(node) (((Plan*)(node))->righttree)
#define outerPlan(node) (((Plan*)(node))->lefttree)
* Result node -
* If no outer plan, evaluate a variable-free targetlist.
* If outer plan, return tuples from outer plan (after a level of
* projection as shown by targetlist).
*
* If resconstantqual isn't NULL, it represents a one-time qualification
* test (i.e., one that doesn't depend on any variables from the outer plan,
* so needs to be evaluated only once).
* ----------------
*/
typedef struct BaseResult {
Plan plan;
Node* resconstantqual;
} BaseResult;
typedef struct VecResult : public BaseResult {
} VecResult;
* ProjectSet node -
* Apply a projection that includes set-returning functions to the
* output tuples of the outer plan.
* ----------------
*/
typedef struct ProjectSet {
Plan plan;
} ProjectSet;
* ModifyTable node -
* Apply rows produced by subplan(s) to result table(s),
* by inserting, updating, or deleting.
*
* Note that rowMarks and epqParam are presumed to be valid for all the
* subplan(s); they can't contain any info that varies across subplans.
* ----------------
*/
typedef struct ModifyTable {
Plan plan;
CmdType operation;
bool canSetTag;
List* resultRelations;
int resultRelIndex;
List* plans;
List* returningLists;
List* fdwPrivLists;
List* rowMarks;
int epqParam;
bool partKeyUpdated;
is to be updated,false: no part key column is to updated */
#ifdef PGXC
List* remote_plans;
List* remote_insert_plans;
List* remote_update_plans;
List* remote_delete_plans;
#endif
bool is_dist_insertselect;
ErrorCacheEntry* cacheEnt;
Index mergeTargetRelation;
List* mergeSourceTargetList;
List* mergeActionList;
UpsertAction upsertAction;
List* updateTlist;
List* exclRelTlist;
Index exclRelRTIndex;
bool isReplace;
Node* upsertWhere;
OpMemInfo mem_info;
List* targetlists;
List* withCheckOptionLists;
#ifdef USE_SPQ
List *isSplitUpdates;
#endif
} ModifyTable;
* Append node -
* Generate the concatenation of the results of sub-plans.
* ----------------
*/
typedef struct Append {
Plan plan;
List* appendplans;
} Append;
typedef struct VecAppend : public Append {
} VecAppend;
* MergeAppend node -
* Merge the results of pre-sorted sub-plans to preserve the ordering.
* ----------------
*/
typedef struct MergeAppend {
Plan plan;
List* mergeplans;
int numCols;
AttrNumber* sortColIdx;
Oid* sortOperators;
Oid* collations;
bool* nullsFirst;
} MergeAppend;
* RecursiveUnion node -
* Generate a recursive union of two subplans.
*
* The "outer" subplan is always the non-recursive term, and the "inner"
* subplan is the recursive term.
* ----------------
*/
typedef struct RecursiveUnion {
Plan plan;
int wtParam;
int numCols;
* duplicate-ness */
AttrNumber* dupColIdx;
Oid* dupOperators;
long numGroups;
bool has_inner_stream;
bool has_outer_stream;
bool is_used;
bool is_correlated;
* in case of correlated term involved, we need broadcast data
* to one datanode to execute the recursive CTE in one-DN mode */
* StartWith Support containt the pseudo target entry, also not-null indicates
* a start-with converted recursive union
* 1. array_key_
* 2. array_path_
* 3. array_root_
* ...
*/
List *internalEntryList;
bool is_under_start_with;
} RecursiveUnion;
* StartWithOp node -
* Generate the start with connect by operator
*
* xxxxxxxxxxxx
* ----------------
*/
struct CteScan;
typedef struct StartWithOp
{
Plan plan;
CteScan *cteplan;
RecursiveUnion *ruplan;
List *keyEntryList;
List *colEntryList;
List *internalEntryList;
List *fullEntryList;
* swoptions, normally store some static information that derived from SQL parsing
* stage, e.g. nocycle, connect_by_type, sibling clause
*/
StartWithOptions *swoptions;
* swExecOptions, exeuction options for StartWithOp operator
*
* store some hint-bit level information supports SWCB runing efficiently, currently
* we only use last 4-bits to indicate if we need skip some pseudo return column
* computation
*/
uint16 swExecOptions;
List *prcTargetEntryList;
List *connect_by_qual;
List *start_with_qual;
List *path_entry_list;
List *root_entry_list;
List *internal_path_entry_list;
List *internal_root_entry_list;
} StartWithOp;
* BitmapAnd node -
* Generate the intersection of the results of sub-plans.
*
* The subplans must be of types that yield tuple bitmaps. The targetlist
* and qual fields of the plan are unused and are always NIL.
* ----------------
*/
typedef struct BitmapAnd {
Plan plan;
List* bitmapplans;
bool is_ustore;
} BitmapAnd;
* BitmapOr node -
* Generate the union of the results of sub-plans.
*
* The subplans must be of types that yield tuple bitmaps. The targetlist
* and qual fields of the plan are unused and are always NIL.
* ----------------
*/
typedef struct BitmapOr {
Plan plan;
List* bitmapplans;
bool is_ustore;
} BitmapOr;
* ==========
* Scan nodes
* ==========
*/
typedef struct Scan {
Plan plan;
Index scanrelid;
bool isPartTbl;
int itrs;
PruningResult* pruningInfo;
BucketInfo* bucketInfo;
ScanDirection partScanDirection;
* @hdfs
* If we use the informational constarint, the following variables will be seted as true.
* If scan_qual_optimized is true, it means that foreign scan will be optimized by using
* scan qual in executor phase.
* If predicate_pushdown_optimized is true, it means that predicate is pushed down and
* foreign scan will be optimized in the executor phase by using the predicate.
*/
bool scan_qual_optimized;
bool predicate_pushdown_optimized;
TableSampleClause* tablesample;
OpMemInfo mem_info;
bool is_inplace;
bool scanBatchMode;
double tableRows;
bool partition_iterator_elimination;
} Scan;
* sequential scan node
* ----------------
*/
typedef Scan SeqScan;
#ifdef USE_SPQ
* Spq scan node
* ----------------
*/
typedef struct SpqSeqScan {
SeqScan scan;
bool isFullTableScan;
bool isAdaptiveScan;
bool isDirectRead;
uint32 DirectReadBlkNum;
} SpqSeqScan;
#endif
* ==========
* Column Store Scan nodes
* ==========
*/
typedef struct CStoreScan : public Scan {
double selectionRatio;
List* cstorequal;
List* minMaxInfo;
RelstoreType relStoreLocation;
bool is_replica_table;
} CStoreScan;
#ifdef ENABLE_HTAP
typedef CStoreScan IMCStoreScan;
#endif
* ==========
* Time Series Store Scan nodes
* ==========
*/
typedef struct TsStoreScan: public Scan {
double selectionRatio;
List *tsstorequal;
List *minMaxInfo;
RelstoreType relStoreLocation;
bool is_replica_table;
AttrNumber sort_by_time_colidx;
int limit;
bool is_simple_scan;
bool has_sort;
int series_func_calls;
int top_key_func_arg;
} TsStoreScan;
* index scan node
*
* indexqualorig is an implicitly-ANDed list of index qual expressions, each
* in the same form it appeared in the query WHERE condition. Each should
* be of the form (indexkey OP comparisonval) or (comparisonval OP indexkey).
* The indexkey is a Var or expression referencing column(s) of the index's
* base table. The comparisonval might be any expression, but it won't use
* any columns of the base table. The expressions are ordered by index
* column position (but items referencing the same index column can appear
* in any order). indexqualorig is used at runtime only if we have to recheck
* a lossy indexqual.
*
* indexqual has the same form, but the expressions have been commuted if
* necessary to put the indexkeys on the left, and the indexkeys are replaced
* by Var nodes identifying the index columns (their varno is INDEX_VAR and
* their varattno is the index column number).
*
* indexorderbyorig is similarly the original form of any ORDER BY expressions
* that are being implemented by the index, while indexorderby is modified to
* have index column Vars on the left-hand side. Here, multiple expressions
* must appear in exactly the ORDER BY order, and this is not necessarily the
* index column order. Only the expressions are provided, not the auxiliary
* sort-order information from the ORDER BY SortGroupClauses; it's assumed
* that the sort ordering is fully determinable from the top-level operators.
* indexorderbyorig is unused at run time, but is needed for EXPLAIN.
* (Note these fields are used for amcanorderbyop cases, not amcanorder cases.)
*
* indexorderdir specifies the scan ordering, for indexscans on amcanorder
* indexes (for other indexes it should be "don't care").
* ----------------
*/
typedef struct IndexScan {
Scan scan;
Oid indexid;
char* indexname;
List* indexqual;
List* indexqualorig;
List* indexorderby;
List* indexorderbyorig;
ScanDirection indexorderdir;
bool usecstoreindex;
Index indexscan_relid;
List* idx_cstorequal;
storage engine */
List* cstorequal;
List* targetlist;
bool index_only_scan;
bool is_ustore;
double selectivity;
bool is_partial;
} IndexScan;
* index-only scan node
*
* IndexOnlyScan is very similar to IndexScan, but it specifies an
* index-only scan, in which the data comes from the index not the heap.
* Because of this, *all* Vars in the plan node's targetlist, qual, and
* index expressions reference index columns and have varno = INDEX_VAR.
* Hence we do not need separate indexqualorig and indexorderbyorig lists,
* since their contents would be equivalent to indexqual and indexorderby.
*
* To help EXPLAIN interpret the index Vars for display, we provide
* indextlist, which represents the contents of the index as a targetlist
* with one TLE per index column. Vars appearing in this list reference
* the base table, and this is the only field in the plan node that may
* contain such Vars.
* ----------------
*/
typedef struct IndexOnlyScan {
Scan scan;
Oid indexid;
List* indexqual;
List* indexqualorig;
List* indexorderby;
List* indextlist;
ScanDirection indexorderdir;
double selectivity;
bool is_partial;
} IndexOnlyScan;
* bitmap index scan node
*
* BitmapIndexScan delivers a bitmap of potential tuple locations;
* it does not access the heap itself. The bitmap is used by an
* ancestor BitmapHeapScan node, possibly after passing through
* intermediate BitmapAnd and/or BitmapOr nodes to combine it with
* the results of other BitmapIndexScans.
*
* The fields have the same meanings as for IndexScan, except we don't
* store a direction flag because direction is uninteresting.
*
* In a BitmapIndexScan plan node, the targetlist and qual fields are
* not used and are always NIL. The indexqualorig field is unused at
* run time too, but is saved for the benefit of EXPLAIN.
* ----------------
*/
typedef struct BitmapIndexScan {
Scan scan;
Oid indexid;
char* indexname;
List* indexqual;
List* indexqualorig;
bool is_ustore;
double selectivity;
bool is_partial;
} BitmapIndexScan;
* bitmap sequential scan node
*
* This needs a copy of the qual conditions being used by the input index
* scans because there are various cases where we need to recheck the quals;
* for example, when the bitmap is lossy about the specific rows on a page
* that meet the index condition.
* ----------------
*/
typedef struct BitmapHeapScan {
Scan scan;
List* bitmapqualorig;
} BitmapHeapScan;
* Column Store index scan node
*
* ----------------
*/
typedef struct CStoreIndexScan {
Scan scan;
Oid indexid;
List* indexqual;
List* indexqualorig;
List* indexorderby;
List* indexorderbyorig;
ScanDirection indexorderdir;
List* baserelcstorequal;
List* cstorequal;
List* indextlist;
RelstoreType relStoreLocation;
bool indexonly;
} CStoreIndexScan;
typedef struct CStoreIndexCtidScan : public BitmapIndexScan {
List* indextlist;
List* cstorequal;
} CStoreIndexCtidScan;
typedef struct CStoreIndexHeapScan : public BitmapHeapScan {
} CStoreIndexHeapScan;
typedef struct CStoreIndexAnd : public BitmapAnd {
} CStoreIndexAnd;
typedef struct CStoreIndexOr : public BitmapOr {
} CStoreIndexOr;
* Vector ann index scan node
* use vector index scan and list of qual expressions to scan data.
*/
typedef struct AnnIndexScan {
Scan scan;
Oid indexid;
char* indexname;
List* indexqual;
List* indexqualorig;
List* indexorderby;
List* indexorderbyorig;
ScanDirection indexorderdir;
Index indexscan_relid;
List* idx_cstorequal;
storage engine */
List* cstorequal;
List* targetlist;
bool index_only_scan;
bool is_ustore;
double selectivity;
bool is_partial;
double annCount;
} AnnIndexScan;
* tid scan node
*
* tidquals is an implicitly OR'ed list of qual expressions of the form
* "CTID = pseudoconstant" or "CTID = ANY(pseudoconstant_array)".
* ----------------
*/
typedef struct TidScan {
Scan scan;
List* tidquals;
} TidScan;
* tid range scan node
*
* tidrangequals is an implicitly AND'ed list of qual expressions of the form
* "CTID relop pseudoconstant", where relop is one of >,>=,<,<=.
* ----------------
*/
typedef struct TidRangeScan
{
Scan scan;
List *tidrangequals;
} TidRangeScan;
* subquery scan node
*
* SubqueryScan is for scanning the output of a sub-query in the range table.
* We often need an extra plan node above the sub-query's plan to perform
* expression evaluations (which we can't push into the sub-query without
* risking changing its semantics). Although we are not scanning a physical
* relation, we make this a descendant of Scan anyway for code-sharing
* purposes.
*
* Note: we store the sub-plan in the type-specific subplan field, not in
* the generic lefttree field as you might expect. This is because we do
* not want plan-tree-traversal routines to recurse into the subplan without
* knowing that they are changing Query contexts.
* ----------------
*/
typedef struct SubqueryScan {
Scan scan;
Plan* subplan;
} SubqueryScan;
typedef struct VecSubqueryScan : public SubqueryScan {
} VecSubqueryScan;
* FunctionScan node
* ----------------
*/
typedef struct FunctionScan {
Scan scan;
Node* funcexpr;
List* funccolnames;
List* funccoltypes;
List* funccoltypmods;
List* funccolcollations;
} FunctionScan;
* ValuesScan node
* ----------------
*/
typedef struct ValuesScan {
Scan scan;
List* values_lists;
} ValuesScan;
* CteScan node
* ----------------
*/
typedef struct CteScan {
Scan scan;
int ctePlanId;
int cteParam;
RecursiveUnion* subplan;
CommonTableExpr *cteRef;
* - pseudoReturnTargetEntryList
*
* Hold the TargetEntry reference for PRC a.w.k. "pseudo return columns"
* [1]. level
* [2]. connect_by_isleaf
* [3]. connect_by_iscycle
* [4]. rownum
*/
List *prcTargetEntryList;
* - internalEntryList
*
* Hold the internal TargetEntry for Hierarchical Query execution (not visible)
* 1. RUITR
* 2. array_column1
* 3. array_column2
* ...
*/
List *internalEntryList;
} CteScan;
* WorkTableScan node
* ----------------
*/
typedef struct WorkTableScan {
Scan scan;
int wtParam;
bool forStartWith;
} WorkTableScan;
* ForeignScan node
*
* fdw_exprs and fdw_private are both under the control of the foreign-data
* wrapper, but fdw_exprs is presumed to contain expression trees and will
* be post-processed accordingly by the planner; fdw_private won't be.
* Note that everything in both lists must be copiable by copyObject().
* One way to store an arbitrary blob of bytes is to represent it as a bytea
* Const. Usually, though, you'll be better off choosing a representation
* that can be dumped usefully by nodeToString().
* ----------------
*/
typedef struct ForeignScan {
Scan scan;
Oid scan_relid;
List* fdw_exprs;
List* fdw_private;
bool fsSystemCol;
bool needSaveError;
ErrorCacheEntry* errCache;
List* prunningResult;
RelationMetaData* rel;
ForeignOptions* options;
int64 objectNum;
BloomFilterSet** bloomFilterSet;
int bfNum;
* the compute pool
*/
bool in_compute_pool;
bool not_use_bloomfilter;
CmdType operation;
Index resultRelation;
Oid fs_server;
Bitmapset *fs_relids;
List *fdw_scan_tlist;
List *fdw_recheck_quals;
} ForeignScan;
* An extensible node is a new type of node defined by an extension. The
* type is always T_ExtensibleNode, while the extnodename identifies the
* specific type of node. extnodename can be looked up to find the
* ExtensibleNodeMethods for this node type.
*/
typedef struct ExtensibleNode
{
NodeTag type;
const char *extnodename;
} ExtensibleNode;
* node_size is the size of an extensible node of this type in bytes.
*
* nodeCopy is a function which performs a deep copy from oldnode to newnode.
* It does not need to copy type or extnodename, which are copied by the
* core system.
*
* nodeEqual is a function which performs a deep equality comparison between
* a and b and returns true or false accordingly. It does not need to compare
* type or extnodename, which are compared by the core system.
*
* nodeOut is a serialization function for the node type. It should use the
* output conventions typical for outfuncs.c. It does not need to output
* type or extnodename; the core system handles those.
*
* nodeRead is a deserialization function for the node type. It does not need
* to read type or extnodename; the core system handles those. It should fetch
* the next token using pg_strtok() from the current input stream, and then
* reconstruct the private fields according to the manner in readfuncs.c.
*
* All callbacks are mandatory.
*/
typedef struct ExtensibleNodeMethods
{
const char *extnodename;
Size node_size;
void (*nodeCopy) (struct ExtensibleNode *newnode,
const struct ExtensibleNode *oldnode);
bool (*nodeEqual) (const struct ExtensibleNode *a,
const struct ExtensibleNode *b);
void (*nodeOut) (struct StringInfoData *str,
const struct ExtensibleNode *node);
void (*nodeRead) (struct ExtensibleNode *node);
} ExtensibleNodeMethods;
* ExtensiblePlan node
*
* The comments for ForeignScan's fdw_exprs, fdw_private, fdw_scan_tlist,
* and fs_relids fields apply equally to ExtensiblePlan's extensible_exprs,
* extensible_data, extensible_plan_tlist, and extensible_relids fields. The
* convention of setting scan.scanrelid to zero for joins applies as well.
*
* Note that since Plan trees can be copied, extensible scan providers *must*
* fit all plan data they need into those fields; embedding ExtensiblePlan in
* a larger struct will not work.
* ----------------
*/
struct ExtensiblePlan;
typedef struct ExtensiblePlanMethods {
char* ExtensibleName;
Node* (*CreateExtensiblePlanState)(struct ExtensiblePlan* cscan);
} ExtensiblePlanMethods;
typedef struct ExtensiblePlan {
Scan scan;
uint32 flags;
List* extensible_plans;
List* extensible_exprs;
List* extensible_private;
List* extensible_plan_tlist;
* tuple */
Bitmapset* extensible_relids;
ExtensiblePlanMethods* methods;
} ExtensiblePlan;
* ==========
* Join nodes
* ==========
*/
* Join node
*
* jointype: rule for joining tuples from left and right subtrees
* joinqual: qual conditions that came from JOIN/ON or JOIN/USING
* (plan.qual contains conditions that came from WHERE)
*
* When jointype is INNER, joinqual and plan.qual are semantically
* interchangeable. For OUTER jointypes, the two are *not* interchangeable;
* only joinqual is used to determine whether a match has been found for
* the purpose of deciding whether to generate null-extended tuples.
* (But plan.qual is still applied before actually returning a tuple.)
* For an outer join, only joinquals are allowed to be used as the merge
* or hash condition of a merge or hash join.
*
* ----------------
*/
typedef struct Join {
Plan plan;
JoinType jointype;
bool inner_unique;
List* joinqual;
* @hdfs
* This flag will be set as true if we use informational constraint
* in order to optimize join plan.
*/
bool optimizable;
List* nulleqqual;
uint32 skewoptimize;
#ifdef USE_SPQ
bool prefetch_inner;
bool is_set_op_join;
#endif
} Join;
* nest loop join node
*
* The nestParams list identifies any executor Params that must be passed
* into execution of the inner subplan carrying values from the current row
* of the outer subplan. Currently we restrict these values to be simple
* Vars, but perhaps someday that'd be worth relaxing. (Note: during plan
* creation, the paramval can actually be a PlaceHolderVar expression; but it
* must be a Var with varno OUTER_VAR by the time it gets to the executor.)
* ----------------
*/
typedef struct NestLoop {
Join join;
List* nestParams;
bool materialAll;
} NestLoop;
typedef struct VecNestLoop : public NestLoop {
} VecNestLoop;
typedef struct NestLoopParam {
NodeTag type;
int paramno;
Var* paramval;
} NestLoopParam;
* merge join node
*
* The expected ordering of each mergeable column is described by a btree
* opfamily OID, a collation OID, a direction (BTLessStrategyNumber or
* BTGreaterStrategyNumber) and a nulls-first flag. Note that the two sides
* of each mergeclause may be of different datatypes, but they are ordered the
* same way according to the common opfamily and collation. The operator in
* each mergeclause must be an equality operator of the indicated opfamily.
* ----------------
*/
typedef struct MergeJoin {
Join join;
bool skip_mark_restore;
List* mergeclauses;
Oid* mergeFamilies;
Oid* mergeCollations;
int* mergeStrategies;
bool* mergeNullsFirst;
#ifdef USE_SPQ
bool unique_outer;
#endif
} MergeJoin;
typedef struct VecMergeJoin : public MergeJoin {
} VecMergeJoin;
* hash join node
* ----------------
*/
typedef struct HashJoin {
Join join;
List* hashclauses;
bool streamBothSides;
bool transferFilterFlag;
bool rebuildHashTable;
bool isSonicHash;
OpMemInfo mem_info;
double joinRows;
List* hash_collations;
#ifdef USE_SPQ
List *hashqualclauses;
#endif
} HashJoin;
* asof join node
* ----------------
*/
typedef struct AsofJoin {
Join join;
List* hashclauses;
List* mergeclauses;
bool streamBothSides;
} AsofJoin;
* materialization node
* ----------------
*/
typedef struct Material {
Plan plan;
bool materialize_all;
OpMemInfo mem_info;
#ifdef USE_SPQ
bool spq_strict;
bool spq_shield_child_from_rescans;
#endif
} Material;
typedef struct VecMaterial : public Material {
} VecMaterial;
* sort node
* ----------------
*/
typedef struct Sort {
Plan plan;
int numCols;
AttrNumber* sortColIdx;
Oid* sortOperators;
Oid* collations;
bool* nullsFirst;
#ifdef PGXC
bool srt_start_merge;
* underlying plan provides those runs. Merge
* them.
*/
#endif
OpMemInfo mem_info;
} Sort;
* SortGroup node
* ----------------
*/
typedef struct SortGroup {
Plan plan;
int numCols;
AttrNumber *sortColIdx;
Oid *sortOperators;
Oid *collations;
bool *nullsFirst;
} SortGroup;
typedef struct VecSort : public Sort {
} VecSort;
* group node -
* Used for queries with GROUP BY (but no aggregates) specified.
* The input must be presorted according to the grouping columns.
* ---------------
*/
typedef struct Group {
Plan plan;
int numCols;
AttrNumber* grpColIdx;
Oid* grpOperators;
Oid* grp_collations;
} Group;
typedef struct VecGroup : public Group {
} VecGroup;
* aggregate node
*
* An Agg node implements plain or grouped aggregation. For grouped
* aggregation, we can work with presorted input or unsorted input;
* the latter strategy uses an internal hashtable.
*
* Notice the lack of any direct info about the aggregate functions to be
* computed. They are found by scanning the node's tlist and quals during
* executor startup. (It is possible that there are no aggregate functions;
* this could happen if they get optimized away by constant-folding, or if
* we are using the Agg node to implement hash-based grouping.)
* ---------------
*/
typedef enum AggStrategy {
AGG_PLAIN,
AGG_SORTED,
AGG_HASHED,
AGG_SORT_GROUP
} AggStrategy;
#ifdef STREAMPLAN
typedef enum SAggMethod {
OPTIMAL_AGG,
DN_AGG_CN_AGG,
DN_REDISTRIBUTE_AGG,
DN_AGG_REDISTRIBUTE_AGG,
DN_REDISTRIBUTE_AGG_CN_AGG,
DN_REDISTRIBUTE_AGG_REDISTRIBUTE_AGG
} SAggMethod;
#define ALLOW_ALL_AGG 0X00
#define DISALLOW_CN_AGG 0x01
#define FOREC_SLVL_AGG 0x02
#endif
typedef struct Agg {
Plan plan;
AggStrategy aggstrategy;
#ifdef USE_SPQ
AggSplit aggsplittype;
#endif
int numCols;
AttrNumber* grpColIdx;
Oid* grpOperators;
long numGroups;
List* groupingSets;
List* chain;
#ifdef PGXC
bool is_final;
bool single_node;
#endif
Bitmapset* aggParams;
OpMemInfo mem_info;
bool is_sonichash;
bool is_dummy;
uint32 skew_optimize;
bool unique_check;
Oid* grp_collations;
} Agg;
* window aggregate node
* ----------------
*/
typedef struct WindowAgg {
Plan plan;
Index winref;
int partNumCols;
AttrNumber* partColIdx;
Oid* partOperators;
int ordNumCols;
AttrNumber* ordColIdx;
Oid* ordOperators;
int frameOptions;
Node* startOffset;
Node* endOffset;
OpMemInfo mem_info;
Oid* part_collations;
Oid* ord_collations;
} WindowAgg;
typedef struct VecWindowAgg : public WindowAgg {
} VecWindowAgg;
* unique node
* ----------------
*/
typedef struct Unique {
Plan plan;
int numCols;
AttrNumber* uniqColIdx;
Oid* uniqOperators;
Oid* uniq_collations;
} Unique;
* hash build node
*
* If the executor is supposed to try to apply skew join optimization, then
* skewTable/skewColumn/skewInherit identify the outer relation's join key
* column, from which the relevant MCV statistics can be fetched. Also, its
* type information is provided to save a lookup.
* ----------------
*/
typedef struct Hash {
Plan plan;
Oid skewTable;
AttrNumber skewColumn;
bool skewInherit;
Oid skewColType;
int32 skewColTypmod;
} Hash;
* setop node
* ----------------
*/
typedef enum SetOpCmd { SETOPCMD_INTERSECT, SETOPCMD_INTERSECT_ALL, SETOPCMD_EXCEPT, SETOPCMD_EXCEPT_ALL } SetOpCmd;
typedef enum SetOpStrategy {
SETOP_SORTED,
SETOP_HASHED
} SetOpStrategy;
typedef struct SetOp {
Plan plan;
SetOpCmd cmd;
SetOpStrategy strategy;
int numCols;
* duplicate-ness */
AttrNumber* dupColIdx;
Oid* dupOperators;
AttrNumber flagColIdx;
int firstFlag;
long numGroups;
OpMemInfo mem_info;
Oid* dup_collations;
} SetOp;
* lock-rows node
*
* rowMarks identifies the rels to be locked by this node; it should be
* a subset of the rowMarks listed in the top-level PlannedStmt.
* epqParam is a Param that all scan nodes below this one must depend on.
* It is used to force re-evaluation of the plan during EvalPlanQual.
* ----------------
*/
typedef struct LockRows {
Plan plan;
List* rowMarks;
int epqParam;
} LockRows;
* limit node
*
* Note: as of Postgres 8.2, the offset and count expressions are expected
* to yield int8, rather than int4 as before.
* ----------------
*/
typedef struct Limit {
Plan plan;
Node* limitOffset;
Node* limitCount;
bool isPercent;
bool withTies;
int numCols;
AttrNumber* sortColIdx;
Oid* equalOperators;
Oid* collations;
bool* nullsFirst;
} Limit;
typedef struct VecLimit : public Limit {
} VecLimit;
* RowMarkType -
* enums for types of row-marking operations
*
* When doing UPDATE, DELETE, or SELECT FOR [KEY] UPDATE/SHARE, we have to uniquely
* identify all the source rows, not only those from the target relations, so
* that we can perform EvalPlanQual rechecking at need. For plain tables we
* can just fetch the TID, the same as for a target relation. Otherwise (for
* example for VALUES or FUNCTION scans) we have to copy the whole row value.
* The latter is pretty inefficient but fortunately the case is not
* performance-critical in practice.
*/
typedef enum RowMarkType {
ROW_MARK_EXCLUSIVE,
ROW_MARK_NOKEYEXCLUSIVE,
ROW_MARK_SHARE,
ROW_MARK_KEYSHARE,
ROW_MARK_REFERENCE,
ROW_MARK_COPY,
ROW_MARK_COPY_DATUM
} RowMarkType;
#define RowMarkRequiresRowShareLock(marktype) ((marktype) <= ROW_MARK_KEYSHARE)
* PlanRowMark -
* plan-time representation of FOR [KEY] UPDATE/SHARE clauses
*
* When doing UPDATE, DELETE, or SELECT FOR [KEY] UPDATE/SHARE, we create a separate
* PlanRowMark node for each non-target relation in the query. Relations that
* are not specified as FOR [KEY] UPDATE/SHARE are marked ROW_MARK_REFERENCE (if
* real tables) or ROW_MARK_COPY (if not).
*
* Initially all PlanRowMarks have rti == prti and isParent == false.
* 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 planner also adds resjunk output columns to the plan that carry
* information sufficient to identify the locked or fetched rows. For
* tables (markType != ROW_MARK_COPY), these columns are named
* tableoid%u OID of table
* ctid%u TID of row
* The tableoid column is only present for an inheritance hierarchy.
* When markType == ROW_MARK_COPY, there is instead a single column named
* wholerow%u whole-row value of relation
* In all three cases, %u represents the rowmark ID number (rowmarkId).
* This number is unique within a plan tree, except that child relation
* entries copy their parent's rowmarkId. (Assigning unique numbers
* means we needn't renumber rowmarkIds when flattening subqueries, which
* would require finding and renaming the resjunk columns as well.)
* Note this means that all tables in an inheritance hierarchy share the
* same resjunk column names. However, in an inherited UPDATE/DELETE the
* columns could have different physical column numbers in each subplan.
*/
typedef struct PlanRowMark {
NodeTag type;
Index rti;
Index prti;
Index rowmarkId;
RowMarkType markType;
LockWaitPolicy waitPolicy;
int waitSec;
bool isParent;
int numAttrs;
Bitmapset* bms_nodeids;
} PlanRowMark;
* Plan invalidation info
*
* We track the objects on which a PlannedStmt depends in two ways:
* relations are recorded as a simple list of OIDs, and everything else
* is represented as a list of PlanInvalItems. A PlanInvalItem is designed
* to be used with the syscache invalidation mechanism, so it identifies a
* system catalog entry by cache ID and hash value.
*/
typedef struct PlanInvalItem {
NodeTag type;
int cacheId;
uint32 hashValue;
} PlanInvalItem;
* Target : data partition
* Brief : structure definition about partition iteration
*/
typedef struct PartIteratorParam {
NodeTag type;
int paramno;
int subPartParamno;
} PartIteratorParam;
typedef struct PartIterator {
Plan plan;
PartitionType partType;
int itrs;
ScanDirection direction;
PartIteratorParam* param;
* Below three variables are used to record starting partition id, ending partition id and number of
* partitions.
*/
int startPartitionId;
int endPartitionId;
} PartIterator;
typedef struct GlobalPartIterator {
int curItrs;
PruningResult* pruningResult;
} GlobalPartIterator;
typedef struct VecPartIterator : public PartIterator {
} VecPartIterator;
* Vector Plan Nodes.
*
*/
* vector hash join node
* ----------------
*/
typedef struct HashJoin VecHashJoin;
typedef struct AsofJoin VecAsofJoin;
typedef struct Agg VecAgg;
typedef struct SetOp VecSetOp;
typedef struct Unique VecUnique;
typedef struct RowToVec {
Plan plan;
} RowToVec;
typedef struct VecToRow {
Plan plan;
} VecToRow;
inline bool IsVecOutput(Plan* p)
{
return p && p->vec_output;
}
typedef struct VecForeignScan : public ForeignScan {
} VecForeignScan;
typedef struct VecModifyTable : public ModifyTable {
} VecModifyTable;
static inline bool IsJoinPlan(Node* node)
{
return IsA(node, Join) || IsA(node, NestLoop) || IsA(node, VecNestLoop) || IsA(node, MergeJoin) ||
IsA(node, VecMergeJoin) || IsA(node, HashJoin) || IsA(node, VecHashJoin);
}
* DB4AI
*/
struct ModelHyperparameters;
typedef struct TrainModel {
Plan plan;
AlgorithmML algorithm;
int configurations;
const ModelHyperparameters **hyperparameters;
MemoryContext cxt;
} TrainModel;
#ifdef USE_SPQ
* Result node -
* If no outer plan, evaluate a variable-free targetlist.
* If outer plan, return tuples from outer plan (after a level of
* projection as shown by targetlist).
*
* If resconstantqual isn't NULL, it represents a one-time qualification
* test (i.e., one that doesn't depend on any variables from the outer plan,
* so needs to be evaluated only once).
*
* If numHashFilterCols is non-zero, we compute a mpphash value based
* on the columns listed in hashFilterColIdx for each input row. If the
* target segment based on the hash doesn't match the current execution
* segment, the row is discarded.
* ----------------
*/
typedef struct Result {
Plan plan;
Node *resconstantqual;
int numHashFilterCols;
AttrNumber *hashFilterColIdx;
Oid *hashFilterFuncs;
} Result;
typedef struct SpqIndexScan {
IndexScan scan;
} SpqIndexScan;
typedef struct SpqIndexOnlyScan {
IndexOnlyScan scan;
} SpqIndexOnlyScan;
typedef struct SpqBitmapHeapScan {
BitmapHeapScan scan;
} SpqBitmapHeapScan;
typedef struct DirectDispatchInfo {
* if true then this Slice requires an n-gang but the gang can be targeted to
* fewer segments than the entire cluster.
*
* When true, directDispatchContentId and directDispathCount will combine to indicate
* the content ids that need segments.
*/
bool isDirectDispatch;
List *contentIds;
bool haveProcessedAnyCalculations;
} DirectDispatchInfo;
typedef enum GangType {
GANGTYPE_UNALLOCATED,
GANGTYPE_ENTRYDB_READER,
GANGTYPE_SINGLETON_READER,
GANGTYPE_PRIMARY_READER,
GANGTYPE_PRIMARY_WRITER
} GangType;
* PlanSlice represents one query slice, to be executed by a separate gang
* of executor processes.
*/
typedef struct PlanSlice {
int sliceIndex;
int parentIndex;
GangType gangType;
int numsegments;
int worker_idx;
DirectDispatchInfo directDispatch;
} PlanSlice;
* motion node structs
* -------------------------
*/
typedef enum MotionType {
MOTIONTYPE_GATHER,
MOTIONTYPE_GATHER_SINGLE,
MOTIONTYPE_HASH,
MOTIONTYPE_BROADCAST,
MOTIONTYPE_EXPLICIT,
MOTIONTYPE_OUTER_QUERY
} MotionType;
* Motion Node
*/
typedef struct Motion {
Plan plan;
MotionType motionType;
bool sendSorted;
int motionID;
List *hashExprs;
Oid *hashFuncs;
int numHashSegments;
AttrNumber segidColIdx;
int numSortCols;
AttrNumber *sortColIdx;
Oid *sortOperators;
Oid *collations;
bool *nullsFirst;
} Motion;
* Sequence node
* Execute a list of subplans in the order of left-to-right, and return
* the results of the last subplan.
*/
typedef struct Sequence {
Plan plan;
List *subplans;
} Sequence;
* PartitionPruneInfo - Details required to allow the executor to prune
* partitions.
*
* Here we store mapping details to allow translation of a partitioned table's
* index as returned by the partition pruning code into subplan indexes for
* plan types which support arbitrary numbers of subplans, such as Append.
* We also store various details to tell the executor when it should be
* performing partition pruning.
*
* Each PartitionedRelPruneInfo describes the partitioning rules for a single
* partitioned table (a/k/a level of partitioning). Since a partitioning
* hierarchy could contain multiple levels, we represent it by a List of
* PartitionedRelPruneInfos, where the first entry represents the topmost
* partitioned table and additional entries represent non-leaf child
* partitions, ordered such that parents appear before their children.
* Then, since an Append-type node could have multiple partitioning
* hierarchies among its children, we have an unordered List of those Lists.
*
* prune_infos List of Lists containing PartitionedRelPruneInfo nodes,
* one sublist per run-time-prunable partition hierarchy
* appearing in the parent plan node's subplans.
* other_subplans Indexes of any subplans that are not accounted for
* by any of the PartitionedRelPruneInfo nodes in
* "prune_infos". These subplans must not be pruned.
*/
typedef struct PartitionPruneInfo {
NodeTag type;
List *prune_infos;
Bitmapset *other_subplans;
} PartitionPruneInfo;
* PartitionSelector node
*
* PartitionSelector performs partition pruning based on rows seen on
* the "other" side of a join. It performs partition pruning similar to
* run-time partition pruning in an Append node, but it is performed based
* on the rows seen, instead of executor params. The set of surviving
* partitions is made available to the Append node, by storing it in a
* special executor param, identified by 'paramid' field.
* ----------------
*/
typedef struct PartitionSelector {
Plan plan;
struct PartitionPruneInfo *part_prune_info;
int32 paramid;
} PartitionSelector;
* shareinputscan node
* ----------------
*/
typedef struct ShareInputScan {
Scan scan;
bool cross_slice;
int share_id;
* Slice that produces the tuplestore for this shared scan.
*
* As a special case, in a plan that has only one slice, this may be left
* to -1. The executor node ignores this when there is only one slice.
*/
int producer_slice_id;
* Slice id that this ShareInputScan node runs in. If it's
* different from current slice ID, this ShareInputScan is "alien"
* to the current slice and doesn't need to be executed at all (in
* this slice). It is used to skip IPC in alien nodes.
*
* Like producer_slice_id, this can be left to -1 if there is only one
* slice in the plan tree.
*/
int this_slice_id;
int nconsumers;
bool discard_output;
bool is_producer;
} ShareInputScan;
* SplitUpdate Node
*
*/
typedef struct SplitUpdate {
Plan plan;
AttrNumber actionColIdx;
AttrNumber tupleoidColIdx;
AttrNumber ctidColIdx;
List *insertColIdx;
List *deleteColIdx;
* Fields for calculating the target segment id.
*
* If the targetlist contains a 'gp_segment_id' field, these fields are
* used to compute the target segment id, for INSERT-action rows.
*/
int numHashAttrs;
AttrNumber *hashAttnos;
Oid *hashFuncs;
int numHashSegments;
} SplitUpdate;
typedef struct AssertOp {
Plan plan;
int errcode;
List *errmessage;
} AssertOp;
typedef enum DMLAction {
DML_DELETE,
DML_INSERT
} DMLAction;
#endif
#endif