久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

PostgreSQL源碼中NOT IN的作用是什么

共計(jì) 30439 個(gè)字符,預(yù)計(jì)需要花費(fèi) 77 分鐘才能閱讀完成。

本篇內(nèi)容主要講解“PostgreSQL 源碼中 NOT IN 的作用是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓丸趣 TV 小編來帶大家學(xué)習(xí)“PostgreSQL 源碼中 NOT IN 的作用是什么”吧!

一、數(shù)據(jù)結(jié)構(gòu)

SubPlanState
子計(jì)劃運(yùn)行期狀態(tài)

/* ----------------
 * SubPlanState node
 * ----------------
 */
typedef struct SubPlanState
 NodeTag type;
 SubPlan *subplan; /* expression plan node */
 struct PlanState *planstate; /* subselect plan s state tree */
 struct PlanState *parent; /* parent plan node s state tree */
 ExprState *testexpr; /*  組合表達(dá)式狀態(tài);state of combining expression */
 List *args; /*  參數(shù)表達(dá)式狀態(tài);states of argument expression(s) */
 HeapTuple curTuple; /* subplan 最近的元組;copy of most recent tuple from subplan */
 Datum curArray; /* most recent array from ARRAY() subplan */
 /* these are used when hashing the subselect s output: */
 TupleDesc descRight; /*  投影后的子查詢描述符;subselect desc after projection */
 ProjectionInfo *projLeft; /* for projecting lefthand exprs */
 ProjectionInfo *projRight; /* for projecting subselect output */
 TupleHashTable hashtable; /* hash table for no-nulls subselect rows */
 TupleHashTable hashnulls; /* hash table for rows with null(s) */
 bool havehashrows; /* true if hashtable is not empty */
 bool havenullrows; /* true if hashnulls is not empty */
 MemoryContext hashtablecxt; /* memory context containing hash tables */
 MemoryContext hashtempcxt; /* temp memory context for hash tables */
 ExprContext *innerecontext; /* econtext for computing inner tuples */
 AttrNumber *keyColIdx; /* control data for hash tables */
 Oid *tab_eq_funcoids; /* equality func oids for table
 * datatype(s) */
 Oid *tab_collations; /* collations for hash and comparison */
 FmgrInfo *tab_hash_funcs; /* hash functions for table datatype(s) */
 FmgrInfo *tab_eq_funcs; /* equality functions for table datatype(s) */
 FmgrInfo *lhs_hash_funcs; /* hash functions for lefthand datatype(s) */
 FmgrInfo *cur_eq_funcs; /* equality functions for LHS vs. table */
 ExprState *cur_eq_comp; /* equality comparator for LHS vs. table */
} SubPlanState;

SubPlan
子查詢計(jì)劃

/*
 * SubPlan - executable expression node for a subplan (sub-SELECT)
 *
 * The planner replaces SubLink nodes in expression trees with SubPlan
 * nodes after it has finished planning the subquery. SubPlan references
 * a sub-plantree stored in the subplans list of the toplevel PlannedStmt.
 * (We avoid a direct link to make it easier to copy expression trees
 * without causing multiple processing of the subplan.)
 *  查詢規(guī)劃器在完成子查詢的規(guī)劃后使用 SubPlan 節(jié)點(diǎn)替換表達(dá)式樹中的 SubLink 節(jié)點(diǎn)。 * SubPlan 引用了存儲(chǔ)在高層 PlannedStmt 中的 subplans 鏈表中的 sub-plantree。 * (避免使用直接鏈接,從而使得拷貝表達(dá)式樹相對(duì)比較簡(jiǎn)單) *
 * In an ordinary subplan, testexpr points to an executable expression
 * (OpExpr, an AND/OR tree of OpExprs, or RowCompareExpr) for the combining
 * operator(s); the left-hand arguments are the original lefthand expressions,
 * and the right-hand arguments are PARAM_EXEC Param nodes representing the
 * outputs of the sub-select. (NOTE: runtime coercion functions may be
 * inserted as well.) This is just the same expression tree as testexpr in
 * the original SubLink node, but the PARAM_SUBLINK nodes are replaced by
 * suitably numbered PARAM_EXEC nodes.
 *  常規(guī)情況下,testexpr 指向用于組合操作的可執(zhí)行表達(dá)式(OpExpr、OpExprs 的 AND/OR 樹或者 RowCompareExpr); *  左參數(shù)是原始的左表達(dá)式,右參數(shù)是 PARAM_EXEC 參數(shù)節(jié)點(diǎn)用以表示子查詢的輸出。 *  與原始 SubLink 節(jié)點(diǎn)的 testexpr 具有相同的表達(dá)式樹,但 PARAM_SUBLINK 節(jié)點(diǎn)則使用合適的已編號(hào) PARAM_EXEC 節(jié)點(diǎn)替代。 *
 * If the sub-select becomes an initplan rather than a subplan, the executable
 * expression is part of the outer plan s expression tree (and the SubPlan
 * node itself is not, but rather is found in the outer plan s initPlan
 * list). In this case testexpr is NULL to avoid duplication.
 *  如果子查詢成了 initplan 而不是 subplan,可執(zhí)行的表達(dá)式是外層 plan 表達(dá)式樹的一部分。 *  這種情況下,testexpr 為 NULL 以避免重復(fù)。 *
 * The planner also derives lists of the values that need to be passed into
 * and out of the subplan. Input values are represented as a list  args  of
 * expressions to be evaluated in the outer-query context (currently these
 * args are always just Vars, but in principle they could be any expression).
 * The values are assigned to the global PARAM_EXEC params indexed by parParam
 * (the parParam and args lists must have the same ordering). setParam is a
 * list of the PARAM_EXEC params that are computed by the sub-select, if it
 * is an initplan; they are listed in order by sub-select output column
 * position. (parParam and setParam are integer Lists, not Bitmapsets,
 * because their ordering is significant.)
 *  規(guī)劃器還派生了需要傳入和傳出子計(jì)劃的值的鏈表。 *  輸入值標(biāo)識(shí)位表達(dá)式的“args”鏈表,在外層查詢上下文中進(jìn)行解析。 * (這些 args 通常是 Vars,但原則上它們可以是任意表達(dá)式) *  這些值以 parParam 為索引給全局 PARAM_EXEC 參數(shù)賦值。 * setParam 是 PARAM_EXEC 參數(shù)鏈表,通過子查詢(如為 initplan)計(jì)算所得。 *  它們按子查詢輸出列的位置進(jìn)行排序組織為鏈表形式。 * (parParam 和 setParam 是整型鏈表,而不是 Bitmapsets 鏈表) *
 * Also, the planner computes startup and per-call costs for use of the
 * SubPlan. Note that these include the cost of the subquery proper,
 * evaluation of the testexpr if any, and any hashtable management overhead.
 *  同時(shí),規(guī)劃器計(jì)算 SubPlan 啟動(dòng)和每次調(diào)用的成本。注意:包括子查詢正常解析 testexpr 的成本以及哈希表管理成本。 */
