aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands')
-rw-r--r--src/backend/commands/copy.c39
-rw-r--r--src/backend/commands/createas.c2
-rw-r--r--src/backend/commands/explain.c46
-rw-r--r--src/backend/commands/extension.c22
-rw-r--r--src/backend/commands/foreigncmds.c14
-rw-r--r--src/backend/commands/portalcmds.c50
-rw-r--r--src/backend/commands/prepare.c34
-rw-r--r--src/backend/commands/schemacmds.c21
-rw-r--r--src/backend/commands/tablecmds.c3
-rw-r--r--src/backend/commands/trigger.c10
-rw-r--r--src/backend/commands/view.c15
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");
/*