aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser')
-rw-r--r--src/backend/parser/analyze.c178
-rw-r--r--src/backend/parser/gram.y8
-rw-r--r--src/backend/parser/parse_clause.c7
-rw-r--r--src/backend/parser/parse_expr.c5
-rw-r--r--src/backend/parser/parse_type.c4
5 files changed, 162 insertions, 40 deletions
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index a4e4418b145..68475387be3 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -20,7 +20,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.362 2007/03/13 00:33:41 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.363 2007/04/27 22:05:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -118,6 +118,10 @@ static Query *transformValuesClause(ParseState *pstate, SelectStmt *stmt);
static Query *transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt);
static Node *transformSetOperationTree(ParseState *pstate, SelectStmt *stmt);
static Query *transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt);
+static Query *transformDeclareCursorStmt(ParseState *pstate,
+ DeclareCursorStmt *stmt);
+static Query *transformExplainStmt(ParseState *pstate,
+ ExplainStmt *stmt);
static Query *transformCreateStmt(ParseState *pstate, CreateStmt *stmt,
List **extras_before, List **extras_after);
static Query *transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt,
@@ -313,20 +317,6 @@ transformStmt(ParseState *pstate, Node *parseTree,
switch (nodeTag(parseTree))
{
/*
- * Non-optimizable statements
- */
- case T_CreateStmt:
- result = transformCreateStmt(pstate, (CreateStmt *) parseTree,
- extras_before, extras_after);
- break;
-
- case T_AlterTableStmt:
- result = transformAlterTableStmt(pstate,
- (AlterTableStmt *) parseTree,
- extras_before, extras_after);
- break;
-
- /*
* Optimizable statements
*/
case T_InsertStmt:
@@ -355,6 +345,33 @@ transformStmt(ParseState *pstate, Node *parseTree,
}
break;
+ /*
+ * Non-optimizable statements
+ */
+ case T_CreateStmt:
+ result = transformCreateStmt(pstate, (CreateStmt *) parseTree,
+ extras_before, extras_after);
+ break;
+
+ case T_AlterTableStmt:
+ result = transformAlterTableStmt(pstate,
+ (AlterTableStmt *) parseTree,
+ extras_before, extras_after);
+ break;
+
+ /*
+ * Special cases
+ */
+ case T_DeclareCursorStmt:
+ result = transformDeclareCursorStmt(pstate,
+ (DeclareCursorStmt *) parseTree);
+ break;
+
+ case T_ExplainStmt:
+ result = transformExplainStmt(pstate,
+ (ExplainStmt *) parseTree);
+ break;
+
default:
/*
@@ -546,9 +563,11 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
release_pstate_resources(sub_pstate);
pfree(sub_pstate);
+ /* The grammar should have produced a SELECT, but it might have INTO */
Assert(IsA(selectQuery, Query));
Assert(selectQuery->commandType == CMD_SELECT);
- if (selectQuery->into)
+ Assert(selectQuery->utilityStmt == NULL);
+ if (selectQuery->intoClause)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("INSERT ... SELECT cannot specify INTO")));
@@ -2029,6 +2048,8 @@ analyzeRuleStmt(RuleStmt *stmt, const char *queryString,
/*
* transformSelectStmt -
* transforms a Select Statement
+ *
+ * Note: this is also used for DECLARE CURSOR statements.
*/
static Query *
transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
@@ -2085,11 +2106,11 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
"LIMIT");
/* handle any SELECT INTO/CREATE TABLE AS spec */
- if (stmt->into)
+ if (stmt->intoClause)
{
- qry->into = stmt->into;
- if (stmt->into->colNames)
- applyColumnNames(qry->targetList, stmt->into->colNames);
+ qry->intoClause = stmt->intoClause;
+ if (stmt->intoClause->colNames)
+ applyColumnNames(qry->targetList, stmt->intoClause->colNames);
}
qry->rtable = pstate->p_rtable;
@@ -2254,11 +2275,11 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
errmsg("SELECT FOR UPDATE/SHARE cannot be applied to VALUES")));
/* handle any CREATE TABLE AS spec */
- if (stmt->into)
+ if (stmt->intoClause)
{
- qry->into = stmt->into;
- if (stmt->into->colNames)
- applyColumnNames(qry->targetList, stmt->into->colNames);
+ qry->intoClause = stmt->intoClause;
+ if (stmt->intoClause->colNames)
+ applyColumnNames(qry->targetList, stmt->intoClause->colNames);
}
/*
@@ -2345,14 +2366,14 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
leftmostSelect = leftmostSelect->larg;
Assert(leftmostSelect && IsA(leftmostSelect, SelectStmt) &&
leftmostSelect->larg == NULL);
- if (leftmostSelect->into)
+ if (leftmostSelect->intoClause)
{
- qry->into = leftmostSelect->into;
- intoColNames = leftmostSelect->into->colNames;
+ qry->intoClause = leftmostSelect->intoClause;
+ intoColNames = leftmostSelect->intoClause->colNames;
}
/* clear this to prevent complaints in transformSetOperationTree() */
- leftmostSelect->into = NULL;
+ leftmostSelect->intoClause = NULL;
/*
* These are not one-time, exactly, but we want to process them here and
@@ -2533,7 +2554,7 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
/*
* Validity-check both leaf and internal SELECTs for disallowed ops.
*/
- if (stmt->into)
+ if (stmt->intoClause)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("INTO is only allowed on first SELECT of UNION/INTERSECT/EXCEPT")));
@@ -3113,6 +3134,105 @@ transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt,
}
+/*
+ * 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;
+}
+
+
/* exported so planner can check again after rewriting, query pullup, etc */
void
CheckSelectLocking(Query *qry)
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index a69e6989a94..8884da22892 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.590 2007/04/26 16:13:11 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.591 2007/04/27 22:05:48 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -2355,12 +2355,12 @@ CreateAsStmt:
* be attached to that Select's target list.
*/
SelectStmt *n = findLeftmostSelect((SelectStmt *) $6);
- if (n->into != NULL)
+ if (n->intoClause != NULL)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("CREATE TABLE AS cannot specify INTO")));
$4->rel->istemp = $2;
- n->into = $4;
+ n->intoClause = $4;
$$ = $6;
}
;
@@ -5993,7 +5993,7 @@ simple_select:
SelectStmt *n = makeNode(SelectStmt);
n->distinctClause = $2;
n->targetList = $3;
- n->into = $4;
+ n->intoClause = $4;
n->fromClause = $5;
n->whereClause = $6;
n->groupClause = $7;
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index 0c718adc32a..4c1fb0cc4c1 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.164 2007/02/01 19:10:27 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.165 2007/04/27 22:05:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -447,9 +447,10 @@ transformRangeSubselect(ParseState *pstate, RangeSubselect *r)
if (query == NULL || !IsA(query, Query))
elog(ERROR, "unexpected parse analysis result for subquery in FROM");
- if (query->commandType != CMD_SELECT)
+ if (query->commandType != CMD_SELECT ||
+ query->utilityStmt != NULL)
elog(ERROR, "expected SELECT query from subquery in FROM");
- if (query->into != NULL)
+ if (query->intoClause != NULL)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("subquery in FROM cannot have SELECT INTO")));
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index d9a6af82962..a0f92f66a64 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.216 2007/04/02 03:49:39 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.217 2007/04/27 22:05:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1117,7 +1117,8 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
elog(ERROR, "bad query in sub-select");
qtree = (Query *) linitial(qtrees);
if (qtree->commandType != CMD_SELECT ||
- qtree->into != NULL)
+ qtree->utilityStmt != NULL ||
+ qtree->intoClause != NULL)
elog(ERROR, "bad query in sub-select");
sublink->subselect = (Node *) qtree;
diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c
index ebb86f8bba9..0263386d2a2 100644
--- a/src/backend/parser/parse_type.c
+++ b/src/backend/parser/parse_type.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.88 2007/04/02 03:49:39 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.89 2007/04/27 22:05:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -519,7 +519,7 @@ parseTypeString(const char *str, Oid *type_id, int32 *typmod)
if (stmt == NULL ||
!IsA(stmt, SelectStmt) ||
stmt->distinctClause != NIL ||
- stmt->into != NULL ||
+ stmt->intoClause != NULL ||
stmt->fromClause != NIL ||
stmt->whereClause != NULL ||
stmt->groupClause != NIL ||