typedef struct SubPlan
 Expr xpr;// 表達(dá)式
 /* Fields copied from original SubLink: */
 // 從 SubLink 中拷貝而來
 SubLinkType subLinkType; /* see above */
 /* The combining operators, transformed to an executable expression: */
 // 組合操作符, 轉(zhuǎn)換為可執(zhí)行的表達(dá)式
 Node *testexpr; /* OpExpr or RowCompareExpr expression tree */
 List *paramIds; /*  參數(shù) IDs;IDs of Params embedded in the above */
 /* Identification of the Plan tree to use: */
 //Plan tree 標(biāo)識(shí)
 int plan_id; /* Index (from 1) in PlannedStmt.subplans */
 /* Identification of the SubPlan for EXPLAIN and debugging purposes: */
 //EXPLAIN 和 debug 目的的 SubPlan 標(biāo)識(shí)
 char *plan_name; /* A name assigned during planning */
 /* Extra data useful for determining subplan s output type: */
 // 用于確定 subplan 輸出類型的額外信息
 Oid firstColType; /* subplan 結(jié)果的第一個(gè)列類型;Type of first column of subplan result */
 int32 firstColTypmod; /*  第一列的 Typmod;Typmod of first column of subplan result */
 Oid firstColCollation; /*  第一列的 Collation;Collation of first column of subplan
 * result */
 /* Information about execution strategy: */
 // 執(zhí)行階段的相關(guān)信息
 bool useHashTable; /*  是否使用哈希表存儲(chǔ)子查詢輸出;true to store subselect output in a hash
 * table (implies we are doing  IN) */
 bool unknownEqFalse; /*  如 OK 為 T, 如為未知?jiǎng)t為 F; 快速處理 null 值;true if it s okay to return FALSE when the
 * spec result is UNKNOWN; this allows much
 * simpler handling of null values */
 bool parallel_safe; /*  是否并行安全?is the subplan parallel-safe? */
 /* Note: parallel_safe does not consider contents of testexpr or args */
 /* Information for passing params into and out of the subselect: */
 // 用于給子查詢傳入和傳出參數(shù)的信息
 /* setParam and parParam are lists of integers (param IDs) */
 //setParam 和 parParam 是整型鏈表(param IDs)
 List *setParam; /* initplan subqueries have to set these
 * Params for parent plan */
 List *parParam; /* indices of input Params from parent plan */
 List *args; /*  以 parParam 值進(jìn)行傳遞的表達(dá)式;exprs to pass as parParam values */
 /* Estimated execution costs: */
 // 估算執(zhí)行成本
 Cost startup_cost; /* one-time setup cost */
 Cost per_call_cost; /* cost for each subplan evaluation */
} SubPlan;

SubLinkType
SubLink 類型

/*
 * SubLink
 *
 * A SubLink represents a subselect appearing in an expression, and in some
 * cases also the combining operator(s) just above it. The subLinkType
 * indicates the form of the expression represented:
 * EXISTS_SUBLINK EXISTS(SELECT ...)
 * ALL_SUBLINK (lefthand) op ALL (SELECT ...)
 * ANY_SUBLINK (lefthand) op ANY (SELECT ...)
 * ROWCOMPARE_SUBLINK (lefthand) op (SELECT ...)
 * EXPR_SUBLINK (SELECT with single targetlist item ...)
 * MULTIEXPR_SUBLINK (SELECT with multiple targetlist items ...)
 * ARRAY_SUBLINK ARRAY(SELECT with single targetlist item ...)
 * CTE_SUBLINK WITH query (never actually part of an expression)
 * For ALL, ANY, and ROWCOMPARE, the lefthand is a list of expressions of the
 * same length as the subselect s targetlist. ROWCOMPARE will *always* have
 * a list with more than one entry; if the subselect has just one target
 * then the parser will create an EXPR_SUBLINK instead (and any operator
 * above the subselect will be represented separately).
 * ROWCOMPARE, EXPR, and MULTIEXPR require the subselect to deliver at most
 * one row (if it returns no rows, the result is NULL).
 * ALL, ANY, and ROWCOMPARE require the combining operators to deliver boolean
 * results. ALL and ANY combine the per-row results using AND and OR
 * semantics respectively.
 * ARRAY requires just one target column, and creates an array of the target
 * column s type using any number of rows resulting from the subselect.
 *
 * SubLink is classed as an Expr node, but it is not actually executable;
 * it must be replaced in the expression tree by a SubPlan node during
 * planning.
 *
 * NOTE: in the raw output of gram.y, testexpr contains just the raw form
 * of the lefthand expression (if any), and operName is the String name of
 * the combining operator. Also, subselect is a raw parsetree. During parse
 * analysis, the parser transforms testexpr into a complete boolean expression
 * that compares the lefthand value(s) to PARAM_SUBLINK nodes representing the
 * output columns of the subselect. And subselect is transformed to a Query.
 * This is the representation seen in saved rules and in the rewriter.
 *
 * In EXISTS, EXPR, MULTIEXPR, and ARRAY SubLinks, testexpr and operName
 * are unused and are always null.
 *
 * subLinkId is currently used only for MULTIEXPR SubLinks, and is zero in
 * other SubLinks. This number identifies different multiple-assignment
 * subqueries within an UPDATE statement s SET list. It is unique only
 * within a particular targetlist. The output column(s) of the MULTIEXPR
 * are referenced by PARAM_MULTIEXPR Params appearing elsewhere in the tlist.
 *
 * The CTE_SUBLINK case never occurs in actual SubLink nodes, but it is used
 * in SubPlans generated for WITH subqueries.
 */
