PostgreSQL中PortalRunMulti函数和PortalRun函数的实现逻辑是什么
发表于:2025-01-20 作者:千家信息网编辑
千家信息网最后更新 2025年01月20日,本篇内容主要讲解"PostgreSQL中PortalRunMulti函数和PortalRun函数的实现逻辑是什么",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学
千家信息网最后更新 2025年01月20日PostgreSQL中PortalRunMulti函数和PortalRun函数的实现逻辑是什么
本篇内容主要讲解"PostgreSQL中PortalRunMulti函数和PortalRun函数的实现逻辑是什么",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"PostgreSQL中PortalRunMulti函数和PortalRun函数的实现逻辑是什么"吧!
一、基础信息
PortalRunMulti函数使用的数据结构、宏定义以及依赖的函数等。
数据结构/宏定义
1、Portal
typedef struct PortalData *Portal; typedef struct PortalData { /* Bookkeeping data */ const char *name; /* portal's name */ const char *prepStmtName; /* source prepared statement (NULL if none) */ MemoryContext portalContext; /* subsidiary memory for portal */ ResourceOwner resowner; /* resources owned by portal */ void (*cleanup) (Portal portal); /* cleanup hook */ /* * State data for remembering which subtransaction(s) the portal was * created or used in. If the portal is held over from a previous * transaction, both subxids are InvalidSubTransactionId. Otherwise, * createSubid is the creating subxact and activeSubid is the last subxact * in which we ran the portal. */ SubTransactionId createSubid; /* the creating subxact */ SubTransactionId activeSubid; /* the last subxact with activity */ /* The query or queries the portal will execute */ const char *sourceText; /* text of query (as of 8.4, never NULL) */ const char *commandTag; /* command tag for original query */ List *stmts; /* list of PlannedStmts */ CachedPlan *cplan; /* CachedPlan, if stmts are from one */ ParamListInfo portalParams; /* params to pass to query */ QueryEnvironment *queryEnv; /* environment for query */ /* Features/options */ PortalStrategy strategy; /* see above */ int cursorOptions; /* DECLARE CURSOR option bits */ bool run_once; /* portal will only be run once */ /* Status data */ PortalStatus status; /* see above */ bool portalPinned; /* a pinned portal can't be dropped */ bool autoHeld; /* was automatically converted from pinned to * held (see HoldPinnedPortals()) */ /* If not NULL, Executor is active; call ExecutorEnd eventually: */ QueryDesc *queryDesc; /* info needed for executor invocation */ /* If portal returns tuples, this is their tupdesc: */ TupleDesc tupDesc; /* descriptor for result tuples */ /* and these are the format codes to use for the columns: */ int16 *formats; /* a format code for each column */ /* * Where we store tuples for a held cursor or a PORTAL_ONE_RETURNING or * PORTAL_UTIL_SELECT query. (A cursor held past the end of its * transaction no longer has any active executor state.) */ Tuplestorestate *holdStore; /* store for holdable cursors */ MemoryContext holdContext; /* memory containing holdStore */ /* * Snapshot under which tuples in the holdStore were read. We must keep a * reference to this snapshot if there is any possibility that the tuples * contain TOAST references, because releasing the snapshot could allow * recently-dead rows to be vacuumed away, along with any toast data * belonging to them. In the case of a held cursor, we avoid needing to * keep such a snapshot by forcibly detoasting the data. */ Snapshot holdSnapshot; /* registered snapshot, or NULL if none */ /* * atStart, atEnd and portalPos indicate the current cursor position. * portalPos is zero before the first row, N after fetching N'th row of * query. After we run off the end, portalPos = # of rows in query, and * atEnd is true. Note that atStart implies portalPos == 0, but not the * reverse: we might have backed up only as far as the first row, not to * the start. Also note that various code inspects atStart and atEnd, but * only the portal movement routines should touch portalPos. */ bool atStart; bool atEnd; uint64 portalPos; /* Presentation data, primarily used by the pg_cursors system view */ TimestampTz creation_time; /* time at which this portal was defined */ bool visible; /* include this portal in pg_cursors? */ } PortalData;
2、List
typedef struct ListCell ListCell; typedef struct List { NodeTag type; /* T_List, T_IntList, or T_OidList */ int length; ListCell *head; ListCell *tail; } List; struct ListCell { union { void *ptr_value; int int_value; Oid oid_value; } data; ListCell *next; };
3、Snapshot
typedef struct SnapshotData *Snapshot; /* * Struct representing all kind of possible snapshots. * * There are several different kinds of snapshots: * * Normal MVCC snapshots * * MVCC snapshots taken during recovery (in Hot-Standby mode) * * Historic MVCC snapshots used during logical decoding * * snapshots passed to HeapTupleSatisfiesDirty() * * snapshots passed to HeapTupleSatisfiesNonVacuumable() * * snapshots used for SatisfiesAny, Toast, Self where no members are * accessed. * * TODO: It's probably a good idea to split this struct using a NodeTag * similar to how parser and executor nodes are handled, with one type for * each different kind of snapshot to avoid overloading the meaning of * individual fields. */ typedef struct SnapshotData { SnapshotSatisfiesFunc satisfies; /* tuple test function */ /* * The remaining fields are used only for MVCC snapshots, and are normally * just zeroes in special snapshots. (But xmin and xmax are used * specially by HeapTupleSatisfiesDirty, and xmin is used specially by * HeapTupleSatisfiesNonVacuumable.) * * An MVCC snapshot can never see the effects of XIDs >= xmax. It can see * the effects of all older XIDs except those listed in the snapshot. xmin * is stored as an optimization to avoid needing to search the XID arrays * for most tuples. */ TransactionId xmin; /* all XID < xmin are visible to me */ TransactionId xmax; /* all XID >= xmax are invisible to me */ /* * For normal MVCC snapshot this contains the all xact IDs that are in * progress, unless the snapshot was taken during recovery in which case * it's empty. For historic MVCC snapshots, the meaning is inverted, i.e. * it contains *committed* transactions between xmin and xmax. * * note: all ids in xip[] satisfy xmin <= xip[i] < xmax */ TransactionId *xip; uint32 xcnt; /* # of xact ids in xip[] */ /* * For non-historic MVCC snapshots, this contains subxact IDs that are in * progress (and other transactions that are in progress if taken during * recovery). For historic snapshot it contains *all* xids assigned to the * replayed transaction, including the toplevel xid. * * note: all ids in subxip[] are >= xmin, but we don't bother filtering * out any that are >= xmax */ TransactionId *subxip; int32 subxcnt; /* # of xact ids in subxip[] */ bool suboverflowed; /* has the subxip array overflowed? */ bool takenDuringRecovery; /* recovery-shaped snapshot? */ bool copied; /* false if it's a static snapshot */ CommandId curcid; /* in my xact, CID < curcid are visible */ /* * An extra return value for HeapTupleSatisfiesDirty, not used in MVCC * snapshots. */ uint32 speculativeToken; /* * Book-keeping information, used by the snapshot manager */ uint32 active_count; /* refcount on ActiveSnapshot stack */ uint32 regd_count; /* refcount on RegisteredSnapshots */ pairingheap_node ph_node; /* link in the RegisteredSnapshots heap */ TimestampTz whenTaken; /* timestamp when snapshot was taken */ XLogRecPtr lsn; /* position in the WAL stream when taken */ } SnapshotData;
依赖的函数
1、lfirst_*
/* * NB: There is an unfortunate legacy from a previous incarnation of * the List API: the macro lfirst() was used to mean "the data in this * cons cell". To avoid changing every usage of lfirst(), that meaning * has been kept. As a result, lfirst() takes a ListCell and returns * the data it contains; to get the data in the first cell of a * List, use linitial(). Worse, lsecond() is more closely related to * linitial() than lfirst(): given a List, lsecond() returns the data * in the second cons cell. */ #define lnext(lc) ((lc)->next) #define lfirst(lc) ((lc)->data.ptr_value) #define lfirst_int(lc) ((lc)->data.int_value) #define lfirst_oid(lc) ((lc)->data.oid_value) #define lfirst_node(type,lc) castNode(type, lfirst(lc)) /* * castNode(type, ptr) casts ptr to "type *", and if assertions are enabled, * verifies that the node has the appropriate type (using its nodeTag()). * * Use an inline function when assertions are enabled, to avoid multiple * evaluations of the ptr argument (which could e.g. be a function call). */ #ifdef USE_ASSERT_CHECKING static inline Node * castNodeImpl(NodeTag type, void *ptr) { Assert(ptr == NULL || nodeTag(ptr) == type); return (Node *) ptr; } #define castNode(_type_, nodeptr) ((_type_ *) castNodeImpl(T_##_type_, nodeptr)) #else #define castNode(_type_, nodeptr) ((_type_ *) (nodeptr)) #endif /* USE_ASSERT_CHECKING */
2、Snapshot相关
//留待MVCC再行解读GetTransactionSnapshotRegisterSnapshotPushCopiedSnapshotUpdateActiveSnapshotCommandIdPopActiveSnapshot
3、ProcessQuery
//上一节已介绍
4、CommandCounterIncrement
/* * CommandCounterIncrement */ void CommandCounterIncrement(void) { /* * If the current value of the command counter hasn't been "used" to mark * tuples, we need not increment it, since there's no need to distinguish * a read-only command from others. This helps postpone command counter * overflow, and keeps no-op CommandCounterIncrement operations cheap. */ if (currentCommandIdUsed) { /* * Workers synchronize transaction state at the beginning of each * parallel operation, so we can't account for new commands after that * point. */ if (IsInParallelMode() || IsParallelWorker()) elog(ERROR, "cannot start commands during a parallel operation"); currentCommandId += 1; if (currentCommandId == InvalidCommandId) { currentCommandId -= 1; ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("cannot have more than 2^32-2 commands in a transaction"))); } currentCommandIdUsed = false; /* Propagate new command ID into static snapshots */ SnapshotSetCommandId(currentCommandId); /* * Make any catalog changes done by the just-completed command visible * in the local syscache. We obviously don't need to do this after a * read-only command. (But see hacks in inval.c to make real sure we * don't think a command that queued inval messages was read-only.) */ AtCCI_LocalCache(); } }
5、MemoryContextDeleteChildren
/* * MemoryContextDeleteChildren * Delete all the descendants of the named context and release all * space allocated therein. The named context itself is not touched. */ void MemoryContextDeleteChildren(MemoryContext context) { AssertArg(MemoryContextIsValid(context)); /* * MemoryContextDelete will delink the child from me, so just iterate as * long as there is a child. */ while (context->firstchild != NULL) MemoryContextDelete(context->firstchild); }
二、源码解读
1、PortalRun
/* * PortalRun * Run a portal's query or queries. * * count <= 0 is interpreted as a no-op: the destination gets started up * and shut down, but nothing else happens. Also, count == FETCH_ALL is * interpreted as "all rows". Note that count is ignored in multi-query * situations, where we always run the portal to completion. * * isTopLevel: true if query is being executed at backend "top level" * (that is, directly from a client command message) * * dest: where to send output of primary (canSetTag) query * * altdest: where to send output of non-primary queries * * completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE * in which to store a command completion status string. * May be NULL if caller doesn't want a status string. * * Returns true if the portal's execution is complete, false if it was * suspended due to exhaustion of the count parameter. *//*输入: 参照PortalRunMulti输出: 布尔变量,成功true,失败false*/boolPortalRun(Portal portal, long count, bool isTopLevel, bool run_once, DestReceiver *dest, DestReceiver *altdest, char *completionTag){ bool result;//返回结果 uint64 nprocessed; ResourceOwner saveTopTransactionResourceOwner;//高层事务资源宿主 MemoryContext saveTopTransactionContext;//内存上下文 Portal saveActivePortal;//活动的Portal ResourceOwner saveResourceOwner; MemoryContext savePortalContext; MemoryContext saveMemoryContext; AssertArg(PortalIsValid(portal)); TRACE_POSTGRESQL_QUERY_EXECUTE_START(); /* Initialize completion tag to empty string */ if (completionTag) completionTag[0] = '\0'; if (log_executor_stats && portal->strategy != PORTAL_MULTI_QUERY) { elog(DEBUG3, "PortalRun"); /* PORTAL_MULTI_QUERY logs its own stats per query */ ResetUsage(); } /* * Check for improper portal use, and mark portal active. */ MarkPortalActive(portal); /* Set run_once flag. Shouldn't be clear if previously set. */ Assert(!portal->run_once || run_once); portal->run_once = run_once; /* * Set up global portal context pointers. * * We have to play a special game here to support utility commands like * VACUUM and CLUSTER, which internally start and commit transactions. * When we are called to execute such a command, CurrentResourceOwner will * be pointing to the TopTransactionResourceOwner --- which will be * destroyed and replaced in the course of the internal commit and * restart. So we need to be prepared to restore it as pointing to the * exit-time TopTransactionResourceOwner. (Ain't that ugly? This idea of * internally starting whole new transactions is not good.) * CurrentMemoryContext has a similar problem, but the other pointers we * save here will be NULL or pointing to longer-lived objects. */ //保护现场 saveTopTransactionResourceOwner = TopTransactionResourceOwner; saveTopTransactionContext = TopTransactionContext; saveActivePortal = ActivePortal; saveResourceOwner = CurrentResourceOwner; savePortalContext = PortalContext; saveMemoryContext = CurrentMemoryContext; PG_TRY(); { ActivePortal = portal; if (portal->resowner) CurrentResourceOwner = portal->resowner; PortalContext = portal->portalContext; MemoryContextSwitchTo(PortalContext); switch (portal->strategy) { case PORTAL_ONE_SELECT: case PORTAL_ONE_RETURNING: case PORTAL_ONE_MOD_WITH: case PORTAL_UTIL_SELECT: /* * If we have not yet run the command, do so, storing its * results in the portal's tuplestore. But we don't do that * for the PORTAL_ONE_SELECT case. */ if (portal->strategy != PORTAL_ONE_SELECT && !portal->holdStore) FillPortalStore(portal, isTopLevel); /* * Now fetch desired portion of results. */ nprocessed = PortalRunSelect(portal, true, count, dest); /* * If the portal result contains a command tag and the caller * gave us a pointer to store it, copy it. Patch the "SELECT" * tag to also provide the rowcount. */ if (completionTag && portal->commandTag) { if (strcmp(portal->commandTag, "SELECT") == 0) snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "SELECT " UINT64_FORMAT, nprocessed); else strcpy(completionTag, portal->commandTag); } /* Mark portal not active */ portal->status = PORTAL_READY; /* * Since it's a forward fetch, say DONE iff atEnd is now true. */ result = portal->atEnd; break; case PORTAL_MULTI_QUERY://INSERT语句 PortalRunMulti(portal, isTopLevel, false, dest, altdest, completionTag); /* Prevent portal's commands from being re-executed */ MarkPortalDone(portal); /* Always complete at end of RunMulti */ result = true; break; default: elog(ERROR, "unrecognized portal strategy: %d", (int) portal->strategy); result = false; /* keep compiler quiet */ break; } } PG_CATCH(); { /* Uncaught error while executing portal: mark it dead */ MarkPortalFailed(portal); /* Restore global vars and propagate error */ if (saveMemoryContext == saveTopTransactionContext) MemoryContextSwitchTo(TopTransactionContext); else MemoryContextSwitchTo(saveMemoryContext); ActivePortal = saveActivePortal; if (saveResourceOwner == saveTopTransactionResourceOwner) CurrentResourceOwner = TopTransactionResourceOwner; else CurrentResourceOwner = saveResourceOwner; PortalContext = savePortalContext; PG_RE_THROW(); } PG_END_TRY(); if (saveMemoryContext == saveTopTransactionContext) MemoryContextSwitchTo(TopTransactionContext); else MemoryContextSwitchTo(saveMemoryContext); ActivePortal = saveActivePortal; if (saveResourceOwner == saveTopTransactionResourceOwner) CurrentResourceOwner = TopTransactionResourceOwner; else CurrentResourceOwner = saveResourceOwner; PortalContext = savePortalContext; if (log_executor_stats && portal->strategy != PORTAL_MULTI_QUERY) ShowUsage("EXECUTOR STATISTICS"); TRACE_POSTGRESQL_QUERY_EXECUTE_DONE(); return result;}
2、PortalRunMulti
/* * PortalRunMulti * Execute a portal's queries in the general case (multi queries * or non-SELECT-like queries) *//*输入: portal-"门户"数据结构 isTopLevel-顶层? setHoldSnapshot-是否持有快照 dest-目标端 altdest-? completionTag-完成标记(用于语句执行结果输出)输出: 无*/static voidPortalRunMulti(Portal portal, bool isTopLevel, bool setHoldSnapshot, DestReceiver *dest, DestReceiver *altdest, char *completionTag){ bool active_snapshot_set = false;//活跃snapshot? ListCell *stmtlist_item;//SQL语句,临时变量 /* * If the destination is DestRemoteExecute, change to DestNone. The * reason is that the client won't be expecting any tuples, and indeed has * no way to know what they are, since there is no provision for Describe * to send a RowDescription message when this portal execution strategy is * in effect. This presently will only affect SELECT commands added to * non-SELECT queries by rewrite rules: such commands will be executed, * but the results will be discarded unless you use "simple Query" * protocol. */ if (dest->mydest == DestRemoteExecute) dest = None_Receiver; if (altdest->mydest == DestRemoteExecute) altdest = None_Receiver; /* * Loop to handle the individual queries generated from a single parsetree * by analysis and rewrite. */ foreach(stmtlist_item, portal->stmts)//循环处理SQL语句 { PlannedStmt *pstmt = lfirst_node(PlannedStmt, stmtlist_item);//获取已规划的语句 /* * If we got a cancel signal in prior command, quit */ CHECK_FOR_INTERRUPTS(); if (pstmt->utilityStmt == NULL)//非"工具类"语句 { /* * process a plannable query. */ TRACE_POSTGRESQL_QUERY_EXECUTE_START(); if (log_executor_stats) ResetUsage(); /* * Must always have a snapshot for plannable queries. First time * through, take a new snapshot; for subsequent queries in the * same portal, just update the snapshot's copy of the command * counter. */ if (!active_snapshot_set) { Snapshot snapshot = GetTransactionSnapshot();//获取事务快照 /* If told to, register the snapshot and save in portal */ if (setHoldSnapshot) { snapshot = RegisterSnapshot(snapshot); portal->holdSnapshot = snapshot; } /* * We can't have the holdSnapshot also be the active one, * because UpdateActiveSnapshotCommandId would complain. So * force an extra snapshot copy. Plain PushActiveSnapshot * would have copied the transaction snapshot anyway, so this * only adds a copy step when setHoldSnapshot is true. (It's * okay for the command ID of the active snapshot to diverge * from what holdSnapshot has.) */ PushCopiedSnapshot(snapshot); active_snapshot_set = true; } else UpdateActiveSnapshotCommandId(); //处理查询 if (pstmt->canSetTag) { /* statement can set tag string */ ProcessQuery(pstmt, portal->sourceText, portal->portalParams, portal->queryEnv, dest, completionTag); } else { /* stmt added by rewrite cannot set tag */ ProcessQuery(pstmt, portal->sourceText, portal->portalParams, portal->queryEnv, altdest, NULL); } if (log_executor_stats) ShowUsage("EXECUTOR STATISTICS"); TRACE_POSTGRESQL_QUERY_EXECUTE_DONE(); } else//"工具类"语句 { /* * process utility functions (create, destroy, etc..) * * We must not set a snapshot here for utility commands (if one is * needed, PortalRunUtility will do it). If a utility command is * alone in a portal then everything's fine. The only case where * a utility command can be part of a longer list is that rules * are allowed to include NotifyStmt. NotifyStmt doesn't care * whether it has a snapshot or not, so we just leave the current * snapshot alone if we have one. */ if (pstmt->canSetTag) { Assert(!active_snapshot_set); /* statement can set tag string */ PortalRunUtility(portal, pstmt, isTopLevel, false, dest, completionTag); } else { Assert(IsA(pstmt->utilityStmt, NotifyStmt)); /* stmt added by rewrite cannot set tag */ PortalRunUtility(portal, pstmt, isTopLevel, false, altdest, NULL); } } /* * Increment command counter between queries, but not after the last * one. */ if (lnext(stmtlist_item) != NULL) CommandCounterIncrement(); /* * Clear subsidiary contexts to recover temporary memory. */ Assert(portal->portalContext == CurrentMemoryContext); MemoryContextDeleteChildren(portal->portalContext);//释放资源 } /* Pop the snapshot if we pushed one. */ if (active_snapshot_set) PopActiveSnapshot(); /* * If a command completion tag was supplied, use it. Otherwise use the * portal's commandTag as the default completion tag. * * Exception: Clients expect INSERT/UPDATE/DELETE tags to have counts, so * fake them with zeros. This can happen with DO INSTEAD rules if there * is no replacement query of the same type as the original. We print "0 * 0" here because technically there is no query of the matching tag type, * and printing a non-zero count for a different query type seems wrong, * e.g. an INSERT that does an UPDATE instead should not print "0 1" if * one row was updated. See QueryRewrite(), step 3, for details. */ if (completionTag && completionTag[0] == '\0')//操作提示 { if (portal->commandTag) strcpy(completionTag, portal->commandTag); if (strcmp(completionTag, "SELECT") == 0) sprintf(completionTag, "SELECT 0 0"); else if (strcmp(completionTag, "INSERT") == 0) strcpy(completionTag, "INSERT 0 0"); else if (strcmp(completionTag, "UPDATE") == 0) strcpy(completionTag, "UPDATE 0"); else if (strcmp(completionTag, "DELETE") == 0) strcpy(completionTag, "DELETE 0"); }}
三、跟踪分析
插入测试数据:
testdb=# -- 获取pidtestdb=# select pg_backend_pid(); pg_backend_pid ---------------- 2551(1 row)testdb=# -- 插入1行testdb=# insert into t_insert values(20,'PortalRun','PortalRun','PortalRun');
启动gdb,跟踪调试:
1、PortalRun
[root@localhost ~]# gdb -p 2551GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-100.el7Copyright (C) 2013 Free Software Foundation, Inc....(gdb) b PortalRunBreakpoint 1 at 0x8528af: file pquery.c, line 707.(gdb) cContinuing.Breakpoint 1, PortalRun (portal=0x2c6f490, count=9223372036854775807, isTopLevel=true, run_once=true, dest=0x2ccb4d8, altdest=0x2ccb4d8, completionTag=0x7ffe94ba4940 "") at pquery.c:707707 if (completionTag)#查看输入参数#1、portal(gdb) p *portal$1 = {name = 0x2c72e98 "", prepStmtName = 0x0, portalContext = 0x2cc1470, resowner = 0x2c3ad10, cleanup = 0x62f15c, createSubid = 1, activeSubid = 1, sourceText = 0x2c09ef0 "insert into t_insert values(20,'PortalRun','PortalRun','PortalRun');", commandTag = 0xb50908 "INSERT", stmts = 0x2ccb4a8, cplan = 0x0, portalParams = 0x0, queryEnv = 0x0, strategy = PORTAL_MULTI_QUERY, cursorOptions = 4, run_once = false, status = PORTAL_READY, portalPinned = false, autoHeld = false, queryDesc = 0x0, tupDesc = 0x0, formats = 0x0, holdStore = 0x0, holdContext = 0x0, holdSnapshot = 0x0, atStart = true, atEnd = true, portalPos = 0, creation_time = 587033564125509, visible = false}(gdb) p *(portal->portalContext)$2 = {type = T_AllocSetContext, isReset = true, allowInCritSection = false, methods = 0xb8c720 , parent = 0x2c6f380, firstchild = 0x0, prevchild = 0x0, nextchild = 0x0, name = 0xb8d2f1 "PortalContext", ident = 0x2c72e98 "", reset_cbs = 0x0}(gdb) p *(portal->resowner)$3 = {parent = 0x2c35518, firstchild = 0x0, nextchild = 0x0, name = 0xb8d2ff "Portal", bufferarr = {itemsarr = 0x0, invalidval = 0, capacity = 0, nitems = 0, maxitems = 0, lastidx = 0}, catrefarr = { itemsarr = 0x0, invalidval = 0, capacity = 0, nitems = 0, maxitems = 0, lastidx = 0}, catlistrefarr = {itemsarr = 0x0, invalidval = 0, capacity = 0, nitems = 0, maxitems = 0, lastidx = 0}, relrefarr = {itemsarr = 0x0, invalidval = 0, capacity = 0, nitems = 0, maxitems = 0, lastidx = 0}, planrefarr = {itemsarr = 0x0, invalidval = 0, capacity = 0, nitems = 0, maxitems = 0, lastidx = 0}, tupdescarr = {itemsarr = 0x0, invalidval = 0, capacity = 0, nitems = 0, maxitems = 0, lastidx = 0}, snapshotarr = {itemsarr = 0x0, invalidval = 0, capacity = 0, nitems = 0, maxitems = 0, lastidx = 0}, filearr = {itemsarr = 0x0, invalidval = 18446744073709551615, capacity = 0, nitems = 0, maxitems = 0, lastidx = 0}, dsmarr = {itemsarr = 0x0, invalidval = 0, capacity = 0, nitems = 0, maxitems = 0, lastidx = 0}, jitarr = {itemsarr = 0x0, invalidval = 0, capacity = 0, nitems = 0, maxitems = 0, lastidx = 0}, nlocks = 0, locks = {0x0 }}(gdb) p *(portal->resowner->parent)$4 = {parent = 0x0, firstchild = 0x2c3ad10, nextchild = 0x0, name = 0xa1b515 "TopTransaction", bufferarr = {itemsarr = 0x0, invalidval = 0, capacity = 0, nitems = 0, maxitems = 0, lastidx = 0}, catrefarr = {itemsarr = 0x2c3b040, invalidval = 0, capacity = 16, nitems = 0, maxitems = 16, lastidx = 4294967295}, catlistrefarr = {itemsarr = 0x0, invalidval = 0, capacity = 0, nitems = 0, maxitems = 0, lastidx = 0}, relrefarr = {itemsarr = 0x2c35728, invalidval = 0, capacity = 16, nitems = 0, maxitems = 16, lastidx = 4294967295}, planrefarr = {itemsarr = 0x0, invalidval = 0, capacity = 0, nitems = 0, maxitems = 0, lastidx = 0}, tupdescarr = {itemsarr = 0x0, invalidval = 0, capacity = 0, nitems = 0, maxitems = 0, lastidx = 0}, snapshotarr = {itemsarr = 0x0, invalidval = 0, capacity = 0, nitems = 0, maxitems = 0, lastidx = 0}, filearr = {itemsarr = 0x0, invalidval = 18446744073709551615, capacity = 0, nitems = 0, maxitems = 0, lastidx = 0}, dsmarr = { itemsarr = 0x0, invalidval = 0, capacity = 0, nitems = 0, maxitems = 0, lastidx = 0}, jitarr = {itemsarr = 0x0, invalidval = 0, capacity = 0, nitems = 0, maxitems = 0, lastidx = 0}, nlocks = 1, locks = {0x2c28320, 0x0 }}#2、count(gdb) p count$5 = 9223372036854775807#3、isTopLevel(gdb) p isTopLevel$6 = true#4、run_once(gdb) p run_once$7 = true#5、dest$8 = (DestReceiver *) 0x2ccb4d8(gdb) p *dest$9 = {receiveSlot = 0x4857ad , rStartup = 0x485196 , rShutdown = 0x485bad , rDestroy = 0x485c21 , mydest = DestRemote}(gdb) #6、altdest(gdb) p altdest$10 = (DestReceiver *) 0x2ccb4d8(gdb) p *altdest$11 = {receiveSlot = 0x4857ad , rStartup = 0x485196 , rShutdown = 0x485bad , rDestroy = 0x485c21 , mydest = DestRemote}(gdb) #7、completionTag(gdb) p completionTag$12 = 0x7ffe94ba4940 ""#单步调试710 if (log_executor_stats && portal->strategy != PORTAL_MULTI_QUERY)(gdb) 720 MarkPortalActive(portal);(gdb) 724 portal->run_once = run_once;(gdb) 740 saveTopTransactionResourceOwner = TopTransactionResourceOwner;(gdb) 741 saveTopTransactionContext = TopTransactionContext;(gdb) 742 saveActivePortal = ActivePortal;(gdb) 743 saveResourceOwner = CurrentResourceOwner;(gdb) 744 savePortalContext = PortalContext;(gdb) 745 saveMemoryContext = CurrentMemoryContext;(gdb) 746 PG_TRY();(gdb) 748 ActivePortal = portal;(gdb) 749 if (portal->resowner)(gdb) 750 CurrentResourceOwner = portal->resowner;(gdb) 751 PortalContext = portal->portalContext;(gdb) 753 MemoryContextSwitchTo(PortalContext);(gdb) 755 switch (portal->strategy)(gdb) p portal->strategy$13 = PORTAL_MULTI_QUERY(gdb) next799 PortalRunMulti(portal, isTopLevel, false,(gdb) 803 MarkPortalDone(portal);(gdb) 806 result = true;(gdb) 807 break;(gdb) 835 PG_END_TRY();(gdb) 837 if (saveMemoryContext == saveTopTransactionContext)(gdb) 838 MemoryContextSwitchTo(TopTransactionContext);(gdb) 841 ActivePortal = saveActivePortal;(gdb) 842 if (saveResourceOwner == saveTopTransactionResourceOwner)(gdb) 843 CurrentResourceOwner = TopTransactionResourceOwner;(gdb) 846 PortalContext = savePortalContext;(gdb) 848 if (log_executor_stats && portal->strategy != PORTAL_MULTI_QUERY)(gdb) 853 return result;(gdb) 854 }#DONE!
2、PortalRunMulti
(gdb) b PortalRunMultiBreakpoint 1 at 0x8533df: file pquery.c, line 1210.(gdb) cContinuing.Breakpoint 1, PortalRunMulti (portal=0x2c6f490, isTopLevel=true, setHoldSnapshot=false, dest=0x2cbe8f8, altdest=0x2cbe8f8, completionTag=0x7ffe94ba4940 "") at pquery.c:12101210 bool active_snapshot_set = false;#输入参数#1、portal(gdb) p *portal$1 = {name = 0x2c72e98 "", prepStmtName = 0x0, portalContext = 0x2c2d3d0, resowner = 0x2c3ad10, cleanup = 0x62f15c, createSubid = 1, activeSubid = 1, sourceText = 0x2c09ef0 "insert into t_insert values(21,'PortalRunMulti','PortalRunMulti','PortalRunMulti');", commandTag = 0xb50908 "INSERT", stmts = 0x2cbe8c8, cplan = 0x0, portalParams = 0x0, queryEnv = 0x0, strategy = PORTAL_MULTI_QUERY, cursorOptions = 4, run_once = true, status = PORTAL_ACTIVE, portalPinned = false, autoHeld = false, queryDesc = 0x0, tupDesc = 0x0, formats = 0x0, holdStore = 0x0, holdContext = 0x0, holdSnapshot = 0x0, atStart = true, atEnd = true, portalPos = 0, creation_time = 587034112962796, visible = false}(gdb) p *(portal->portalContext)$2 = {type = T_AllocSetContext, isReset = true, allowInCritSection = false, methods = 0xb8c720 , parent = 0x2c6f380, firstchild = 0x0, prevchild = 0x0, nextchild = 0x0, name = 0xb8d2f1 "PortalContext", ident = 0x2c72e98 "", reset_cbs = 0x0}#2、isTopLevel(gdb) p isTopLevel$3 = true#3、setHoldSnapshot(gdb) p setHoldSnapshot$4 = false#4、dest(gdb) p *dest$5 = {receiveSlot = 0x4857ad , rStartup = 0x485196 , rShutdown = 0x485bad , rDestroy = 0x485c21 , mydest = DestRemote}#5、altdest(gdb) p *altdest$6 = {receiveSlot = 0x4857ad , rStartup = 0x485196 , rShutdown = 0x485bad , rDestroy = 0x485c21 , mydest = DestRemote}#6、completionTag(gdb) p *completionTag$7 = 0 '\000'#单步调试...(gdb) next1234 PlannedStmt *pstmt = lfirst_node(PlannedStmt, stmtlist_item);(gdb) 1239 CHECK_FOR_INTERRUPTS();(gdb) p *pstmt$12 = {type = T_PlannedStmt, commandType = CMD_INSERT, queryId = 0, hasReturning = false, hasModifyingCTE = false, canSetTag = true, transientPlan = false, dependsOnRole = false, parallelModeNeeded = false, jitFlags = 0, planTree = 0x2c0aff8, rtable = 0x2cbe7d8, resultRelations = 0x2cbe878, nonleafResultRelations = 0x0, rootResultRelations = 0x0, subplans = 0x0, rewindPlanIDs = 0x0, rowMarks = 0x0, relationOids = 0x2cbe828, invalItems = 0x0, paramExecTypes = 0x2c31700, utilityStmt = 0x0, stmt_location = 0, stmt_len = 82}(gdb) next1241 if (pstmt->utilityStmt == NULL)(gdb) 1248 if (log_executor_stats)(gdb) 1257 if (!active_snapshot_set)(gdb) 1259 Snapshot snapshot = GetTransactionSnapshot();(gdb) 1262 if (setHoldSnapshot)(gdb) p *snapshot$13 = {satisfies = 0x9f73fc , xmin = 1612887, xmax = 1612887, xip = 0x2c2d1c0, xcnt = 0, subxip = 0x2c81c70, subxcnt = 0, suboverflowed = false, takenDuringRecovery = false, copied = false, curcid = 0, speculativeToken = 0, active_count = 0, regd_count = 0, ph_node = {first_child = 0x0, next_sibling = 0x0, prev_or_parent = 0x0}, whenTaken = 0, lsn = 0}(gdb) ...(gdb) PortalRun (portal=0x2c6f490, count=9223372036854775807, isTopLevel=true, run_once=true, dest=0x2cbe8f8, altdest=0x2cbe8f8, completionTag=0x7ffe94ba4940 "INSERT 0 1") at pquery.c:803803 MarkPortalDone(portal);#DONE!
到此,相信大家对"PostgreSQL中PortalRunMulti函数和PortalRun函数的实现逻辑是什么"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
函数
语句
数据
逻辑
数据结构
结构
输入
内容
参数
工具
快照
e.g.
处理
学习
查询
跟踪
输出
实用
更深
事务
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
网络安全小知识短句
数据库表名用拼音坏处
北京网络技术推广
网络安全共享网络文明征文
天津哪做软件开发的多
数据库打通技术
emc服务器我的世界
教软件开发武汉哪家靠谱
服务器 短信费
流量转发服务器ip
强网杯 网络安全竞赛
沈阳网络安全科技馆
互联网金融科技公司干啥的
周村人事hr软件开发
肃南融媒体中心网络安全
软件开发公司组织形式
数据交换服务器网络架构
软件开发技术怎么收费
武汉安卓软件开发教程
失落的方舟玩了俄区怎么换服务器
如何弘扬网络安全文化
宝武网络安全
抚顺政务软件开发技术
emc服务器我的世界
方舟生存进化服务器满了怎么办
网络安全认证考试考什么
心电图下面的数据库
绍兴运维管理软件开发
wcba数据库
深圳融博软件开发收入