+/*
+ * transformDeclareCursorStmt -
+ * transform a DECLARE CURSOR Statement
+ *
+ * DECLARE CURSOR is a hybrid case: it's an optimizable statement (in fact not
+ * significantly different from a SELECT) as far as parsing/rewriting/planning
+ * are concerned, but it's not passed to the executor and so in that sense is
+ * a utility statement. We transform it into a Query exactly as if it were
+ * a SELECT, then stick the original DeclareCursorStmt into the utilityStmt
+ * field to carry the cursor name and options.
+ */
+static Query *
+transformDeclareCursorStmt(ParseState *pstate, DeclareCursorStmt *stmt)
+{
+ Query *result;
+ List *extras_before = NIL,
+ *extras_after = NIL;
+
+ /*
+ * Don't allow both SCROLL and NO SCROLL to be specified
+ */
+ if ((stmt->options & CURSOR_OPT_SCROLL) &&
+ (stmt->options & CURSOR_OPT_NO_SCROLL))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
+ errmsg("cannot specify both SCROLL and NO SCROLL")));
+
+ result = transformStmt(pstate, stmt->query,
+ &extras_before, &extras_after);
+
+ /* Shouldn't get any extras, since grammar only allows SelectStmt */
+ if (extras_before || extras_after)
+ elog(ERROR, "unexpected extra stuff in cursor statement");
+ if (!IsA(result, Query) ||
+ result->commandType != CMD_SELECT ||
+ result->utilityStmt != NULL)
+ elog(ERROR, "unexpected non-SELECT command in cursor statement");
+
+ /* But we must explicitly disallow DECLARE CURSOR ... SELECT INTO */
+ if (result->intoClause)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
+ errmsg("DECLARE CURSOR cannot specify INTO")));
+
+ /* Implementation restriction (might go away someday) */
+ if (result->rowMarks != NIL)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("DECLARE CURSOR ... FOR UPDATE/SHARE is not supported"),
+ errdetail("Cursors must be READ ONLY.")));
+
+ /* We won't need the raw querytree any more */
+ stmt->query = NULL;
+
+ result->utilityStmt = (Node *) stmt;
+
+ return result;
+}
+
+
+/*
+ * transformExplainStmt -
+ * transform an EXPLAIN Statement
+ *
+ * EXPLAIN is just like other utility statements in that we emit it as a
+ * CMD_UTILITY Query node with no transformation of the raw parse tree.
+ * However, if p_variableparams is set, it could be that the client is
+ * expecting us to resolve parameter types in something like
+ * EXPLAIN SELECT * FROM tab WHERE col = $1
+ * To deal with such cases, we run parse analysis and throw away the result;
+ * this is a bit grotty but not worth contorting the rest of the system for.
+ * (The approach we use for DECLARE CURSOR won't work because the statement
+ * being explained isn't necessarily a SELECT, and in particular might rewrite
+ * to multiple parsetrees.)
+ */
+static Query *
+transformExplainStmt(ParseState *pstate, ExplainStmt *stmt)
+{
+ Query *result;
+
+ if (pstate->p_variableparams)
+ {
+ List *extras_before = NIL,
+ *extras_after = NIL;
+
+ /* Since parse analysis scribbles on its input, copy the tree first! */
+ (void) transformStmt(pstate, copyObject(stmt->query),
+ &extras_before, &extras_after);
+ }
+
+ /* Now return the untransformed command as a utility Query */
+ result = makeNode(Query);
+ result->commandType = CMD_UTILITY;
+ result->utilityStmt = (Node *) stmt;
+
+ return result;
+}
+
+