typedef enum SubLinkType
 EXISTS_SUBLINK,
 ALL_SUBLINK,
 ANY_SUBLINK,
 ROWCOMPARE_SUBLINK,
 EXPR_SUBLINK,
 MULTIEXPR_SUBLINK,
 ARRAY_SUBLINK,
 CTE_SUBLINK /* for SubPlans only */
} SubLinkType;

SubLink
SubLink 結(jié)構(gòu)體

typedef struct SubLink
 Expr xpr;
 SubLinkType subLinkType; /* see above */
 int subLinkId; /* ID (1..n); 0 if not MULTIEXPR */
 Node *testexpr; /* outer-query test for ALL/ANY/ROWCOMPARE */
 List *operName; /* originally specified operator name */
 Node *subselect; /* subselect as Query* or raw parsetree */
 int location; /* token location, or -1 if unknown */
} SubLink;

二、源碼解讀

ExecScanSubPlan

/*
 * ExecScanSubPlan: default case where we have to rescan subplan each time
 *  默認(rèn)情況下每次都不得不重新掃描 subplan
 */
static Datum
ExecScanSubPlan(SubPlanState *node,
 ExprContext *econtext,
 bool *isNull)
 SubPlan *subplan = node- subplan;// 子計(jì)劃
 PlanState *planstate = node- planstate;// 計(jì)劃運(yùn)行期狀態(tài)
 SubLinkType subLinkType = subplan- subLinkType;// 子鏈接類型
 MemoryContext oldcontext;// 原內(nèi)存上下文
 TupleTableSlot *slot;// 元組 slot
 Datum result;// 結(jié)果指針
 bool found = false; /*  如找到至少一個(gè)元組, 則返回 T;true if got at least one subplan tuple */
 ListCell *pvar;// 臨時(shí)變量
 ListCell *l;// 臨時(shí)變量
 ArrayBuildStateAny *astate = NULL;//
 /*
 * MULTIEXPR subplans, when  executed , just return NULL; but first we
 * mark the subplan s output parameters as needing recalculation. (This
 * is a bit of a hack: it relies on the subplan appearing later in its
 * targetlist than any of the referencing Params, so that all the Params
 * have been evaluated before we re-mark them for the next evaluation
 * cycle. But in general resjunk tlist items appear after non-resjunk
 * ones, so this should be safe.) Unlike ExecReScanSetParamPlan, we do
 * *not* set bits in the parent plan node s chgParam, because we don t
 * want to cause a rescan of the parent.
 *
 * MULTIEXPR 處理邏輯
 */
 if (subLinkType == MULTIEXPR_SUBLINK)
 {
 EState *estate = node- parent- state;
 foreach(l, subplan- setParam)
 { int paramid = lfirst_int(l);
 ParamExecData *prm =  (estate- es_param_exec_vals[paramid]);
 prm- execPlan = node;
 }
 *isNull = true;
 return (Datum) 0;
 }
 /* Initialize ArrayBuildStateAny in caller s context, if needed */
 // 數(shù)組
 if (subLinkType == ARRAY_SUBLINK)
 astate = initArrayResultAny(subplan- firstColType,
 CurrentMemoryContext, true);
 /*
 * We are probably in a short-lived expression-evaluation context. Switch
 * to the per-query context for manipulating the child plan s chgParam,
 * calling ExecProcNode on it, etc.
 */
 // 切換上下文
 oldcontext = MemoryContextSwitchTo(econtext- ecxt_per_query_memory);
 /*
 * Set Params of this plan from parent plan correlation values. (Any
 * calculation we have to do is done in the parent econtext, since the
 * Param values don t need to have per-query lifetime.)
 */
 // 通過父計(jì)劃相關(guān)值中設(shè)置子計(jì)劃參數(shù)
 Assert(list_length(subplan- parParam) == list_length(node- args));
 forboth(l, subplan- parParam, pvar, node- args)
 { int paramid = lfirst_int(l);
 ParamExecData *prm =  (econtext- ecxt_param_exec_vals[paramid]);
 prm- value = ExecEvalExprSwitchContext((ExprState *) lfirst(pvar),
 econtext,
  (prm- isnull));
 planstate- chgParam = bms_add_member(planstate- chgParam, paramid);
 }
 /*
 * Now that we ve set up its parameters, we can reset the subplan.
 */
 // 執(zhí)行 ReScan
 //Reset a plan node so that its output can be re-scanned.
 ExecReScan(planstate);
 /*
 * For all sublink types except EXPR_SUBLINK and ARRAY_SUBLINK, the result
 * is boolean as are the results of the combining operators. We combine
 * results across tuples (if the subplan produces more than one) using OR
 * semantics for ANY_SUBLINK or AND semantics for ALL_SUBLINK.
 * (ROWCOMPARE_SUBLINK doesn t allow multiple tuples from the subplan.)
 * NULL results from the combining operators are handled according to the
 * usual SQL semantics for OR and AND. The result for no input tuples is
 * FALSE for ANY_SUBLINK, TRUE for ALL_SUBLINK, NULL for
 * ROWCOMPARE_SUBLINK.
 *  除 EXPR_SUBLINK 和 ARRAY_SUBLINK 外的所有 sublink, 結(jié)果是布爾值(組合運(yùn)算符的結(jié)果).
 * PG 通過跨元組 (如子計(jì)劃產(chǎn)生多個(gè)元組) 合并結(jié)果, 對(duì)于 ANY_SUBLINK 使用 OR 語義,ALL_SUBLINK 則使用 AND 語義.
 * (ROWCOMPARE_SUBLINK 不允許子計(jì)劃返回多個(gè)元組)
 *  從組合操作符中返回的 NULL 遵循 SQL 中的 OR 和 AND 語義.
 *  如沒有輸入元組,ANY_SUBLINK 為 FALSE,ALL_SUBLINK 為 TRUE,ROWCOMPARE_SUBLINK 為 NULL.
 *
 * For EXPR_SUBLINK we require the subplan to produce no more than one
 * tuple, else an error is raised. If zero tuples are produced, we return
 * NULL. Assuming we get a tuple, we just use its first column (there can
 * be only one non-junk column in this case).
 *  對(duì)于 EXPR_SUBLINK, 需要 subplan 產(chǎn)生不超過一個(gè)元組, 否則報(bào)錯(cuò). 如果沒有元組產(chǎn)生, 返回 NULL.
 *  假定獲取到一個(gè)元組, 則使用第一個(gè)列(這種情況下只有一個(gè) non-junk 列).
 *
 * For ARRAY_SUBLINK we allow the subplan to produce any number of tuples,
 * and form an array of the first column s values. Note in particular
 * that we produce a zero-element array if no tuples are produced (this is
 * a change from pre-8.3 behavior of returning NULL).
 *  對(duì)于 ARRAY_SUBLINK, 允許 subplan 產(chǎn)生任意數(shù)目的元組, 使用第一個(gè)列值組成數(shù)組.
 *  特別注意的是如沒有元組產(chǎn)生則產(chǎn)生 0 個(gè)元素的數(shù)組(8.3 以前是返回 NULL).
 */
 result = BoolGetDatum(subLinkType == ALL_SUBLINK);//ALL 為 T, 否則為 F
 *isNull = false;
 for (slot = ExecProcNode(planstate);
 !TupIsNull(slot);
 slot = ExecProcNode(planstate))// 循環(huán)獲取元組, 直至沒有元組為 NULL(即已完成)
 {
 // 元組描述符
 TupleDesc tdesc = slot- tts_tupleDescriptor;
 Datum rowresult;// 結(jié)果
 bool rownull;// 是否為空?
 int col;// 列計(jì)數(shù)器
 ListCell *plst;// 臨時(shí)變量
 if (subLinkType == EXISTS_SUBLINK)//EXISTS
 {
 found = true;
 result = BoolGetDatum(true);
 break;
 }
 if (subLinkType == EXPR_SUBLINK)//EXPR 表達(dá)式
 {
 /* cannot allow multiple input tuples for EXPR sublink */
 if (found)
 ereport(ERROR,
 (errcode(ERRCODE_CARDINALITY_VIOLATION),
 errmsg(more than one row returned by a subquery used as an expression)));
 found = true;
 /*
 * We need to copy the subplan s tuple in case the result is of
 * pass-by-ref type --- our return value will point into this
 * copied tuple! Can t use the subplan s instance of the tuple
 * since it won t still be valid after next ExecProcNode() call.
 * node- curTuple keeps track of the copied tuple for eventual
 * freeing.
 */
 if (node- curTuple)
 heap_freetuple(node- curTuple);
 node- curTuple = ExecCopySlotHeapTuple(slot);
 result = heap_getattr(node- curTuple, 1, tdesc, isNull);
 /* keep scanning subplan to make sure there s only one tuple */
 continue;
 }
 if (subLinkType == ARRAY_SUBLINK)// 數(shù)組
 {
 Datum dvalue;
 bool disnull;
 found = true;
 /* stash away current value */
 Assert(subplan- firstColType == TupleDescAttr(tdesc, 0)- atttypid);
 dvalue = slot_getattr(slot, 1,  disnull);
 astate = accumArrayResultAny(astate, dvalue, disnull,
 subplan- firstColType, oldcontext);
 /* keep scanning subplan to collect all values */
 continue;
 }
 /* cannot allow multiple input tuples for ROWCOMPARE sublink either */
 if (subLinkType == ROWCOMPARE_SUBLINK   found)// 行比較
 ereport(ERROR,
 (errcode(ERRCODE_CARDINALITY_VIOLATION),
 errmsg(more than one row returned by a subquery used as an expression)));
 found = true;// 初始為 T
 /*
 * For ALL, ANY, and ROWCOMPARE sublinks, load up the Params
 * representing the columns of the sub-select, and then evaluate the
 * combining expression.
 *  對(duì)于 ALL,ANY 和 ROWCOMPARE 子鏈接, 加載表示子查詢列的 Params, 并解析組合表達(dá)式
 */
 col = 1;// 列從 1 計(jì)數(shù)
 foreach(plst, subplan- paramIds)// 循環(huán)遍歷子查詢參數(shù)
 { int paramid = lfirst_int(plst);
 ParamExecData *prmdata;
 prmdata =  (econtext- ecxt_param_exec_vals[paramid]);
 Assert(prmdata- execPlan == NULL);
 // 獲取參數(shù)值
 prmdata- value = slot_getattr(slot, col,  (prmdata- isnull));
 // 下一個(gè)列
 col++;
 }
 // 解析表達(dá)式
 rowresult = ExecEvalExprSwitchContext(node- testexpr, econtext,
  rownull);
 if (subLinkType == ANY_SUBLINK)
 {
 //ANY :  使用 OR 語義組合
 /* combine across rows per OR semantics */
 if (rownull)
 *isNull = true;
 else if (DatumGetBool(rowresult))
 { result = BoolGetDatum(true);
 *isNull = false;
 break; /* needn t look at any more rows */
 }
 }
 else if (subLinkType == ALL_SUBLINK)
 {
 //ALL :  使用 AND 語義
 /* combine across rows per AND semantics */
 if (rownull)
 *isNull = true;
 else if (!DatumGetBool(rowresult))
 { result = BoolGetDatum(false);
 *isNull = false;
 break; /* needn t look at any more rows */
 }
 }
 else
 {
 /* must be ROWCOMPARE_SUBLINK */
 // 這里一定是 ROWCOMPARE
 result = rowresult;
 *isNull = rownull;
 }
 }
 MemoryContextSwitchTo(oldcontext);
 if (subLinkType == ARRAY_SUBLINK)
 {
 /* We return the result in the caller s context */
 // 在調(diào)用者上下文中返回結(jié)果
 result = makeArrayResultAny(astate, oldcontext, true);
 }
 else if (!found)
 {
 /*
 * deal with empty subplan result. result/isNull were previously
 * initialized correctly for all sublink types except EXPR and
 * ROWCOMPARE; for those, return NULL.
 * subplan 沒有結(jié)果返回, 設(shè)置 result isNull 值
 */
 if (subLinkType == EXPR_SUBLINK ||
 subLinkType == ROWCOMPARE_SUBLINK)
 { result = (Datum) 0;
 *isNull = true;
 }
 }
 // 返回結(jié)果
 return result;
}

