static int executeXMLQuery(char *szXml) { Query *pquery = COptTasks::PqueryFromXML(szXml); PlannedStmt *pplstmt = pg_plan_query(pquery, NULL); DestReceiver *pdest = CreateDestReceiver(DestNone, NULL); QueryDesc *pqueryDesc = CreateQueryDesc(pplstmt, PStrDup("Internal Query") /*plan->query */, ActiveSnapshot, InvalidSnapshot, pdest, NULL /*paramLI*/, false); elog(NOTICE, "Executing thawed plan..."); ExecutorStart(pqueryDesc, 0); ExecutorRun(pqueryDesc, ForwardScanDirection, 0); ExecutorEnd(pqueryDesc); int iProcessed = (int) pqueryDesc->es_processed; FreeQueryDesc(pqueryDesc); return iProcessed; }
/* * refresh_matview_datafill */ static void refresh_matview_datafill(DestReceiver *dest, Query *query, const char *queryString) { List *rewritten; PlannedStmt *plan; QueryDesc *queryDesc; Query *copied_query; /* Lock and rewrite, using a copy to preserve the original query. */ copied_query = copyObject(query); AcquireRewriteLocks(copied_query, true, false); rewritten = QueryRewrite(copied_query); /* SELECT should never rewrite to more or less than one SELECT query */ if (list_length(rewritten) != 1) elog(ERROR, "unexpected rewrite result for REFRESH MATERIALIZED VIEW"); query = (Query *) linitial(rewritten); /* Check for user-requested abort. */ CHECK_FOR_INTERRUPTS(); /* Plan the query which will generate data for the refresh. */ plan = pg_plan_query(query, 0, NULL); /* * Use a snapshot with an updated command ID to ensure this query sees * results of any previously executed queries. (This could only matter if * the planner executed an allegedly-stable function that changed the * database contents, but let's do it anyway to be safe.) */ PushCopiedSnapshot(GetActiveSnapshot()); UpdateActiveSnapshotCommandId(); /* Create a QueryDesc, redirecting output to our tuple receiver */ queryDesc = CreateQueryDesc(plan, queryString, GetActiveSnapshot(), InvalidSnapshot, dest, NULL, 0); /* call ExecutorStart to prepare the plan for execution */ ExecutorStart(queryDesc, EXEC_FLAG_WITHOUT_OIDS); /* run the plan */ ExecutorRun(queryDesc, ForwardScanDirection, 0L); /* and clean up */ ExecutorFinish(queryDesc); ExecutorEnd(queryDesc); FreeQueryDesc(queryDesc); PopActiveSnapshot(); }
static int extractFrozenQueryPlanAndExecute(char *pcQuery) { Assert(pcQuery); ULONG ulQueryLen = -1; memcpy(&ulQueryLen, pcQuery, sizeof(ULONG)); pcQuery+=sizeof(ULONG); Query *pquery = (Query *) readNodeFromBinaryString(pcQuery, ulQueryLen); pcQuery+=ulQueryLen; PlannedStmt *pplstmt = pg_plan_query(pquery, NULL); if (!pplstmt) { elog(ERROR, "Problem with planned statement of query tree %s", gpdb::SzNodeToString(pquery)); } // The following steps are required to be able to execute the query. DestReceiver *pdest = CreateDestReceiver(DestNone, NULL); QueryDesc *pqueryDesc = CreateQueryDesc(pplstmt, PStrDup("Internal Query") /*plan->query */, ActiveSnapshot, InvalidSnapshot, pdest, NULL /*paramLI*/, false); // Do not record gpperfmon information about internal queries pqueryDesc->gpmon_pkt = NULL; elog(NOTICE, "Executing thawed plan..."); ExecutorStart(pqueryDesc, 0); ExecutorRun(pqueryDesc, ForwardScanDirection, 0); ExecutorEnd(pqueryDesc); int iProcessed = (int) pqueryDesc->es_processed; FreeQueryDesc(pqueryDesc); return iProcessed; }
static PlannedStmt * get_plan_from_stmt(Oid id, Node *node, const char *sql, bool is_combine) { Query *query; PlannedStmt *plan; query = linitial(pg_analyze_and_rewrite(node, sql, NULL, 0)); query->isContinuous = true; query->isCombine = is_combine; query->cq_id = id; plan = pg_plan_query(query, 0, NULL); plan->is_continuous = true; plan->is_combine = is_combine; plan->cq_id = id; /* * Unique plans get transformed into ContinuousUnique plans for * continuous query processes. */ if (IsA(plan->planTree, Unique)) { ContinuousUnique *cunique = makeNode(ContinuousUnique); Unique *unique = (Unique *) plan->planTree; memcpy((char *) &cunique->unique, (char *) unique, sizeof(Unique)); cunique->cq_id = id; cunique->unique.plan.type = T_ContinuousUnique; plan->planTree = (Plan *) cunique; Assert(IsA(plan->planTree->lefttree, Sort)); /* Strip out the sort since its not needed */ plan->planTree->lefttree = plan->planTree->lefttree->lefttree; } return plan; }
static PlannedStmt *planQuery(char *szSqlText) { Assert(szSqlText); Assert(szSqlText); List *plQueryTree = pg_parse_and_rewrite(szSqlText, NULL, 0); if (1 != gpdb::UlListLength(plQueryTree)) { elog(ERROR, "problem parsing query %s", szSqlText); } Query *pqueryTree = (Query *) lfirst(gpdb::PlcListHead(plQueryTree)); PlannedStmt *pplstmt = pg_plan_query(pqueryTree, NULL); if (!pplstmt) { elog(ERROR, "problem planned query %s. query tree is %s", szSqlText, gpdb::SzNodeToString(pqueryTree)); } return pplstmt; }
/* * ExecCreateTableAs -- execute a CREATE TABLE AS command */ void ExecCreateTableAs(CreateTableAsStmt *stmt, const char *queryString, ParamListInfo params, char *completionTag) { Query *query = (Query *) stmt->query; IntoClause *into = stmt->into; bool is_matview = (into->viewQuery != NULL); DestReceiver *dest; Oid save_userid = InvalidOid; int save_sec_context = 0; int save_nestlevel = 0; List *rewritten; PlannedStmt *plan; QueryDesc *queryDesc; ScanDirection dir; /* * Create the tuple receiver object and insert info it will need */ dest = CreateIntoRelDestReceiver(into); /* * The contained Query could be a SELECT, or an EXECUTE utility command. * If the latter, we just pass it off to ExecuteQuery. */ Assert(IsA(query, Query)); if (query->commandType == CMD_UTILITY && IsA(query->utilityStmt, ExecuteStmt)) { ExecuteStmt *estmt = (ExecuteStmt *) query->utilityStmt; Assert(!is_matview); /* excluded by syntax */ ExecuteQuery(estmt, into, queryString, params, dest, completionTag); return; } Assert(query->commandType == CMD_SELECT); /* * For materialized views, lock down security-restricted operations and * arrange to make GUC variable changes local to this command. This is * not necessary for security, but this keeps the behavior similar to * REFRESH MATERIALIZED VIEW. Otherwise, one could create a materialized * view not possible to refresh. */ if (is_matview) { GetUserIdAndSecContext(&save_userid, &save_sec_context); SetUserIdAndSecContext(save_userid, save_sec_context | SECURITY_RESTRICTED_OPERATION); save_nestlevel = NewGUCNestLevel(); } /* * Parse analysis was done already, but we still have to run the rule * rewriter. We do not do AcquireRewriteLocks: we assume the query either * came straight from the parser, or suitable locks were acquired by * plancache.c. * * Because the rewriter and planner tend to scribble on the input, we make * a preliminary copy of the source querytree. This prevents problems in * the case that CTAS is in a portal or plpgsql function and is executed * repeatedly. (See also the same hack in EXPLAIN and PREPARE.) */ rewritten = QueryRewrite((Query *) copyObject(query)); /* SELECT should never rewrite to more or less than one SELECT query */ if (list_length(rewritten) != 1) elog(ERROR, "unexpected rewrite result for CREATE TABLE AS SELECT"); query = (Query *) linitial(rewritten); Assert(query->commandType == CMD_SELECT); /* plan the query */ plan = pg_plan_query(query, 0, params); /* * Use a snapshot with an updated command ID to ensure this query sees * results of any previously executed queries. (This could only matter if * the planner executed an allegedly-stable function that changed the * database contents, but let's do it anyway to be parallel to the EXPLAIN * code path.) */ PushCopiedSnapshot(GetActiveSnapshot()); UpdateActiveSnapshotCommandId(); /* Create a QueryDesc, redirecting output to our tuple receiver */ queryDesc = CreateQueryDesc(plan, queryString, GetActiveSnapshot(), InvalidSnapshot, dest, params, 0); /* call ExecutorStart to prepare the plan for execution */ ExecutorStart(queryDesc, GetIntoRelEFlags(into)); /* * Normally, we run the plan to completion; but if skipData is specified, * just do tuple receiver startup and shutdown. */ if (into->skipData) dir = NoMovementScanDirection; else dir = ForwardScanDirection; /* run the plan */ ExecutorRun(queryDesc, dir, 0L); /* save the rowcount if we're given a completionTag to fill */ if (completionTag) snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "SELECT %u", queryDesc->estate->es_processed); /* and clean up */ ExecutorFinish(queryDesc); ExecutorEnd(queryDesc); FreeQueryDesc(queryDesc); PopActiveSnapshot(); if (is_matview) { /* Roll back any GUC changes */ AtEOXact_GUC(false, save_nestlevel); /* Restore userid and security context */ SetUserIdAndSecContext(save_userid, save_sec_context); } }
/* * ExecCreateTableAs -- execute a CREATE TABLE AS command */ void ExecCreateTableAs(CreateTableAsStmt *stmt, const char *queryString, ParamListInfo params, char *completionTag) { Query *query = (Query *) stmt->query; IntoClause *into = stmt->into; DestReceiver *dest; List *rewritten; PlannedStmt *plan; QueryDesc *queryDesc; ScanDirection dir; /* * Create the tuple receiver object and insert info it will need */ dest = CreateIntoRelDestReceiver(into); /* * The contained Query could be a SELECT, or an EXECUTE utility command. * If the latter, we just pass it off to ExecuteQuery. */ Assert(IsA(query, Query)); if (query->commandType == CMD_UTILITY && IsA(query->utilityStmt, ExecuteStmt)) { ExecuteStmt *estmt = (ExecuteStmt *) query->utilityStmt; ExecuteQuery(estmt, into, queryString, params, dest, completionTag); return; } Assert(query->commandType == CMD_SELECT); /* * Parse analysis was done already, but we still have to run the rule * rewriter. We do not do AcquireRewriteLocks: we assume the query either * came straight from the parser, or suitable locks were acquired by * plancache.c. * * Because the rewriter and planner tend to scribble on the input, we make * a preliminary copy of the source querytree. This prevents problems in * the case that CTAS is in a portal or plpgsql function and is executed * repeatedly. (See also the same hack in EXPLAIN and PREPARE.) */ rewritten = QueryRewrite((Query *) copyObject(query)); /* SELECT should never rewrite to more or less than one SELECT query */ if (list_length(rewritten) != 1) elog(ERROR, "unexpected rewrite result for CREATE TABLE AS SELECT"); query = (Query *) linitial(rewritten); Assert(query->commandType == CMD_SELECT); /* plan the query */ plan = pg_plan_query(query, 0, params); /* * Use a snapshot with an updated command ID to ensure this query sees * results of any previously executed queries. (This could only matter if * the planner executed an allegedly-stable function that changed the * database contents, but let's do it anyway to be parallel to the EXPLAIN * code path.) */ PushCopiedSnapshot(GetActiveSnapshot()); UpdateActiveSnapshotCommandId(); /* Create a QueryDesc, redirecting output to our tuple receiver */ queryDesc = CreateQueryDesc(plan, queryString, GetActiveSnapshot(), InvalidSnapshot, dest, params, 0); /* call ExecutorStart to prepare the plan for execution */ ExecutorStart(queryDesc, GetIntoRelEFlags(into)); /* * Normally, we run the plan to completion; but if skipData is specified, * just do tuple receiver startup and shutdown. */ if (into->skipData) dir = NoMovementScanDirection; else dir = ForwardScanDirection; /* run the plan */ ExecutorRun(queryDesc, dir, 0L); /* save the rowcount if we're given a completionTag to fill */ if (completionTag) snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "SELECT %u", queryDesc->estate->es_processed); /* and clean up */ ExecutorFinish(queryDesc); ExecutorEnd(queryDesc); FreeQueryDesc(queryDesc); PopActiveSnapshot(); }
/* * refresh_matview_datafill */ static void refresh_matview_datafill(DestReceiver *dest, Query *query, const char *queryString, Oid relowner) { List *rewritten; PlannedStmt *plan; QueryDesc *queryDesc; Oid save_userid; int save_sec_context; int save_nestlevel; Query *copied_query; /* * Switch to the owner's userid, so that any functions are run as that * user. Also lock down security-restricted operations and arrange to * make GUC variable changes local to this command. */ GetUserIdAndSecContext(&save_userid, &save_sec_context); SetUserIdAndSecContext(relowner, save_sec_context | SECURITY_RESTRICTED_OPERATION); save_nestlevel = NewGUCNestLevel(); /* Lock and rewrite, using a copy to preserve the original query. */ copied_query = copyObject(query); AcquireRewriteLocks(copied_query, true, false); rewritten = QueryRewrite(copied_query); /* SELECT should never rewrite to more or less than one SELECT query */ if (list_length(rewritten) != 1) elog(ERROR, "unexpected rewrite result for REFRESH MATERIALIZED VIEW"); query = (Query *) linitial(rewritten); /* Check for user-requested abort. */ CHECK_FOR_INTERRUPTS(); /* Plan the query which will generate data for the refresh. */ plan = pg_plan_query(query, 0, NULL); /* * Use a snapshot with an updated command ID to ensure this query sees * results of any previously executed queries. (This could only matter if * the planner executed an allegedly-stable function that changed the * database contents, but let's do it anyway to be safe.) */ PushCopiedSnapshot(GetActiveSnapshot()); UpdateActiveSnapshotCommandId(); /* Create a QueryDesc, redirecting output to our tuple receiver */ queryDesc = CreateQueryDesc(plan, queryString, GetActiveSnapshot(), InvalidSnapshot, dest, NULL, 0); /* call ExecutorStart to prepare the plan for execution */ ExecutorStart(queryDesc, EXEC_FLAG_WITHOUT_OIDS); /* run the plan */ ExecutorRun(queryDesc, ForwardScanDirection, 0L); /* and clean up */ ExecutorFinish(queryDesc); ExecutorEnd(queryDesc); FreeQueryDesc(queryDesc); PopActiveSnapshot(); /* Roll back any GUC changes */ AtEOXact_GUC(false, save_nestlevel); /* Restore userid and security context */ SetUserIdAndSecContext(save_userid, save_sec_context); }
/* * PerformCursorOpen * Execute SQL DECLARE CURSOR command. */ void PerformCursorOpen(DeclareCursorStmt *cstmt, ParamListInfo params, const char *queryString, bool isTopLevel) { Query *query = (Query *) cstmt->query; List *rewritten; PlannedStmt *plan; Portal portal; MemoryContext oldContext; Assert(IsA(query, Query)); /* else parse analysis wasn't done */ /* * Disallow empty-string cursor name (conflicts with protocol-level * unnamed portal). */ if (!cstmt->portalname || cstmt->portalname[0] == '\0') ereport(ERROR, (errcode(ERRCODE_INVALID_CURSOR_NAME), errmsg("invalid cursor name: must not be empty"))); /* * If this is a non-holdable cursor, we require that this statement has * been executed inside a transaction block (or else, it would have no * user-visible effect). */ if (!(cstmt->options & CURSOR_OPT_HOLD)) RequireTransactionChain(isTopLevel, "DECLARE CURSOR"); /* * Parse analysis was done already, but we still have to run the rule * rewriter. We do not do AcquireRewriteLocks: we assume the query either * came straight from the parser, or suitable locks were acquired by * plancache.c. * * Because the rewriter and planner tend to scribble on the input, we make * a preliminary copy of the source querytree. This prevents problems in * the case that the DECLARE CURSOR is in a portal or plpgsql function and * is executed repeatedly. (See also the same hack in EXPLAIN and * PREPARE.) XXX FIXME someday. */ rewritten = QueryRewrite((Query *) copyObject(query)); /* SELECT should never rewrite to more or less than one query */ if (list_length(rewritten) != 1) elog(ERROR, "non-SELECT statement in DECLARE CURSOR"); query = (Query *) linitial(rewritten); if (query->commandType != CMD_SELECT) elog(ERROR, "non-SELECT statement in DECLARE CURSOR"); /* Plan the query, applying the specified options */ plan = pg_plan_query(query, cstmt->options, params); /* * Create a portal and copy the plan and queryString into its memory. */ portal = CreatePortal(cstmt->portalname, false, false); oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal)); plan = copyObject(plan); queryString = pstrdup(queryString); PortalDefineQuery(portal, NULL, queryString, "SELECT", /* cursor's query is always a SELECT */ list_make1(plan), NULL); /*---------- * Also copy the outer portal's parameter list into the inner portal's * memory context. We want to pass down the parameter values in case we * had a command like * DECLARE c CURSOR FOR SELECT ... WHERE foo = $1 * This will have been parsed using the outer parameter set and the * parameter value needs to be preserved for use when the cursor is * executed. *---------- */ params = copyParamList(params); MemoryContextSwitchTo(oldContext); /* * Set up options for portal. * * If the user didn't specify a SCROLL type, allow or disallow scrolling * based on whether it would require any additional runtime overhead to do * so. Also, we disallow scrolling for FOR UPDATE cursors. */ portal->cursorOptions = cstmt->options; if (!(portal->cursorOptions & (CURSOR_OPT_SCROLL | CURSOR_OPT_NO_SCROLL))) { if (plan->rowMarks == NIL && ExecSupportsBackwardScan(plan->planTree)) portal->cursorOptions |= CURSOR_OPT_SCROLL; else portal->cursorOptions |= CURSOR_OPT_NO_SCROLL; } /* * Start execution, inserting parameters if any. */ PortalStart(portal, params, 0, GetActiveSnapshot()); Assert(portal->strategy == PORTAL_ONE_SELECT); /* * We're done; the query won't actually be run until PerformPortalFetch is * called. */ }
/* * refresh_matview_datafill */ static void refresh_matview_datafill(DestReceiver *dest, Query *query, const char *queryString) { List *rewritten; PlannedStmt *plan; QueryDesc *queryDesc; List *rtable; RangeTblEntry *initial_rte; RangeTblEntry *second_rte; rewritten = QueryRewrite((Query *) copyObject(query)); /* SELECT should never rewrite to more or less than one SELECT query */ if (list_length(rewritten) != 1) elog(ERROR, "unexpected rewrite result for REFRESH MATERIALIZED VIEW"); query = (Query *) linitial(rewritten); /* Check for user-requested abort. */ CHECK_FOR_INTERRUPTS(); /* * Kludge here to allow refresh of a materialized view which is invalid * (that is, it was created or refreshed WITH NO DATA. We flag the first * two RangeTblEntry list elements, which were added to the front of the * rewritten Query to keep the rules system happy, with the isResultRel * flag to indicate that it is OK if they are flagged as invalid. See * UpdateRangeTableOfViewParse() for details. * * NOTE: The rewrite has switched the frist two RTEs, but they are still * in the first two positions. If that behavior changes, the asserts here * will fail. */ rtable = query->rtable; initial_rte = ((RangeTblEntry *) linitial(rtable)); Assert(strcmp(initial_rte->alias->aliasname, "new")); initial_rte->isResultRel = true; second_rte = ((RangeTblEntry *) lsecond(rtable)); Assert(strcmp(second_rte->alias->aliasname, "old")); second_rte->isResultRel = true; /* Plan the query which will generate data for the refresh. */ plan = pg_plan_query(query, 0, NULL); /* * Use a snapshot with an updated command ID to ensure this query sees * results of any previously executed queries. (This could only matter if * the planner executed an allegedly-stable function that changed the * database contents, but let's do it anyway to be safe.) */ PushCopiedSnapshot(GetActiveSnapshot()); UpdateActiveSnapshotCommandId(); /* Create a QueryDesc, redirecting output to our tuple receiver */ queryDesc = CreateQueryDesc(plan, queryString, GetActiveSnapshot(), InvalidSnapshot, dest, NULL, 0); /* call ExecutorStart to prepare the plan for execution */ ExecutorStart(queryDesc, EXEC_FLAG_WITHOUT_OIDS); /* run the plan */ ExecutorRun(queryDesc, ForwardScanDirection, 0L); /* and clean up */ ExecutorFinish(queryDesc); ExecutorEnd(queryDesc); FreeQueryDesc(queryDesc); PopActiveSnapshot(); }
/* * Set up the per-query execution_state records for a SQL function. * * The input is a List of Lists of parsed and rewritten, but not planned, * querytrees. The sublist structure denotes the original query boundaries. */ static List * init_execution_state(List *queryTree_list, SQLFunctionCachePtr fcache, bool lazyEvalOK) { List *eslist = NIL; execution_state *lasttages = NULL; ListCell *lc1; foreach(lc1, queryTree_list) { List *qtlist = (List *) lfirst(lc1); execution_state *firstes = NULL; execution_state *preves = NULL; ListCell *lc2; foreach(lc2, qtlist) { Query *queryTree = (Query *) lfirst(lc2); Node *stmt; execution_state *newes; Assert(IsA(queryTree, Query)); /* Plan the query if needed */ if (queryTree->commandType == CMD_UTILITY) stmt = queryTree->utilityStmt; else stmt = (Node *) pg_plan_query(queryTree, 0, NULL); /* Precheck all commands for validity in a function */ if (IsA(stmt, TransactionStmt)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), /* translator: %s is a SQL statement name */ errmsg("%s is not allowed in a SQL function", CreateCommandTag(stmt)))); if (fcache->readonly_func && !CommandIsReadOnly(stmt)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), /* translator: %s is a SQL statement name */ errmsg("%s is not allowed in a non-volatile function", CreateCommandTag(stmt)))); /* OK, build the execution_state for this query */ newes = (execution_state *) palloc(sizeof(execution_state)); if (preves) preves->next = newes; else firstes = newes; newes->next = NULL; newes->status = F_EXEC_START; newes->setsResult = false; /* might change below */ newes->lazyEval = false; /* might change below */ newes->stmt = stmt; newes->qd = NULL; if (queryTree->canSetTag) lasttages = newes; preves = newes; }