diff options
Diffstat (limited to 'src/backend/commands')
-rw-r--r-- | src/backend/commands/copy.c | 39 | ||||
-rw-r--r-- | src/backend/commands/createas.c | 2 | ||||
-rw-r--r-- | src/backend/commands/explain.c | 46 | ||||
-rw-r--r-- | src/backend/commands/extension.c | 22 | ||||
-rw-r--r-- | src/backend/commands/foreigncmds.c | 14 | ||||
-rw-r--r-- | src/backend/commands/portalcmds.c | 50 | ||||
-rw-r--r-- | src/backend/commands/prepare.c | 34 | ||||
-rw-r--r-- | src/backend/commands/schemacmds.c | 21 | ||||
-rw-r--r-- | src/backend/commands/tablecmds.c | 3 | ||||
-rw-r--r-- | src/backend/commands/trigger.c | 10 | ||||
-rw-r--r-- | src/backend/commands/view.c | 15 |
11 files changed, 181 insertions, 75 deletions
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index f56b2ac49b0..1fd21627948 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -287,13 +287,13 @@ static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0"; /* non-export function prototypes */ -static CopyState BeginCopy(ParseState *pstate, bool is_from, Relation rel, Node *raw_query, - const Oid queryRelId, List *attnamelist, +static CopyState BeginCopy(ParseState *pstate, bool is_from, Relation rel, + RawStmt *raw_query, Oid queryRelId, List *attnamelist, List *options); static void EndCopy(CopyState cstate); static void ClosePipeToProgram(CopyState cstate); -static CopyState BeginCopyTo(ParseState *pstate, Relation rel, Node *query, - const Oid queryRelId, const char *filename, bool is_program, +static CopyState BeginCopyTo(ParseState *pstate, Relation rel, RawStmt *query, + Oid queryRelId, const char *filename, bool is_program, List *attnamelist, List *options); static void EndCopyTo(CopyState cstate); static uint64 DoCopyTo(CopyState cstate); @@ -770,15 +770,17 @@ CopyLoadRawBuf(CopyState cstate) * Do not allow the copy if user doesn't have proper permission to access * the table or the specifically requested columns. */ -Oid -DoCopy(ParseState *pstate, const CopyStmt *stmt, uint64 *processed) +void +DoCopy(ParseState *pstate, const CopyStmt *stmt, + int stmt_location, int stmt_len, + uint64 *processed) { CopyState cstate; bool is_from = stmt->is_from; bool pipe = (stmt->filename == NULL); Relation rel; Oid relid; - Node *query = NULL; + RawStmt *query = NULL; List *range_table = NIL; /* Disallow COPY to/from file or program except to superusers. */ @@ -929,7 +931,10 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt, uint64 *processed) select->targetList = targetList; select->fromClause = list_make1(from); - query = (Node *) select; + query = makeNode(RawStmt); + query->stmt = (Node *) select; + query->stmt_location = stmt_location; + query->stmt_len = stmt_len; /* * Close the relation for now, but keep the lock on it to prevent @@ -945,7 +950,11 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt, uint64 *processed) { Assert(stmt->query); - query = stmt->query; + query = makeNode(RawStmt); + query->stmt = stmt->query; + query->stmt_location = stmt_location; + query->stmt_len = stmt_len; + relid = InvalidOid; rel = NULL; } @@ -981,8 +990,6 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt, uint64 *processed) */ if (rel != NULL) heap_close(rel, (is_from ? NoLock : AccessShareLock)); - - return relid; } /* @@ -1364,8 +1371,8 @@ static CopyState BeginCopy(ParseState *pstate, bool is_from, Relation rel, - Node *raw_query, - const Oid queryRelId, + RawStmt *raw_query, + Oid queryRelId, List *attnamelist, List *options) { @@ -1456,7 +1463,7 @@ BeginCopy(ParseState *pstate, * function and is executed repeatedly. (See also the same hack in * DECLARE CURSOR and PREPARE.) XXX FIXME someday. */ - rewritten = pg_analyze_and_rewrite((Node *) copyObject(raw_query), + rewritten = pg_analyze_and_rewrite((RawStmt *) copyObject(raw_query), pstate->p_sourcetext, NULL, 0); /* check that we got back something we can work with */ @@ -1747,8 +1754,8 @@ EndCopy(CopyState cstate) static CopyState BeginCopyTo(ParseState *pstate, Relation rel, - Node *query, - const Oid queryRelId, + RawStmt *query, + Oid queryRelId, const char *filename, bool is_program, List *attnamelist, diff --git a/src/backend/commands/createas.c b/src/backend/commands/createas.c index 57ef9817653..cee3b4d50b5 100644 --- a/src/backend/commands/createas.c +++ b/src/backend/commands/createas.c @@ -326,7 +326,7 @@ ExecCreateTableAs(CreateTableAsStmt *stmt, const char *queryString, query = (Query *) linitial(rewritten); Assert(query->commandType == CMD_SELECT); - /* plan the query */ + /* plan the query --- note we disallow parallelism */ plan = pg_plan_query(query, 0, params); /* diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index c762fb07d4d..ee7046c47b9 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -53,7 +53,8 @@ explain_get_index_name_hook_type explain_get_index_name_hook = NULL; #define X_CLOSE_IMMEDIATE 2 #define X_NOWHITESPACE 4 -static void ExplainOneQuery(Query *query, IntoClause *into, ExplainState *es, +static void ExplainOneQuery(Query *query, int cursorOptions, + IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params); static void report_triggers(ResultRelInfo *rInfo, bool show_relname, ExplainState *es); @@ -245,7 +246,8 @@ ExplainQuery(ParseState *pstate, ExplainStmt *stmt, const char *queryString, /* Explain every plan */ foreach(l, rewritten) { - ExplainOneQuery((Query *) lfirst(l), NULL, es, + ExplainOneQuery((Query *) lfirst(l), + CURSOR_OPT_PARALLEL_OK, NULL, es, queryString, params); /* Separate plans with an appropriate separator */ @@ -329,7 +331,8 @@ ExplainResultDesc(ExplainStmt *stmt) * "into" is NULL unless we are explaining the contents of a CreateTableAsStmt. */ static void -ExplainOneQuery(Query *query, IntoClause *into, ExplainState *es, +ExplainOneQuery(Query *query, int cursorOptions, + IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params) { /* planner will not cope with utility statements */ @@ -341,7 +344,8 @@ ExplainOneQuery(Query *query, IntoClause *into, ExplainState *es, /* if an advisor plugin is present, let it manage things */ if (ExplainOneQuery_hook) - (*ExplainOneQuery_hook) (query, into, es, queryString, params); + (*ExplainOneQuery_hook) (query, cursorOptions, into, es, + queryString, params); else { PlannedStmt *plan; @@ -351,7 +355,7 @@ ExplainOneQuery(Query *query, IntoClause *into, ExplainState *es, INSTR_TIME_SET_CURRENT(planstart); /* plan the query */ - plan = pg_plan_query(query, into ? 0 : CURSOR_OPT_PARALLEL_OK, params); + plan = pg_plan_query(query, cursorOptions, params); INSTR_TIME_SET_CURRENT(planduration); INSTR_TIME_SUBTRACT(planduration, planstart); @@ -385,6 +389,8 @@ ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es, * We have to rewrite the contained SELECT and then pass it back to * ExplainOneQuery. It's probably not really necessary to copy the * contained parsetree another time, but let's be safe. + * + * Like ExecCreateTableAs, disallow parallelism in the plan. */ CreateTableAsStmt *ctas = (CreateTableAsStmt *) utilityStmt; List *rewritten; @@ -392,7 +398,28 @@ ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es, Assert(IsA(ctas->query, Query)); rewritten = QueryRewrite((Query *) copyObject(ctas->query)); Assert(list_length(rewritten) == 1); - ExplainOneQuery((Query *) linitial(rewritten), ctas->into, es, + ExplainOneQuery((Query *) linitial(rewritten), + 0, ctas->into, es, + queryString, params); + } + else if (IsA(utilityStmt, DeclareCursorStmt)) + { + /* + * Likewise for DECLARE CURSOR. + * + * Notice that if you say EXPLAIN ANALYZE DECLARE CURSOR then we'll + * actually run the query. This is different from pre-8.3 behavior + * but seems more useful than not running the query. No cursor will + * be created, however. + */ + DeclareCursorStmt *dcs = (DeclareCursorStmt *) utilityStmt; + List *rewritten; + + Assert(IsA(dcs->query, Query)); + rewritten = QueryRewrite((Query *) copyObject(dcs->query)); + Assert(list_length(rewritten) == 1); + ExplainOneQuery((Query *) linitial(rewritten), + dcs->options, NULL, es, queryString, params); } else if (IsA(utilityStmt, ExecuteStmt)) @@ -423,11 +450,6 @@ ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es, * "into" is NULL unless we are explaining the contents of a CreateTableAsStmt, * in which case executing the query should result in creating that table. * - * Since we ignore any DeclareCursorStmt that might be attached to the query, - * if you say EXPLAIN ANALYZE DECLARE CURSOR then we'll actually run the - * query. This is different from pre-8.3 behavior but seems more useful than - * not running the query. No cursor will be created, however. - * * This is exported because it's called back from prepare.c in the * EXPLAIN EXECUTE case, and because an index advisor plugin would need * to call it. @@ -444,6 +466,8 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, int eflags; int instrument_option = 0; + Assert(plannedstmt->commandType != CMD_UTILITY); + if (es->analyze && es->timing) instrument_option |= INSTRUMENT_TIMER; else if (es->analyze) diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c index be521484d08..967b52a133f 100644 --- a/src/backend/commands/extension.c +++ b/src/backend/commands/extension.c @@ -712,7 +712,7 @@ execute_sql_string(const char *sql, const char *filename) */ foreach(lc1, raw_parsetree_list) { - Node *parsetree = (Node *) lfirst(lc1); + RawStmt *parsetree = (RawStmt *) lfirst(lc1); List *stmt_list; ListCell *lc2; @@ -724,23 +724,17 @@ execute_sql_string(const char *sql, const char *filename) foreach(lc2, stmt_list) { - Node *stmt = (Node *) lfirst(lc2); - - if (IsA(stmt, TransactionStmt)) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("transaction control statements are not allowed within an extension script"))); + PlannedStmt *stmt = (PlannedStmt *) lfirst(lc2); CommandCounterIncrement(); PushActiveSnapshot(GetTransactionSnapshot()); - if (IsA(stmt, PlannedStmt) && - ((PlannedStmt *) stmt)->utilityStmt == NULL) + if (stmt->utilityStmt == NULL) { QueryDesc *qdesc; - qdesc = CreateQueryDesc((PlannedStmt *) stmt, + qdesc = CreateQueryDesc(stmt, sql, GetActiveSnapshot(), NULL, dest, NULL, 0); @@ -754,6 +748,11 @@ execute_sql_string(const char *sql, const char *filename) } else { + if (IsA(stmt->utilityStmt, TransactionStmt)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("transaction control statements are not allowed within an extension script"))); + ProcessUtility(stmt, sql, PROCESS_UTILITY_QUERY, @@ -1434,7 +1433,8 @@ CreateExtensionInternal(char *extensionName, csstmt->authrole = NULL; /* will be created by current user */ csstmt->schemaElts = NIL; csstmt->if_not_exists = false; - CreateSchemaCommand(csstmt, NULL); + CreateSchemaCommand(csstmt, "(generated CREATE SCHEMA command)", + -1, -1); /* * CreateSchemaCommand includes CommandCounterIncrement, so new diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c index 06b4bc3ba9a..476a023ec54 100644 --- a/src/backend/commands/foreigncmds.c +++ b/src/backend/commands/foreigncmds.c @@ -1572,7 +1572,9 @@ ImportForeignSchema(ImportForeignSchemaStmt *stmt) */ foreach(lc2, raw_parsetree_list) { - CreateForeignTableStmt *cstmt = lfirst(lc2); + RawStmt *rs = (RawStmt *) lfirst(lc2); + CreateForeignTableStmt *cstmt = (CreateForeignTableStmt *) rs->stmt; + PlannedStmt *pstmt; /* * Because we only allow CreateForeignTableStmt, we can skip parse @@ -1593,8 +1595,16 @@ ImportForeignSchema(ImportForeignSchemaStmt *stmt) /* Ensure creation schema is the one given in IMPORT statement */ cstmt->base.relation->schemaname = pstrdup(stmt->local_schema); + /* No planning needed, just make a wrapper PlannedStmt */ + pstmt = makeNode(PlannedStmt); + pstmt->commandType = CMD_UTILITY; + pstmt->canSetTag = false; + pstmt->utilityStmt = (Node *) cstmt; + pstmt->stmt_location = rs->stmt_location; + pstmt->stmt_len = rs->stmt_len; + /* Execute statement */ - ProcessUtility((Node *) cstmt, + ProcessUtility(pstmt, cmd, PROCESS_UTILITY_SUBCOMMAND, NULL, None_Receiver, NULL); diff --git a/src/backend/commands/portalcmds.c b/src/backend/commands/portalcmds.c index 71640b7748f..1d3e39299b9 100644 --- a/src/backend/commands/portalcmds.c +++ b/src/backend/commands/portalcmds.c @@ -27,7 +27,9 @@ #include "commands/portalcmds.h" #include "executor/executor.h" #include "executor/tstoreReceiver.h" +#include "rewrite/rewriteHandler.h" #include "tcop/pquery.h" +#include "tcop/tcopprot.h" #include "utils/memutils.h" #include "utils/snapmgr.h" @@ -35,21 +37,18 @@ /* * PerformCursorOpen * Execute SQL DECLARE CURSOR command. - * - * The query has already been through parse analysis, rewriting, and planning. - * When it gets here, it looks like a SELECT PlannedStmt, except that the - * utilityStmt field is set. */ void -PerformCursorOpen(PlannedStmt *stmt, ParamListInfo params, +PerformCursorOpen(DeclareCursorStmt *cstmt, ParamListInfo params, const char *queryString, bool isTopLevel) { - DeclareCursorStmt *cstmt = (DeclareCursorStmt *) stmt->utilityStmt; + Query *query = (Query *) cstmt->query; + List *rewritten; + PlannedStmt *plan; Portal portal; MemoryContext oldContext; - if (cstmt == NULL || !IsA(cstmt, DeclareCursorStmt)) - elog(ERROR, "PerformCursorOpen called for non-cursor query"); + Assert(IsA(query, Query)); /* else parse analysis wasn't done */ /* * Disallow empty-string cursor name (conflicts with protocol-level @@ -69,14 +68,39 @@ PerformCursorOpen(PlannedStmt *stmt, ParamListInfo params, 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)); - stmt = copyObject(stmt); - stmt->utilityStmt = NULL; /* make it look like plain SELECT */ + plan = copyObject(plan); queryString = pstrdup(queryString); @@ -84,7 +108,7 @@ PerformCursorOpen(PlannedStmt *stmt, ParamListInfo params, NULL, queryString, "SELECT", /* cursor's query is always a SELECT */ - list_make1(stmt), + list_make1(plan), NULL); /*---------- @@ -111,8 +135,8 @@ PerformCursorOpen(PlannedStmt *stmt, ParamListInfo params, portal->cursorOptions = cstmt->options; if (!(portal->cursorOptions & (CURSOR_OPT_SCROLL | CURSOR_OPT_NO_SCROLL))) { - if (stmt->rowMarks == NIL && - ExecSupportsBackwardScan(stmt->planTree)) + if (plan->rowMarks == NIL && + ExecSupportsBackwardScan(plan->planTree)) portal->cursorOptions |= CURSOR_OPT_SCROLL; else portal->cursorOptions |= CURSOR_OPT_NO_SCROLL; diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c index d768cf8dda3..1ff41661a55 100644 --- a/src/backend/commands/prepare.c +++ b/src/backend/commands/prepare.c @@ -52,8 +52,10 @@ static Datum build_regtype_array(Oid *param_types, int num_params); * Implements the 'PREPARE' utility statement. */ void -PrepareQuery(PrepareStmt *stmt, const char *queryString) +PrepareQuery(PrepareStmt *stmt, const char *queryString, + int stmt_location, int stmt_len) { + RawStmt *rawstmt; CachedPlanSource *plansource; Oid *argtypes = NULL; int nargs; @@ -71,10 +73,22 @@ PrepareQuery(PrepareStmt *stmt, const char *queryString) errmsg("invalid statement name: must not be empty"))); /* + * Need to wrap the contained statement in a RawStmt node to pass it to + * parse analysis. + * + * Because parse analysis scribbles on the raw querytree, we must make a + * copy to ensure we don't modify the passed-in tree. FIXME someday. + */ + rawstmt = makeNode(RawStmt); + rawstmt->stmt = (Node *) copyObject(stmt->query); + rawstmt->stmt_location = stmt_location; + rawstmt->stmt_len = stmt_len; + + /* * Create the CachedPlanSource before we do parse analysis, since it needs * to see the unmodified raw parse tree. */ - plansource = CreateCachedPlan(stmt->query, queryString, + plansource = CreateCachedPlan(rawstmt, queryString, CreateCommandTag(stmt->query)); /* Transform list of TypeNames to array of type OIDs */ @@ -108,12 +122,8 @@ PrepareQuery(PrepareStmt *stmt, const char *queryString) * Analyze the statement using these parameter types (any parameters * passed in from above us will not be visible to it), allowing * information about unknown parameters to be deduced from context. - * - * Because parse analysis scribbles on the raw querytree, we must make a - * copy to ensure we don't modify the passed-in tree. FIXME someday. */ - query = parse_analyze_varparams((Node *) copyObject(stmt->query), - queryString, + query = parse_analyze_varparams(rawstmt, queryString, &argtypes, &nargs); /* @@ -256,9 +266,8 @@ ExecuteQuery(ExecuteStmt *stmt, IntoClause *intoClause, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("prepared statement is not a SELECT"))); pstmt = (PlannedStmt *) linitial(plan_list); - if (!IsA(pstmt, PlannedStmt) || - pstmt->commandType != CMD_SELECT || - pstmt->utilityStmt != NULL) + Assert(IsA(pstmt, PlannedStmt)); + if (pstmt->commandType != CMD_SELECT) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("prepared statement is not a SELECT"))); @@ -664,10 +673,11 @@ ExplainExecuteQuery(ExecuteStmt *execstmt, IntoClause *into, ExplainState *es, { PlannedStmt *pstmt = (PlannedStmt *) lfirst(p); - if (IsA(pstmt, PlannedStmt)) + Assert(IsA(pstmt, PlannedStmt)); + if (pstmt->commandType != CMD_UTILITY) ExplainOnePlan(pstmt, into, es, query_string, paramLI, NULL); else - ExplainOneUtility((Node *) pstmt, into, es, query_string, paramLI); + ExplainOneUtility(pstmt->utilityStmt, into, es, query_string, paramLI); /* No need for CommandCounterIncrement, as ExplainOnePlan did it */ diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c index c475613b1c5..c3b37b26259 100644 --- a/src/backend/commands/schemacmds.c +++ b/src/backend/commands/schemacmds.c @@ -40,9 +40,16 @@ static void AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerI /* * CREATE SCHEMA + * + * Note: caller should pass in location information for the whole + * CREATE SCHEMA statement, which in turn we pass down as the location + * of the component commands. This comports with our general plan of + * reporting location/len for the whole command even when executing + * a subquery. */ Oid -CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString) +CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString, + int stmt_location, int stmt_len) { const char *schemaName = stmt->schemaname; Oid namespaceId; @@ -172,14 +179,24 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString) foreach(parsetree_item, parsetree_list) { Node *stmt = (Node *) lfirst(parsetree_item); + PlannedStmt *wrapper; + + /* need to make a wrapper PlannedStmt */ + wrapper = makeNode(PlannedStmt); + wrapper->commandType = CMD_UTILITY; + wrapper->canSetTag = false; + wrapper->utilityStmt = stmt; + wrapper->stmt_location = stmt_location; + wrapper->stmt_len = stmt_len; /* do this step */ - ProcessUtility(stmt, + ProcessUtility(wrapper, queryString, PROCESS_UTILITY_SUBCOMMAND, NULL, None_Receiver, NULL); + /* make sure later steps can see the object created here */ CommandCounterIncrement(); } diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index f913e87bc8b..e633a50dd2d 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -9285,7 +9285,8 @@ ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd, querytree_list = NIL; foreach(list_item, raw_parsetree_list) { - Node *stmt = (Node *) lfirst(list_item); + RawStmt *rs = (RawStmt *) lfirst(list_item); + Node *stmt = rs->stmt; if (IsA(stmt, IndexStmt)) querytree_list = lappend(querytree_list, diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 61666ad1923..b404d1ea16f 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -1078,6 +1078,7 @@ ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid) AlterTableStmt *atstmt = makeNode(AlterTableStmt); AlterTableCmd *atcmd = makeNode(AlterTableCmd); Constraint *fkcon = makeNode(Constraint); + PlannedStmt *wrapper = makeNode(PlannedStmt); ereport(NOTICE, (errmsg("converting trigger group into constraint \"%s\" %s", @@ -1167,8 +1168,15 @@ ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid) fkcon->skip_validation = false; fkcon->initially_valid = true; + /* finally, wrap it in a dummy PlannedStmt */ + wrapper->commandType = CMD_UTILITY; + wrapper->canSetTag = false; + wrapper->utilityStmt = (Node *) atstmt; + wrapper->stmt_location = -1; + wrapper->stmt_len = -1; + /* ... and execute it */ - ProcessUtility((Node *) atstmt, + ProcessUtility(wrapper, "(generated ALTER TABLE ADD FOREIGN KEY command)", PROCESS_UTILITY_SUBCOMMAND, NULL, None_Receiver, NULL); diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c index e4be5c53320..1f008b07566 100644 --- a/src/backend/commands/view.c +++ b/src/backend/commands/view.c @@ -414,8 +414,10 @@ UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse) * Execute a CREATE VIEW command. */ ObjectAddress -DefineView(ViewStmt *stmt, const char *queryString) +DefineView(ViewStmt *stmt, const char *queryString, + int stmt_location, int stmt_len) { + RawStmt *rawstmt; Query *viewParse; RangeVar *view; ListCell *cell; @@ -429,8 +431,12 @@ DefineView(ViewStmt *stmt, const char *queryString) * Since parse analysis scribbles on its input, copy the raw parse tree; * this ensures we don't corrupt a prepared statement, for example. */ - viewParse = parse_analyze((Node *) copyObject(stmt->query), - queryString, NULL, 0); + rawstmt = makeNode(RawStmt); + rawstmt->stmt = (Node *) copyObject(stmt->query); + rawstmt->stmt_location = stmt_location; + rawstmt->stmt_len = stmt_len; + + viewParse = parse_analyze(rawstmt, queryString, NULL, 0); /* * The grammar should ensure that the result is a single SELECT Query. @@ -443,8 +449,7 @@ DefineView(ViewStmt *stmt, const char *queryString) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("views must not contain SELECT INTO"))); - if (viewParse->commandType != CMD_SELECT || - viewParse->utilityStmt != NULL) + if (viewParse->commandType != CMD_SELECT) elog(ERROR, "unexpected parse analysis result"); /* |