ExecProcNode
執(zhí)行輸入?yún)?shù) node 的 ExecProcNode 方法。

/* ----------------------------------------------------------------
 * ExecProcNode
 *
 * Execute the given node to return a(nother) tuple.
 * ----------------------------------------------------------------
 */
#ifndef FRONTEND
static inline TupleTableSlot *
ExecProcNode(PlanState *node)
 if (node- chgParam != NULL) /* something changed? */
 ExecReScan(node); /* let ReScan handle this */
 return node- ExecProcNode(node);
#endif

三、跟蹤分析

執(zhí)行 SQL:

[pg12@localhost ~]$ psql -d testdb
Timing is on.
Expanded display is used automatically.
psql (12.0)
Type  help  for help.
[local]:5432 pg12@testdb=# 
[local]:5432 pg12@testdb=# select * from tbl;
 id | value 
----+-------
 1 | 2
(1 row)
Time: 2.678 ms
[local]:5432 pg12@testdb=# select count(*) from t_big_null;
 count 
----------
 10000001
(1 row)
Time: 679.972 ms
[local]:5432 pg12@testdb=# analyze tbl;
ANALYZE
Time: 64.442 ms
[local]:5432 pg12@testdb=# analyze t_big_null;
ANALYZE
Time: 434.702 ms
[local]:5432 pg12@testdb=# 
[local]:5432 pg12@testdb=# select pg_backend_pid();
 pg_backend_pid 
