Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitbbbe825

Browse files
committed
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. DECLARECURSOR is now treated almost exactly like a plain SELECT through parseanalysis, rewrite, and planning; only just before sending to the executordo we divert it away to ProcessUtility. This requires a special-case checkin a number of places, but practically all of them were already special-casingSELECT INTO, so it's not too ugly. (Maybe it would be a good idea to mergethe two by treating IntoClause as a form of utility statement? Not going toworry about that now, though.) That approach doesn't work for EXPLAIN,however, so for that I punted and used a klugy solution of running parseanalysis an extra time if under extended query protocol.
1 parenta264671 commitbbbe825

File tree

26 files changed

+333
-246
lines changed

26 files changed

+333
-246
lines changed

‎src/backend/commands/copy.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.282 2007/04/18 02:28:22 momjian Exp $
11+
* $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.283 2007/04/27 22:05:46 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -1015,9 +1015,10 @@ DoCopy(const CopyStmt *stmt, const char *queryString)
10151015

10161016
query= (Query*)linitial(rewritten);
10171017
Assert(query->commandType==CMD_SELECT);
1018+
Assert(query->utilityStmt==NULL);
10181019

10191020
/* Query mustn't use INTO, either */
1020-
if (query->into)
1021+
if (query->intoClause)
10211022
ereport(ERROR,
10221023
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
10231024
errmsg("COPY (SELECT INTO) is not supported")));

‎src/backend/commands/explain.c

Lines changed: 13 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1994-5, Regents of the University of California
88
*
99
* IDENTIFICATION
10-
* $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.161 2007/04/16 01:14:55 tgl Exp $
10+
* $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.162 2007/04/27 22:05:47 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -42,8 +42,8 @@ typedef struct ExplainState
4242
List*rtable;/* range table */
4343
}ExplainState;
4444

