pg的语句处理主控函数

//pgsql/src/backend/executor/spi

/*
* Parse and plan a querystring.
*
* At entry, plan->argtypes and plan->nargs must be valid.
*
* Query and plan lists are stored into *plan.
*/
static void
_SPI_prepare_plan(const char *src, _SPI_plan *plan)
{
List *raw_parsetree_list;
List *query_list_list;
List *plan_list;
ListCell *list_item;
ErrorContextCallback spierrcontext;
Oid *argtypes = plan->argtypes;
int nargs = plan->nargs;

/*
* Increment CommandCounter to see changes made by now. We must do this
* to be sure of seeing any schema changes made by a just-preceding SPI
* command. (But we don't bother advancing the snapshot, since the
* planner generally operates under SnapshotNow rules anyway.)
*/
CommandCounterIncrement();

/*
* Setup error traceback support for ereport()
*/
spierrcontext.callback = _SPI_error_callback;
spierrcontext.arg = (void *) src;
spierrcontext.previous = error_context_stack;
error_context_stack = &spierrcontext;

/*
* Parse the request string into a list of raw parse trees.
*

raw_parsetree_list = pg_parse_query(src);/

/*
* Do parse analysis and rule rewrite for each raw parsetree.
*
* We save the querytrees from each raw parsetree as a separate sublist.
* This allows _SPI_execute_plan() to know where the boundaries between
* original queries fall.
*/
query_list_list = NIL;
plan_list = NIL;

foreach(list_item, raw_parsetree_list)
{
Node *parsetree = (Node *) lfirst(list_item);
List *query_list;

query_list = pg_analyze_and_rewrite(parsetree, argtypes, nargs);

query_list_list = lappend(query_list_list, query_list);

plan_list = list_concat(plan_list,
pg_plan_queries(query_list, NULL, false));
}

plan->qtlist = query_list_list;
plan->ptlist = plan_list;

/*
* Pop the error context stack
*/
error_context_stack = spierrcontext.previous;
}

/*
* Execute the given plan with the given parameter values
*
* snapshot: query snapshot to use, or InvalidSnapshot for the normal
* behavior of taking a new snapshot for each query.
* crosscheck_snapshot: for RI use, all others pass InvalidSnapshot
* read_only: TRUE for read-only execution (no CommandCounterIncrement)
* fire_triggers: TRUE to fire AFTER triggers at end of query (normal case);
* FALSE means any AFTER triggers are postponed to end of outer query
* tcount: execution tuple-count limit, or 0 for none
*/
static int
_SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
Snapshot snapshot, Snapshot crosscheck_snapshot,
bool read_only, bool fire_triggers, long tcount)
{
volatile int res = 0;
volatile uint32 my_processed = 0;
volatile Oid my_lastoid = InvalidOid;
SPITupleTable *volatile my_tuptable = NULL;
Snapshot saveActiveSnapshot;

/* Be sure to restore ActiveSnapshot on error exit */
saveActiveSnapshot = ActiveSnapshot;
PG_TRY();
{
List *query_list_list = plan->qtlist;
ListCell *plan_list_item = list_head(plan->ptlist);
ListCell *query_list_list_item;
ErrorContextCallback spierrcontext;
int nargs = plan->nargs;
ParamListInfo paramLI;

/* Convert parameters to form wanted by executor */
if (nargs > 0)
{
int k;

paramLI = (ParamListInfo)
palloc0((nargs + 1) * sizeof(ParamListInfoData));

for (k = 0; k < nargs; k++)
{
paramLI[k].kind = PARAM_NUM;
paramLI[k].id = k + 1;
paramLI[k].ptype = plan->argtypes[k];
paramLI[k].isnull = (Nulls && Nulls[k] == 'n');
paramLI[k].value = Values[k];
}
paramLI[k].kind = PARAM_INVALID;
}
else
paramLI = NULL;

/*
* Setup error traceback support for ereport()
*/
spierrcontext.callback = _SPI_error_callback;
spierrcontext.arg = (void *) plan->query;
spierrcontext.previous = error_context_stack;
error_context_stack = &spierrcontext;

foreach(query_list_list_item, query_list_list)
{
List *query_list = lfirst(query_list_list_item);
ListCell *query_list_item;

foreach(query_list_item, query_list)
{
Query *queryTree = (Query *) lfirst(query_list_item);
Plan *planTree;
QueryDesc *qdesc;
DestReceiver *dest;

planTree = lfirst(plan_list_item);
plan_list_item = lnext(plan_list_item);

_SPI_current->processed = 0;
_SPI_current->lastoid = InvalidOid;
_SPI_current->tuptable = NULL;

if (queryTree->commandType == CMD_UTILITY)
{
if (IsA(queryTree->utilityStmt, CopyStmt))
{
CopyStmt *stmt = (CopyStmt *) queryTree->utilityStmt;

if (stmt->filename == NULL)
{
res = SPI_ERROR_COPY;
goto fail;
}
}
else if (IsA(queryTree->utilityStmt, DeclareCursorStmt) ||
IsA(queryTree->utilityStmt, ClosePortalStmt) ||
IsA(queryTree->utilityStmt, FetchStmt))
{
res = SPI_ERROR_CURSOR;
goto fail;
}
else if (IsA(queryTree->utilityStmt, TransactionStmt))
{
res = SPI_ERROR_TRANSACTION;
goto fail;
}
}

if (read_only && !QueryIsReadOnly(queryTree))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
/* translator: %s is a SQL statement name */
errmsg("%s is not allowed in a non-volatile function",
CreateQueryTag(queryTree))));

/*
* If not read-only mode, advance the command counter before
* each command.
*/
if (!read_only)
CommandCounterIncrement();

dest = CreateDestReceiver(queryTree->canSetTag ? DestSPI : DestNone,
NULL);

if (snapshot == InvalidSnapshot)
{
/*
* Default read_only behavior is to use the entry-time
* ActiveSnapshot; if read-write, grab a full new snap.
*/
if (read_only)
ActiveSnapshot = CopySnapshot(saveActiveSnapshot);
else
ActiveSnapshot = CopySnapshot(GetTransactionSnapshot());
}
else
{
/*
* We interpret read_only with a specified snapshot to be
* exactly that snapshot, but read-write means use the
* snap with advancing of command ID.
*/
ActiveSnapshot = CopySnapshot(snapshot);
if (!read_only)
ActiveSnapshot->curcid = GetCurrentCommandId();
}

if (queryTree->commandType == CMD_UTILITY)
{
ProcessUtility(queryTree->utilityStmt, paramLI,
dest, NULL);
res = SPI_OK_UTILITY;
}
else
{
qdesc = CreateQueryDesc(queryTree, planTree,
ActiveSnapshot,
crosscheck_snapshot,
dest,
paramLI, false);
res = _SPI_pquery(qdesc, fire_triggers,
queryTree->canSetTag ? tcount : 0);
FreeQueryDesc(qdesc);
}
FreeSnapshot(ActiveSnapshot);
ActiveSnapshot = NULL;

/*
* The last canSetTag query sets the auxiliary values returned
* to the caller. Be careful to free any tuptables not
* returned, to avoid intratransaction memory leak.
*/
if (queryTree->canSetTag)
{
my_processed = _SPI_current->processed;
my_lastoid = _SPI_current->lastoid;
SPI_freetuptable(my_tuptable);
my_tuptable = _SPI_current->tuptable;
}
else
{
SPI_freetuptable(_SPI_current->tuptable);
_SPI_current->tuptable = NULL;
}
/* we know that the receiver doesn't need a destroy call */
if (res < 0)
goto fail;
}
}