----------------
 18758
(1 row)
Time: 1.990 ms
[local]:5432 pg12@testdb=# select * from tbl a where a.id not in (select b.id from t_big_null b);

啟動(dòng) gdb 跟蹤

(gdb) b ExecScanSubPlan
Breakpoint 1 at 0x73014b: file nodeSubplan.c, line 228.
(gdb) c
Continuing.
Breakpoint 1, ExecScanSubPlan (node=0x1c89158, econtext=0x1c88990, isNull=0x1c88cad)
 at nodeSubplan.c:228
228 SubPlan *subplan = node- subplan;
(gdb) 
(gdb) n
229 PlanState *planstate = node- planstate;
(gdb) 
230 SubLinkType subLinkType = subplan- subLinkType;
(gdb) 
234 bool found = false; /* true if got at least one subplan tuple */

subplan 變量值(結(jié)構(gòu)體 SubPlan)
其中 testexpr 是測(cè)試表達(dá)式,操作符是整型的等值比較,
左操作符是 Var,數(shù)據(jù)表的第一個(gè)列,類型為 23-int4(select * from pg_type where oid=23;)
有操作符是 Param,執(zhí)行期設(shè)置,對(duì)應(yīng)參數(shù)索引編號(hào)為 0,類型為 23-int4
paramIds 是鏈表,第一項(xiàng) ID 值為 0(int_value = 0)
子查詢結(jié)果的第一個(gè)列類型為 23-int4

(gdb) p *subplan
$1 = {xpr = {type = T_SubPlan}, subLinkType = ANY_SUBLINK, testexpr = 0x1cb8790, 
 paramIds = 0x1cb8758, plan_id = 1, plan_name = 0x1cb8a80  SubPlan 1 , 
 firstColType = 23, firstColTypmod = -1, firstColCollation = 0, useHashTable = false, 
 unknownEqFalse = false, parallel_safe = true, setParam = 0x0, parParam = 0x0, 
 args = 0x0, startup_cost = 0, per_call_cost = 129155.31875000001}
