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、付费专栏及课程。

余额充值