/* ------------------------------------------------------------------------- * * executor.h * support for the POSTGRES executor module * * * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/executor/executor.h * * ------------------------------------------------------------------------- */ #ifndef EXECUTOR_H #define EXECUTOR_H #include "executor/execdesc.h" #include "nodes/parsenodes.h" #include "nodes/params.h" #include "pgxc/pgxc.h" #include "utils/memprot.h" #include "utils/memutils.h" #include "utils/resowner.h" #include "utils/partitionmap_gs.h" #include "utils/plpgsql.h" /* * The "eflags" argument to ExecutorStart and the various ExecInitNode * routines is a bitwise OR of the following flag bits, which tell the * called plan node what to expect. Note that the flags will get modified * as they are passed down the plan tree, since an upper node may require * functionality in its subnode not demanded of the plan as a whole * (example: MergeJoin requires mark/restore capability in its inner input), * or an upper node may shield its input from some functionality requirement * (example: Materialize shields its input from needing to do backward scan). * * EXPLAIN_ONLY indicates that the plan tree is being initialized just so * EXPLAIN can print it out; it will not be run. Hence, no side-effects * of startup should occur. However, error checks (such as permission checks) * should be performed. * * REWIND indicates that the plan node should try to efficiently support * rescans without parameter changes. (Nodes must support ExecReScan calls * in any case, but if this flag was not given, they are at liberty to do it * through complete recalculation. Note that a parameter change forces a * full recalculation in any case.) * * BACKWARD indicates that the plan node must respect the es_direction flag. * When this is not passed, the plan node will only be run forwards. * * MARK indicates that the plan node must support Mark/Restore calls. * When this is not passed, no Mark/Restore will occur. * * SKIP_TRIGGERS tells ExecutorStart/ExecutorFinish to skip calling * AfterTriggerBeginQuery/AfterTriggerEndQuery. This does not necessarily * mean that the plan can't queue any AFTER triggers; just that the caller * is responsible for there being a trigger context for them to be queued in. * * WITH/WITHOUT_OIDS tell the executor to emit tuples with or without space * for OIDs, respectively. These are currently used only for CREATE TABLE AS. * If neither is set, the plan may or may not produce tuples including OIDs. */ #define EXEC_FLAG_EXPLAIN_ONLY 0x0001 /* EXPLAIN, no ANALYZE */ #define EXEC_FLAG_REWIND 0x0002 /* need efficient rescan */ #define EXEC_FLAG_BACKWARD 0x0004 /* need backward scan */ #define EXEC_FLAG_MARK 0x0008 /* need mark/restore */ #define EXEC_FLAG_SKIP_TRIGGERS 0x0010 /* skip AfterTrigger calls */ #define EXEC_FLAG_WITH_OIDS 0x0020 /* force OIDs in returned tuples */ #define EXEC_FLAG_WITHOUT_OIDS 0x0040 /* force no OIDs in returned tuples */ #define EXEC_FLAG_WITH_NO_DATA 0x0080 /* rel scannability doesn't matter */ extern inline bool is_errmodule_enable(int elevel, ModuleId mod_id); #define STREAM_LOG(level, format, ...) \ do { \ if (is_errmodule_enable(level, MOD_STREAM)) { \ ereport(level, (errmodule(MOD_STREAM), errmsg(format, ##__VA_ARGS__), ignore_interrupt(true))); \ } \ } while (0) #define MEMCTL_LOG(level, format, ...) \ do { \ if (is_errmodule_enable(level, MOD_MEM)) { \ ereport(level, (errmodule(MOD_MEM), errmsg(format, ##__VA_ARGS__), ignore_interrupt(true))); \ } \ } while (0) #ifdef USE_ASSERT_CHECKING #define EARLY_FREE_LOG(A) #else #define EARLY_FREE_LOG(A) #endif #ifdef USE_ASSERT_CHECKING #define RECURSIVE_LOG(level, format, ...) \ do { \ ereport(level, (errmsg(format, ##__VA_ARGS__))); \ } while (0) #else #define RECURSIVE_LOG(level, format, ...) \ do { \ ereport(DEBUG1, (errmsg(format, ##__VA_ARGS__))); \ } while (0) #endif #define SET_DOP(dop) (dop > 1 ? dop : 1) /* * Calculate the memory restriction in each thread. * And the memeory in each thread must be larger than 64K. */ #define SET_NODEMEM(opmem, dop) \ ((opmem > 0 ? opmem : u_sess->attr.attr_memory.work_mem) / \ ((opmem > 0 ? opmem : u_sess->attr.attr_memory.work_mem) > (SET_DOP(dop) * 64) ? SET_DOP(dop) : 1)) #define SET_NUMGROUPS(node) \ (node->numGroups / SET_DOP(node->plan.dop) > 0 ? node->numGroups / SET_DOP(node->plan.dop) : 1) #define HAS_INSTR(node, dnonly) \ (!dnonly || IS_PGXC_DATANODE) && u_sess->instr_cxt.global_instr != NULL && (node)->ps.instrument != NULL /* * ExecEvalExpr was formerly a function containing a switch statement; * now it's just a macro invoking the function pointed to by an ExprState * node. Beware of double evaluation of the ExprState argument! */ #define ExecEvalExpr(expr, econtext, isNull, isDone) ((*(expr)->evalfunc)(expr, econtext, isNull, isDone)) /* * recursive union macro */ #define INVALID_RU_PLANNODE_ID 0 #define EXEC_IN_RECURSIVE_MODE(x) (((Plan*)x)->recursive_union_plan_nodeid != INVALID_RU_PLANNODE_ID) /* Hook for plugins to get control in ExecutorStart() */ typedef void (*ExecutorStart_hook_type)(QueryDesc* queryDesc, int eflags); extern THR_LOCAL PGDLLIMPORT ExecutorStart_hook_type ExecutorStart_hook; /* Hook for plugins to get control in ExecutorRun() */ typedef void (*ExecutorRun_hook_type)(QueryDesc* queryDesc, ScanDirection direction, long count); extern THR_LOCAL PGDLLIMPORT ExecutorRun_hook_type ExecutorRun_hook; /* Hook for plugins to get control in ExecutorFinish() */ typedef void (*ExecutorFinish_hook_type)(QueryDesc* queryDesc); extern THR_LOCAL PGDLLIMPORT ExecutorFinish_hook_type ExecutorFinish_hook; /* Hook for plugins to get control in ExecutorEnd() */ typedef void (*ExecutorEnd_hook_type)(QueryDesc* queryDesc); extern THR_LOCAL PGDLLIMPORT ExecutorEnd_hook_type ExecutorEnd_hook; /* Hook for plugins to get control in ExecCheckRTPerms() */ typedef bool (*ExecutorCheckPerms_hook_type)(List*, bool); extern THR_LOCAL PGDLLIMPORT ExecutorCheckPerms_hook_type ExecutorCheckPerms_hook; /* * prototypes from functions in execAmi.c */ extern void ExecReScan(PlanState* node); extern void ExecMarkPos(PlanState* node); extern void ExecRestrPos(PlanState* node); extern bool ExecSupportsMarkRestore(NodeTag plantype); extern bool ExecSupportsBackwardScan(Plan* node); extern bool ExecMaterializesOutput(NodeTag plantype); /* * prototypes from functions in execCurrent.c */ extern bool execCurrentOf(CurrentOfExpr* cexpr, ExprContext* econtext, Relation relation, ItemPointer current_tid, RelationPtr partitionOfCursor_tid); #ifdef PGXC ScanState* search_plan_tree(PlanState* node, Oid table_oid); #endif /* * prototypes from functions in execGrouping.c */ extern bool execTuplesMatch(TupleTableSlot* slot1, TupleTableSlot* slot2, int numCols, AttrNumber* matchColIdx, FmgrInfo* eqfunctions, MemoryContext evalContext); extern bool execTuplesUnequal(TupleTableSlot* slot1, TupleTableSlot* slot2, int numCols, AttrNumber* matchColIdx, FmgrInfo* eqfunctions, MemoryContext evalContext); extern FmgrInfo* execTuplesMatchPrepare(int numCols, Oid* eqOperators); extern void execTuplesHashPrepare(int numCols, Oid* eqOperators, FmgrInfo** eqFunctions, FmgrInfo** hashFunctions); extern TupleHashTable BuildTupleHashTable(int numCols, AttrNumber* keyColIdx, FmgrInfo* eqfunctions, FmgrInfo* hashfunctions, long nbuckets, Size entrysize, MemoryContext tablecxt, MemoryContext tempcxt, int workMem); extern TupleHashEntry LookupTupleHashEntry( TupleHashTable hashtable, TupleTableSlot* slot, bool* isnew, bool isinserthashtbl = true); extern TupleHashEntry FindTupleHashEntry( TupleHashTable hashtable, TupleTableSlot* slot, FmgrInfo* eqfunctions, FmgrInfo* hashfunctions); /* * prototypes from functions in execJunk.c */ extern JunkFilter* ExecInitJunkFilter(List* targetList, bool hasoid, TupleTableSlot* slot, TableAmType tam = TAM_HEAP); extern JunkFilter* ExecInitJunkFilterConversion(List* targetList, TupleDesc cleanTupType, TupleTableSlot* slot); extern AttrNumber ExecFindJunkAttribute(JunkFilter* junkfilter, const char* attrName); extern AttrNumber ExecFindJunkAttributeInTlist(List* targetlist, const char* attrName); extern Datum ExecGetJunkAttribute(TupleTableSlot* slot, AttrNumber attno, bool* isNull); extern TupleTableSlot* ExecFilterJunk(JunkFilter* junkfilter, TupleTableSlot* slot); extern void ExecSetjunkFilteDescriptor(JunkFilter* junkfilter, TupleDesc tupdesc); #ifdef PGXC extern List* ExecFindJunkPrimaryKeys(List* targetlist); #endif extern VectorBatch* BatchExecFilterJunk(JunkFilter* junkfilter, VectorBatch* batch); extern void BatchCheckNodeIdentifier(JunkFilter* junkfilter, VectorBatch* batch); extern int ExecGetPlanNodeid(void); /* * prototypes from functions in execMain.c */ extern void ExecutorStart(QueryDesc* queryDesc, int eflags); extern void standard_ExecutorStart(QueryDesc* queryDesc, int eflags); extern void ExecutorRun(QueryDesc* queryDesc, ScanDirection direction, long count); extern void standard_ExecutorRun(QueryDesc* queryDesc, ScanDirection direction, long count); extern void ExecutorFinish(QueryDesc* queryDesc); extern void standard_ExecutorFinish(QueryDesc* queryDesc); extern void ExecutorEnd(QueryDesc* queryDesc); extern void standard_ExecutorEnd(QueryDesc* queryDesc); extern void ExecutorRewind(QueryDesc* queryDesc); extern bool ExecCheckRTPerms(List* rangeTable, bool ereport_on_violation); extern void CheckValidResultRel(Relation resultRel, CmdType operation); extern void InitResultRelInfo( ResultRelInfo* resultRelInfo, Relation resultRelationDesc, Index resultRelationIndex, int instrument_options); extern ResultRelInfo* ExecGetTriggerResultRel(EState* estate, Oid relid); extern bool ExecContextForcesOids(PlanState* planstate, bool* hasoids); extern void ExecConstraints(ResultRelInfo* resultRelInfo, TupleTableSlot* slot, EState* estate); extern ExecRowMark* ExecFindRowMark(EState* estate, Index rti); extern ExecAuxRowMark* ExecBuildAuxRowMark(ExecRowMark* erm, List* targetlist); extern TupleTableSlot* EvalPlanQual( EState* estate, EPQState* epqstate, Relation relation, Index rti, ItemPointer tid, TransactionId priorXmax); extern HeapTuple heap_lock_updated( CommandId cid, Relation relation, int lockmode, ItemPointer tid, TransactionId priorXmax); extern void EvalPlanQualInit(EPQState* epqstate, EState* estate, Plan* subplan, List* auxrowmarks, int epqParam); extern void EvalPlanQualSetPlan(EPQState* epqstate, Plan* subplan, List* auxrowmarks); extern void EvalPlanQualSetTuple(EPQState* epqstate, Index rti, HeapTuple tuple); extern HeapTuple EvalPlanQualGetTuple(EPQState* epqstate, Index rti); #define EvalPlanQualSetSlot(epqstate, slot) ((epqstate)->origslot = (slot)) extern void EvalPlanQualFetchRowMarks(EPQState* epqstate); extern TupleTableSlot* EvalPlanQualNext(EPQState* epqstate); extern void EvalPlanQualBegin(EPQState* epqstate, EState* parentestate); extern void EvalPlanQualEnd(EPQState* epqstate); /* * prototypes from functions in execProcnode.c */ extern PlanState* ExecInitNode(Plan* node, EState* estate, int eflags); extern TupleTableSlot* ExecProcNode(PlanState* node); extern Node* MultiExecProcNode(PlanState* node); extern void ExecEndNode(PlanState* node); extern bool NeedStubExecution(Plan* plan); extern long ExecGetPlanMemCost(Plan* node); /* * prototypes from functions in execQual.c */ extern Datum GetAttributeByNum(HeapTupleHeader tuple, AttrNumber attrno, bool* isNull); extern Datum GetAttributeByName(HeapTupleHeader tuple, const char* attname, bool* isNull); extern Tuplestorestate* ExecMakeTableFunctionResult( ExprState* funcexpr, ExprContext* econtext, TupleDesc expectedDesc, bool randomAccess, FunctionScanState* node); extern Datum ExecEvalExprSwitchContext( ExprState* expression, ExprContext* econtext, bool* isNull, ExprDoneCond* isDone); extern ExprState* ExecInitExpr(Expr* node, PlanState* parent); extern ExprState* ExecPrepareExpr(Expr* node, EState* estate); extern bool ExecQual(List* qual, ExprContext* econtext, bool resultForNull); extern int ExecTargetListLength(List* targetlist); extern int ExecCleanTargetListLength(List* targetlist); extern TupleTableSlot* ExecProject(ProjectionInfo* projInfo, ExprDoneCond* isDone); extern TupleTableSlot* ExecScan(ScanState* node, ExecScanAccessMtd accessMtd, ExecScanRecheckMtd recheckMtd); extern void ExecAssignScanProjectionInfo(ScanState* node); extern void ExecScanReScan(ScanState* node); /* * prototypes from functions in execTuples.c */ extern void ExecInitResultTupleSlot(EState* estate, PlanState* planstate, TableAmType tam = TAM_HEAP); extern void ExecInitScanTupleSlot(EState* estate, ScanState* scanstate, TableAmType tam = TAM_HEAP); extern TupleTableSlot* ExecInitExtraTupleSlot(EState* estate, TableAmType tam = TAM_HEAP); extern TupleTableSlot* ExecInitNullTupleSlot(EState* estate, TupleDesc tupType); extern TupleDesc ExecTypeFromTL(List* targetList, bool hasoid, bool markdropped = false, TableAmType tam = TAM_HEAP); extern TupleDesc ExecCleanTypeFromTL(List* targetList, bool hasoid, TableAmType tam = TAM_HEAP); extern TupleDesc ExecTypeFromExprList(List* exprList, List* namesList, TableAmType tam = TAM_HEAP); extern void UpdateChangedParamSet(PlanState* node, Bitmapset* newchg); typedef struct TupOutputState { TupleTableSlot* slot; DestReceiver* dest; } TupOutputState; extern TupOutputState* begin_tup_output_tupdesc(DestReceiver* dest, TupleDesc tupdesc); extern void do_tup_output( TupOutputState* tstate, Datum* values, size_t values_len, const bool* isnull, size_t isnull_len); extern int do_text_output_multiline(TupOutputState* tstate, char* text); extern void end_tup_output(TupOutputState* tstate); /* * Write a single line of text given as a C string. * * Should only be used with a single-TEXT-attribute tupdesc. */ #define do_text_output_oneline(tstate, str_to_emit) \ do { \ Datum values_[1]; \ bool isnull_[1]; \ values_[0] = PointerGetDatum(cstring_to_text(str_to_emit)); \ isnull_[0] = false; \ do_tup_output(tstate, values_, 1, isnull_, 1); \ pfree(DatumGetPointer(values_[0])); \ } while (0) /* * prototypes from functions in execUtils.c */ extern EState* CreateExecutorState(void); extern void FreeExecutorState(EState* estate); extern ExprContext* CreateExprContext(EState* estate); extern ExprContext* CreateStandaloneExprContext(void); extern void FreeExprContext(ExprContext* econtext, bool isCommit); extern void ReScanExprContext(ExprContext* econtext); #define ResetExprContext(econtext) MemoryContextReset((econtext)->ecxt_per_tuple_memory) extern ExprContext* MakePerTupleExprContext(EState* estate); #define RuntimeBinding(func, strategy) (this->*func[strategy]) #define InvokeFp(func) (this->*func) /* Get an EState's per-output-tuple exprcontext, making it if first use */ #define GetPerTupleExprContext(estate) \ ((estate)->es_per_tuple_exprcontext ? (estate)->es_per_tuple_exprcontext : MakePerTupleExprContext(estate)) #define GetPerTupleMemoryContext(estate) (GetPerTupleExprContext(estate)->ecxt_per_tuple_memory) /* Reset an EState's per-output-tuple exprcontext, if one's been created */ #define ResetPerTupleExprContext(estate) \ do { \ if ((estate)->es_per_tuple_exprcontext) \ ResetExprContext((estate)->es_per_tuple_exprcontext); \ } while (0) /* Reset an Slot's per-output-tuple context, if one's been created */ #define ResetSlotPerTupleContext(slot) \ do { \ if ((slot) && (slot)->tts_per_tuple_mcxt) \ MemoryContextReset((slot)->tts_per_tuple_mcxt); \ } while (0) extern void ExecAssignExprContext(EState* estate, PlanState* planstate); extern void ExecAssignResultType(PlanState* planstate, TupleDesc tupDesc); extern void ExecAssignResultTypeFromTL(PlanState* planstate, TableAmType tam = TAM_HEAP); extern TupleDesc ExecGetResultType(PlanState* planstate); extern void ExecAssignVectorForExprEval(ExprContext* econtext); extern ProjectionInfo* ExecBuildProjectionInfo( List* targetList, ExprContext* econtext, TupleTableSlot* slot, TupleDesc inputDesc); extern void ExecAssignProjectionInfo(PlanState* planstate, TupleDesc inputDesc); extern void ExecAssignScanProjectionInfoWithVarno(ScanState* node, Index varno); extern void ExecFreeExprContext(PlanState* planstate); extern TupleDesc ExecGetScanType(ScanState* scanstate); extern void ExecAssignScanType(ScanState* scanstate, TupleDesc tupDesc); extern void ExecAssignScanTypeFromOuterPlan(ScanState* scanstate); extern bool ExecRelationIsTargetRelation(EState* estate, Index scanrelid); extern Relation ExecOpenScanRelation(EState* estate, Index scanrelid); extern void ExecCloseScanRelation(Relation scanrel); extern Partition ExecOpenScanParitition( EState* estate, Relation parent, PartitionIdentifier* partID, LOCKMODE lockmode); extern void ExecOpenIndices(ResultRelInfo* resultRelInfo, bool speculative); extern void ExecCloseIndices(ResultRelInfo* resultRelInfo); extern List* ExecInsertIndexTuples( TupleTableSlot* slot, ItemPointer tupleid, EState* estate, Relation targetPartRel, Partition p, int2 bucketId, bool* conflict); extern bool ExecCheckIndexConstraints(TupleTableSlot* slot, EState* estate, Relation targetRel, Partition p, int2 bucketId, ItemPointer conflictTid); extern bool check_exclusion_constraint(Relation heap, Relation index, IndexInfo* indexInfo, ItemPointer tupleid, Datum* values, const bool* isnull, EState* estate, bool newIndex, bool errorOK); extern void RegisterExprContextCallback(ExprContext* econtext, ExprContextCallbackFunction function, Datum arg); extern void UnregisterExprContextCallback(ExprContext* econtext, ExprContextCallbackFunction function, Datum arg); extern List* GetAccessedVarnoList(List* targetList, List* qual); extern ProjectionInfo* ExecBuildVecProjectionInfo( List* targetList, List* nt_qual, ExprContext* econtext, TupleTableSlot* slot, TupleDesc inputDesc); extern bool tlist_matches_tupdesc(PlanState* ps, List* tlist, Index varno, TupleDesc tupdesc); extern int PthreadMutexLock(ResourceOwner owner, pthread_mutex_t* mutex, bool trace = true); extern int PthreadMutexTryLock(ResourceOwner owner, pthread_mutex_t* mutex, bool trace = true); extern int PthreadMutexUnlock(ResourceOwner owner, pthread_mutex_t* mutex, bool trace = true); extern bool executorEarlyStop(); extern void ExecEarlyFree(PlanState* node); extern void ExecEarlyFreeBody(PlanState* node); extern void ExecReSetRecursivePlanTree(PlanState* node); extern void ExplainNodePending(PlanState* result_plan); extern void ExplainNodeFinish(PlanState* result_plan, PlannedStmt* pstmt, TimestampTz current_time, bool is_pending); extern void ExecCopyDataFromDatum(PLpgSQL_datum** datums, int dno, Cursor_Data* target_cursor); extern void ExecCopyDataToDatum(PLpgSQL_datum** datums, int dno, Cursor_Data* target_cursor); // AutoMutexLock // Auto object for non-recursive pthread_mutex_t lock // class AutoMutexLock { public: AutoMutexLock(pthread_mutex_t* mutex, bool trace = true) : m_mutex(mutex), m_fLocked(false), m_trace(trace), m_owner(t_thrd.utils_cxt.CurrentResourceOwner) {} ~AutoMutexLock() { unLock(); } inline void lock() { // Guard against recursive lock // if (!m_fLocked) { int ret = 0; ret = PthreadMutexLock(m_owner, m_mutex, m_trace); m_fLocked = (ret == 0 ? true : false); if (!m_fLocked) { /* this should never happen, system may be completely in a mess */ if (ErrorContext == NULL) { write_stderr(_("ERROR: pthread mutex lock failed, query id %lu: %s\n"), u_sess->debug_query_id, strerror(ret)); abort(); } else ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("pthread mutex lock failed: %s", strerror(ret)))); } } } inline bool TryLock() { // Guard against recursive lock // if (!m_fLocked) { m_fLocked = (PthreadMutexTryLock(m_owner, m_mutex, m_trace) == 0 ? true : false); return m_fLocked; } return false; } inline void unLock() { if (m_fLocked) { int ret = 0; if (t_thrd.utils_cxt.CurrentResourceOwner == NULL) m_owner = NULL; ret = PthreadMutexUnlock(m_owner, m_mutex, m_trace); m_fLocked = (ret == 0 ? false : true); if (m_fLocked) { /* this should never happen, system may be completely in a mess */ if (ErrorContext == NULL) { write_stderr(_("ERROR: pthread mutex unlock failed, query id %lu: %s\n"), u_sess->debug_query_id, strerror(ret)); abort(); } else ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("pthread mutex unlock failed: %s", strerror(ret)))); } } } private: pthread_mutex_t* m_mutex; bool m_fLocked; bool m_trace; ResourceOwner m_owner; }; #endif /* EXECUTOR_H */