(gdb) p *subplan- testexpr
$2 = {type = T_OpExpr}
(gdb) p *(OpExpr *)subplan- testexpr
$3 = {xpr = {type = T_OpExpr}, opno = 96, opfuncid = 65, opresulttype = 16, 
 opretset = false, opcollid = 0, inputcollid = 0, args = 0x1cb8868, location = 31}
(gdb) set $expr=(OpExpr *)subplan- testexpr
(gdb) p *$expr- args
$4 = {type = T_List, length = 2, head = 0x1cb8840, tail = 0x1cb88d8}
(gdb) p *$expr- args- head
$5 = {data = {ptr_value = 0x1cb87e8, int_value = 30115816, oid_value = 30115816}, 
 next = 0x1cb88d8}
(gdb) p *(Node *)$expr- args- head- data.ptr_value
$6 = {type = T_Var}
(gdb) p *(Var *)$expr- args- head- data.ptr_value
$7 = {xpr = {type = T_Var}, varno = 1, varattno = 1, vartype = 23, vartypmod = -1, 
 varcollid = 0, varlevelsup = 0, varnoold = 1, varoattno = 1, location = 26}
(gdb) p *(Var *)$expr- args- head- next- data.ptr_value
$8 = {xpr = {type = T_Param}, varno = 1, varattno = 0, vartype = 23, vartypmod = -1, 
 varcollid = 0, varlevelsup = 4294967295, varnoold = 2139062142, varoattno = 16, 
 location = 0}
(gdb) p *(Param *)$expr- args- head- next- data.ptr_value
$9 = {xpr = {type = T_Param}, paramkind = PARAM_EXEC, paramid = 0, paramtype = 23, 
 paramtypmod = -1, paramcollid = 0, location = -1}
(gdb) 
[local]:5432 pg12@testdb=# select * from pg_proc where oid = 65; --  opfuncid = 65,函數(shù)
-[ RECORD 1 ]---+-------
oid | 65
proname | int4eq
pronamespace | 11
proowner | 10
prolang | 12
procost | 1
prorows | 0
provariadic | 0
prosupport | -
prokind | f
prosecdef | f
proleakproof | t
proisstrict | t
proretset | f
provolatile | i
proparallel | s
pronargs | 2
pronargdefaults | 0
prorettype | 16
proargtypes | 23 23
proallargtypes | 
proargmodes | 
proargnames | 
proargdefaults | 
protrftypes | 
prosrc | int4eq
probin | 
proconfig | 
proacl | 
Time: 6.253 ms
(gdb) p *subplan- paramIds
$11 = {type = T_IntList, length = 1, head = 0x1cb8730, tail = 0x1cb8730}
(gdb) p *subplan- paramIds- head
$12 = {data = {ptr_value = 0x7f7f7f7f00000000, int_value = 0, oid_value = 0}, next = 0x0}
(gdb)

planstate 變量值,實(shí)際的執(zhí)行節(jié)點(diǎn)是 ExecMaterial

(gdb) p *planstate
$15 = {type = T_MaterialState, plan = 0x1cb8900, state = 0x1c87da8, 
 ExecProcNode = 0x6f802a  ExecProcNodeFirst , 
 ExecProcNodeReal = 0x720ecf  ExecMaterial , instrument = 0x0, worker_instrument = 0x0, 
 worker_jit_instrument = 0x0, qual = 0x0, lefttree = 0x1c88160, righttree = 0x0, 
 initPlan = 0x0, subPlan = 0x0, chgParam = 0x0, ps_ResultTupleDesc = 0x1c88580, 
 ps_ResultTupleSlot = 0x1c88698, ps_ExprContext = 0x0, ps_ProjInfo = 0x0, 
 scandesc = 0x1c88468, scanops = 0xc3e720  TTSOpsMinimalTuple , outerops = 0x0, 
 innerops = 0x0, resultops = 0xc3e720  TTSOpsMinimalTuple , scanopsfixed = true, 
 outeropsfixed = false, inneropsfixed = false, resultopsfixed = true, scanopsset = true, 
 outeropsset = false, inneropsset = false, resultopsset = true}
(gdb)

subLinkType 變量,類型為 ANY_SUBLINK,把 NOT IN 轉(zhuǎn)為 ANY_SUBLINK

(gdb) p subLinkType
$16 = ANY_SUBLINK

設(shè)置變量,執(zhí)行相關(guān)檢查等

(gdb) n
237 ArrayBuildStateAny *astate = NULL;
(gdb) 
250 if (subLinkType == MULTIEXPR_SUBLINK)
(gdb) 
266 if (subLinkType == ARRAY_SUBLINK)
(gdb) 
275 oldcontext = MemoryContextSwitchTo(econtext- ecxt_per_query_memory);
(gdb) 
282 Assert(list_length(subplan- parParam) == list_length(node- args));
(gdb) 
284 forboth(l, subplan- parParam, pvar, node- args)
(gdb) p subplan- parParam
$17 = (List *) 0x0

執(zhí)行 ExecReScan,planstate- ExecProcNode 實(shí)際為 ExecMaterial

(gdb) n
298 ExecReScan(planstate);
(gdb) p *planstate
$20 = {type = T_MaterialState, plan = 0x1cb8900, state = 0x1c87da8, 
 ExecProcNode = 0x720ecf  ExecMaterial , ExecProcNodeReal = 0x720ecf  ExecMaterial , 
 instrument = 0x0, worker_instrument = 0x0, worker_jit_instrument = 0x0, qual = 0x0, 
 lefttree = 0x1c88160, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0, 
 ps_ResultTupleDesc = 0x1c88580, ps_ResultTupleSlot = 0x1c88698, ps_ExprContext = 0x0, 
 ps_ProjInfo = 0x0, scandesc = 0x1c88468, scanops = 0xc3e720  TTSOpsMinimalTuple , 
 outerops = 0x0, innerops = 0x0, resultops = 0xc3e720  TTSOpsMinimalTuple , 
 scanopsfixed = true, outeropsfixed = false, inneropsfixed = false, 
 resultopsfixed = true, scanopsset = true, outeropsset = false, inneropsset = false, 
 resultopsset = true}
