]> granicus.if.org Git - postgresql/blob - src/backend/commands/prepare.c
More janitorial work: remove the explicit casting of NULL literals to a
[postgresql] / src / backend / commands / prepare.c
1 /*-------------------------------------------------------------------------
2  *
3  * prepare.c
4  *        Prepareable SQL statements via PREPARE, EXECUTE and DEALLOCATE
5  *
6  * This module also implements storage of prepared statements that are
7  * accessed via the extended FE/BE query protocol.
8  *
9  *
10  * Copyright (c) 2002-2003, PostgreSQL Global Development Group
11  *
12  * IDENTIFICATION
13  *        $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.25 2004/01/07 18:56:25 neilc Exp $
14  *
15  *-------------------------------------------------------------------------
16  */
17 #include "postgres.h"
18
19 #include "commands/explain.h"
20 #include "commands/prepare.h"
21 #include "executor/executor.h"
22 #include "utils/guc.h"
23 #include "optimizer/planner.h"
24 #include "rewrite/rewriteHandler.h"
25 #include "tcop/pquery.h"
26 #include "tcop/tcopprot.h"
27 #include "tcop/utility.h"
28 #include "utils/hsearch.h"
29 #include "utils/memutils.h"
30
31
32 /*
33  * The hash table in which prepared queries are stored. This is
34  * per-backend: query plans are not shared between backends.
35  * The keys for this hash table are the arguments to PREPARE and EXECUTE
36  * (statement names); the entries are PreparedStatement structs.
37  */
38 static HTAB *prepared_queries = NULL;
39
40 static void InitQueryHashTable(void);
41 static ParamListInfo EvaluateParams(EState *estate,
42                            List *params, List *argtypes);
43
44 /*
45  * Implements the 'PREPARE' utility statement.
46  */
47 void
48 PrepareQuery(PrepareStmt *stmt)
49 {
50         const char *commandTag;
51         List       *query_list,
52                            *plan_list;
53
54         /*
55          * Disallow empty-string statement name (conflicts with protocol-level
56          * unnamed statement).
57          */
58         if (!stmt->name || stmt->name[0] == '\0')
59                 ereport(ERROR,
60                                 (errcode(ERRCODE_INVALID_PSTATEMENT_DEFINITION),
61                                  errmsg("invalid statement name: must not be empty")));
62
63         switch (stmt->query->commandType)
64         {
65                 case CMD_SELECT:
66                         commandTag = "SELECT";
67                         break;
68                 case CMD_INSERT:
69                         commandTag = "INSERT";
70                         break;
71                 case CMD_UPDATE:
72                         commandTag = "UPDATE";
73                         break;
74                 case CMD_DELETE:
75                         commandTag = "DELETE";
76                         break;
77                 default:
78                         ereport(ERROR,
79                                         (errcode(ERRCODE_INVALID_PSTATEMENT_DEFINITION),
80                                          errmsg("utility statements cannot be prepared")));
81                         commandTag = NULL;      /* keep compiler quiet */
82                         break;
83         }
84
85         /*
86          * Parse analysis is already done, but we must still rewrite and plan
87          * the query.
88          */
89
90         /* Rewrite the query. The result could be 0, 1, or many queries. */
91         query_list = QueryRewrite(stmt->query);
92
93         /* Generate plans for queries.  Snapshot is already set. */
94         plan_list = pg_plan_queries(query_list, false);
95
96         /* Save the results. */
97         StorePreparedStatement(stmt->name,
98                                                    NULL,        /* text form not available */
99                                                    commandTag,
100                                                    query_list,
101                                                    plan_list,
102                                                    stmt->argtype_oids);
103 }
104
105 /*
106  * Implements the 'EXECUTE' utility statement.
107  */
108 void
109 ExecuteQuery(ExecuteStmt *stmt, DestReceiver *dest)
110 {
111         PreparedStatement *entry;
112         char       *query_string;
113         List       *query_list,
114                            *plan_list;
115         MemoryContext qcontext;
116         ParamListInfo paramLI = NULL;
117         EState     *estate = NULL;
118         Portal          portal;
119
120         /* Look it up in the hash table */
121         entry = FetchPreparedStatement(stmt->name, true);
122
123         query_string = entry->query_string;
124         query_list = entry->query_list;
125         plan_list = entry->plan_list;
126         qcontext = entry->context;
127
128         Assert(length(query_list) == length(plan_list));
129
130         /* Evaluate parameters, if any */
131         if (entry->argtype_list != NIL)
132         {
133                 /*
134                  * Need an EState to evaluate parameters; must not delete it till
135                  * end of query, in case parameters are pass-by-reference.
136                  */
137                 estate = CreateExecutorState();
138                 paramLI = EvaluateParams(estate, stmt->params, entry->argtype_list);
139         }
140
141         /*
142          * Create a new portal to run the query in
143          */
144         portal = CreateNewPortal();
145
146         /*
147          * For CREATE TABLE / AS EXECUTE, make a copy of the stored query so
148          * that we can modify its destination (yech, but this has always been
149          * ugly).  For regular EXECUTE we can just use the stored query where
150          * it sits, since the executor is read-only.
151          */
152         if (stmt->into)
153         {
154                 MemoryContext oldContext;
155                 Query      *query;
156
157                 oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
158
159                 if (query_string)
160                         query_string = pstrdup(query_string);
161                 query_list = copyObject(query_list);
162                 plan_list = copyObject(plan_list);
163                 qcontext = PortalGetHeapMemory(portal);
164
165                 if (length(query_list) != 1)
166                         ereport(ERROR,
167                                         (errcode(ERRCODE_WRONG_OBJECT_TYPE),
168                                          errmsg("prepared statement is not a SELECT")));
169                 query = (Query *) lfirst(query_list);
170                 if (query->commandType != CMD_SELECT)
171                         ereport(ERROR,
172                                         (errcode(ERRCODE_WRONG_OBJECT_TYPE),
173                                          errmsg("prepared statement is not a SELECT")));
174                 query->into = copyObject(stmt->into);
175
176                 MemoryContextSwitchTo(oldContext);
177         }
178
179         PortalDefineQuery(portal,
180                                           query_string,
181                                           entry->commandTag,
182                                           query_list,
183                                           plan_list,
184                                           qcontext);
185
186         /*
187          * Run the portal to completion.
188          */
189         PortalStart(portal, paramLI);
190
191         (void) PortalRun(portal, FETCH_ALL, dest, dest, NULL);
192
193         PortalDrop(portal, false);
194
195         if (estate)
196                 FreeExecutorState(estate);
197
198         /* No need to pfree other memory, MemoryContext will be reset */
199 }
200
201 /*
202  * Evaluates a list of parameters, using the given executor state. It
203  * requires a list of the parameter values themselves, and a list of
204  * their types. It returns a filled-in ParamListInfo -- this can later
205  * be passed to CreateQueryDesc(), which allows the executor to make use
206  * of the parameters during query execution.
207  */
208 static ParamListInfo
209 EvaluateParams(EState *estate, List *params, List *argtypes)
210 {
211         int                     nargs = length(argtypes);
212         ParamListInfo paramLI;
213         List       *exprstates;
214         List       *l;
215         int                     i = 0;
216
217         /* Parser should have caught this error, but check for safety */
218         if (length(params) != nargs)
219                 elog(ERROR, "wrong number of arguments");
220
221         exprstates = (List *) ExecPrepareExpr((Expr *) params, estate);
222
223         paramLI = (ParamListInfo)
224                 palloc0((nargs + 1) * sizeof(ParamListInfoData));
225
226         foreach(l, exprstates)
227         {
228                 ExprState  *n = lfirst(l);
229                 bool            isNull;
230
231                 paramLI[i].value = ExecEvalExprSwitchContext(n,
232                                                                                   GetPerTupleExprContext(estate),
233                                                                                                          &isNull,
234                                                                                                          NULL);
235                 paramLI[i].kind = PARAM_NUM;
236                 paramLI[i].id = i + 1;
237                 paramLI[i].isnull = isNull;
238
239                 i++;
240         }
241
242         paramLI[i].kind = PARAM_INVALID;
243
244         return paramLI;
245 }
246
247
248 /*
249  * Initialize query hash table upon first use.
250  */
251 static void
252 InitQueryHashTable(void)
253 {
254         HASHCTL         hash_ctl;
255
256         MemSet(&hash_ctl, 0, sizeof(hash_ctl));
257
258         hash_ctl.keysize = NAMEDATALEN;
259         hash_ctl.entrysize = sizeof(PreparedStatement);
260
261         prepared_queries = hash_create("Prepared Queries",
262                                                                    32,
263                                                                    &hash_ctl,
264                                                                    HASH_ELEM);
265
266         if (!prepared_queries)
267                 elog(ERROR, "could not create hash table");
268 }
269
270 /*
271  * Store all the data pertaining to a query in the hash table using
272  * the specified key. A copy of the data is made in a memory context belonging
273  * to the hash entry, so the caller can dispose of their copy.
274  *
275  * Exception: commandTag is presumed to be a pointer to a constant string,
276  * or possibly NULL, so it need not be copied.  Note that commandTag should
277  * be NULL only if the original query (before rewriting) was empty.
278  */
279 void
280 StorePreparedStatement(const char *stmt_name,
281                                            const char *query_string,
282                                            const char *commandTag,
283                                            List *query_list,
284                                            List *plan_list,
285                                            List *argtype_list)
286 {
287         PreparedStatement *entry;
288         MemoryContext oldcxt,
289                                 entrycxt;
290         char       *qstring;
291         char            key[NAMEDATALEN];
292         bool            found;
293
294         /* Initialize the hash table, if necessary */
295         if (!prepared_queries)
296                 InitQueryHashTable();
297
298         /* Check for pre-existing entry of same name */
299         /* See notes in FetchPreparedStatement */
300         MemSet(key, 0, sizeof(key));
301         strncpy(key, stmt_name, sizeof(key));
302
303         hash_search(prepared_queries, key, HASH_FIND, &found);
304
305         if (found)
306                 ereport(ERROR,
307                                 (errcode(ERRCODE_DUPLICATE_PSTATEMENT),
308                                  errmsg("prepared statement \"%s\" already exists",
309                                                 stmt_name)));
310
311         /* Make a permanent memory context for the hashtable entry */
312         entrycxt = AllocSetContextCreate(TopMemoryContext,
313                                                                          stmt_name,
314                                                                          ALLOCSET_SMALL_MINSIZE,
315                                                                          ALLOCSET_SMALL_INITSIZE,
316                                                                          ALLOCSET_SMALL_MAXSIZE);
317
318         oldcxt = MemoryContextSwitchTo(entrycxt);
319
320         /*
321          * We need to copy the data so that it is stored in the correct memory
322          * context.  Do this before making hashtable entry, so that an
323          * out-of-memory failure only wastes memory and doesn't leave us with
324          * an incomplete (ie corrupt) hashtable entry.
325          */
326         qstring = query_string ? pstrdup(query_string) : NULL;
327         query_list = (List *) copyObject(query_list);
328         plan_list = (List *) copyObject(plan_list);
329         argtype_list = listCopy(argtype_list);
330
331         /* Now we can add entry to hash table */
332         entry = (PreparedStatement *) hash_search(prepared_queries,
333                                                                                           key,
334                                                                                           HASH_ENTER,
335                                                                                           &found);
336
337         /* Shouldn't get a failure, nor a duplicate entry */
338         if (!entry || found)
339                 elog(ERROR, "could not store prepared statement \"%s\"",
340                          stmt_name);
341
342         /* Fill in the hash table entry with copied data */
343         entry->query_string = qstring;
344         entry->commandTag = commandTag;
345         entry->query_list = query_list;
346         entry->plan_list = plan_list;
347         entry->argtype_list = argtype_list;
348         entry->context = entrycxt;
349
350         MemoryContextSwitchTo(oldcxt);
351 }
352
353 /*
354  * Lookup an existing query in the hash table. If the query does not
355  * actually exist, throw ereport(ERROR) or return NULL per second parameter.
356  */
357 PreparedStatement *
358 FetchPreparedStatement(const char *stmt_name, bool throwError)
359 {
360         char            key[NAMEDATALEN];
361         PreparedStatement *entry;
362
363         /*
364          * If the hash table hasn't been initialized, it can't be storing
365          * anything, therefore it couldn't possibly store our plan.
366          */
367         if (prepared_queries)
368         {
369                 /*
370                  * We can't just use the statement name as supplied by the user:
371                  * the hash package is picky enough that it needs to be
372                  * NULL-padded out to the appropriate length to work correctly.
373                  */
374                 MemSet(key, 0, sizeof(key));
375                 strncpy(key, stmt_name, sizeof(key));
376
377                 entry = (PreparedStatement *) hash_search(prepared_queries,
378                                                                                                   key,
379                                                                                                   HASH_FIND,
380                                                                                                   NULL);
381         }
382         else
383                 entry = NULL;
384
385         if (!entry && throwError)
386                 ereport(ERROR,
387                                 (errcode(ERRCODE_UNDEFINED_PSTATEMENT),
388                                  errmsg("prepared statement \"%s\" does not exist",
389                                                 stmt_name)));
390
391         return entry;
392 }
393
394 /*
395  * Look up a prepared statement given the name (giving error if not found).
396  * If found, return the list of argument type OIDs.
397  */
398 List *
399 FetchPreparedStatementParams(const char *stmt_name)
400 {
401         PreparedStatement *entry;
402
403         entry = FetchPreparedStatement(stmt_name, true);
404
405         return entry->argtype_list;
406 }
407
408 /*
409  * Given a prepared statement, determine the result tupledesc it will
410  * produce.  Returns NULL if the execution will not return tuples.
411  *
412  * Note: the result is created or copied into current memory context.
413  */
414 TupleDesc
415 FetchPreparedStatementResultDesc(PreparedStatement *stmt)
416 {
417         Query      *query;
418
419         switch (ChoosePortalStrategy(stmt->query_list))
420         {
421                 case PORTAL_ONE_SELECT:
422                         query = (Query *) lfirst(stmt->query_list);
423                         return ExecCleanTypeFromTL(query->targetList, false);
424
425                 case PORTAL_UTIL_SELECT:
426                         query = (Query *) lfirst(stmt->query_list);
427                         return UtilityTupleDescriptor(query->utilityStmt);
428
429                 case PORTAL_MULTI_QUERY:
430                         /* will not return tuples */
431                         break;
432         }
433         return NULL;
434 }
435
436 /*
437  * Implements the 'DEALLOCATE' utility statement: deletes the
438  * specified plan from storage.
439  */
440 void
441 DeallocateQuery(DeallocateStmt *stmt)
442 {
443         DropPreparedStatement(stmt->name, true);
444 }
445
446 /*
447  * Internal version of DEALLOCATE
448  *
449  * If showError is false, dropping a nonexistent statement is a no-op.
450  */
451 void
452 DropPreparedStatement(const char *stmt_name, bool showError)
453 {
454         PreparedStatement *entry;
455
456         /* Find the query's hash table entry; raise error if wanted */
457         entry = FetchPreparedStatement(stmt_name, showError);
458
459         if (entry)
460         {
461                 /* Drop any open portals that depend on this prepared statement */
462                 Assert(MemoryContextIsValid(entry->context));
463                 DropDependentPortals(entry->context);
464
465                 /* Flush the context holding the subsidiary data */
466                 MemoryContextDelete(entry->context);
467
468                 /* Now we can remove the hash table entry */
469                 hash_search(prepared_queries, entry->stmt_name, HASH_REMOVE, NULL);
470         }
471 }
472
473 /*
474  * Implements the 'EXPLAIN EXECUTE' utility statement.
475  */
476 void
477 ExplainExecuteQuery(ExplainStmt *stmt, TupOutputState *tstate)
478 {
479         ExecuteStmt *execstmt = (ExecuteStmt *) stmt->query->utilityStmt;
480         PreparedStatement *entry;
481         List       *l,
482                            *query_list,
483                            *plan_list;
484         ParamListInfo paramLI = NULL;
485         EState     *estate = NULL;
486
487         /* explain.c should only call me for EXECUTE stmt */
488         Assert(execstmt && IsA(execstmt, ExecuteStmt));
489
490         /* Look it up in the hash table */
491         entry = FetchPreparedStatement(execstmt->name, true);
492
493         query_list = entry->query_list;
494         plan_list = entry->plan_list;
495
496         Assert(length(query_list) == length(plan_list));
497
498         /* Evaluate parameters, if any */
499         if (entry->argtype_list != NIL)
500         {
501                 /*
502                  * Need an EState to evaluate parameters; must not delete it till
503                  * end of query, in case parameters are pass-by-reference.
504                  */
505                 estate = CreateExecutorState();
506                 paramLI = EvaluateParams(estate, execstmt->params,
507                                                                  entry->argtype_list);
508         }
509
510         /* Explain each query */
511         foreach(l, query_list)
512         {
513                 Query      *query = (Query *) lfirst(l);
514                 Plan       *plan = (Plan *) lfirst(plan_list);
515                 bool            is_last_query;
516
517                 plan_list = lnext(plan_list);
518                 is_last_query = (plan_list == NIL);
519
520                 if (query->commandType == CMD_UTILITY)
521                 {
522                         if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt))
523                                 do_text_output_oneline(tstate, "NOTIFY");
524                         else
525                                 do_text_output_oneline(tstate, "UTILITY");
526                 }
527                 else
528                 {
529                         QueryDesc  *qdesc;
530
531                         if (execstmt->into)
532                         {
533                                 if (query->commandType != CMD_SELECT)
534                                         ereport(ERROR,
535                                                         (errcode(ERRCODE_WRONG_OBJECT_TYPE),
536                                                   errmsg("prepared statement is not a SELECT")));
537
538                                 /* Copy the query so we can modify it */
539                                 query = copyObject(query);
540
541                                 query->into = execstmt->into;
542                         }
543
544                         /* Create a QueryDesc requesting no output */
545                         qdesc = CreateQueryDesc(query, plan, None_Receiver,
546                                                                         paramLI, stmt->analyze);
547
548                         ExplainOnePlan(qdesc, stmt, tstate);
549                 }
550
551                 /* No need for CommandCounterIncrement, as ExplainOnePlan did it */
552
553                 /* put a blank line between plans */
554                 if (!is_last_query)
555                         do_text_output_oneline(tstate, "");
556         }
557
558         if (estate)
559                 FreeExecutorState(estate);
560 }