本节介绍了PortalStart函数,该函数在create_simple_query中被调用,用于执行前初始化portal结构体中的相关信息。 一、数据结构 Portal 包括场景
本节介绍了PortalStart函数,该函数在create_simple_query中被调用,用于执行前初始化portal结构体中的相关信息。
Portal
包括场景PortalStrategy枚举定义/PortalStatus状态定义/PortalData结构体.Portal是PortalData结构体指针,详见代码注释.
typedef enum PortalStrategy
{
PORTAL_ONE_SELECT,
PORTAL_ONE_RETURNING,
PORTAL_ONE_MOD_WITH,
PORTAL_UTIL_SELECT,
PORTAL_MULTI_QUERY
} PortalStrategy;
typedef enum PortalStatus
{
PORTAL_NEW,
PORTAL_DEFINED,
PORTAL_READY,
PORTAL_ACTIVE,
PORTAL_DONE,
PORTAL_FaiLED
} PortalStatus;
typedef struct PortalData *Portal;//结构体指针
typedef struct PortalData
{
const char *name;
const char *prepStmtName;
MemoryContext portalContext;
ResourceOwner resowner;
void (*cleanup) (Portal portal);
SubTransactionId createSubid;
SubTransactionId activeSubid;
//portal将会执行的查询
const char *sourceText;
const char *commandTag;
List *stmts;
CachedPlan *cplan;
ParamListInfo portalParams;
QueryEnvironment *queryEnv;
PortalStrategy strategy;
int cursorOptions;
bool run_once;
PortalStatus status;
bool portalPinned;
bool autoHeld;
//如不为NULL,执行器处于活动状态
QueryDesc *queryDesc;
//如Portal需要返回元组,这是元组的描述
TupleDesc tupDesc;
//列信息的格式码
int16 *fORMats;
Tuplestorestate *holdStore;
MemoryContext holdContext;
Snapshot holdSnapshot;
bool atStart;//处于开始位置?
bool atEnd;//处于结束位置?
uint64 portalPos;//实际行号
//用于表示的数据,主要由pg_cursors系统视图使用
TimestampTz creation_time;
bool visible;
} PortalData;
#define PortalIsValid(p) PointerIsValid(p)
QueryDesc
QueryDesc封装了执行器执行查询所需的所有内容。
typedef struct QueryDesc
{
//以下变量由CreateQueryDesc函数设置
CmdType operation;
PlannedStmt *plannedstmt;
const char *sourceText;
Snapshot snapshot;
Snapshot crosscheck_snapshot;
DestReceiver *dest;
ParamListInfo params;
QueryEnvironment *queryEnv;
int instrument_options;
//以下变量由ExecutorStart函数设置
TupleDesc tupDesc;
EState *estate;
PlanState *planstate;
//以下变量由ExecutorRun设置
bool already_executed;
//内核设置为NULL,可由插件修改
struct Instrumentation *totaltime;
} QueryDesc;
PortalStart
PortalStart函数的作用是在执行sql语句前初始化portal结构体中的相关信息,其中有2个重要数据结构的初始化:
1.调用CreateQueryDesc函数结构体QueryDesc
2.调用ExecutorStart函数初始化结构体EState,ExecutorStart函数调用InitPlan(下一节介绍)初始化计划状态树.
void
PortalStart(Portal portal, ParamListInfo params,
int eflags, Snapshot snapshot)
{
Portal saveActivePortal;
ResourceOwner saveResourceOwner;
MemoryContext savePortalContext;
MemoryContext oldContext;
QueryDesc *queryDesc;
int myeflags;
AssertArg(PortalIsValid(portal));
AssertState(portal->status == PORTAL_DEFINED);
//保护"现场"
saveActivePortal = ActivePortal;
saveResourceOwner = CurrentResourceOwner;
savePortalContext = PortalContext;
PG_TRY();
{
ActivePortal = portal;
if (portal->resowner)
CurrentResourceOwner = portal->resowner;
PortalContext = portal->portalContext;
oldContext = MemoryContextSwitchTo(PortalContext);
//记录传递的参数信息
portal->portalParams = params;
portal->strategy = ChoosePortalStrategy(portal->stmts);
switch (portal->strategy)
{
case PORTAL_ONE_SELECT://PORTAL_ONE_SELECT
//在开始执行前必须设置快照snapshot
if (snapshot)
PushActiveSnapshot(snapshot);
else
PushActiveSnapshot(GetTransactionSnapshot());
queryDesc = CreateQueryDesc(linitial_node(PlannedStmt, portal->stmts),
portal->sourceText,
GetActiveSnapshot(),
InvalidSnapshot,
None_Receiver,
params,
portal->queryEnv,
0);
if (portal->cursorOptions & CURSOR_OPT_SCROLL)
myeflags = eflags | EXEC_FLAG_REWIND | EXEC_FLAG_BACKWARD;
else
myeflags = eflags;
ExecutorStart(queryDesc, myeflags);
portal->queryDesc = queryDesc;
portal->tupDesc = queryDesc->tupDesc;
portal->atStart = true;//开始的位置
portal->atEnd = false;
portal->portalPos = 0;//游标位置
PopActiveSnapshot();
break;
case PORTAL_ONE_RETURNING:
case PORTAL_ONE_MOD_WITH:
{
PlannedStmt *pstmt;
pstmt = PortalGetPrimaryStmt(portal);//获取主stmt
portal->tupDesc =
ExecCleanTypeFromTL(pstmt->planTree->targetlist,
false);//设置元组描述符
}
portal->atStart = true;
portal->atEnd = false;
portal->portalPos = 0;
break;
case PORTAL_UTIL_SELECT://PORTAL_UTIL_SELECT
{
PlannedStmt *pstmt = PortalGetPrimaryStmt(portal);
Assert(pstmt->commandType == CMD_UTILITY);
portal->tupDesc = UtilityTupleDescriptor(pstmt->utilityStmt);
}
portal->atStart = true;
portal->atEnd = false;
portal->portalPos = 0;
break;
case PORTAL_MULTI_QUERY://PORTAL_MULTI_QUERY
portal->tupDesc = NULL;
break;
}
}
PG_CATCH();
{
MarkPortalFailed(portal);
ActivePortal = saveActivePortal;
CurrentResourceOwner = saveResourceOwner;
PortalContext = savePortalContext;
PG_RE_THROW();
}
PG_END_TRY();
MemoryContextSwitchTo(oldContext);
ActivePortal = saveActivePortal;
CurrentResourceOwner = saveResourceOwner;
PortalContext = savePortalContext;
portal->status = PORTAL_READY;
}
PortalStrategy
ChoosePortalStrategy(List *stmts)
{
int nSetTag;
ListCell *lc;
if (list_length(stmts) == 1)//只有1条语句
{
Node *stmt = (Node *) linitial(stmts);//获取stmt
if (IsA(stmt, Query))//Query
{
Query *query = (Query *) stmt;
if (query->canSetTag)
{
if (query->commandType == CMD_SELECT)//查询命令
{
if (query->hasModifyinGCTE)
return PORTAL_ONE_MOD_WITH;//存在可更新的CTE-->PORTAL_ONE_MOD_WITH
else
return PORTAL_ONE_SELECT;//单个查询语句
}
if (query->commandType == CMD_UTILITY)//工具语句
{
if (UtilityReturnsTuples(query->utilityStmt))//返回元组
return PORTAL_UTIL_SELECT;//PORTAL_UTIL_SELECT
return PORTAL_MULTI_QUERY;//返回PORTAL_MULTI_QUERY
}
}
}
else if (IsA(stmt, PlannedStmt))//PlannedStmt,参见Query处理逻辑
{
PlannedStmt *pstmt = (PlannedStmt *) stmt;
if (pstmt->canSetTag)
{
if (pstmt->commandType == CMD_SELECT)
{
if (pstmt->hasModifyingCTE)
return PORTAL_ONE_MOD_WITH;
else
return PORTAL_ONE_SELECT;
}
if (pstmt->commandType == CMD_UTILITY)
{
if (UtilityReturnsTuples(pstmt->utilityStmt))
return PORTAL_UTIL_SELECT;
return PORTAL_MULTI_QUERY;
}
}
}
else
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(stmt));
}
//存在多条语句
nSetTag = 0;
foreach(lc, stmts)//遍历
{
Node *stmt = (Node *) lfirst(lc);
if (IsA(stmt, Query))
{
Query *query = (Query *) stmt;
if (query->canSetTag)
{
if (++nSetTag > 1)
return PORTAL_MULTI_QUERY;
if (query->commandType == CMD_UTILITY ||
query->returningList == NIL)
return PORTAL_MULTI_QUERY;
}
}
else if (IsA(stmt, PlannedStmt))
{
PlannedStmt *pstmt = (PlannedStmt *) stmt;
if (pstmt->canSetTag)
{
if (++nSetTag > 1)
return PORTAL_MULTI_QUERY;
if (pstmt->commandType == CMD_UTILITY ||
!pstmt->hasReturning)
return PORTAL_MULTI_QUERY;
}
}
else
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(stmt));
}
if (nSetTag == 1)
return PORTAL_ONE_RETURNING;
//通常的情况
return PORTAL_MULTI_QUERY;
}
QueryDesc *
CreateQueryDesc(PlannedStmt *plannedstmt,
const char *sourceText,
Snapshot snapshot,
Snapshot crosscheck_snapshot,
DestReceiver *dest,
ParamListInfo params,
QueryEnvironment *queryEnv,
int instrument_options)
{
QueryDesc *qd = (QueryDesc *) palloc(sizeof(QueryDesc));
qd->operation = plannedstmt->commandType;
qd->plannedstmt = plannedstmt;
qd->sourceText = sourceText;
qd->snapshot = ReGISterSnapshot(snapshot);
qd->crosscheck_snapshot = RegisterSnapshot(crosscheck_snapshot);
qd->dest = dest;
qd->params = params;
qd->queryEnv = queryEnv; //查询环境变量
qd->instrument_options = instrument_options;
qd->tupDesc = NULL;//初始化为NULL
qd->estate = NULL;
qd->planstate = NULL;
qd->totaltime = NULL;
qd->already_executed = false;//未执行
return qd;
}
void
ExecutorStart(QueryDesc *queryDesc, int eflags)
{
if (ExecutorStart_hook)//存在钩子函数
(*ExecutorStart_hook) (queryDesc, eflags);
else
standard_ExecutorStart(queryDesc, eflags);
}
void
standard_ExecutorStart(QueryDesc *queryDesc, int eflags)
{
EState *estate;
MemoryContext oldcontext;
Assert(queryDesc != NULL);
Assert(queryDesc->estate == NULL);
if ((XactReadOnly || IsInParallelMode()) &&
!(eflags & EXEC_FLAG_EXPLAIN_ONLY))
ExecCheckXactReadOnly(queryDesc->plannedstmt);
estate = CreateExecutorState();
queryDesc->estate = estate;
oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
estate->es_param_list_info = queryDesc->params;
if (queryDesc->plannedstmt->paramExecTypes != NIL)
{
int nParamExec;
nParamExec = list_length(queryDesc->plannedstmt->paramExecTypes);
estate->es_param_exec_vals = (ParamExecData *)
palloc0(nParamExec * sizeof(ParamExecData));
}
estate->es_sourceText = queryDesc->sourceText;
estate->es_queryEnv = queryDesc->queryEnv;
switch (queryDesc->operation)
{
case CMD_SELECT:
if (queryDesc->plannedstmt->rowMarks != NIL ||
queryDesc->plannedstmt->hasModifyingCTE)
estate->es_output_cid = GetCurrentCommandId(true);
if (!queryDesc->plannedstmt->hasModifyingCTE)
eflags |= EXEC_FLAG_SKIP_TRIGGERS;
break;
case CMD_INSERT:
case CMD_DELETE:
case CMD_UPDATE:
estate->es_output_cid = GetCurrentCommandId(true);
break;
default:
elog(ERROR, "unrecognized operation code: %d",
(int) queryDesc->operation);
break;
}
estate->es_snapshot = RegisterSnapshot(queryDesc->snapshot);
estate->es_crosscheck_snapshot = RegisterSnapshot(queryDesc->crosscheck_snapshot);
estate->es_top_eflags = eflags;
estate->es_instrument = queryDesc->instrument_options;
estate->es_jit_flags = queryDesc->plannedstmt->jitFlags;
if (!(eflags & (EXEC_FLAG_SKIP_TRIGGERS | EXEC_FLAG_EXPLAIN_ONLY)))
AfterTriggerBeginQuery();
InitPlan(queryDesc, eflags);
MemoryContextSwitchTo(oldcontext);
}
测试脚本如下
testdb=# explain select dw.*,grjf.grbh,grjf.xm,grjf.ny,grjf.je
testdb-# from t_dwxx dw,lateral (select gr.grbh,gr.xm,jf.ny,jf.je
testdb(# from t_grxx gr inner join t_jfxx jf
testdb(# on gr.dwbh = dw.dwbh
testdb(# and gr.grbh = jf.grbh) grjf
testdb-# order by dw.dwbh;
QUERY PLAN
------------------------------------------------------------------------------------------
Sort (cost=20070.93..20320.93 rows=100000 width=47)
Sort Key: dw.dwbh
-> Hash Join (cost=3754.00..8689.61 rows=100000 width=47)
Hash Cond: ((gr.dwbh)::text = (dw.dwbh)::text)
-> Hash Join (cost=3465.00..8138.00 rows=100000 width=31)
Hash Cond: ((jf.grbh)::text = (gr.grbh)::text)
-> Seq Scan on t_jfxx jf (cost=0.00..1637.00 rows=100000 width=20)
-> Hash (cost=1726.00..1726.00 rows=100000 width=16)
-> Seq Scan on t_grxx gr (cost=0.00..1726.00 rows=100000 width=16)
-> Hash (cost=164.00..164.00 rows=10000 width=20)
-> Seq Scan on t_dwxx dw (cost=0.00..164.00 rows=10000 width=20)
(11 rows)
启动gdb,设置断点,进入PortalStart函数
(gdb) b PortalStart
Breakpoint 1 at 0x8cb67b: file pquery.c, line 455.
(gdb) c
Continuing.
Breakpoint 1, PortalStart (portal=0x25cd468, params=0x0, eflags=0, snapshot=0x0) at pquery.c:455
455 AssertArg(PortalIsValid(portal));
校验并保护现场
455 AssertArg(PortalIsValid(portal));
(gdb) n
456 AssertState(portal->status == PORTAL_DEFINED);
(gdb)
461 saveActivePortal = ActivePortal;
(gdb)
462 saveResourceOwner = CurrentResourceOwner;
(gdb)
463 savePortalContext = PortalContext;
设置内存上下文,资源owner等信息
466 ActivePortal = portal;
(gdb)
467 if (portal->resowner)
(gdb)
468 CurrentResourceOwner = portal->resowner;
(gdb)
469 PortalContext = portal->portalContext;
(gdb)
471 oldContext = MemoryContextSwitchTo(PortalContext);
(gdb)
474 portal->portalParams = params;
场景为PORTAL_ONE_SELECT
(gdb) p portal->strategy
$1 = PORTAL_ONE_SELECT
根据strategy,进入相应的处理分支(PORTAL_ONE_SELECT)
设置快照
489 if (snapshot)
(gdb)
492 PushActiveSnapshot(GetTransactionSnapshot());
创建QueryDesc结构体
(gdb)
498 queryDesc = CreateQueryDesc(linitial_node(PlannedStmt, portal->stmts),
查看queryDesc结构体信息
(gdb) n
512 if (portal->cursorOptions & CURSOR_OPT_SCROLL)
(gdb) p *queryDesc
$2 = {operation = CMD_SELECT, plannedstmt = 0x2650df0,
sourceText = 0x2567eb8 "select dw.*,grjf.grbh,grjf.xm,grjf.ny,grjf.je \nfrom t_dwxx dw,lateral (select gr.grbh,gr.xm,jf.ny,jf.je \n", ' ' <repeats 24 times>, "from t_grxx gr inner join t_jfxx jf \n", ' ' <repeats 34 times>...,
snapshot = 0x260ce10, crosscheck_snapshot = 0x0, dest = 0xf8f280 <donothingDR>, params = 0x0, queryEnv = 0x0,
instrument_options = 0, tupDesc = 0x0, estate = 0x0, planstate = 0x0, already_executed = false, totaltime = 0x0}
设置标记位
(gdb) n
515 myeflags = eflags;
(gdb) p eflags
$3 = 0
进入ExecutorStart函数
(gdb) n
147 standard_ExecutorStart(queryDesc, eflags);
(gdb) step
standard_ExecutorStart (queryDesc=0x2657f68, eflags=0) at execMain.c:157
157 Assert(queryDesc != NULL);
ExecutorStart-->执行相关校验和判断
157 Assert(queryDesc != NULL);
(gdb) n
158 Assert(queryDesc->estate == NULL);
(gdb)
175 if ((XactReadOnly || IsInParallelMode()) &&
ExecutorStart-->创建EState,初始化EState结构体
(gdb)
182 estate = CreateExecutorState();
(gdb)
183 queryDesc->estate = estate;
(gdb) p *estate
$4 = {type = T_EState, es_direction = ForwardScanDirection, es_snapshot = 0x0, es_crosscheck_snapshot = 0x0,
es_range_table = 0x0, es_plannedstmt = 0x0, es_sourceText = 0x0, es_junkFilter = 0x0, es_output_cid = 0,
es_result_relations = 0x0, es_num_result_relations = 0, es_result_relation_info = 0x0, es_root_result_relations = 0x0,
es_num_root_result_relations = 0, es_tuple_routing_result_relations = 0x0, es_trig_target_relations = 0x0,
es_trig_tuple_slot = 0x0, es_trig_oldtup_slot = 0x0, es_trig_newtup_slot = 0x0, es_param_list_info = 0x0,
es_param_exec_vals = 0x0, es_queryEnv = 0x0, es_query_cxt = 0x2653e30, es_tupleTable = 0x0, es_rowMarks = 0x0,
es_processed = 0, es_lastoid = 0, es_top_eflags = 0, es_instrument = 0, es_finished = false, es_exprcontexts = 0x0,
es_subplanstates = 0x0, es_auxmodifytables = 0x0, es_per_tuple_exprcontext = 0x0, es_epQtuple = 0x0,
es_epqTupleSet = 0x0, es_epqScanDone = 0x0, es_use_parallel_mode = false, es_query_dsa = 0x0, es_jit_flags = 0,
es_jit = 0x0, es_jit_worker_instr = 0x0}
ExecutorStart-->EState结构体中的变量赋值
(gdb) n
185 oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
(gdb)
191 estate->es_param_list_info = queryDesc->params;
(gdb)
193 if (queryDesc->plannedstmt->paramExecTypes != NIL)
(gdb)
202 estate->es_sourceText = queryDesc->sourceText;
(gdb)
207 estate->es_queryEnv = queryDesc->queryEnv;
ExecutorStart-->根据queryDesc->operation的不同执行的处理
(gdb)
212 switch (queryDesc->operation)
(gdb)
220 if (queryDesc->plannedstmt->rowMarks != NIL ||
(gdb) p queryDesc->operation
$5 = CMD_SELECT
(gdb) n
221 queryDesc->plannedstmt->hasModifyingCTE)
(gdb)
220 if (queryDesc->plannedstmt->rowMarks != NIL ||
(gdb)
230 if (!queryDesc->plannedstmt->hasModifyingCTE)
(gdb)
231 eflags |= EXEC_FLAG_SKIP_TRIGGERS;
(gdb)
232 break;
ExecutorStart-->设置快照
(gdb) n
249 estate->es_snapshot = RegisterSnapshot(queryDesc->snapshot);
(gdb) p *queryDesc->snapshot
$6 = {satisfies = 0xa923ca <HeapTupleSatisfiesmvcC>, xmin = 1689, xmax = 1689, xip = 0x0, xcnt = 0, subxip = 0x0,
subxcnt = 0, suboverflowed = false, takenDuringRecovery = false, copied = true, curcid = 0, speculativeToken = 0,
active_count = 1, regd_count = 1, ph_node = {first_child = 0x0, next_sibling = 0x0, prev_or_parent = 0x0}, whenTaken = 0,
lsn = 0}
ExecutorStart-->设置其他EState中的变量
(gdb) n
250 estate->es_crosscheck_snapshot = RegisterSnapshot(queryDesc->crosscheck_snapshot);
(gdb) p *queryDesc->crosscheck_snapshot
Cannot access memory at address 0x0
(gdb) n
251 estate->es_top_eflags = eflags;
(gdb)
252 estate->es_instrument = queryDesc->instrument_options;
(gdb)
253 estate->es_jit_flags = queryDesc->plannedstmt->jitFlags;
(gdb)
259 if (!(eflags & (EXEC_FLAG_SKIP_TRIGGERS | EXEC_FLAG_EXPLAIN_ONLY)))
ExecutorStart-->执行InitPlan
(gdb)
265 InitPlan(queryDesc, eflags);
(gdb)
267 MemoryContextSwitchTo(oldcontext);
(gdb)
268 }
ExecutorStart-->查看QueryDesc和EState
(gdb) p *queryDesc
$7 = {operation = CMD_SELECT, plannedstmt = 0x2650df0,
sourceText = 0x2567eb8 "select dw.*,grjf.grbh,grjf.xm,grjf.ny,grjf.je \nfrom t_dwxx dw,lateral (select gr.grbh,gr.xm,jf.ny,jf.je \n", ' ' <repeats 24 times>, "from t_grxx gr inner join t_jfxx jf \n", ' ' <repeats 34 times>...,
snapshot = 0x25e46c0, crosscheck_snapshot = 0x0, dest = 0xf8f280 <donothingDR>, params = 0x0, queryEnv = 0x0,
instrument_options = 0, tupDesc = 0x2665058, estate = 0x2653f48, planstate = 0x2654160, already_executed = false,
totaltime = 0x0}
(gdb) p *estate
$8 = {type = T_EState, es_direction = ForwardScanDirection, es_snapshot = 0x25e46c0, es_crosscheck_snapshot = 0x0,
es_range_table = 0x264ec98, es_plannedstmt = 0x2650df0,
es_sourceText = 0x2567eb8 "select dw.*,grjf.grbh,grjf.xm,grjf.ny,grjf.je \nfrom t_dwxx dw,lateral (select gr.grbh,gr.xm,jf.ny,jf.je \n", ' ' <repeats 24 times>, "from t_grxx gr inner join t_jfxx jf \n", ' ' <repeats 34 times>...,
es_junkFilter = 0x0, es_output_cid = 0, es_result_relations = 0x0, es_num_result_relations = 0,
es_result_relation_info = 0x0, es_root_result_relations = 0x0, es_num_root_result_relations = 0,
es_tuple_routing_result_relations = 0x0, es_trig_target_relations = 0x0, es_trig_tuple_slot = 0x0,
es_trig_oldtup_slot = 0x0, es_trig_newtup_slot = 0x0, es_param_list_info = 0x0, es_param_exec_vals = 0x0,
es_queryEnv = 0x0, es_query_cxt = 0x2653e30, es_tupleTable = 0x2654af8, es_rowMarks = 0x0, es_processed = 0,
es_lastoid = 0, es_top_eflags = 16, es_instrument = 0, es_finished = false, es_exprcontexts = 0x2654550,
es_subplanstates = 0x0, es_auxmodifytables = 0x0, es_per_tuple_exprcontext = 0x0, es_epqTuple = 0x0,
es_epqTupleSet = 0x0, es_epqScanDone = 0x0, es_use_parallel_mode = false, es_query_dsa = 0x0, es_jit_flags = 0,
es_jit = 0x0, es_jit_worker_instr = 0x0}
ExecutorStart-->回到PortalStart
(gdb) n
ExecutorStart (queryDesc=0x2657f68, eflags=0) at execMain.c:148
148 }
(gdb) n
PortalStart (portal=0x25cd468, params=0x0, eflags=0, snapshot=0x0) at pquery.c:525
525 portal->queryDesc = queryDesc;
设置portal中的变量atStart等
525 portal->queryDesc = queryDesc;
(gdb) n
530 portal->tupDesc = queryDesc->tupDesc;
(gdb)
535 portal->atStart = true;
(gdb)
536 portal->atEnd = false;
(gdb)
537 portal->portalPos = 0;
(gdb)
539 PopActiveSnapshot();
(gdb)
540 break;
执行完毕,回到exec_simple_query
(gdb)
613 portal->status = PORTAL_READY;
(gdb)
614 }
(gdb)
exec_simple_query (
query_string=0x2567eb8 "select dw.*,grjf.grbh,grjf.xm,grjf.ny,grjf.je \nfrom t_dwxx dw,lateral (select gr.grbh,gr.xm,jf.ny,jf.je \n", ' ' <repeats 24 times>, "from t_grxx gr inner join t_jfxx jf \n", ' ' <repeats 34 times>...) at postgres.c:1091
warning: Source file is more recent than executable.
1091 format = 0;
(gdb)
DONE!
postgres.c
PG Document:Query Planning
--结束END--
本文标题: PostgreSQL 源码解读(83)- 查询语句#68(PortalStart函数)
本文链接: https://lsjlt.com/news/47904.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-10-23
2024-10-22
2024-10-22
2024-10-22
2024-10-22
2024-10-22
2024-10-22
2024-10-22
2024-10-22
2024-10-22
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0