(gdb)

初始化 result isNull 變量

(gdb) n
321 result = BoolGetDatum(subLinkType == ALL_SUBLINK);
(gdb) 
322 *isNull = false;
(gdb) p result
$18 = 0

執(zhí)行循環(huán),slot 從 planstate- ExecProcNode(即 ExecMaterial)中獲取

(gdb) n
324 for (slot = ExecProcNode(planstate);
(gdb) 
325 !TupIsNull(slot);
(gdb) 
(gdb) p *slot
$22 = {type = T_TupleTableSlot, tts_flags = 20, tts_nvalid = 0, 
 tts_ops = 0xc3e720  TTSOpsMinimalTuple , tts_tupleDescriptor = 0x1c88580, 
 tts_values = 0x1c88708, tts_isnull = 0x1c88710, tts_mcxt = 0x1c87c90, tts_tid = { ip_blkid = {bi_hi = 65535, bi_lo = 65535}, ip_posid = 0}, tts_tableOid = 0}
(gdb) p slot- tts_values[0]
$23 = 0
(gdb)

獲取 slot 的描述符

(gdb) 
328 TupleDesc tdesc = slot- tts_tupleDescriptor;
(gdb) p tdesc
$21 = (TupleDesc) 0x206e6f6900000000

判斷 subLink 類型執(zhí)行相關(guān)邏輯,循環(huán) paramIds,填充參數(shù)值

(gdb) n
334 if (subLinkType == EXISTS_SUBLINK)
(gdb) 
341 if (subLinkType == EXPR_SUBLINK)
(gdb) 
367 if (subLinkType == ARRAY_SUBLINK)
(gdb) 
383 if (subLinkType == ROWCOMPARE_SUBLINK   found)
(gdb) 
388 found = true;
(gdb) 
395 col = 1;
(gdb) 
396 foreach(plst, subplan- paramIds)
(gdb) p *slot
$22 = {type = T_TupleTableSlot, tts_flags = 20, tts_nvalid = 0, 
 tts_ops = 0xc3e720  TTSOpsMinimalTuple , tts_tupleDescriptor = 0x1c88580, 
 tts_values = 0x1c88708, tts_isnull = 0x1c88710, tts_mcxt = 0x1c87c90, tts_tid = { ip_blkid = {bi_hi = 65535, bi_lo = 65535}, ip_posid = 0}, tts_tableOid = 0}
(gdb) p *slot- tts_values[0]
Cannot access memory at address 0x0
(gdb) p slot- tts_values[0]
$23 = 0
(gdb) n
398 int paramid = lfirst_int(plst);
(gdb) 
401 prmdata =  (econtext- ecxt_param_exec_vals[paramid]);
(gdb) p paramid
$24 = 0
(gdb) n
402 Assert(prmdata- execPlan == NULL);
(gdb) p *prmdata
$25 = {execPlan = 0x0, value = 0, isnull = false}
(gdb) n
403 prmdata- value = slot_getattr(slot, col,  (prmdata- isnull));
(gdb) n
404 col++;
(gdb) p *prmdata
$26 = {execPlan = 0x0, value = 2, isnull = false}
(gdb) n
396 foreach(plst, subplan- paramIds)
(gdb)

解析表達(dá)式,亦即解析表達(dá)式 tbl.id = 2,獲取結(jié)果

(gdb) 
407 rowresult = ExecEvalExprSwitchContext(node- testexpr, econtext,
(gdb) p *(Var *)$expr- args- head- data.ptr_value
$28 = {xpr = {type = T_Var}, varno = 1, varattno = 1, vartype = 23, vartypmod = -1, 
 varcollid = 0, varlevelsup = 0, varnoold = 1, varoattno = 1, location = 26}
(gdb) p *(Param *)$expr- args- head- next- data.ptr_value
$29 = {xpr = {type = T_Param}, paramkind = PARAM_EXEC, paramid = 0, paramtype = 23, 
 paramtypmod = -1, paramcollid = 0, location = -1}
(gdb) p econtext- ecxt_param_exec_vals[0]
$30 = {execPlan = 0x0, value = 2, isnull = false}

由于 tbl.id = 1,因此表達(dá)式解析結(jié)果為 F

(gdb) n
410 if (subLinkType == ANY_SUBLINK)
(gdb) p rowresult
$31 = 0
(gdb)

判斷 subLink 類型,如為 ANY 則進(jìn)入相應(yīng)邏輯

(gdb) n
410 if (subLinkType == ANY_SUBLINK)
(gdb) p rowresult
$31 = 0
(gdb) n
413 if (rownull)
(gdb) p rownull
$32 = false
(gdb) n
415 else if (DatumGetBool(rowresult))
(gdb)

結(jié)果不為 T,因此再次循環(huán)執(zhí)行,獲取 slot,這次的值應(yīng)為 3,因?yàn)?3 1,因此再次循環(huán)直至 t_big_null 中出現(xiàn)值 1 或完成掃描

326 slot = ExecProcNode(planstate))
(gdb) 
(gdb) 
403 prmdata- value = slot_getattr(slot, col,  (prmdata- isnull));
(gdb) 
404 col++;
(gdb) p prmdata- value
$36 = 3
(gdb) p slot- tts_values[0]
$37 = 3
(gdb) 
...

完成執(zhí)行