45-
staticvoidExplainOneQuery(Query*query,intcursorOptions,
46-
ExplainStmt*stmt,constchar*queryString,
45+
staticvoidExplainOneQuery(Query*query,ExplainStmt*stmt,
46+
constchar*queryString,
4747
ParamListInfoparams,TupOutputState*tstate);
4848
staticdoubleelapsed_time(instr_time*starttime);
4949
staticvoidexplain_outNode(StringInfostr,
@@ -102,8 +102,8 @@ ExplainQuery(ExplainStmt *stmt, const char *queryString,
102102
/* Explain every plan */
103103
foreach(l,rewritten)
104104
{
105-
ExplainOneQuery((Query*)lfirst(l),0,
106-
stmt,queryString,params,tstate);
105+
ExplainOneQuery((Query*)lfirst(l),stmt,
106+
queryString,params,tstate);
107107
/* put a blank line between plans */
108108
if (lnext(l)!=NULL)
109109
do_text_output_oneline(tstate,"");
@@ -134,8 +134,7 @@ ExplainResultDesc(ExplainStmt *stmt)
134134
* print out the execution plan for one Query
135135
*/
136136
staticvoid
137-
ExplainOneQuery(Query*query,intcursorOptions,
138-
ExplainStmt*stmt,constchar*queryString,
137+
ExplainOneQuery(Query*query,ExplainStmt*stmt,constchar*queryString,
139138
ParamListInfoparams,TupOutputState*tstate)
140139
{
141140
PlannedStmt*plan;
@@ -150,7 +149,7 @@ ExplainOneQuery(Query *query, int cursorOptions,
150149
}
151150

152151
/* plan the query */
153-
plan=planner(query,cursorOptions,params);
152+
plan=planner(query,0,params);
154153

155154
/*
156155
* Update snapshot command ID to ensure this query sees results of any
@@ -187,52 +186,7 @@ ExplainOneUtility(Node *utilityStmt, ExplainStmt *stmt,
187186
if (utilityStmt==NULL)
188187
return;
189188

190-
if (IsA(utilityStmt,DeclareCursorStmt))
191-
{
192-
DeclareCursorStmt*dcstmt= (DeclareCursorStmt*)utilityStmt;
193-
Oid*param_types;
194-
intnum_params;
195-
Query*query;
196-
List*rewritten;
197-
ExplainStmtnewstmt;
198-
199-
/* Convert parameter type data to the form parser wants */
200-
getParamListTypes(params,&param_types,&num_params);
201-
202-
/*
203-
* Run parse analysis and rewrite. Note this also acquires sufficient
204-
* locks on the source table(s).
205-
*
206-
* Because the parser and planner tend to scribble on their input, we
207-
* make a preliminary copy of the source querytree. This prevents
208-
* problems in the case that the DECLARE CURSOR is in a portal or
209-
* plpgsql function and is executed repeatedly. (See also the same
210-
* hack in COPY and PREPARE.) XXX FIXME someday.
211-
*/
212-
rewritten=pg_analyze_and_rewrite((Node*)copyObject(dcstmt->query),
213-
queryString,
214-
param_types,num_params);
215-
216-
/* We don't expect more or less than one result query */
217-
if (list_length(rewritten)!=1|| !IsA(linitial(rewritten),Query))
218-
elog(ERROR,"unexpected rewrite result");
219-
query= (Query*)linitial(rewritten);
220-
if (query->commandType!=CMD_SELECT)
221-
elog(ERROR,"unexpected rewrite result");
222-
223-
/* But we must explicitly disallow DECLARE CURSOR ... SELECT INTO */
224-
if (query->into)
225-
ereport(ERROR,
226-
(errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
227-
errmsg("DECLARE CURSOR cannot specify INTO")));
228-
229-
/* do not actually execute the underlying query! */
230-
memcpy(&newstmt,stmt,sizeof(ExplainStmt));
231-
newstmt.analyze= false;
232-
ExplainOneQuery(query,dcstmt->options,&newstmt,
233-
queryString,params,tstate);
234-
}
235-
elseif (IsA(utilityStmt,ExecuteStmt))
189+
if (IsA(utilityStmt,ExecuteStmt))
236190
ExplainExecuteQuery((ExecuteStmt*)utilityStmt,stmt,
237191
queryString,params,tstate);
238192
elseif (IsA(utilityStmt,NotifyStmt))
@@ -247,6 +201,11 @@ ExplainOneUtility(Node *utilityStmt, ExplainStmt *stmt,
247201
*given a planned query, execute it if needed, and then print
248202
*EXPLAIN output
249203
*
204+
* Since we ignore any DeclareCursorStmt that might be attached to the query,
205+
* if you say EXPLAIN ANALYZE DECLARE CURSOR then we'll actually run the
206+
* query. This is different from pre-8.3 behavior but seems more useful than
207+
* not running the query. No cursor will be created, however.
208+
*
250209
* This is exported because it's called back from prepare.c in the
251210
* EXPLAIN EXECUTE case
252211
*

‎src/backend/commands/portalcmds.c

Lines changed: 18 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
*
1515
*
1616
* IDENTIFICATION
17-
* $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.64 2007/04/16 01:14:55 tgl Exp $
17+
* $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.65 2007/04/27 22:05:47 tgl Exp $
1818
*
1919
*-------------------------------------------------------------------------
2020
*/
@@ -26,34 +26,34 @@
2626
#include"access/xact.h"
2727
#include"commands/portalcmds.h"
2828
#include"executor/executor.h"
29-
#include"optimizer/planner.h"
30-
#include"rewrite/rewriteHandler.h"
3129
#include"tcop/pquery.h"
32-
#include"tcop/tcopprot.h"
3330
#include"utils/memutils.h"
3431

3532

3633
/*
3734
* PerformCursorOpen
3835
*Execute SQL DECLARE CURSOR command.
36+
*
37+
* The query has already been through parse analysis, rewriting, and planning.
38+
* When it gets here, it looks like a SELECT PlannedStmt, except that the
39+
* utilityStmt field is set.
3940
*/
4041
void
41-
PerformCursorOpen(DeclareCursorStmt*stmt,ParamListInfoparams,
42+
PerformCursorOpen(PlannedStmt*stmt,ParamListInfoparams,
4243
constchar*queryString,boolisTopLevel)
4344
{
44-
Oid*param_types;
45-
intnum_params;
46-
List*rewritten;
47-
Query*query;
48-
PlannedStmt*plan;
45+
DeclareCursorStmt*cstmt= (DeclareCursorStmt*)stmt->utilityStmt;
4946
Portalportal;
5047
MemoryContextoldContext;
5148

49+
if (cstmt==NULL|| !IsA(cstmt,DeclareCursorStmt))
50+
elog(ERROR,"PerformCursorOpen called for non-cursor query");
51+
5252
/*
5353
* Disallow empty-string cursor name (conflicts with protocol-level
5454
* unnamed portal).
5555
*/
56-
if (!stmt->portalname||stmt->portalname[0]=='\0')
56+
if (!cstmt->portalname||cstmt->portalname[0]=='\0')
5757
ereport(ERROR,
5858
(errcode(ERRCODE_INVALID_CURSOR_NAME),
5959
errmsg("invalid cursor name: must not be empty")));
@@ -63,70 +63,24 @@ PerformCursorOpen(DeclareCursorStmt *stmt, ParamListInfo params,
6363
* been executed inside a transaction block (or else, it would have no
6464
* user-visible effect).
6565
*/
66-
if (!(stmt->options&CURSOR_OPT_HOLD))
66+
if (!(cstmt->options&CURSOR_OPT_HOLD))
6767
RequireTransactionChain(isTopLevel,"DECLARE CURSOR");
6868

69-
/*
70-
* Don't allow both SCROLL and NO SCROLL to be specified
71-
*/
72-
if ((stmt->options&CURSOR_OPT_SCROLL)&&
73-
(stmt->options&CURSOR_OPT_NO_SCROLL))
74-
ereport(ERROR,
75-
(errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
76-
errmsg("cannot specify both SCROLL and NO SCROLL")));
77-
78-
/* Convert parameter type data to the form parser wants */
79-
getParamListTypes(params,&param_types,&num_params);
80-
81-
/*
82-
* Run parse analysis and rewrite. Note this also acquires sufficient
83-
* locks on the source table(s).
84-
*
85-
* Because the parser and planner tend to scribble on their input, we
86-
* make a preliminary copy of the source querytree. This prevents
87-
* problems in the case that the DECLARE CURSOR is in a portal or plpgsql
88-
* function and is executed repeatedly. (See also the same hack in
89-
* COPY and PREPARE.) XXX FIXME someday.
90-
*/
91-
rewritten=pg_analyze_and_rewrite((Node*)copyObject(stmt->query),
92-
queryString,param_types,num_params);
93-
94-
/* We don't expect more or less than one result query */
95-
if (list_length(rewritten)!=1|| !IsA(linitial(rewritten),Query))
96-
elog(ERROR,"unexpected rewrite result");
97-
query= (Query*)linitial(rewritten);
98-
if (query->commandType!=CMD_SELECT)
99-
elog(ERROR,"unexpected rewrite result");
100-
101-
/* But we must explicitly disallow DECLARE CURSOR ... SELECT INTO */
102-
if (query->into)
103-
ereport(ERROR,
104-
(errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
105-
errmsg("DECLARE CURSOR cannot specify INTO")));
106-
107-
if (query->rowMarks!=NIL)
108-
ereport(ERROR,
109-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
110-
errmsg("DECLARE CURSOR ... FOR UPDATE/SHARE is not supported"),
111-
errdetail("Cursors must be READ ONLY.")));
112-
113-
/* plan the query */
114-
plan=planner(query,stmt->options,params);
115-
11669
/*
11770
* Create a portal and copy the plan into its memory context.
11871
*/
119-
portal=CreatePortal(stmt->portalname, false, false);
72+
portal=CreatePortal(cstmt->portalname, false, false);
12073

12174
oldContext=MemoryContextSwitchTo(PortalGetHeapMemory(portal));
12275

123-
plan=copyObject(plan);
76+
stmt=copyObject(stmt);
77+
stmt->utilityStmt=NULL;/* make it look like plain SELECT */
12478

12579
PortalDefineQuery(portal,
12680
NULL,
12781
queryString,
12882
"SELECT",/* cursor's query is always a SELECT */
129-
list_make1(plan),
83+
list_make1(stmt),
13084
NULL);
13185

13286
/*----------
@@ -150,10 +104,10 @@ PerformCursorOpen(DeclareCursorStmt *stmt, ParamListInfo params,
150104
* based on whether it would require any additional runtime overhead to do
151105
* so.
152106
*/
153-
portal->cursorOptions=stmt->options;
107+
portal->cursorOptions=cstmt->options;
154108
if (!(portal->cursorOptions& (CURSOR_OPT_SCROLL |CURSOR_OPT_NO_SCROLL)))
155109
{
156-
if (ExecSupportsBackwardScan(plan->planTree))
110+
if (ExecSupportsBackwardScan(stmt->planTree))
157111
portal->cursorOptions |=CURSOR_OPT_SCROLL;
158112
else
159113
portal->cursorOptions |=CURSOR_OPT_NO_SCROLL;

‎src/backend/commands/prepare.c

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* Copyright (c) 2002-2007, PostgreSQL Global Development Group
1111
*
1212
* IDENTIFICATION
13-
* $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.74 2007/04/26 23:24:44 tgl Exp $
13+
* $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.75 2007/04/27 22:05:47 tgl Exp $
1414
*
1515
*-------------------------------------------------------------------------
1616
*/
@@ -57,7 +57,6 @@ PrepareQuery(PrepareStmt *stmt, const char *queryString)
5757
intnargs;
5858
List*queries;
5959
Query*query;
60-
constchar*commandTag;
6160
List*query_list,
6261
*plan_list;
6362
inti;
@@ -137,22 +136,15 @@ PrepareQuery(PrepareStmt *stmt, const char *queryString)
137136
switch (query->commandType)
138137
{
139138
caseCMD_SELECT:
140-
commandTag="SELECT";
141-
break;
142139
caseCMD_INSERT:
143-
commandTag="INSERT";
144-
break;
145140
caseCMD_UPDATE:
146-
commandTag="UPDATE";
147-
break;
148141
caseCMD_DELETE:
149-
commandTag="DELETE";
142+
/* OK */
150143
break;
151144
default:
152145
ereport(ERROR,
153146
(errcode(ERRCODE_INVALID_PSTATEMENT_DEFINITION),
154147
errmsg("utility statements cannot be prepared")));
155-
commandTag=NULL;/* keep compiler quiet */
156148
break;
157149
}
158150

@@ -168,7 +160,7 @@ PrepareQuery(PrepareStmt *stmt, const char *queryString)
168160
StorePreparedStatement(stmt->name,
169161
stmt->query,
170162
queryString,
171-
commandTag,
163+
CreateCommandTag((Node*)query),
172164
argtypes,
173165
nargs,
174166
0,/* default cursor options */
@@ -244,11 +236,12 @@ ExecuteQuery(ExecuteStmt *stmt, const char *queryString,
244236
errmsg("prepared statement is not a SELECT")));
245237
pstmt= (PlannedStmt*)linitial(plan_list);
246238
if (!IsA(pstmt,PlannedStmt)||
247-
pstmt->commandType!=CMD_SELECT)
239+
pstmt->commandType!=CMD_SELECT||
240+
pstmt->utilityStmt!=NULL)
248241
ereport(ERROR,
249242
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
250243
errmsg("prepared statement is not a SELECT")));
251-
pstmt->into=copyObject(stmt->into);
244+
pstmt->intoClause=copyObject(stmt->into);
252245

253246
MemoryContextSwitchTo(oldContext);
254247

@@ -689,15 +682,16 @@ ExplainExecuteQuery(ExecuteStmt *execstmt, ExplainStmt *stmt,
689682

690683
if (execstmt->into)
691684
{
692-
if (pstmt->commandType!=CMD_SELECT)
685+
if (pstmt->commandType!=CMD_SELECT||
686+
pstmt->utilityStmt!=NULL)
693687
ereport(ERROR,
694688
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
695689
errmsg("prepared statement is not a SELECT")));
696690

697691
/* Copy the stmt so we can modify it */
698692
pstmt=copyObject(pstmt);
699693

700-
pstmt->into=execstmt->into;
694+
pstmt->intoClause=execstmt->into;
701695
}
702696

703697
/*

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp