1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-26 01:22:12 +03:00

Modify processing of DECLARE CURSOR and EXPLAIN so that they can resolve the

types of unspecified parameters when submitted via extended query protocol.
This worked in 8.2 but I had broken it during plancache changes.  DECLARE
CURSOR is now treated almost exactly like a plain SELECT through parse
analysis, rewrite, and planning; only just before sending to the executor
do we divert it away to ProcessUtility.  This requires a special-case check
in a number of places, but practically all of them were already special-casing
SELECT INTO, so it's not too ugly.  (Maybe it would be a good idea to merge
the two by treating IntoClause as a form of utility statement?  Not going to
worry about that now, though.)  That approach doesn't work for EXPLAIN,
however, so for that I punted and used a klugy solution of running parse
analysis an extra time if under extended query protocol.
This commit is contained in:
Tom Lane
2007-04-27 22:05:49 +00:00
parent a264671116
commit bbbe825f5f
26 changed files with 333 additions and 246 deletions

View File

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.278 2007/04/26 16:13:12 neilc Exp $
* $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.279 2007/04/27 22:05:49 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -268,7 +268,7 @@ CommandIsReadOnly(Node *parsetree)
switch (stmt->commandType)
{
case CMD_SELECT:
if (stmt->into != NULL)
if (stmt->intoClause != NULL)
return false; /* SELECT INTO */
else if (stmt->rowMarks != NIL)
return false; /* SELECT FOR UPDATE/SHARE */
@ -505,10 +505,20 @@ ProcessUtility(Node *parsetree,
/*
* Portal (cursor) manipulation
*
* Note: DECLARE CURSOR is processed mostly as a SELECT, and
* therefore what we will get here is a PlannedStmt not a bare
* DeclareCursorStmt.
*/
case T_DeclareCursorStmt:
PerformCursorOpen((DeclareCursorStmt *) parsetree, params,
queryString, isTopLevel);
case T_PlannedStmt:
{
PlannedStmt *stmt = (PlannedStmt *) parsetree;
if (stmt->utilityStmt == NULL ||
!IsA(stmt->utilityStmt, DeclareCursorStmt))
elog(ERROR, "non-DECLARE CURSOR PlannedStmt passed to ProcessUtility");
PerformCursorOpen(stmt, params, queryString, isTopLevel);
}
break;
case T_ClosePortalStmt:
@ -1272,8 +1282,9 @@ QueryReturnsTuples(Query *parsetree)
switch (parsetree->commandType)
{
case CMD_SELECT:
/* returns tuples ... unless it's SELECT INTO */
if (parsetree->into == NULL)
/* returns tuples ... unless it's DECLARE CURSOR or SELECT INTO */
if (parsetree->utilityStmt == NULL &&
parsetree->intoClause == NULL)
return true;
break;
case CMD_INSERT:
@ -1899,7 +1910,12 @@ CreateCommandTag(Node *parsetree)
* will be useful for complaints about read-only
* statements
*/
if (stmt->into != NULL)
if (stmt->utilityStmt != NULL)
{
Assert(IsA(stmt->utilityStmt, DeclareCursorStmt));
tag = "DECLARE CURSOR";
}
else if (stmt->intoClause != NULL)
tag = "SELECT INTO";
else if (stmt->rowMarks != NIL)
{
@ -1942,7 +1958,12 @@ CreateCommandTag(Node *parsetree)
* will be useful for complaints about read-only
* statements
*/
if (stmt->into != NULL)
if (stmt->utilityStmt != NULL)
{
Assert(IsA(stmt->utilityStmt, DeclareCursorStmt));
tag = "DECLARE CURSOR";
}
else if (stmt->intoClause != NULL)
tag = "SELECT INTO";
else if (stmt->rowMarks != NIL)
{
@ -2009,7 +2030,7 @@ GetCommandLogLevel(Node *parsetree)
break;
case T_SelectStmt:
if (((SelectStmt *) parsetree)->into)
if (((SelectStmt *) parsetree)->intoClause)
lev = LOGSTMT_DDL; /* CREATE AS, SELECT INTO */
else
lev = LOGSTMT_ALL;
@ -2330,10 +2351,10 @@ GetCommandLogLevel(Node *parsetree)
switch (stmt->commandType)
{
case CMD_SELECT:
if (stmt->into != NULL)
if (stmt->intoClause != NULL)
lev = LOGSTMT_DDL; /* CREATE AS, SELECT INTO */
else
lev = LOGSTMT_ALL;
lev = LOGSTMT_ALL; /* SELECT or DECLARE CURSOR */
break;
case CMD_UPDATE:
@ -2359,10 +2380,10 @@ GetCommandLogLevel(Node *parsetree)
switch (stmt->commandType)
{
case CMD_SELECT:
if (stmt->into != NULL)
if (stmt->intoClause != NULL)
lev = LOGSTMT_DDL; /* CREATE AS, SELECT INTO */
else
lev = LOGSTMT_ALL;
lev = LOGSTMT_ALL; /* SELECT or DECLARE CURSOR */
break;
case CMD_UPDATE: