您的位置:首页 > 数据库

转载:数据库查询过程是怎么实现的?

2014-12-25 06:56 573 查看
转载来自: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)

|->
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