(gdb) c
Continuing.
[local]:5432 pg12@testdb=# select * from tbl a where a.id not in (select b.id from t_big_null b);
 id | value 
----+-------
(0 rows)
Time: 3089703.031 ms (51:29.703)
[local]:5432 pg12@testdb=# 
[local]:5432 pg12@testdb=# 
###

調(diào)用棧

Breakpoint 1, ExecScanSubPlan (node=0x1c89158, econtext=0x1c88990, isNull=0x1c88cad)
 at nodeSubplan.c:228
228 SubPlan *subplan = node- subplan;
(gdb) bt
#0 ExecScanSubPlan (node=0x1c89158, econtext=0x1c88990, isNull=0x1c88cad)
 at nodeSubplan.c:228
#1 0x000000000072fe5e in ExecSubPlan (node=0x1c89158, econtext=0x1c88990, 
 isNull=0x1c88cad) at nodeSubplan.c:90
#2 0x00000000006e90a8 in ExecEvalSubPlan (state=0x1c88ca8, op=0x1c88d80, 
 econtext=0x1c88990) at execExprInterp.c:3783
#3 0x00000000006e48b2 in ExecInterpExpr (state=0x1c88ca8, econtext=0x1c88990, 
 isnull=0x7fff7b9514f7) at execExprInterp.c:1484
#4 0x00000000006e50b8 in ExecInterpExprStillValid (state=0x1c88ca8, econtext=0x1c88990, 
 isNull=0x7fff7b9514f7) at execExprInterp.c:1769
#5 0x00000000006f9ec0 in ExecEvalExprSwitchContext (state=0x1c88ca8, econtext=0x1c88990, 
 isNull=0x7fff7b9514f7) at ../../../src/include/executor/executor.h:307
#6 0x00000000006f9fb8 in ExecQual (state=0x1c88ca8, econtext=0x1c88990)
 at ../../../src/include/executor/executor.h:376
#7 0x00000000006fa37d in ExecScan (node=0x1c88878, accessMtd=0x72b84c  SeqNext , 
 recheckMtd=0x72b8f1  SeqRecheck ) at execScan.c:228
#8 0x000000000072b93b in ExecSeqScan (pstate=0x1c88878) at nodeSeqscan.c:112
#9 0x00000000006f8077 in ExecProcNodeFirst (node=0x1c88878) at execProcnode.c:445
#10 0x00000000006ed3cd in ExecProcNode (node=0x1c88878)
 at ../../../src/include/executor/executor.h:239
#11 0x00000000006efbb3 in ExecutePlan (estate=0x1c87da8, planstate=0x1c88878, 
 use_parallel_mode=false, operation=CMD_SELECT, sendTuples=true, numberTuples=0, 
 direction=ForwardScanDirection, dest=0x1cbc7c0, execute_once=true) at execMain.c:1646
#12 0x00000000006ed9df in standard_ExecutorRun (queryDesc=0x1be78b8, 
 direction=ForwardScanDirection, count=0, execute_once=true) at execMain.c:364
#13 0x00000000006ed815 in ExecutorRun (queryDesc=0x1be78b8, 
 direction=ForwardScanDirection, count=0, execute_once=true) at execMain.c:308
#14 0x00000000008f1010 in PortalRunSelect (portal=0x1c27d78, forward=true, count=0, 
 dest=0x1cbc7c0) at pquery.c:929
#15 0x00000000008f0cae in PortalRun (portal=0x1c27d78, count=9223372036854775807, 
 isTopLevel=true, run_once=true, dest=0x1cbc7c0, altdest=0x1cbc7c0, 
 completionTag=0x7fff7b951890  ) at pquery.c:770
#16 0x00000000008ead35 in exec_simple_query ( query_string=0x1bc1d88  select * from tbl a where a.id not in (select b.id from t_big_null b); ) at postgres.c:1215
#17 0x00000000008eefa5 in PostgresMain (argc=1, argv=0x1bedf18, 
 dbname=0x1bedd60  testdb , username=0x1bbeaa8  pg12 ) at postgres.c:4236
#18 0x0000000000845915 in BackendRun (port=0x1be3d30) at postmaster.c:4431
#19 0x00000000008450f3 in BackendStartup (port=0x1be3d30) at postmaster.c:4122
#20 0x000000000084132f in ServerLoop () at postmaster.c:1704
#21 0x0000000000840be5 in PostmasterMain (argc=1, argv=0x1bbca60) at postmaster.c:1377
#22 0x0000000000761469 in main (argc=1, argv=0x1bbca60) at main.c:228
(gdb)

到此,相信大家對(duì)“PostgreSQL 源碼中 NOT IN 的作用是什么”有了更深的了解,不妨來實(shí)際操作一番吧!這里是丸趣 TV 網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

正文完
 
丸趣
版權(quán)聲明:本站原創(chuàng)文章,由 丸趣 2023-07-28發(fā)表,共計(jì)30439字。
轉(zhuǎn)載說明:除特殊說明外本站除技術(shù)相關(guān)以外文章皆由網(wǎng)絡(luò)搜集發(fā)布,轉(zhuǎn)載請(qǐng)注明出處。
評(píng)論(沒有評(píng)論)
主站蜘蛛池模板: 上思县| 晋城| 铜山县| 百色市| 松江区| 玉山县| 稻城县| 广南县| 和平县| 普兰县| 安化县| 临桂县| 黄山市| 博湖县| 莱阳市| 万山特区| 上高县| 遵义市| 合阳县| 古交市| 南召县| 阳高县| 稷山县| 英超| 洛宁县| 江永县| 厦门市| 蕲春县| 全州县| 遂川县| 永安市| 乐都县| 太保市| 行唐县| 邮箱| 光山县| 通化县| 东至县| 中宁县| 新津县| 古田县|