fail:

/*
* Pop the error context stack
*/
error_context_stack = spierrcontext.previous;
}
PG_CATCH();
{
/* Restore global vars and propagate error */
ActiveSnapshot = saveActiveSnapshot;
PG_RE_THROW();
}
PG_END_TRY();

ActiveSnapshot = saveActiveSnapshot;

/* Save results for caller */
SPI_processed = my_processed;
SPI_lastoid = my_lastoid;
SPI_tuptable = my_tuptable;

return res;
}
//调用执行器

static int
_SPI_pquery(QueryDesc *queryDesc, bool fire_triggers, long tcount)
{
int operation = queryDesc->operation;
int res;

switch (operation)
{
case CMD_SELECT:
res = SPI_OK_SELECT;
if (queryDesc->parsetree->into) /* select into table? */
{
res = SPI_OK_SELINTO;
queryDesc->dest = None_Receiver; /* don't output results */
}
else if (queryDesc->dest->mydest != DestSPI)
{
/* Don't return SPI_OK_SELECT if we're discarding result */
res = SPI_OK_UTILITY;
}
break;
case CMD_INSERT:
res = SPI_OK_INSERT;
break;
case CMD_DELETE:
res = SPI_OK_DELETE;
break;
case CMD_UPDATE:
res = SPI_OK_UPDATE;
break;
default:
return SPI_ERROR_OPUNKNOWN;
}

#ifdef SPI_EXECUTOR_STATS
if (ShowExecutorStats)
ResetUsage();
#endif

if (fire_triggers)
AfterTriggerBeginQuery();

ExecutorStart(queryDesc, false);

ExecutorRun(queryDesc, ForwardScanDirection, tcount);

_SPI_current->processed = queryDesc->estate->es_processed;
_SPI_current->lastoid = queryDesc->estate->es_lastoid;

if (operation == CMD_SELECT && queryDesc->dest->mydest == DestSPI)
{
if (_SPI_checktuples())
elog(ERROR, "consistency check on SPI tuple count failed");
}

/* Take care of any queued AFTER triggers */
if (fire_triggers)
AfterTriggerEndQuery(queryDesc->estate);

ExecutorEnd(queryDesc);

#ifdef SPI_EXECUTOR_STATS
if (ShowExecutorStats)
ShowUsage("SPI EXECUTOR STATS");
#endif

return res;
}

由于IE浏览器升级禁用了alt+x快捷键,请用alt+q快捷键来快速进入写说说入口
正在加载中...
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值