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:
@ -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:
|
||||
|
Reference in New Issue
Block a user