转载来自:http://www.newsmth.net/nForum/#!article/Database/122316
例如一条查询语句
select person.id from department;
数据库底层是如何实现的呢
****************************************************************************************
*** 位于tcop目录下的函数 ***
****************************************************************************************
exec_simple_query (tcop/postgres.c)
|->pgstat_report_activity (postmaster/pgstat.c)
|->start_xact_command (*)
|->drop_unnamed_stmt (*)
|->MemoryContextSwitchTo (utils/palloc.h) (内存上下文切换到MessageContext)
|->pg_parse_query (*) (对查询串做basic parse,获得raw parse tree)
|->(根据log_statement配置往日志中输出语句)
|->MemoryContextSwitchTo (utils/palloc.h) (切换到以前的内存上下文)
|->foreach(parsetree_item, parsetree_list) (处理每个parse tree)
| |->CreateCommandTag (tcop/utility.c) (创建命令tag)
| |->set_ps_display (utils/misc/pg_status.c) (在ps中显示命令tag)
| |->BeginCommand (tcop/dest.c)
| |->(检查事务状态,如果是aborted则除了ABORT/COMMIT,其他语句都报错)
| |->start_xact_command (*)
| |->CHECK_FOR_INTERRUPTS
| |->if (analyze_requires_snapshot(parsetree)) (parser/analyze.c) (parse analyze是否需要快照)
| | |->PushActiveSnapshot(GetTransactionSnapshot()) (utils/time/snapmgr.c) (获取并设置快照)
| |->(OK to analyze,rewrite and plan this query)
| |->MemoryContextSwitchTo (切换到MessageContext内存上下文)\
| |->pg_analyze_and_rewrite (*) (analyze and rewrite parsetree,获得querytree_list)
| |->pg_plan_queries (*) (plan querytree_list,获得plantree_list)
| |->PopActiveSnapshot (utils/time/snapmgr.c)
| |->CHECK_FOR_INTERRUPTS
| |->CreatePortal (utils/mmgr/portalmem.c) (创建匿名portal,用于运行查询,设为invisible,这样就不会在pg_cursors中显示)
| |->PortalDefineQuery (utils/mmgr/portalmem.c) (设置portal中的各项)
| |->PortalStart (tcop/pquery.c) (准备portal运行)
| |->MemoryContextSwitchTo (切换到以前的内存上下文)
| |->PortalRun (tcop/pquery.c) (运行portal中的查询)
| |->PortalDrop (utils/mmgr/portalmem.c)
| |->EndCommand (tcop/dest.c)
|
|->finish_xact_command (*)
|->(根据log_duration配置往日志输出语句执行信息)
exec_parse_message (tcop/postgres.c)
|->pgstat_report_activity (postmaster/pgstat.c)
|->set_ps_display (utils/misc/pg_status.c)
|->start_xact_command (*)
|->(检查是否是命名语句)
| |*->(is_named 命名语句)
| | |->MemoryContextSwitchTo (切换到MessageContext内存上下文)
| |*->(not is_named 匿名语句)
| |->drop_unnamed_stmt (*)
| |->AllocSetContextCreate (utils/mmgr/aset.c) (创建匿名语句内存上下文)
| |->MemoryContextSwitchTo (切换到匿名语句内存上下文)
|->pg_parse_query (*) (parse query_string,获得parsetree_list)
|->(检查是否包含多条语句,如果多条就报错)
|->if (parsetree_list != NIL)
| |->CreateCommandTag (tcop/utility.c)
| |->(检查事务状态,如果是aborted则除了ABORT/COMMIT,其他语句都报错)
| |->CreateCachedPlan (utils/cache/plancache.c) (创建并初始化CachedPlanSource)
| |->(检查analyze是否需要快照,如果需要则获得并设置当前快照)
| |->parse_analyze_varparams (parser/analyze.c) (analyze parsetree,获得Query)
| |->(检查参数类型是否已确定)
| |->pg_rewrite_query (*) (rewrite query,获得querytree_list)
| |->PopActiveSnapshot (utils/time/snapmgr.c)
|->CompleteCachedPlan (最后设置CachedPlanSource)
|->CHECK_FOR_INTERRUPTS
|->(检查是否是命名语句)
| |*->(is_named 命名语句)
| | |->StorePreparedStatement (commands/prepare.c) (保存为prepared语句)
| |*->(not is_named 匿名语句)
| |->SaveCachedPlan (utils/cache/plancache.c)
|->MemoryContextSwitchTo (切换到以前的内存上下文)
|->(根据log_duration配置往日志输出语句执行信息)
exec_bind_message (tcop/postgres.c)
|->(从客户端获得portal_name和stmt_name)
|->(如果是命名语句则从中获得CachedPlanSource,否则直接从unnamed_stmt_psrc获得CachedPlanSource)
|->pgstat_report_activity (postmaster/pgstat.c)
|->set_ps_display (utils/misc/pg_status.c)
|->start_xact_command (*)
|->MemoryContextSwitchTo (切换到MessageContext内存上下文)
|->(从客户端获得参数格式和参数个数)
|->CreatePortal (utils/mmgr/portalmem.c)
|->MemoryContextSwitchTo (切换到portal使用的内存上下文)
|->(如果需要则设置快照)
|->(从客户端获得参数值,然后调用相应类型的input/receive函数)
|->MemoryContextSwitchTo (切换到以前的内存上下文)
|->(从客户端获得result format代码)
|->GetCachedPlan (utils/cache/plancache.c) (从CachedPlanSource获得CachedPlan)
|->PortalDefineQuery (utils/mmgr/portalmem.c)
|->PopActiveSnapshot (utils/time/snapmgr.c)
|->PortalStart (tcop/pquery.c)
|->PortalSetResultFormat (tcop/pquery.c)
|->(根据log_duration配置往日志输出语句执行信息)
exec_execute_message (tcop/postgres.c)
|->GetPortalByName (utils/mmgr/portalmem.c)
|->pgstat_report_activity (postmaster/pgstat.c)
|->set_ps_display (utils/misc/pg_status.c)
|->BeginCommand (tcop/dest.c)
|->start_xact_command (*)
|->(根据log_statement配置往日志中输出信息)
|->(检查事务状态)
|->CHECK_FOR_INTERRUPTS
|->PortalRun (tcop/pquery.c)
|->(根据log_duration配置往日志输出语句执行信息)
exec_describe_statement_message (tcop/postgres.c)
|->
exec_describe_portal_message (tcop/postgres.c)
|->
pg_parse_query (tcop/postgres.c) (对查询串做raw parse,返回parsetree_list)
|->raw_parser (parser/parser.c)
pg_analyze_and_rewrite (tcop/postgres.c) (对parsetree analyze并且rewrite,获得querytree_list)
|->parse_analyze (parser/analyze.c)
|->pg_rewrite_query (*)
pg_rewrite_query (tcop/postgres.c)
|->(检查命令类型)
|*->(CMD_UTILITY)
| |->list_make1 (nodes/pg_list.h) (对于utility命令,不rewrite,直接返回)
|*->(其他)
|->QueryRewrite (rewrite/rewriteHandler.c)
pg_plan_queries (tcop/postgres.c)
|->(对querytree_list中的每个querytree做处理)
|->pg_plan_query (*) (如果是utility命令,则直接从Query中拷贝utilityStmt,否则调用pg_plan_query,其返回PlannedStmt)
|->planner (optimizer/plan/planner.c)
PortalStart (tcop/pquery.c)
|->ChoosePortalStrategy (*)
|->(根据PortalStrategy做分别处理)
|*->(PORTAL_ONE_SELECT)
| |->PushActiveSnapshot (utils/time/snapmgr.c)
| |->CreateQueryDesc (*) (创建并初始化QueryDesc)
| |->ExecutorStart (executor/execMain.c)
| |->PopActiveSnapshot (utils/time/snapmgr.c)
|*->(PORTAL_ONE_RETURNING)
|*->(PORTAL_ONE_MOD_WITH)
| |->(设置portal的tupDesc,以及其他项)
|*->(PORTAL_UTIL_SELECT)
| |->(设置portal的tupDesc,以及其他项)
|*->(PORTAL_MULTI_QUERY)
|->(NULL)
PortalRun (tcop/pquery.c)
|->(根据PortalStrategy做分别处理)
|*->(PORTAL_ONE_SELECT)
|*->(PORTAL_ONE_RETURNING)
|*->(PORTAL_ONE_MOD_WITH)
|*->(PORTAL_UTIL_SELECT)
| |->FillPortalStore (*) (如果不是PORTAL_ONE_SELECT,并且portal的holdStore没有初始化,则调用该函数去填充holdStore)
| |->PortalRunSelect (*)
|*->(PORTAL_MULTI_QUERY)
|->PortalRunMulti (*)
|->MarkPortalDone (utils/mmgr/portalmem.c)
PortalRunSelect (tcop/pquery.c)
|->(检查方向)
|*->(forward 向前读取)
| |->(检查holdStore)
| | |*->(hodlStore!=NULL)
| | | |->RunFromStore (*) (直接从holdStore中读取)
| | |*->(holdStore==NULL)
| | |->PushActiveSnapshot (utils/time/snapmgr.c)
| | |->ExecutorRun (executor/execMain.c)
| | |->PopActiveSnapshot (utils/time/snapmgr.c)
| |->(设置portal中位置相关的项)
|*->(not forward 向后读取)
| |->(检查holdStore)
| | |*->(hodlStore!=NULL)
| | | |->RunFromStore (*) (直接从holdStore中读取)
| | |*->(holdStore==NULL)
| | |->PushActiveSnapshot (utils/time/snapmgr.c)
| | |->ExecutorRun (executor/execMain.c)
| | |->PopActiveSnapshot (utils/time/snapmgr.c)
| |->(设置portal中位置相关的项)
FillPortalStore (tcop/pquery.c)
|->PortalCreateHoldStore (utils/mmgr/portalmem.c)
|->CreateDestReceiver (tcop/dest.c)
|->SetTuplestoreDestReceiverParams (executor/tstoreReceiver.c)
|->(根据PortalStrategy做分别处理)
|*->(PORTAL_ONE_RETURNING)
|*->(PORTAL_ONE_MOD_WITH)
| |->PortalRunMulti (*)
|*->(PORTAL_UTIL_SELECT)
|->PortalRunUtility (*)
PortalRunMulti (tcop/pquery.c)
|->(对portal中的每个计划语句做处理)
|->(检查计划语句类型)
| |*->(PlannedStmt)
| | |->ProcessQuery (*)
| |*->(utility语句)
| |->PortalRunUtility (*)
PortalRunUtility (tcop/pquery.c)
|->(根据utility语句类型设置快照)
|->ProcessUtility (*)
RunFromStore (tcop/pquery.c)
|->MakeSingleTupleTableSlot (executor/execTuples.c)
|->(调用dest的rStartup函数)
|->for(;;)
| |->tuplestore_gettupleslot (utils/sort/tuplestore.c)
| |->(调用dest的receiveSlot函数)
| |->ExecClearTuple (executor/execTuples.c)
|->(调用dest的rShutdown函数)
|->ExecDropSingleTupleTableSlot (executor/execTuples.c)
ProcessQuery (tcop/pquery.c)
|->CreateQueryDesc (*)
|->ExecutorStart (executor/execMain.c)
|->ExecutorRun (executor/execMain.c)
|->ExecutorFinish (xecutor/execMain.c)
|->ExecutorEnd (xecutor/execMain.c)
|->FreeQueryDesc (*)
ProcessUtility (tcop/utility.c)
|->if (ProcessUtility_hook) (如果设置了hook,则调用它)
|*->(*ProcessUtility_hook)
|*->standard_ProcessUtility (*)
standard_ProcessUtility (tcop/utility.c)
|->check_xact_readonly (*) (检查是否在只读事务中执行的是会修改数据库的命令)
|->switch (nodeTag(parsetree))
|*->(T_TransactionStmt)
| |->switch (stmt->kind)
| |*->(TRANS_STMT_BEGIN)
| |*->(TRANS_STMT_START)
| | |->BeginTransactionBlock (access/transam/xact.c)
| | |->(处理每个事务选项:transaction_isolation/transaction_read_only/transaction_deferrable)
| |*->(TRANS_STMT_COMMIT)
| | |->EndTransactionBlock (access/transam/xact.c)
| |*->(TRANS_STMT_PREPARE)
| | |->PreventCommandDuringRecovery (*)
| | |->PrepareTransactionBlock (access/transam/xact.c)
| |*->(TRANS_STMT_COMMIT_PREPARED)
| | |->PreventTransactionChain (access/transam/xact.c)
| | |->PreventCommandDuringRecovery (*)
| | |->FinishPreparedTransaction (access/transam/twophase.c)
| |*->(TRANS_STMT_ROLLBACK_PREPARED)
| | |->PreventTransactionChain (access/transam/xact.c)
| | |->PreventCommandDuringRecovery (*)
| | |->FinishPreparedTransaction (access/transam/twophase.c)
| |*->(TRANS_STMT_ROLLBACK)
| | |->UserAbortTransactionBlock (access/transam/xact.c)
| |*->(TRANS_STMT_SAVEPOINT)
| | |->RequireTransactionChain (access/transam/xact.c)
| | |->(获得savepoint_name)
| | |->DefineSavepoint (access/transam/xact.c)
| |*->(TRANS_STMT_RELEASE)
| | |->RequireTransactionChain (access/transam/xact.c)
| | |->ReleaseSavepoint (access/transam/xact.c)
| |*->(TRANS_STMT_ROLLBACK_TO)
| |->RequireTransactionChain (access/transam/xact.c)
| |->RollbackToSavepoint (access/transam/xact.c)
|*->(T_PlannedStmt)
| |->PerformCursorOpen (commands/portalcmds.c)
|*->(T_ClosePortalStmt)
| |->PerformPortalClose (commands/portalcmds.c)
|*->(T_FetchStmt)
| |->PerformPortalFetch (commands/portalcmds.c)
|*->(T_DoStmt)
| |->ExecuteDoStmt (commands/functioncmds.c)
|*->(T_CreateTableSpaceStmt)
| |->PreventTransactionChain (access/transam/xact.c)
| |->CreateTableSpace (commands/tablespace.c)
|*->(T_DropTableSpaceStmt)
| |->PreventTransactionChain (access/transam/xact.c)
| |->DropTableSpace (commands/tablespace.c)
|*->(T_AlterTableSpaceOptionsStmt)
| |->AlterTableSpaceOptions (commands/tablespace.c)
|*->(T_TruncateStmt)
| |->ExecuteTruncate (commands/tablecmds.c)
|*->(T_CommentStmt)
| |->CommentObject (commands/comment.c)
|*->(T_SecLabelStmt)
| |->ExecSecLabelStmt (commands/seclable.c)
|*->(T_CopyStmt)
| |->DoCopy (commands/copy.c)
|*->(T_PrepareStmt)
| |->CheckRestrictedOperation (*)
| |->PrepareQuery (commands/prepare.c)
|*->(T_ExecuteStmt)
| |->ExecuteQuery (commands/prepare.c)
|*->(T_DeallocateStmt)
| |->CheckRestrictedOperation (*)
| |->DeallocateQuery (commands/prepare.c)
|*->(T_GrantStmt)
| |->ExecuteGrantStmt (catalog/aclchk.c)
|*->(T_GrantRoleStmt)
| |->GrantRole (commands/user.c)
|*->(T_CreatedbStmt)
| |->PreventTransactionChain (access/transam/xact.c)
| |->createdb (commands/dbcommands.c)
|*->(T_AlterDatabaseStmt)
| |->AlterDatabase (commands/dbcommands.c)
|*->(T_AlterDatabaseSetStmt)
| |->AlterDatabaseSet (commands/dbcommands.c)
|*->(T_DropdbStmt)
| |->PreventTransactionChain (access/transam/xact.c)
| |->dropdb (commands/dbcommands.c)
|*->(T_NotifyStmt)
| |->PreventCommandDuringRecovery (*)
| |->Async_Notify (commands/async.c)
|*->(T_ListenStmt)
| |->PreventCommandDuringRecovery (*)
| |->CheckRestrictedOperation (*)
| |->Async_Listen (commands/async.c)
|*->(T_UnlistenStmt)
| |->PreventCommandDuringRecovery (*)
| |->CheckRestrictedOperation (*)
| |->if (stmt->conditionname)
| |*->Async_Unlisten (commands/async.c)
| |*->Async_UnlistenAll (commands/async.c)
|*->(T_LoadStmt)
| |->closeAllVfds (storage/file/fd.c)
| |->load_file (utils/fmgr/dfmgr.c)
|*->(T_ClusterStmt)
| |->PreventCommandDuringRecovery (*)
| |->cluster (commands/cluster.c)
|*->(T_VacuumStmt)
| |->PreventCommandDuringRecovery (*)
| |->vacuum (commands/vacuum.c)
|*->(T_ExplainStmt)
| |->ExplainQuery (commands/explain.c)
|*->(T_VariableSetStmt)
| |->ExecSetVariableStmt (utils/misc/guc.c)
|*->(T_VariableShowStmt)
| |->GetPGVariable (utils/misc/guc.c)
|*->(T_DiscardStmt)
| |->CheckRestrictedOperation (*)
| |->DiscardCommand (commands/discard.c)
|*->(T_CreateEventTrigStmt)
| |->CreateEventTrigger (commands/event_trigger.c)
|*->(T_AlterEventTrigStmt)
| |->AlterEventTrigger (commands/event_trigger.c)
|*->(T_CreateRoleStmt)
| |->CreateRole (commands/user.c)
|*->(T_AlterRoleStmt)
| |->AlterRole (commands/user.c)
|*->(T_AlterRoleSetStmt)
| |->AlterRoleSet (commands/user.c)
|*->(T_DropRoleStmt)
| |->DropRole (commands/user.c)
|*->(T_ReassignOwnedStmt)
| |->ReassignOwnedObjects (commands/user.c)
|*->(T_LockStmt)
| |->RequireTransactionChain (access/transam/xact.c)
| |->LockTableCommand (commands/lockcmds.c)
|*->(T_ConstraintsSetStmt)
| |->AfterTriggerSetState (commands/trigger.c)
|*->(T_CheckPointStmt)
| |->(检查是否是超级用户)
| |->RequestCheckpoint (postmaster/checkpointer.c)
|*->(T_ReindexStmt)
| |->PreventCommandDuringRecovery (*)
| |->switch (stmt->kind)
| |*->(OBJECT_INDEX)
| | |->ReindexIndex (commands/indexcmds.c)
| |*->(OBJECT_TABLE)
| |*->(OBJECT_MATVIEW)
| | |->ReindexTable (commands/indexcmds.c)
| |*->(OBJECT_DATABASE)
| |->PreventTransactionChain (access/transam/xact.c)
| |->ReindexDatabase (commands/indexcmds.c)
|*->(T_DropStmt)
| |->if (EventTriggerSupportsObjectType(stmt->removeType)) (commands/event_trigger.c)
| |*->ProcessUtilitySlow (*)
| |*->ExecDropStmt (*)
|*->(T_RenameStmt)
| |->if (EventTriggerSupportsObjectType(stmt->removeType)) (commands/event_trigger.c)
| |*->ProcessUtilitySlow (*)
| |*->ExecRenameStmt (commands/alter.c)
|*->(T_AlterObjectSchemaStmt)
| |->if (EventTriggerSupportsObjectType(stmt->removeType)) (commands/event_trigger.c)
| |*->ProcessUtilitySlow (*)
| |*->ExecAlterObjectSchemaStmt (commands/alter.c)
|*->(T_AlterOwnerStmt)
| |->if (EventTriggerSupportsObjectType(stmt->removeType)) (commands/event_trigger.c)
| |*->ProcessUtilitySlow (*)
| |*->ExecAlterOwnerStmt (commands/alter.c)
|*->(default)
| |->ProcessUtilitySlow (*) (该函数用于处理支持event trigger的语句)
ProcessUtilitySlow (tcop/utility.c)
|->
*************************************************************************************************
*** 位于parser/rewrite/optimizer/executor目录下的函数 ***
*************************************************************************************************
**************
** parser **
**************
raw_parser (parser/parser.c) (返回parsetree list(也就是各种语句列表))
|->scanner_init (parser/scan.c)
|->parser_init (parser/gram.c)
|->base_yyparse (parser/gram.c)
|->scanner_finish (parser/scan.c)
parse_analyze (parser/analyze.c) (analyze一个parsetree,返回一个Query)
|->make_parsestate (parser/parse_node.c)
|->if (numParams > 0)
| |*->parse_fixed_parameters (parser/parse_param.c)
|->transformTopLevelStmt (*)
|->if (post_parse_analyze_hook)
| |*->(*post_parse_analyze_hook)(...)
|->free_parsestate (parser/parse_node.c)
transformTopLevelStmt (parser/analyze.c)
|->(把select into语句变成create table as语句)
|->transformStmt (*)
transformStmt (parser/analyze.c)
|->switch (nodeTag(parseTree))
| |*->(T_InsertStmt)
| | |->transformInsertStmt (*)
| |*->(T_DeleteStmt)
| | |->transformDeleteStmt (*)
| |*->(T_UpdateStmt)
| | |->transformUpdateStmt (*)
| |*->(T_SelectStmt)
| | |->(根据不同类型的语句做分别处理)
| | |*->transformValuesClause (*) (VALUES列表)
| | |*->transformSelectStmt (*) (普通的SELECT语句)
| | |*->transformSetOperationStmt (*) (有集合操作的SELECT语句)
| |*->(T_DeclareCursorStmt)
| | |->transformDeclareCursorStmt (*)
| |*->(T_ExplainStmt)
| | |->transformExplainStmt (*)
| |*->(T_CreateTableAsStmt)
| | |->transformCreateTableAsStmt (*)
| |*->(default)
| |->(其他类型的语句不需要transform)
| |->result = makeNode(Query)
| |->result->commandType = CMD_UTILITY
| |->result->utilityStmt = (Node *) parseTree
|->(设置Query中的其他项)
*** 具体语句的transform ***
transformInsertStmt (parser/analyze.c)
|->if (stmt->withClause)
| |*->transformWithClause (parser/parse_cte.c)
|->setTargetTable (parser/parse_clause.c)
|->checkInsertTargets (parser/parse_target.c) (检查插入列)
|->(根据INSERT语句类型做分别处理)
| |*->(selectStmt == NULL : DEFAULT VALUES)
| | |->(把targetlist设为空)
| |*->(isGeneralSelect : 普通的SELECT语句)
| | |->make_parsestate (parser/parse_node.c)
| | |->transformStmt (*)
| | |->free_parsestate (parser/parse_node.c)
| | |->addRangeTableEntryForSubquery (parser/parse_relation.c)
| | |->(创建RangeTblRef,并把它添加到ParseState中的p_joinlist)
| | |->(从SELECT的targetList创建exprList)
| | |->transformInsertRow (*)
| |*->(list_length(selectStmt->valuesLists) > 1 : VALUES中有多个列表)
| | |->foreach(lc, selectStmt->valuesLists) (处理VALUES中的每个list,生成exprLists)
| | | |->transformExpressionList (parser/parse_target.c)
| | | |->(检查每个列表的长度是否相等)
| | | |->transformInsertRow (*)
| | | |->assign_list_collations (parser/parse_collate.c)
| | |->addRangeTableEntryForValues (parser/parse_relation.c)
| | |->(创建RangeTblRef,并把它添加到ParseState中的p_joinlist)
| | |->expandRTE (parser/parse_relation.c) (生成引用RTE的Var列表)
| |*->(VALUES中只有一个列表,也就是插入一行)
| |->transformExpressionList (parser/parse_target.c)
| |->transformInsertRow (*)
|->(从前面生成的exprLists生成targetList)
|->if (stmt->returningList) (如果有RETURNING子句)
| |->addRTEtoQuery (parser/parse_relation.c)
| |->transformReturningList (*)
|->(设置Query的range table)
|->makeFromExpr (nodes/makefuncs.c) (设置Query的join tree)
|->assign_query_collations (parser/parse_collate.c) (设置Query中所有表达式的collate信息)
transformDeleteStmt (parser/analyze.c)
|->if (stmt->withClause)
| |*->transformWithClause (parser/parse_cte.c)
|->setTargetTable (parser/parse_clause.c)
|->transformFromClause (parser/parse_clause.c) (transform USING子句,该子句和FROM类似)
|->transformWhereClause (parser/parse_clause.c)
|->transformReturningList (*)
|->(设置Query的range table)
|->makeFromExpr (nodes/makefuncs.c) (设置Query的join tree)
|->(设置Query的其他项)
|->if (pstate->p_hasAggs)
| |->parseCheckAggregates (parser/parse_agg.c)
|->assign_query_collations (parser/parse_collate.c)
transformUpdateStmt (parser/analyze.c)
|->if (stmt->withClause)
| |*->transformWithClause (parser/parse_cte.c)
|->setTargetTable (parser/parse_clause.c)
|->transformFromClause (parser/parse_clause.c)
|->transformTargetList (parser/parse_target.c)
|->transformWhereClause (parser/parse_clause.c)
|->transformReturningList (*)
|->(设置Query的range table)
|->makeFromExpr (nodes/makefuncs.c) (设置Query的join tree)
|->(从stmt->targetList更新上面获得的targetList中的所有TargetEntry)
|->assign_query_collations (parser/parse_collate.c)
transformValuesClause (parser/analyze.c)
|->if (stmt->withClause)
| |*->transformWithClause (parser/parse_cte.c)
|->foreach(lc, stmt->valuesLists) (处理每一行)
| |->transformExpressionList (parser/parse_target.c)
| |->(检查每个VALUES列表是否相同大小)
| |->(把VALUES从行结构变成列结构)
|->(对VALUES中的每一列列表做处理)
| |->select_common_type (parser/parse_coerce.c) (获得列的common类型)
| |->(把列列表中的所有列coerce_to_common_type) (parser/parse_coerce.c)
| |->select_common_collation (parser/parse_collate.c) (获得common collation)
|->(把VALUES从列结构变成行结构)
|->addRangeTableEntryForValues (parser/parse_relation.c)
|->addRTEtoQuery (parser/parse_relation.c)
|->expandRelAttrs (parser/parse_relation.c) (生成targetList)
|->transformSortClause (parser/parse_clause.c) (处理ORDER BY子句)
|->transformLimitClause (parser/parse_clause.c) (处理OFFSET子句)
|->transformLimitClause (parser/parse_clause.c) (处理LIMIT子句)
|->(设置Query的range table)
|->makeFromExpr (nodes/makefuncs.c) (设置Query的join tree)
|->assign_query_collations (parser/parse_collate.c)
transformSelectStmt (parser/analyze.c)
|->if (stmt->withClause)
| |*->transformWithClause (parser/parse_cte.c)
|->transformFromClause (parser/parse_clause.c) (处理FROM子句)
|->transformTargetList (parser/parse_target.c)
|->markTargetListOrigins (parser/parse_target.c)
|->transformWhereClause (parser/parse_clause.c) (处理WHERE子句)
|->transformWhereClause (parser/parse_clause.c) (处理HAVING子句)
|->transformSortClause (parser/parse_clause.c) (处理ORDER BY子句。因为GROUP BY/DISTINCT需要ORDER BY的结果,所以先处理ORDER BY)
|->transformGroupClause (parser/parse_clause.c) (处理GROUP BY子句)
|->(处理DISTINCT子句)
| |*->(没有DISTINCT子句)
| | |->(设置相关的项为空)
| |*->(DISTINCT子句)
| | |->transformDistinctClause (parser/parse_clause.c)
| |*->(DISTINCT ON子句)
| |->transformDistinctOnClause (parser/parse_clause.c)
|->transformLimitClause (parser/parse_clause.c) (处理OFFSET子句)
|->transformLimitClause (parser/parse_clause.c) (处理LIMIT子句)
|->transformWindowDefinitions (parser/parse_clause.c)
|
|->(设置Query的range table)
|->makeFromExpr (nodes/makefuncs.c) (设置Query的join tree)
|->(设置Query的其他项)
|->if (pstate->p_hasAggs || qry->groupClause || qry->havingQual)
| |->parseCheckAggregates (parser/parse_agg.c)
|->foreach(l, stmt->lockingClause)
| |->transformLockingClause (*) (处理FOR UPDATE/SHARE子句)
|->assign_query_collations (parser/parse_collate.c)
transformSetOperationStmt (parser/analyze.c)
|->if (stmt->withClause)
| |*->transformWithClause (parser/parse_cte.c)
|->transformSetOperationTree (*)
|->(找到最左边的SELECT对应的RangeTblRef)
|->(生成targetList)
|->addRangeTableEntryForJoin (parser/parse_relation.c)
|->addRTEtoQuery (parser/parse_relation.c)
|->transformSortClause (parser/parse_clause.c)
|->transformLimitClause (parser/parse_clause.c) (处理OFFSET子句)
|->transformLimitClause (parser/parse_clause.c) (处理LIMIT子句)
|
|->(设置Query的range table)
|->makeFromExpr (nodes/makefuncs.c) (设置Query的join tree)
|->(设置Query的其他项)
|->if (pstate->p_hasAggs || qry->groupClause || qry->havingQual)
| |->parseCheckAggregates (parser/parse_agg.c)
|->foreach(l, stmt->lockingClause)
| |->transformLockingClause (*) (处理FOR UPDATE/SHARE子句)
|->assign_query_collations (parser/parse_collate.c)
transformDeclareCursorStmt (parser/analyze.c)
|->transformStmt (*) (transform DECLARE语句中的SELECT语句)
|->(检查各种无效的情况)
|->stmt->query = NULL; (不再需要DeclareCursorStmt中的SELECT语句)
|->result->utilityStmt = (Node *) stmt; (设置Query中的utilityStmt为本DeclareCursorStmt)
transformExplainStmt (parser/analyze.c)
|->transformTopLevelStmt (*)
|
|->result = makeNode(Query);
|->result->commandType = CMD_UTILITY;
|->result->utilityStmt = (Node *) stmt;
transformCreateTableAsStmt (parser/analyze.c) (处理CREATE TABLE AS, SELECT ... INTO, CREATE MATERIALIZED VIEW)
|->transformStmt (*)
|->if (stmt->relkind == OBJECT_MATVIEW)
| |->(检查各种无效的情况)
| |->stmt->into->viewQuery = copyObject(query); (把query保存到IntoClause中)
|
|->result = makeNode(Query);
|->result->commandType = CMD_UTILITY;
|->result->utilityStmt = (Node *) stmt;
***************
** rewrite **
***************
QueryRewrite (rewrite/rewriteHandler.c)
|->RewriteQuery (*) (查询重写,获得querylist)
|->foreach(l, querylist)
| |->fireRIRrules (*)
| |->(设置queryId)
|->(在query list中查找并设置可以set tag的query)
RewriteQuery (rewrite/rewriteHandler.c)
|->foreach(lc1, parsetree->cteList) (处理WITH子句中的所有CTE)
| |->(如果CTE是SELECT,则直接跳过不处理)
| |->RewriteQuery (*) (重写CTE中的查询)
| |->(用重写后的query覆盖CTE中的查询,对CTE,当前只支持单条语句的DO INSTEAD规则,其他情况都报错)
|->(如果查询语句不是SELECT和UTILITY)
| |->rt_fetch (parser/parsetree.h) (获得resultRelation对应的RTE)
| |->heap_open (access/heap/heapam.c)
| |->(对不同语句类型做分别处理:重写targetList)
| | |*->(CMD_INSERT)
| | | |->(如果有VALUES,则获得其对应的RTE)
| | | |->if (values_rte)
| | | |*->(有VALUES对应的RTE)
| | | | |->rewriteTargetListIU (*) (重写INSERT/UPDATE的targetList)
| | | | |->rewriteValuesRTE (*) (重写VALUES,把DEFAULT变成缺省值表达式)
| | | |*->rewriteTargetListIU (*)
| | |*->(CMD_UPDATE)
| | | |->rewriteTargetListIU (*)
| | | |->rewriteTargetListUD (*) (重写UPDATE/DELETE的targetList)
| | |*->(CMD_DELETE)
| | | |->rewriteTargetListUD (*)
| | |*->(其他)
| | |->(报错)
| |->matchLocks (*) (获得匹配的规则,规则保存在RelationData结构中的rd_rules,其类型是RuleLock(rewrite/prs2lock.h))
| |->fireRules (*)
| |->if(没有INSTEAD规则,并且是个视图,该视图没有INSTEAD触发器) (该视图必须是可更新视图)
| | |->rewriteTargetView (*) (如果不是可更新视图则报错)
| | |->(把原来的query加到product_queries,加在前面或者后面)
| | |->(把instead和returning设为true)
| |->if (product_queries != NIL) (product_queries是在fireRules函数中生成的所有规则的动作语句)
| | |->(首先检查规则是否递归了)
| | |->(创建rewritten_event,并添加到列表rewritten_events的开头)
| | |->foreach(n, product_queries) (重写规则中的动作语句)
| | | |->RewriteQuery (*)
| | | |->(把重写结果加到rewritten列表中)
| | |->(从rewritten_events的开头删除rewritten_event)
| |->(如果有INSTEAD规则并且原始查询有RETURNING子句,而规则动作中没有RETURNING,则报错)
| |->heap_close (access/heap/heapam.c)
|->if (!instead) (如果没有unqualified INSTEAD规则)
| |->if (parsetree->commandType == CMD_INSERT)
| | |*->(把quad_product或者原来的query添加到rewritten列表的开头)
| | |*->(把quad_product或者原来的query添加到rewritten列表的结尾)
|->(如果重写结果包括多个非utility语句,并且原来的query中有CTE则报错)
fireRIRrules (rewrite/rewriteHandler.c)
|->while (rt_index < list_length(parsetree->rtable)) (处理每个RTE)
| |->rt_fetch (parser/parsetree.h)
| |->(如果是RTE_SUBQUERY)
| | |->fireRIRrules (*)
| | |->(continue)
| |->(如果不是RTE_RELATION,则跳过不处理)
| |->(如果是物化视图,则跳过不处理)
| |->(跳过没有在查询中引用到的RTE)
| |->(跳过在ApplyRetrieveRule中新增加的RTE)
| |->heap_open (access/heap/heapam.c)
| |->(收集所有SELECT规则)
| |->if (locks != NIL) (收集到的SELECT规则)
| | |->(检查是否有无穷递归)
| | |->foreach(l, locks) (处理每个规则)
| | | |->ApplyRetrieveRule (*)
| |->heap_close (access/heap/heapam.c)
|->foreach(lc, parsetree->cteList) (处理每个CTE)
| |->fireRIRrules (*)
|->if (parsetree->hasSubLinks)
| |->query_tree_walker (nodes/nodeFuncs.c) (fireRIRonSubLink (*))
ApplyRetrieveRule (rewrite/rewriteHandler.c)
|->(检查各种无效情况)
|->if (rt_index == parsetree->resultRelation) (可更新视图,已经经过rewriteTargetView处理)
| |->
|->get_parse_rowmark (parser/parse_relation.c)
|->AcquireRewriteLocks (*)
|->fireRIRrules (*)
|->(把对rule_action的fireRIRrule的结果作为子查询挂到当前RTE下)
|->markQueryForLocking (*)
************
** plan **
************
nodes/nodes.h : 包含Cost/Selectivity类型
nodes/primnodes.h : 包含在parse/plan/execute阶段都要用到的类型
nodes/plannodes.h : 查询计划节点类型
nodes/relation.h : planner的内部数据结构
planner (optimizer/plan/planner.c)
|->if (planner_hook)
|*->(*planner_hook)(...)
|*->standard_planner (*)
standard_planner (optimizer/plan/planner.c)
|->(创建并初始化PlannerGlobal结构)
|->subquery_planner (*)
|->(如果是SCROLLABLE CUROSOR,并且上面生成的计划不支持向后扫描,则在上面增加一个物化计划节点)
|->set_plan_references (optimizer/plan/setrefs.c)
|->forboth(lp, glob->subplans, lr, glob->subroots) (对所有subplan执行set_plan_references)
| |->set_plan_references (optimizer/plan/setrefs.c)
|->(创建并设置PlannedStmt,其中设置的值来自Query和PlannerGlobal)
subquery_planner (optimizer/plan/planner.c)
|->(创建并初始化PlannerInfo结构root)
|->if (hasRecursion)
| |*->root->wt_param_id = SS_assign_special_param(root); (optimizer/plan/subselect.c)
| |*->root->wt_param_id = -1;
|->if (parse->cteList)
| |->SS_process_ctes (optimizer/plan/subselect.c) (处理所有CTE)
|->if (parse->hasSubLinks)
| |->pull_up_sublinks (optimizer/prep/prepjointree.c) (处理WHERE和JOIN/ON中的EXISTS和ANY SubLink,把他们变换成SEMI/ANTI-SEMI JOIN)
|->inline_set_returning_functions (optimizer/prep/prepjointree.c) (inline集合返回函数:就是把rtable中的RTE_FUNCTION变成RTE_SUBQUERY)
| |->inline_set_returning_function (optimizer/util/clauses.c) (输入RTE_FUNCTION rte,返回函数对应的Query)
|->pull_up_subqueries (optimizer/prep/prepjointree.c) (处理query.jointree,上拉子查询)
|->if (parse->setOperations)
| |->flatten_simple_union_all (optimizer/prep/prepjointree.c) (把UNION ALL变换成Append)
|->(遍历所有RTE,检查是否有JOIN/LATERAL/OUTER JOIN)
|->preprocess_rowmarks (*) (生成PlanRowMark列表,即PlannerInfo.rowMarks)
|->expand_inherited_tables (optimizer/prep/prepunion.c) (处理继承表,生成Append)
|
|->preprocess_expression (*) (预处理parse->targetList)
|->preprocess_expression (*) (预处理parse->returningList)
|->preprocess_qual_conditions (*) (预处理parse->jointree)
|->preprocess_expression (*) (预处理parse->havingQual)
|->foreach(l, parse->windowClause)
| |->preprocess_expression (*) (预处理WindowClause子句中的startOffset)
| |->preprocess_expression (*) (预处理WindowClause子句中的endOffset)
|->preprocess_expression (*) (预处理parse->limitOffset)
|->preprocess_expression (*) (预处理parse->limitCount)
|->preprocess_expression (*) (预处理root->append_rel_list)
|->foreach(l, parse->rtable) (处理RTE内的表达式,需要处理的RTE:RTE_SUBQUERY/RTE_FUNCTION/RTE_VALUES)
| |->(根据RTE类型做分别处理)
| |*->(RTE_SUBQUERY)
| | |->flatten_join_alias_vars (optimizer/util/var.c) (只有当有joinRTE,并且RTE是lateral的时候才处理)
| |*->(RTE_FUNCTION)
| | |->preprocess_expression (*) (预处理rte->funcexpr)
| |*->(RTE_VALUES)
| |->preprocess_expression (*) (预处理rte->values_lists)
|->(处理havingQual中的每一项,分为三种情况:保留在havingQual中/移到WHERE中/移到WHERER同时保留在havingQual中)
|->if (hasOuterJoins)
| |->reduce_outer_joins (optimizer/prep/prepjointree.c) (试图把外连接变成内连接)
|
|->if (parse->resultRelation有效并且是个父表)
| |*->inheritance_planner (*)
| |*->(...)
| |->grouping_planner (*)
| |->if (parse->commandType != CMD_SELECT)
| |->make_modifytable (optimizer/plan/createplan.c)
|->if (list_length(glob->subplans) != num_old_subplans || root->glob->nParamExec > 0)
| |->SS_finalize_plan (optimizer/plan/subselect.c) (对sublink和parameter做最后的处理)
|
grouping_planner (optimizer/plan/planner.c) (处理group by/聚集等相关的planning,而基本的查询规划是由query_planner来处理的)
|->if (parse->limitCount || parse->limitOffset)
| |->preprocess_limit (*)
|->if (parse->setOperations)
| |*->(...)
| | |->if (parse->sortClause)
| | | |->tuple_fraction = 0.0;
| | |->plan_set_operations (optimizer/prep/prepunion.c) (对集合SQL语句进行规划)
| | |->make_pathkeys_for_sortclauses (optimizer/path/pathkeys.c)
| | |->postprocess_setop_tlist (*)
| | |->make_pathkeys_for_sortclauses (optimizer/path/pathkeys.c)
| |*->(...)
| |->if (parse->groupClause)
| | |->preprocess_groupclause (*)
| |->preprocess_targetlist (optimizer/prep/preptlist.c)
| |->if (parse->hasWindowFuncs)
| | |->find_window_functions (optimizer/util/clauses.c) (找到所有的窗口函数,具有相同winref的窗口函数[也就是引用同一个窗口子句的窗口函数]保存在同一个列表中)
| | |->if (wflists->numWindowFuncs > 0)
| | |*->select_active_windows (*) (获得所有活动的窗口子句,并且把具有相同的partition_by和order_by的窗口子句放在一起)
| | |*->parse->hasWindowFuncs = false;
| |->make_subplanTargetList (*)
| |->if (parse->hasAggs)
| | |->count_agg_clauses (optimizer/util/clauses.c) (处理targetlist)
| | |->count_agg_clauses (optimizer/util/clauses.c) (处理havingQual)
| | |->preprocess_minmax_aggregates (optimizer/plan/planagg.c)
| |->(设置standard_qp_extra结构,在standard_qp_callback函数中用到)
| |->query_planner (optimizer/plan/planmain.c)
| |->(...)
| | |*->if (parse->groupClause)
| | | |->choose_hashed_grouping (*) (是否用hash来处理GROUP的代价更低)
| | |*->else if (parse->distinctClause && sorted_path && !root->hasHavingQual && !parse->hasAggs && !activeWindows)
| | |->choose_hashed_distinct (*) (是否用hash来处理DISTINCT的代价更低)
| |->if (use_hashed_grouping || use_hashed_distinct || !sorted_path)
| | |*->best_path = cheapest_path;
| | |*->best_path = sorted_path;
| |->result_plan = optimize_minmax_aggregates (optimizer/plan/planagg.c) (检查是否可以通过索引来优化MINMAX聚集)
| |->
|
inheritance_planner (optimizer/plan/planner.c)
|->
query_planner (optimizer/plan/planmain.c)
|->(如果parse->jointree->fromlist为空,则直接创建一个ResultPath)
|->setup_simple_rel_arrays (optimizer/util/relnode.c) (初始化PlannerInfo中的simple_rel_array和simple_rte_array)
|->add_base_rels_to_query (optimizer/plan/initsplan.c) (对jointree中的所有base relation创建RelOptInfo,包括子表)
|
|->build_base_rel_tlists (optimizer/plan/initsplan.c) (把finalTargetList中的Var加到相应的base relation的RelOptInfo中,以及处理PlaceHolderVar)
|->find_placeholders_in_jointree (optimizer/util/placeholder.c) (搜索jointree中的PLV,创建相应的PlaceHolderInfo)
|->find_lateral_references (optimizer/plan/initsplan.c) (处理lateral RTE中的Var和PLV)
|->deconstruct_jointree (optimizer/plan/initsplan.c) (把jointree flatten,并且处理WHERE/JOIN ON中的qual)
|
|->reconsider_outer_join_clauses (optimizer/path/equivclass.c) ()
|->generate_base_implied_equalities (optimizer/path/equivclass.c) ()
|->(*qp_callback) (从EquivalenceClass生成query PathKeys)
|->fix_placeholder_input_needed_levels (optimizer/util/placeholder.c) ()
|->remove_useless_joins (optimizer/plan/analyzejoins.c) (遍历root->join_info_list,找到无用的连接然后删除)
|->add_placeholders_to_base_rels (optimizer/util/placeholder.c)
|->create_lateral_join_info (optimizer/plan/initsplan.c)
|->(计算涉及的baserel的磁盘页的总和)
|
|->make_one_rel (optimizer/path/allpaths.c) (找到所有的path,并且返回一个最后的join对应的RelOptInfo)
|
|->(...)
| |*->if (parse->groupClause)
| | |->get_sortgrouplist_exprs (optimizer/util/tlist.c)
| | |->estimate_num_groups (utils/adt/selfuncs.c)
| | |->(调整tuple_fraction)
| |*->else if (parse->hasAggs || root->hasHavingQual) (有聚集但是没有group by,那么只有一个group,所以必须读取所有元组)
| | |->tuple_fraction = 0.0;
| |*->else if (parse->distinctClause) (没有group by和聚集,只有distinct)
| | |->get_sortgrouplist_exprs (optimizer/util/tlist.c)
| | |->estimate_num_groups (utils/adt/selfuncs.c)
| | |->(调整tuple_fraction)
| |*->else
| |->(把tuple_fraction从绝对数变成比例)
|->get_cheapest_fractional_path_for_pathkeys (optimizer/path/pathkeys.c)
|->if (sortedpath) (检查如果对cheapest-total path进行排序,其结果比sorted_path还代价低,则丢弃前面获得的sorted_path)
| |->if (root->query_pathkeys == NIL || pathkeys_contained_in(root->query_pathkeys,cheapestpath->pathkeys))
| | |*->(设置sorted_path的代价和cheapest_path的代价一样)
| | |*->cost_sort (optimizer/path/costsize.c) (计算排序的代价)
| |->if (compare_fractional_path_costs(sortedpath, &sort_path, tuple_fraction) > 0)
| |->sortedpath = NULL;
|->(设置返回的cheapest_path和sorted_path)
make_one_rel (optimizer/path/allpaths.c)
|->(生成root->all_baserels)
|->set_base_rel_sizes (*) (设置baserel的大小估计值:行数和行宽度)
| |->for (rti = 1; rti < root->simple_rel_array_size; rti++)
| |->(如果不是baserel则跳过)
| |->set_rel_size (*)
|->set_base_rel_pathlists (*)
| |->for (rti = 1; rti < root->simple_rel_array_size; rti++)
| |->(如果不是baserel则跳过)
| |->set_rel_pathlist (*)
|->make_rel_from_joinlist (*) ()
make_rel_from_joinlist (optimizer/path/allpaths.c)
|->levels_needed = list_length(joinlist);
|->foreach(jl, joinlist) (创建与joinlist对应的RelOptInfo列表initial_rels)
| |->(...)
| | |*->if (IsA(jlnode, RangeTblRef))
| | | |->find_base_rel (optimizer/util/relnode.c)
| | |*->else if (IsA(jlnode, List))
| | | |->make_rel_from_joinlist (*)
| | |*->else
| | |->(报错)
| |->initial_rels = lappend(initial_rels, thisrel);
|->(...)
|*->if (levels_needed == 1)
| |->return (RelOptInfo *) linitial(initial_rels);
|*->else
|->root->initial_rels = initial_rels;
|->(...)
|*->if (join_search_hook)
| |->(*join_search_hook)(...) (调用hook)
|*->else if (enable_geqo && levels_needed >= geqo_threshold)
| |->geqo (optimizer/geqo/geqo_main.c)
|*->else
|->standard_join_search (*)
standard_join_search (optimizer/path/allpaths.c)
|->(分配List*数组root->join_rel_level,并且设置root->join_rel_level[1] = initial_rels)
|->for (lev = 2; lev <= levels_needed; lev++)
| |->join_search_one_level (optimizer/path/joinrels.c)
| |->foreach(lc, root->join_rel_level[lev])
| |->set_cheapest (optimizer/util/pathnode.c)
|
|->rel = (RelOptInfo *) linitial(root->join_rel_level[levels_needed]);
|->return rel;
join_search_one_level (optimizer/path/joinrels.c)
|->foreach(r, joinrels[level - 1]) (对于下一级的每个RelOptInfo)
| |->RelOptInfo *old_rel = (RelOptInfo *) lfirst(r);
| |->if (old_rel->joininfo != NIL || old_rel->has_eclass_joins || has_join_restriction(root, old_rel))
| |*->make_rels_by_clause_joins (*)
| | |->for_each_cell(l, other_rels)
| | |->if (!bms_overlap(old_rel->relids, other_rel->relids) &&
| | | (have_relevant_joinclause(root, old_rel, other_rel) || have_join_order_restriction(root, old_rel, other_rel)))
| | |*->make_join_rel (*)
| |*->make_rels_by_clauseless_joins (*)
| |->for_each_cell(l, other_rels)
| |->if (!bms_overlap(other_rel->relids, old_rel->relids))
| |*->make_join_rel (*)
|->for (k = 2;; k++) (考虑bushy join。此时不考虑笛卡尔积)
| |->int other_level = level - k;
| |->if (k > other_level)
| | |*->break;
| |->foreach(r, joinrels[k])
| |->if (old_rel->joininfo == NIL && !old_rel->has_eclass_joins && !has_join_restriction(root, old_rel))
| | |*->continue;
| |->if (k == other_level)
| | |*->other_rels = lnext(r);
| | |*->other_rels = list_head(joinrels[other_level]);
| |->for_each_cell(r2, other_rels)
| |->if (!bms_overlap(old_rel->relids, new_rel->relids))
| |*->if (have_relevant_joinclause(root, old_rel, new_rel) || have_join_order_restriction(root, old_rel, new_rel))
| |*->make_join_rel (*)
|->if (joinrels[level] == NIL)
| |->foreach(r, joinrels[level - 1])
| | |->make_rels_by_clauseless_joins (*)
| |->if (joinrels[level] == NIL && root->join_info_list == NIL && root->lateral_info_list == NIL)
| |->(报错)
make_join_rel (optimizer/path/joinrels.c)
|->join_is_legal (*) (检查正要进行的连接是否legal,如果不legal则直接返回NULL)
|->(如果需要,交换两边的rel)
|->(如果是内连接则初始化SpecialJoinInfo)
|->build_join_rel (optimizer/util/relnode.c) (如果joinrel已经存在则直接返回,否则创建新的)
|->(如果是dummy rel则返回)
|->switch (sjinfo->jointype)
| |*->case JOIN_INNER:
| | |->if (is_dummy_rel(rel1) || is_dummy_rel(rel2) || restriction_is_constant_false(restrictlist, false))
| | | |->mark_dummy_rel (*)
| | | |->break;
| | |->add_paths_to_joinrel (optimizer/path/joinpath.c)
| | |->add_paths_to_joinrel (optimizer/path/joinpath.c)
| |*->case JOIN_LEFT:
| |*->case JOIN_FULL:
| |*->case JOIN_SEMI:
| |*->case JOIN_ANTI:
| | |->
| |*->default:
| |->(报错)
join_is_legal (optimizer/path/joinrels.c)
|->
set_rel_size (optimizer/path/allpaths.c)
|->(...)
|*->if (rel->reloptkind == RELOPT_BASEREL && relation_excluded_by_constraints(root, rel, rte)) (如果通过约束检查,本表不需要扫描)
| |->set_dummy_rel_pathlist (*)
|*->else if (rte->inh)
| |->set_append_rel_size (*)
|*->else
|->switch (rel->rtekind)
|*->case RTE_RELATION:
| |->if (rte->relkind == RELKIND_FOREIGN_TABLE)
| |*->set_foreign_size (*)
| |*->set_plain_rel_size (*)
|*->case RTE_SUBQUERY:
| |->set_subquery_pathlist (*)
|*->case RTE_FUNCTION:
| |->set_function_size_estimates (optimizer/path/costsize.c)
|*->case RTE_VALUES:
| |->set_values_size_estimates (optimizer/path/costsize.c)
|*->case RTE_CTE:
| |->if (rte->self_reference)
| |*->set_worktable_pathlist (*)
| |*->set_cte_pathlist (*)
|*->default:
|->(报错)
set_rel_pathlist (optimizer/path/allpaths.c)
|->(...)
|*->if (IS_DUMMY_REL(rel))
| |->(空)
|*->else if (rte->inh)
| |->set_append_rel_pathlist (*)
|*->else
|->switch (rel->rtekind)
|*->case RTE_RELATION:
| |->if (rte->relkind == RELKIND_FOREIGN_TABLE)
| |*->set_foreign_pathlist (*)
| | |->(rel->fdwroutine->GetForeignPaths 调用FDW中的GetForeignPaths函数来生成path)
| | |->set_cheapest (optimizer/util/pathnode.c)
| |*->set_plain_rel_pathlist (*)
| |->add_path (optimizer/util/pathnode.c) (把 create_seqscan_path 的结果添加到RelOptInfo的pathlist中)
| |->create_index_paths (optimizer/path/indxpath.c) (创建并添加索引path)
| |->create_tidscan_paths (optimizer/path/tidpath.c) (创建并添加TID path)
| |->set_cheapest (optimizer/util/pathnode.c)
|*->case RTE_SUBQUERY:
| |->(空,已经在set_rel_size里面处理了)
|*->case RTE_FUNCTION:
| |->set_function_pathlist (*)
| |->add_path (optimizer/util/pathnode.c) (把 create_functionscan_path 的结果添加到RelOptInfo的pathlist中)
| |->set_cheapest (optimizer/util/pathnode.c)
|*->case RTE_VALUES:
| |->set_values_pathlist (*)
| |->add_path (optimizer/util/pathnode.c) (把 create_valuesscan_path 的结果添加到RelOptInfo的pathlist中)
| |->set_cheapest (optimizer/util/pathnode.c)
|*->case RTE_CTE:
| |->(空,已经在set_rel_size里面处理了)
|*->default:
|->(报错)
****************
** executor **
****************
ExecutorStart (executor/execMain.c)
|->
ExecutorRun (executor/execMain.c)
|->
ExecutorFinish (xecutor/execMain.c)
|->
ExecutorEnd (xecutor/execMain.c)
|->