⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 readme

📁 PostgreSQL7.4.6 for Linux
💻
字号:
$Header: /cvsroot/pgsql/src/backend/executor/README,v 1.3 2002/12/15 16:17:45 tgl Exp $The Postgres Executor---------------------The executor processes a tree of "plan nodes".  The plan tree is essentiallya demand-pull pipeline of tuple processing operations.  Each node, whencalled, will produce the next tuple in its output sequence, or NULL if nomore tuples are available.  If the node is not a primitive relation-scanningnode, it will have child node(s) that it calls in turn to obtain inputtuples.Refinements on this basic model include:* Choice of scan direction (forwards or backwards).  Caution: this is notcurrently well-supported.  It works for primitive scan nodes, but not verywell for joins, aggregates, etc.* Rescan command to reset a node and make it generate its output sequenceover again.* Parameters that can alter a node's results.  After adjusting a parameter,the rescan command must be applied to that node and all nodes above it.There is a moderately intelligent scheme to avoid rescanning nodesunnecessarily (for example, Sort does not rescan its input if no parametersof the input have changed, since it can just reread its stored sorted data).The plan tree concept implements SELECT directly: it is only necessary todeliver the top-level result tuples to the client, or insert them intoanother table in the case of INSERT ... SELECT.  (INSERT ... VALUES ishandled similarly, but the plan tree is just a Result node with no sourcetables.)  For UPDATE, the plan tree selects the tuples that need to beupdated (WHERE condition) and delivers a new calculated tuple value for eachsuch tuple, plus a "junk" (hidden) tuple CTID identifying the target tuple.The executor's top level then uses this information to update the correcttuple.  DELETE is similar to UPDATE except that only a CTID need bedelivered by the plan tree.XXX a great deal more documentation needs to be written here...Plan Trees and State Trees--------------------------The plan tree delivered by the planner contains a tree of Plan nodes (structtypes derived from struct Plan).  Each Plan node may have expression treesassociated with it, to represent its target list, qualification conditions,etc.  During executor startup we build a parallel tree of identical structurecontaining executor state nodes --- every plan and expression node type hasa corresponding executor state node type.  Each node in the state tree has apointer to its corresponding node in the plan tree, plus executor state dataas needed to implement that node type.  This arrangement allows the plantree to be completely read-only as far as the executor is concerned: all datathat is modified during execution is in the state tree.  Read-only plan treesmake life much simpler for plan caching and reuse.Altogether there are four classes of nodes used in these trees: Plan nodes,their corresponding PlanState nodes, Expr nodes, and their correspondingExprState nodes.  (Actually, there are also List nodes, which are used as"glue" in all four kinds of tree.)Memory Management-----------------A "per query" memory context is created during CreateExecutorState();all storage allocated during an executor invocation is allocated in thatcontext or a child context.  This allows easy reclamation of storageduring executor shutdown --- rather than messing with retail pfree's andprobable storage leaks, we just destroy the memory context.In particular, the plan state trees and expression state trees describedin the previous section are allocated in the per-query memory context.To avoid intra-query memory leaks, most processing while a query runsis done in "per tuple" memory contexts, which are so-called because theyare typically reset to empty once per tuple.  Per-tuple contexts are usuallyassociated with ExprContexts, and commonly each PlanState node has its ownExprContext to evaluate its qual and targetlist expressions in.Query Processing Control Flow-----------------------------This is a sketch of control flow for full query processing:	CreateQueryDesc	ExecutorStart		CreateExecutorState			creates per-query context		switch to per-query context to run ExecInitNode		ExecInitNode --- recursively scans plan tree			CreateExprContext				creates per-tuple context			ExecInitExpr	ExecutorRun		ExecProcNode --- recursively called in per-query context			ExecEvalExpr --- called in per-tuple context			ResetExprContext --- to free memory	ExecutorEnd		ExecEndNode --- recursively releases resources		FreeExecutorState			frees per-query context and child contexts	FreeQueryDescPer above comments, it's not really critical for ExecEndNode to free anymemory; it'll all go away in FreeExecutorState anyway.  However, we do need tobe careful to close relations, drop buffer pins, etc, so we do need to scanthe plan state tree to find these sorts of resources.The executor can also be used to evaluate simple expressions without any Plantree ("simple" meaning "no aggregates and no sub-selects", though such mightbe hidden inside function calls).  This case has a flow of control like	CreateExecutorState		creates per-query context	CreateExprContext	-- or use GetPerTupleExprContext(estate)		creates per-tuple context	ExecPrepareExpr		switch to per-query context to run ExecInitExpr		ExecInitExpr	Repeatedly do:		ExecEvalExprSwitchContext			ExecEvalExpr --- called in per-tuple context		ResetExprContext --- to free memory	FreeExecutorState		frees per-query context, as well as ExprContext		(a separate FreeExprContext call is not necessary)EvalPlanQual (READ COMMITTED update checking)---------------------------------------------For simple SELECTs, the executor need only pay attention to tuples that arevalid according to the snapshot seen by the current transaction (ie, theywere inserted by a previously committed transaction, and not deleted by anypreviously committed transaction).  However, for UPDATE and DELETE it is notcool to modify or delete a tuple that's been modified by an open orconcurrently-committed transaction.  If we are running in SERIALIZABLEisolation level then we just raise an error when this condition is seen tooccur.  In READ COMMITTED isolation level, we must work a lot harder.The basic idea in READ COMMITTED mode is to take the modified tuplecommitted by the concurrent transaction (after waiting for it to commit,if need be) and re-evaluate the query qualifications to see if it wouldstill meet the quals.  If so, we regenerate the updated tuple (if we aredoing an UPDATE) from the modified tuple, and finally update/delete themodified tuple.  SELECT FOR UPDATE behaves similarly, except that its actionis just to mark the modified tuple for update by the current transaction.To implement this checking, we actually re-run the entire query from scratchfor each modified tuple, but with the scan node that sourced the originaltuple set to return only the modified tuple, not the original tuple or anyof the rest of the relation.  If this query returns a tuple, then themodified tuple passes the quals (and the query output is the suitablymodified update tuple, if we're doing UPDATE).  If no tuple is returned,then the modified tuple fails the quals, so we ignore it and continue theoriginal query.  (This is reasonably efficient for simple queries, but maybe horribly slow for joins.  A better design would be nice; one thought forfuture investigation is to treat the tuple substitution like a parameter,so that we can avoid rescanning unrelated nodes.)Note a fundamental bogosity of this approach: if the relation containingthe original tuple is being used in a self-join, the other instance(s) ofthe relation will be treated as still containing the original tuple, whereaslogical consistency would demand that the modified tuple appear in them too.But we'd have to actually substitute the modified tuple for the original,while still returning all the rest of the relation, to ensure consistentanswers.  Implementing this correctly is a task for future work.In UPDATE/DELETE, only the target relation needs to be handled this way,so only one special recheck query needs to execute at a time.  In SELECT FORUPDATE, there may be multiple relations flagged FOR UPDATE, so it's possiblethat while we are executing a recheck query for one modified tuple, we willhit another modified tuple in another relation.  In this case we "stack up"recheck queries: a sub-recheck query is spawned in which both the first andsecond modified tuples will be returned as the only components of theirrelations.  (In event of success, all these modified tuples will be markedfor update.)  Again, this isn't necessarily quite the right thing ... but insimple cases it works.  Potentially, recheck queries could get nested to thedepth of the number of FOR UPDATE relations in the query.It should be noted also that UPDATE/DELETE expect at most one tuple toresult from the modified query, whereas in the FOR UPDATE case it's possiblefor multiple tuples to result (since we could be dealing with a join inwhich multiple tuples join to the modified tuple).  We want FOR UPDATE tomark all relevant tuples, so we pass all tuples output by all the stackedrecheck queries back to the executor toplevel for marking.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -