]> granicus.if.org Git - postgresql/blob - src/backend/tcop/utility.c
Support data-modifying commands (INSERT/UPDATE/DELETE) in WITH.
[postgresql] / src / backend / tcop / utility.c
1 /*-------------------------------------------------------------------------
2  *
3  * utility.c
4  *        Contains functions which control the execution of the POSTGRES utility
5  *        commands.  At one time acted as an interface between the Lisp and C
6  *        systems.
7  *
8  * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
9  * Portions Copyright (c) 1994, Regents of the University of California
10  *
11  *
12  * IDENTIFICATION
13  *        src/backend/tcop/utility.c
14  *
15  *-------------------------------------------------------------------------
16  */
17 #include "postgres.h"
18
19 #include "access/reloptions.h"
20 #include "access/twophase.h"
21 #include "access/xact.h"
22 #include "catalog/catalog.h"
23 #include "catalog/namespace.h"
24 #include "catalog/toasting.h"
25 #include "commands/alter.h"
26 #include "commands/async.h"
27 #include "commands/cluster.h"
28 #include "commands/comment.h"
29 #include "commands/collationcmds.h"
30 #include "commands/conversioncmds.h"
31 #include "commands/copy.h"
32 #include "commands/dbcommands.h"
33 #include "commands/defrem.h"
34 #include "commands/discard.h"
35 #include "commands/explain.h"
36 #include "commands/extension.h"
37 #include "commands/lockcmds.h"
38 #include "commands/portalcmds.h"
39 #include "commands/prepare.h"
40 #include "commands/proclang.h"
41 #include "commands/schemacmds.h"
42 #include "commands/seclabel.h"
43 #include "commands/sequence.h"
44 #include "commands/tablecmds.h"
45 #include "commands/tablespace.h"
46 #include "commands/trigger.h"
47 #include "commands/typecmds.h"
48 #include "commands/user.h"
49 #include "commands/vacuum.h"
50 #include "commands/view.h"
51 #include "miscadmin.h"
52 #include "parser/parse_utilcmd.h"
53 #include "postmaster/bgwriter.h"
54 #include "rewrite/rewriteDefine.h"
55 #include "rewrite/rewriteRemove.h"
56 #include "storage/fd.h"
57 #include "tcop/pquery.h"
58 #include "tcop/utility.h"
59 #include "utils/acl.h"
60 #include "utils/guc.h"
61 #include "utils/syscache.h"
62
63
64 /* Hook for plugins to get control in ProcessUtility() */
65 ProcessUtility_hook_type ProcessUtility_hook = NULL;
66
67
68 /*
69  * Verify user has ownership of specified relation, else ereport.
70  *
71  * If noCatalogs is true then we also deny access to system catalogs,
72  * except when allowSystemTableMods is true.
73  */
74 void
75 CheckRelationOwnership(RangeVar *rel, bool noCatalogs)
76 {
77         Oid                     relOid;
78         HeapTuple       tuple;
79
80         relOid = RangeVarGetRelid(rel, false);
81         tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
82         if (!HeapTupleIsValid(tuple))           /* should not happen */
83                 elog(ERROR, "cache lookup failed for relation %u", relOid);
84
85         if (!pg_class_ownercheck(relOid, GetUserId()))
86                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
87                                            rel->relname);
88
89         if (noCatalogs)
90         {
91                 if (!allowSystemTableMods &&
92                         IsSystemClass((Form_pg_class) GETSTRUCT(tuple)))
93                         ereport(ERROR,
94                                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
95                                          errmsg("permission denied: \"%s\" is a system catalog",
96                                                         rel->relname)));
97         }
98
99         ReleaseSysCache(tuple);
100 }
101
102
103 /*
104  * CommandIsReadOnly: is an executable query read-only?
105  *
106  * This is a much stricter test than we apply for XactReadOnly mode;
107  * the query must be *in truth* read-only, because the caller wishes
108  * not to do CommandCounterIncrement for it.
109  *
110  * Note: currently no need to support Query nodes here
111  */
112 bool
113 CommandIsReadOnly(Node *parsetree)
114 {
115         if (IsA(parsetree, PlannedStmt))
116         {
117                 PlannedStmt *stmt = (PlannedStmt *) parsetree;
118
119                 switch (stmt->commandType)
120                 {
121                         case CMD_SELECT:
122                                 if (stmt->intoClause != NULL)
123                                         return false;           /* SELECT INTO */
124                                 else if (stmt->rowMarks != NIL)
125                                         return false;           /* SELECT FOR UPDATE/SHARE */
126                                 else if (stmt->hasModifyingCTE)
127                                         return false;           /* data-modifying CTE */
128                                 else
129                                         return true;
130                         case CMD_UPDATE:
131                         case CMD_INSERT:
132                         case CMD_DELETE:
133                                 return false;
134                         default:
135                                 elog(WARNING, "unrecognized commandType: %d",
136                                          (int) stmt->commandType);
137                                 break;
138                 }
139         }
140         /* For now, treat all utility commands as read/write */
141         return false;
142 }
143
144 /*
145  * check_xact_readonly: is a utility command read-only?
146  *
147  * Here we use the loose rules of XactReadOnly mode: no permanent effects
148  * on the database are allowed.
149  */
150 static void
151 check_xact_readonly(Node *parsetree)
152 {
153         if (!XactReadOnly)
154                 return;
155
156         /*
157          * Note: Commands that need to do more complicated checking are handled
158          * elsewhere, in particular COPY and plannable statements do their own
159          * checking.  However they should all call PreventCommandIfReadOnly to
160          * actually throw the error.
161          */
162
163         switch (nodeTag(parsetree))
164         {
165                 case T_AlterDatabaseStmt:
166                 case T_AlterDatabaseSetStmt:
167                 case T_AlterDomainStmt:
168                 case T_AlterFunctionStmt:
169                 case T_AlterRoleStmt:
170                 case T_AlterRoleSetStmt:
171                 case T_AlterObjectSchemaStmt:
172                 case T_AlterOwnerStmt:
173                 case T_AlterSeqStmt:
174                 case T_AlterTableStmt:
175                 case T_RenameStmt:
176                 case T_CommentStmt:
177                 case T_DefineStmt:
178                 case T_CreateCastStmt:
179                 case T_CreateConversionStmt:
180                 case T_CreatedbStmt:
181                 case T_CreateDomainStmt:
182                 case T_CreateFunctionStmt:
183                 case T_CreateRoleStmt:
184                 case T_IndexStmt:
185                 case T_CreatePLangStmt:
186                 case T_CreateOpClassStmt:
187                 case T_CreateOpFamilyStmt:
188                 case T_AlterOpFamilyStmt:
189                 case T_RuleStmt:
190                 case T_CreateSchemaStmt:
191                 case T_CreateSeqStmt:
192                 case T_CreateStmt:
193                 case T_CreateTableSpaceStmt:
194                 case T_CreateTrigStmt:
195                 case T_CompositeTypeStmt:
196                 case T_CreateEnumStmt:
197                 case T_AlterEnumStmt:
198                 case T_ViewStmt:
199                 case T_DropCastStmt:
200                 case T_DropStmt:
201                 case T_DropdbStmt:
202                 case T_DropTableSpaceStmt:
203                 case T_RemoveFuncStmt:
204                 case T_DropRoleStmt:
205                 case T_DropPLangStmt:
206                 case T_RemoveOpClassStmt:
207                 case T_RemoveOpFamilyStmt:
208                 case T_DropPropertyStmt:
209                 case T_GrantStmt:
210                 case T_GrantRoleStmt:
211                 case T_AlterDefaultPrivilegesStmt:
212                 case T_TruncateStmt:
213                 case T_DropOwnedStmt:
214                 case T_ReassignOwnedStmt:
215                 case T_AlterTSDictionaryStmt:
216                 case T_AlterTSConfigurationStmt:
217                 case T_CreateExtensionStmt:
218                 case T_AlterExtensionStmt:
219                 case T_AlterExtensionContentsStmt:
220                 case T_CreateFdwStmt:
221                 case T_AlterFdwStmt:
222                 case T_DropFdwStmt:
223                 case T_CreateForeignServerStmt:
224                 case T_AlterForeignServerStmt:
225                 case T_DropForeignServerStmt:
226                 case T_CreateUserMappingStmt:
227                 case T_AlterUserMappingStmt:
228                 case T_DropUserMappingStmt:
229                 case T_AlterTableSpaceOptionsStmt:
230                 case T_CreateForeignTableStmt:
231                 case T_SecLabelStmt:
232                         PreventCommandIfReadOnly(CreateCommandTag(parsetree));
233                         break;
234                 default:
235                         /* do nothing */
236                         break;
237         }
238 }
239
240 /*
241  * PreventCommandIfReadOnly: throw error if XactReadOnly
242  *
243  * This is useful mainly to ensure consistency of the error message wording;
244  * most callers have checked XactReadOnly for themselves.
245  */
246 void
247 PreventCommandIfReadOnly(const char *cmdname)
248 {
249         if (XactReadOnly)
250                 ereport(ERROR,
251                                 (errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),
252                 /* translator: %s is name of a SQL command, eg CREATE */
253                                  errmsg("cannot execute %s in a read-only transaction",
254                                                 cmdname)));
255 }
256
257 /*
258  * PreventCommandDuringRecovery: throw error if RecoveryInProgress
259  *
260  * The majority of operations that are unsafe in a Hot Standby slave
261  * will be rejected by XactReadOnly tests.      However there are a few
262  * commands that are allowed in "read-only" xacts but cannot be allowed
263  * in Hot Standby mode.  Those commands should call this function.
264  */
265 void
266 PreventCommandDuringRecovery(const char *cmdname)
267 {
268         if (RecoveryInProgress())
269                 ereport(ERROR,
270                                 (errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),
271                 /* translator: %s is name of a SQL command, eg CREATE */
272                                  errmsg("cannot execute %s during recovery",
273                                                 cmdname)));
274 }
275
276 /*
277  * CheckRestrictedOperation: throw error for hazardous command if we're
278  * inside a security restriction context.
279  *
280  * This is needed to protect session-local state for which there is not any
281  * better-defined protection mechanism, such as ownership.
282  */
283 static void
284 CheckRestrictedOperation(const char *cmdname)
285 {
286         if (InSecurityRestrictedOperation())
287                 ereport(ERROR,
288                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
289                 /* translator: %s is name of a SQL command, eg PREPARE */
290                          errmsg("cannot execute %s within security-restricted operation",
291                                         cmdname)));
292 }
293
294
295 /*
296  * ProcessUtility
297  *              general utility function invoker
298  *
299  *      parsetree: the parse tree for the utility statement
300  *      queryString: original source text of command
301  *      params: parameters to use during execution
302  *      isTopLevel: true if executing a "top level" (interactively issued) command
303  *      dest: where to send results
304  *      completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
305  *              in which to store a command completion status string.
306  *
307  * Notes: as of PG 8.4, caller MUST supply a queryString; it is not
308  * allowed anymore to pass NULL.  (If you really don't have source text,
309  * you can pass a constant string, perhaps "(query not available)".)
310  *
311  * completionTag is only set nonempty if we want to return a nondefault status.
312  *
313  * completionTag may be NULL if caller doesn't want a status string.
314  */
315 void
316 ProcessUtility(Node *parsetree,
317                            const char *queryString,
318                            ParamListInfo params,
319                            bool isTopLevel,
320                            DestReceiver *dest,
321                            char *completionTag)
322 {
323         Assert(queryString != NULL);    /* required as of 8.4 */
324
325         /*
326          * We provide a function hook variable that lets loadable plugins get
327          * control when ProcessUtility is called.  Such a plugin would normally
328          * call standard_ProcessUtility().
329          */
330         if (ProcessUtility_hook)
331                 (*ProcessUtility_hook) (parsetree, queryString, params,
332                                                                 isTopLevel, dest, completionTag);
333         else
334                 standard_ProcessUtility(parsetree, queryString, params,
335                                                                 isTopLevel, dest, completionTag);
336 }
337
338 void
339 standard_ProcessUtility(Node *parsetree,
340                                                 const char *queryString,
341                                                 ParamListInfo params,
342                                                 bool isTopLevel,
343                                                 DestReceiver *dest,
344                                                 char *completionTag)
345 {
346         check_xact_readonly(parsetree);
347
348         if (completionTag)
349                 completionTag[0] = '\0';
350
351         switch (nodeTag(parsetree))
352         {
353                         /*
354                          * ******************** transactions ********************
355                          */
356                 case T_TransactionStmt:
357                         {
358                                 TransactionStmt *stmt = (TransactionStmt *) parsetree;
359
360                                 switch (stmt->kind)
361                                 {
362                                                 /*
363                                                  * START TRANSACTION, as defined by SQL99: Identical
364                                                  * to BEGIN.  Same code for both.
365                                                  */
366                                         case TRANS_STMT_BEGIN:
367                                         case TRANS_STMT_START:
368                                                 {
369                                                         ListCell   *lc;
370
371                                                         BeginTransactionBlock();
372                                                         foreach(lc, stmt->options)
373                                                         {
374                                                                 DefElem    *item = (DefElem *) lfirst(lc);
375
376                                                                 if (strcmp(item->defname, "transaction_isolation") == 0)
377                                                                         SetPGVariable("transaction_isolation",
378                                                                                                   list_make1(item->arg),
379                                                                                                   true);
380                                                                 else if (strcmp(item->defname, "transaction_read_only") == 0)
381                                                                         SetPGVariable("transaction_read_only",
382                                                                                                   list_make1(item->arg),
383                                                                                                   true);
384                                                                 else if (strcmp(item->defname, "transaction_deferrable") == 0)
385                                                                         SetPGVariable("transaction_deferrable",
386                                                                                                   list_make1(item->arg),
387                                                                                                   true);
388                                                         }
389                                                 }
390                                                 break;
391
392                                         case TRANS_STMT_COMMIT:
393                                                 if (!EndTransactionBlock())
394                                                 {
395                                                         /* report unsuccessful commit in completionTag */
396                                                         if (completionTag)
397                                                                 strcpy(completionTag, "ROLLBACK");
398                                                 }
399                                                 break;
400
401                                         case TRANS_STMT_PREPARE:
402                                                 PreventCommandDuringRecovery("PREPARE TRANSACTION");
403                                                 if (!PrepareTransactionBlock(stmt->gid))
404                                                 {
405                                                         /* report unsuccessful commit in completionTag */
406                                                         if (completionTag)
407                                                                 strcpy(completionTag, "ROLLBACK");
408                                                 }
409                                                 break;
410
411                                         case TRANS_STMT_COMMIT_PREPARED:
412                                                 PreventTransactionChain(isTopLevel, "COMMIT PREPARED");
413                                                 PreventCommandDuringRecovery("COMMIT PREPARED");
414                                                 FinishPreparedTransaction(stmt->gid, true);
415                                                 break;
416
417                                         case TRANS_STMT_ROLLBACK_PREPARED:
418                                                 PreventTransactionChain(isTopLevel, "ROLLBACK PREPARED");
419                                                 PreventCommandDuringRecovery("ROLLBACK PREPARED");
420                                                 FinishPreparedTransaction(stmt->gid, false);
421                                                 break;
422
423                                         case TRANS_STMT_ROLLBACK:
424                                                 UserAbortTransactionBlock();
425                                                 break;
426
427                                         case TRANS_STMT_SAVEPOINT:
428                                                 {
429                                                         ListCell   *cell;
430                                                         char       *name = NULL;
431
432                                                         RequireTransactionChain(isTopLevel, "SAVEPOINT");
433
434                                                         foreach(cell, stmt->options)
435                                                         {
436                                                                 DefElem    *elem = lfirst(cell);
437
438                                                                 if (strcmp(elem->defname, "savepoint_name") == 0)
439                                                                         name = strVal(elem->arg);
440                                                         }
441
442                                                         Assert(PointerIsValid(name));
443
444                                                         DefineSavepoint(name);
445                                                 }
446                                                 break;
447
448                                         case TRANS_STMT_RELEASE:
449                                                 RequireTransactionChain(isTopLevel, "RELEASE SAVEPOINT");
450                                                 ReleaseSavepoint(stmt->options);
451                                                 break;
452
453                                         case TRANS_STMT_ROLLBACK_TO:
454                                                 RequireTransactionChain(isTopLevel, "ROLLBACK TO SAVEPOINT");
455                                                 RollbackToSavepoint(stmt->options);
456
457                                                 /*
458                                                  * CommitTransactionCommand is in charge of
459                                                  * re-defining the savepoint again
460                                                  */
461                                                 break;
462                                 }
463                         }
464                         break;
465
466                         /*
467                          * Portal (cursor) manipulation
468                          *
469                          * Note: DECLARE CURSOR is processed mostly as a SELECT, and
470                          * therefore what we will get here is a PlannedStmt not a bare
471                          * DeclareCursorStmt.
472                          */
473                 case T_PlannedStmt:
474                         {
475                                 PlannedStmt *stmt = (PlannedStmt *) parsetree;
476
477                                 if (stmt->utilityStmt == NULL ||
478                                         !IsA(stmt->utilityStmt, DeclareCursorStmt))
479                                         elog(ERROR, "non-DECLARE CURSOR PlannedStmt passed to ProcessUtility");
480                                 PerformCursorOpen(stmt, params, queryString, isTopLevel);
481                         }
482                         break;
483
484                 case T_ClosePortalStmt:
485                         {
486                                 ClosePortalStmt *stmt = (ClosePortalStmt *) parsetree;
487
488                                 CheckRestrictedOperation("CLOSE");
489                                 PerformPortalClose(stmt->portalname);
490                         }
491                         break;
492
493                 case T_FetchStmt:
494                         PerformPortalFetch((FetchStmt *) parsetree, dest,
495                                                            completionTag);
496                         break;
497
498                         /*
499                          * relation and attribute manipulation
500                          */
501                 case T_CreateSchemaStmt:
502                         CreateSchemaCommand((CreateSchemaStmt *) parsetree,
503                                                                 queryString);
504                         break;
505
506                 case T_CreateStmt:
507                 case T_CreateForeignTableStmt:
508                         {
509                                 List       *stmts;
510                                 ListCell   *l;
511                                 Oid                     relOid;
512
513                                 /* Run parse analysis ... */
514                                 stmts = transformCreateStmt((CreateStmt *) parsetree,
515                                                                                         queryString);
516
517                                 /* ... and do it */
518                                 foreach(l, stmts)
519                                 {
520                                         Node       *stmt = (Node *) lfirst(l);
521
522                                         if (IsA(stmt, CreateStmt))
523                                         {
524                                                 Datum           toast_options;
525                                                 static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
526
527                                                 /* Create the table itself */
528                                                 relOid = DefineRelation((CreateStmt *) stmt,
529                                                                                                 RELKIND_RELATION,
530                                                                                                 InvalidOid);
531
532                                                 /*
533                                                  * If "IF NOT EXISTS" was specified and the relation
534                                                  * already exists, do nothing further.
535                                                  */
536                                                 if (relOid == InvalidOid)
537                                                         continue;
538
539                                                 /*
540                                                  * Let AlterTableCreateToastTable decide if this one
541                                                  * needs a secondary relation too.
542                                                  */
543                                                 CommandCounterIncrement();
544
545                                                 /* parse and validate reloptions for the toast table */
546                                                 toast_options = transformRelOptions((Datum) 0,
547                                                                                           ((CreateStmt *) stmt)->options,
548                                                                                                                         "toast",
549                                                                                                                         validnsps,
550                                                                                                                         true, false);
551                                                 (void) heap_reloptions(RELKIND_TOASTVALUE, toast_options,
552                                                                                            true);
553
554                                                 AlterTableCreateToastTable(relOid, toast_options);
555                                         }
556                                         else if (IsA(stmt, CreateForeignTableStmt))
557                                         {
558                                                 /* Create the table itself */
559                                                 relOid = DefineRelation((CreateStmt *) stmt,
560                                                                                                 RELKIND_FOREIGN_TABLE,
561                                                                                                 InvalidOid);
562
563                                                 /*
564                                                  * Unless "IF NOT EXISTS" was specified and the
565                                                  * relation already exists, create the pg_foreign_table
566                                                  * entry.
567                                                  */
568                                                 if (relOid != InvalidOid)
569                                                         CreateForeignTable((CreateForeignTableStmt *) stmt,
570                                                                                                 relOid);
571                                         }
572                                         else
573                                         {
574                                                 /* Recurse for anything else */
575                                                 ProcessUtility(stmt,
576                                                                            queryString,
577                                                                            params,
578                                                                            false,
579                                                                            None_Receiver,
580                                                                            NULL);
581                                         }
582
583                                         /* Need CCI between commands */
584                                         if (lnext(l) != NULL)
585                                                 CommandCounterIncrement();
586                                 }
587                         }
588                         break;
589
590                 case T_CreateTableSpaceStmt:
591                         PreventTransactionChain(isTopLevel, "CREATE TABLESPACE");
592                         CreateTableSpace((CreateTableSpaceStmt *) parsetree);
593                         break;
594
595                 case T_DropTableSpaceStmt:
596                         PreventTransactionChain(isTopLevel, "DROP TABLESPACE");
597                         DropTableSpace((DropTableSpaceStmt *) parsetree);
598                         break;
599
600                 case T_AlterTableSpaceOptionsStmt:
601                         AlterTableSpaceOptions((AlterTableSpaceOptionsStmt *) parsetree);
602                         break;
603
604                 case T_CreateExtensionStmt:
605                         CreateExtension((CreateExtensionStmt *) parsetree);
606                         break;
607
608                 case T_AlterExtensionStmt:
609                         ExecAlterExtensionStmt((AlterExtensionStmt *) parsetree);
610                         break;
611
612                 case T_AlterExtensionContentsStmt:
613                         ExecAlterExtensionContentsStmt((AlterExtensionContentsStmt *) parsetree);
614                         break;
615
616                 case T_CreateFdwStmt:
617                         CreateForeignDataWrapper((CreateFdwStmt *) parsetree);
618                         break;
619
620                 case T_AlterFdwStmt:
621                         AlterForeignDataWrapper((AlterFdwStmt *) parsetree);
622                         break;
623
624                 case T_DropFdwStmt:
625                         RemoveForeignDataWrapper((DropFdwStmt *) parsetree);
626                         break;
627
628                 case T_CreateForeignServerStmt:
629                         CreateForeignServer((CreateForeignServerStmt *) parsetree);
630                         break;
631
632                 case T_AlterForeignServerStmt:
633                         AlterForeignServer((AlterForeignServerStmt *) parsetree);
634                         break;
635
636                 case T_DropForeignServerStmt:
637                         RemoveForeignServer((DropForeignServerStmt *) parsetree);
638                         break;
639
640                 case T_CreateUserMappingStmt:
641                         CreateUserMapping((CreateUserMappingStmt *) parsetree);
642                         break;
643
644                 case T_AlterUserMappingStmt:
645                         AlterUserMapping((AlterUserMappingStmt *) parsetree);
646                         break;
647
648                 case T_DropUserMappingStmt:
649                         RemoveUserMapping((DropUserMappingStmt *) parsetree);
650                         break;
651
652                 case T_DropStmt:
653                         {
654                                 DropStmt   *stmt = (DropStmt *) parsetree;
655
656                                 switch (stmt->removeType)
657                                 {
658                                         case OBJECT_TABLE:
659                                         case OBJECT_SEQUENCE:
660                                         case OBJECT_VIEW:
661                                         case OBJECT_INDEX:
662                                         case OBJECT_FOREIGN_TABLE:
663                                                 RemoveRelations(stmt);
664                                                 break;
665
666                                         case OBJECT_TYPE:
667                                         case OBJECT_DOMAIN:
668                                                 RemoveTypes(stmt);
669                                                 break;
670
671                                         case OBJECT_COLLATION:
672                                                 DropCollationsCommand(stmt);
673                                                 break;
674
675                                         case OBJECT_CONVERSION:
676                                                 DropConversionsCommand(stmt);
677                                                 break;
678
679                                         case OBJECT_SCHEMA:
680                                                 RemoveSchemas(stmt);
681                                                 break;
682
683                                         case OBJECT_TSPARSER:
684                                                 RemoveTSParsers(stmt);
685                                                 break;
686
687                                         case OBJECT_TSDICTIONARY:
688                                                 RemoveTSDictionaries(stmt);
689                                                 break;
690
691                                         case OBJECT_TSTEMPLATE:
692                                                 RemoveTSTemplates(stmt);
693                                                 break;
694
695                                         case OBJECT_TSCONFIGURATION:
696                                                 RemoveTSConfigurations(stmt);
697                                                 break;
698
699                                         case OBJECT_EXTENSION:
700                                                 RemoveExtensions(stmt);
701                                                 break;
702
703                                         default:
704                                                 elog(ERROR, "unrecognized drop object type: %d",
705                                                          (int) stmt->removeType);
706                                                 break;
707                                 }
708                         }
709                         break;
710
711                 case T_TruncateStmt:
712                         ExecuteTruncate((TruncateStmt *) parsetree);
713                         break;
714
715                 case T_CommentStmt:
716                         CommentObject((CommentStmt *) parsetree);
717                         break;
718
719                 case T_SecLabelStmt:
720                         ExecSecLabelStmt((SecLabelStmt *) parsetree);
721                         break;
722
723                 case T_CopyStmt:
724                         {
725                                 uint64          processed;
726
727                                 processed = DoCopy((CopyStmt *) parsetree, queryString);
728                                 if (completionTag)
729                                         snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
730                                                          "COPY " UINT64_FORMAT, processed);
731                         }
732                         break;
733
734                 case T_PrepareStmt:
735                         CheckRestrictedOperation("PREPARE");
736                         PrepareQuery((PrepareStmt *) parsetree, queryString);
737                         break;
738
739                 case T_ExecuteStmt:
740                         ExecuteQuery((ExecuteStmt *) parsetree, queryString, params,
741                                                  dest, completionTag);
742                         break;
743
744                 case T_DeallocateStmt:
745                         CheckRestrictedOperation("DEALLOCATE");
746                         DeallocateQuery((DeallocateStmt *) parsetree);
747                         break;
748
749                         /*
750                          * schema
751                          */
752                 case T_RenameStmt:
753                         ExecRenameStmt((RenameStmt *) parsetree);
754                         break;
755
756                 case T_AlterObjectSchemaStmt:
757                         ExecAlterObjectSchemaStmt((AlterObjectSchemaStmt *) parsetree);
758                         break;
759
760                 case T_AlterOwnerStmt:
761                         ExecAlterOwnerStmt((AlterOwnerStmt *) parsetree);
762                         break;
763
764                 case T_AlterTableStmt:
765                         {
766                                 List       *stmts;
767                                 ListCell   *l;
768
769                                 /* Run parse analysis ... */
770                                 stmts = transformAlterTableStmt((AlterTableStmt *) parsetree,
771                                                                                                 queryString);
772
773                                 /* ... and do it */
774                                 foreach(l, stmts)
775                                 {
776                                         Node       *stmt = (Node *) lfirst(l);
777
778                                         if (IsA(stmt, AlterTableStmt))
779                                         {
780                                                 /* Do the table alteration proper */
781                                                 AlterTable((AlterTableStmt *) stmt);
782                                         }
783                                         else
784                                         {
785                                                 /* Recurse for anything else */
786                                                 ProcessUtility(stmt,
787                                                                            queryString,
788                                                                            params,
789                                                                            false,
790                                                                            None_Receiver,
791                                                                            NULL);
792                                         }
793
794                                         /* Need CCI between commands */
795                                         if (lnext(l) != NULL)
796                                                 CommandCounterIncrement();
797                                 }
798                         }
799                         break;
800
801                 case T_AlterDomainStmt:
802                         {
803                                 AlterDomainStmt *stmt = (AlterDomainStmt *) parsetree;
804
805                                 /*
806                                  * Some or all of these functions are recursive to cover
807                                  * inherited things, so permission checks are done there.
808                                  */
809                                 switch (stmt->subtype)
810                                 {
811                                         case 'T':       /* ALTER DOMAIN DEFAULT */
812
813                                                 /*
814                                                  * Recursively alter column default for table and, if
815                                                  * requested, for descendants
816                                                  */
817                                                 AlterDomainDefault(stmt->typeName,
818                                                                                    stmt->def);
819                                                 break;
820                                         case 'N':       /* ALTER DOMAIN DROP NOT NULL */
821                                                 AlterDomainNotNull(stmt->typeName,
822                                                                                    false);
823                                                 break;
824                                         case 'O':       /* ALTER DOMAIN SET NOT NULL */
825                                                 AlterDomainNotNull(stmt->typeName,
826                                                                                    true);
827                                                 break;
828                                         case 'C':       /* ADD CONSTRAINT */
829                                                 AlterDomainAddConstraint(stmt->typeName,
830                                                                                                  stmt->def);
831                                                 break;
832                                         case 'X':       /* DROP CONSTRAINT */
833                                                 AlterDomainDropConstraint(stmt->typeName,
834                                                                                                   stmt->name,
835                                                                                                   stmt->behavior);
836                                                 break;
837                                         default:        /* oops */
838                                                 elog(ERROR, "unrecognized alter domain type: %d",
839                                                          (int) stmt->subtype);
840                                                 break;
841                                 }
842                         }
843                         break;
844
845                 case T_GrantStmt:
846                         ExecuteGrantStmt((GrantStmt *) parsetree);
847                         break;
848
849                 case T_GrantRoleStmt:
850                         GrantRole((GrantRoleStmt *) parsetree);
851                         break;
852
853                 case T_AlterDefaultPrivilegesStmt:
854                         ExecAlterDefaultPrivilegesStmt((AlterDefaultPrivilegesStmt *) parsetree);
855                         break;
856
857                         /*
858                          * **************** object creation / destruction *****************
859                          */
860                 case T_DefineStmt:
861                         {
862                                 DefineStmt *stmt = (DefineStmt *) parsetree;
863
864                                 switch (stmt->kind)
865                                 {
866                                         case OBJECT_AGGREGATE:
867                                                 DefineAggregate(stmt->defnames, stmt->args,
868                                                                                 stmt->oldstyle, stmt->definition);
869                                                 break;
870                                         case OBJECT_OPERATOR:
871                                                 Assert(stmt->args == NIL);
872                                                 DefineOperator(stmt->defnames, stmt->definition);
873                                                 break;
874                                         case OBJECT_TYPE:
875                                                 Assert(stmt->args == NIL);
876                                                 DefineType(stmt->defnames, stmt->definition);
877                                                 break;
878                                         case OBJECT_TSPARSER:
879                                                 Assert(stmt->args == NIL);
880                                                 DefineTSParser(stmt->defnames, stmt->definition);
881                                                 break;
882                                         case OBJECT_TSDICTIONARY:
883                                                 Assert(stmt->args == NIL);
884                                                 DefineTSDictionary(stmt->defnames, stmt->definition);
885                                                 break;
886                                         case OBJECT_TSTEMPLATE:
887                                                 Assert(stmt->args == NIL);
888                                                 DefineTSTemplate(stmt->defnames, stmt->definition);
889                                                 break;
890                                         case OBJECT_TSCONFIGURATION:
891                                                 Assert(stmt->args == NIL);
892                                                 DefineTSConfiguration(stmt->defnames, stmt->definition);
893                                                 break;
894                                         case OBJECT_COLLATION:
895                                                 Assert(stmt->args == NIL);
896                                                 DefineCollation(stmt->defnames, stmt->definition);
897                                                 break;
898                                         default:
899                                                 elog(ERROR, "unrecognized define stmt type: %d",
900                                                          (int) stmt->kind);
901                                                 break;
902                                 }
903                         }
904                         break;
905
906                 case T_CompositeTypeStmt:               /* CREATE TYPE (composite) */
907                         {
908                                 CompositeTypeStmt *stmt = (CompositeTypeStmt *) parsetree;
909
910                                 DefineCompositeType(stmt->typevar, stmt->coldeflist);
911                         }
912                         break;
913
914                 case T_CreateEnumStmt:  /* CREATE TYPE (enum) */
915                         DefineEnum((CreateEnumStmt *) parsetree);
916                         break;
917
918                 case T_AlterEnumStmt:   /* ALTER TYPE (enum) */
919                         /*
920                          * We disallow this in transaction blocks, because we can't cope
921                          * with enum OID values getting into indexes and then having their
922                          * defining pg_enum entries go away.
923                          */
924                         PreventTransactionChain(isTopLevel, "ALTER TYPE ... ADD");
925                         AlterEnum((AlterEnumStmt *) parsetree);
926                         break;
927
928                 case T_ViewStmt:                /* CREATE VIEW */
929                         DefineView((ViewStmt *) parsetree, queryString);
930                         break;
931
932                 case T_CreateFunctionStmt:              /* CREATE FUNCTION */
933                         CreateFunction((CreateFunctionStmt *) parsetree, queryString);
934                         break;
935
936                 case T_AlterFunctionStmt:               /* ALTER FUNCTION */
937                         AlterFunction((AlterFunctionStmt *) parsetree);
938                         break;
939
940                 case T_IndexStmt:               /* CREATE INDEX */
941                         {
942                                 IndexStmt  *stmt = (IndexStmt *) parsetree;
943
944                                 if (stmt->concurrent)
945                                         PreventTransactionChain(isTopLevel,
946                                                                                         "CREATE INDEX CONCURRENTLY");
947
948                                 CheckRelationOwnership(stmt->relation, true);
949
950                                 /* Run parse analysis ... */
951                                 stmt = transformIndexStmt(stmt, queryString);
952
953                                 /* ... and do it */
954                                 DefineIndex(stmt->relation,             /* relation */
955                                                         stmt->idxname,          /* index name */
956                                                         InvalidOid, /* no predefined OID */
957                                                         stmt->accessMethod, /* am name */
958                                                         stmt->tableSpace,
959                                                         stmt->indexParams,      /* parameters */
960                                                         (Expr *) stmt->whereClause,
961                                                         stmt->options,
962                                                         stmt->excludeOpNames,
963                                                         stmt->unique,
964                                                         stmt->primary,
965                                                         stmt->isconstraint,
966                                                         stmt->deferrable,
967                                                         stmt->initdeferred,
968                                                         false,          /* is_alter_table */
969                                                         true,           /* check_rights */
970                                                         false,          /* skip_build */
971                                                         false,          /* quiet */
972                                                         stmt->concurrent);      /* concurrent */
973                         }
974                         break;
975
976                 case T_RuleStmt:                /* CREATE RULE */
977                         DefineRule((RuleStmt *) parsetree, queryString);
978                         break;
979
980                 case T_CreateSeqStmt:
981                         DefineSequence((CreateSeqStmt *) parsetree);
982                         break;
983
984                 case T_AlterSeqStmt:
985                         AlterSequence((AlterSeqStmt *) parsetree);
986                         break;
987
988                 case T_RemoveFuncStmt:
989                         {
990                                 RemoveFuncStmt *stmt = (RemoveFuncStmt *) parsetree;
991
992                                 switch (stmt->kind)
993                                 {
994                                         case OBJECT_FUNCTION:
995                                                 RemoveFunction(stmt);
996                                                 break;
997                                         case OBJECT_AGGREGATE:
998                                                 RemoveAggregate(stmt);
999                                                 break;
1000                                         case OBJECT_OPERATOR:
1001                                                 RemoveOperator(stmt);
1002                                                 break;
1003                                         default:
1004                                                 elog(ERROR, "unrecognized object type: %d",
1005                                                          (int) stmt->kind);
1006                                                 break;
1007                                 }
1008                         }
1009                         break;
1010
1011                 case T_DoStmt:
1012                         ExecuteDoStmt((DoStmt *) parsetree);
1013                         break;
1014
1015                 case T_CreatedbStmt:
1016                         PreventTransactionChain(isTopLevel, "CREATE DATABASE");
1017                         createdb((CreatedbStmt *) parsetree);
1018                         break;
1019
1020                 case T_AlterDatabaseStmt:
1021                         AlterDatabase((AlterDatabaseStmt *) parsetree, isTopLevel);
1022                         break;
1023
1024                 case T_AlterDatabaseSetStmt:
1025                         AlterDatabaseSet((AlterDatabaseSetStmt *) parsetree);
1026                         break;
1027
1028                 case T_DropdbStmt:
1029                         {
1030                                 DropdbStmt *stmt = (DropdbStmt *) parsetree;
1031
1032                                 PreventTransactionChain(isTopLevel, "DROP DATABASE");
1033                                 dropdb(stmt->dbname, stmt->missing_ok);
1034                         }
1035                         break;
1036
1037                         /* Query-level asynchronous notification */
1038                 case T_NotifyStmt:
1039                         {
1040                                 NotifyStmt *stmt = (NotifyStmt *) parsetree;
1041
1042                                 PreventCommandDuringRecovery("NOTIFY");
1043                                 Async_Notify(stmt->conditionname, stmt->payload);
1044                         }
1045                         break;
1046
1047                 case T_ListenStmt:
1048                         {
1049                                 ListenStmt *stmt = (ListenStmt *) parsetree;
1050
1051                                 PreventCommandDuringRecovery("LISTEN");
1052                                 CheckRestrictedOperation("LISTEN");
1053                                 Async_Listen(stmt->conditionname);
1054                         }
1055                         break;
1056
1057                 case T_UnlistenStmt:
1058                         {
1059                                 UnlistenStmt *stmt = (UnlistenStmt *) parsetree;
1060
1061                                 PreventCommandDuringRecovery("UNLISTEN");
1062                                 CheckRestrictedOperation("UNLISTEN");
1063                                 if (stmt->conditionname)
1064                                         Async_Unlisten(stmt->conditionname);
1065                                 else
1066                                         Async_UnlistenAll();
1067                         }
1068                         break;
1069
1070                 case T_LoadStmt:
1071                         {
1072                                 LoadStmt   *stmt = (LoadStmt *) parsetree;
1073
1074                                 closeAllVfds(); /* probably not necessary... */
1075                                 /* Allowed names are restricted if you're not superuser */
1076                                 load_file(stmt->filename, !superuser());
1077                         }
1078                         break;
1079
1080                 case T_ClusterStmt:
1081                         /* we choose to allow this during "read only" transactions */
1082                         PreventCommandDuringRecovery("CLUSTER");
1083                         cluster((ClusterStmt *) parsetree, isTopLevel);
1084                         break;
1085
1086                 case T_VacuumStmt:
1087                         /* we choose to allow this during "read only" transactions */
1088                         PreventCommandDuringRecovery("VACUUM");
1089                         vacuum((VacuumStmt *) parsetree, InvalidOid, true, NULL, false,
1090                                    isTopLevel);
1091                         break;
1092
1093                 case T_ExplainStmt:
1094                         ExplainQuery((ExplainStmt *) parsetree, queryString, params, dest);
1095                         break;
1096
1097                 case T_VariableSetStmt:
1098                         ExecSetVariableStmt((VariableSetStmt *) parsetree);
1099                         break;
1100
1101                 case T_VariableShowStmt:
1102                         {
1103                                 VariableShowStmt *n = (VariableShowStmt *) parsetree;
1104
1105                                 GetPGVariable(n->name, dest);
1106                         }
1107                         break;
1108
1109                 case T_DiscardStmt:
1110                         /* should we allow DISCARD PLANS? */
1111                         CheckRestrictedOperation("DISCARD");
1112                         DiscardCommand((DiscardStmt *) parsetree, isTopLevel);
1113                         break;
1114
1115                 case T_CreateTrigStmt:
1116                         (void) CreateTrigger((CreateTrigStmt *) parsetree, queryString,
1117                                                                  InvalidOid, InvalidOid, false);
1118                         break;
1119
1120                 case T_DropPropertyStmt:
1121                         {
1122                                 DropPropertyStmt *stmt = (DropPropertyStmt *) parsetree;
1123                                 Oid                     relId;
1124
1125                                 relId = RangeVarGetRelid(stmt->relation, false);
1126
1127                                 switch (stmt->removeType)
1128                                 {
1129                                         case OBJECT_RULE:
1130                                                 /* RemoveRewriteRule checks permissions */
1131                                                 RemoveRewriteRule(relId, stmt->property,
1132                                                                                   stmt->behavior, stmt->missing_ok);
1133                                                 break;
1134                                         case OBJECT_TRIGGER:
1135                                                 /* DropTrigger checks permissions */
1136                                                 DropTrigger(relId, stmt->property,
1137                                                                         stmt->behavior, stmt->missing_ok);
1138                                                 break;
1139                                         default:
1140                                                 elog(ERROR, "unrecognized object type: %d",
1141                                                          (int) stmt->removeType);
1142                                                 break;
1143                                 }
1144                         }
1145                         break;
1146
1147                 case T_CreatePLangStmt:
1148                         CreateProceduralLanguage((CreatePLangStmt *) parsetree);
1149                         break;
1150
1151                 case T_DropPLangStmt:
1152                         DropProceduralLanguage((DropPLangStmt *) parsetree);
1153                         break;
1154
1155                         /*
1156                          * ******************************** DOMAIN statements ****
1157                          */
1158                 case T_CreateDomainStmt:
1159                         DefineDomain((CreateDomainStmt *) parsetree);
1160                         break;
1161
1162                         /*
1163                          * ******************************** ROLE statements ****
1164                          */
1165                 case T_CreateRoleStmt:
1166                         CreateRole((CreateRoleStmt *) parsetree);
1167                         break;
1168
1169                 case T_AlterRoleStmt:
1170                         AlterRole((AlterRoleStmt *) parsetree);
1171                         break;
1172
1173                 case T_AlterRoleSetStmt:
1174                         AlterRoleSet((AlterRoleSetStmt *) parsetree);
1175                         break;
1176
1177                 case T_DropRoleStmt:
1178                         DropRole((DropRoleStmt *) parsetree);
1179                         break;
1180
1181                 case T_DropOwnedStmt:
1182                         DropOwnedObjects((DropOwnedStmt *) parsetree);
1183                         break;
1184
1185                 case T_ReassignOwnedStmt:
1186                         ReassignOwnedObjects((ReassignOwnedStmt *) parsetree);
1187                         break;
1188
1189                 case T_LockStmt:
1190
1191                         /*
1192                          * Since the lock would just get dropped immediately, LOCK TABLE
1193                          * outside a transaction block is presumed to be user error.
1194                          */
1195                         RequireTransactionChain(isTopLevel, "LOCK TABLE");
1196                         LockTableCommand((LockStmt *) parsetree);
1197                         break;
1198
1199                 case T_ConstraintsSetStmt:
1200                         AfterTriggerSetState((ConstraintsSetStmt *) parsetree);
1201                         break;
1202
1203                 case T_CheckPointStmt:
1204                         if (!superuser())
1205                                 ereport(ERROR,
1206                                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1207                                                  errmsg("must be superuser to do CHECKPOINT")));
1208
1209                         /*
1210                          * You might think we should have a PreventCommandDuringRecovery()
1211                          * here, but we interpret a CHECKPOINT command during recovery as
1212                          * a request for a restartpoint instead. We allow this since it
1213                          * can be a useful way of reducing switchover time when using
1214                          * various forms of replication.
1215                          */
1216                         RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_WAIT |
1217                                                           (RecoveryInProgress() ? 0 : CHECKPOINT_FORCE));
1218                         break;
1219
1220                 case T_ReindexStmt:
1221                         {
1222                                 ReindexStmt *stmt = (ReindexStmt *) parsetree;
1223
1224                                 /* we choose to allow this during "read only" transactions */
1225                                 PreventCommandDuringRecovery("REINDEX");
1226                                 switch (stmt->kind)
1227                                 {
1228                                         case OBJECT_INDEX:
1229                                                 ReindexIndex(stmt->relation);
1230                                                 break;
1231                                         case OBJECT_TABLE:
1232                                                 ReindexTable(stmt->relation);
1233                                                 break;
1234                                         case OBJECT_DATABASE:
1235
1236                                                 /*
1237                                                  * This cannot run inside a user transaction block; if
1238                                                  * we were inside a transaction, then its commit- and
1239                                                  * start-transaction-command calls would not have the
1240                                                  * intended effect!
1241                                                  */
1242                                                 PreventTransactionChain(isTopLevel,
1243                                                                                                 "REINDEX DATABASE");
1244                                                 ReindexDatabase(stmt->name,
1245                                                                                 stmt->do_system, stmt->do_user);
1246                                                 break;
1247                                         default:
1248                                                 elog(ERROR, "unrecognized object type: %d",
1249                                                          (int) stmt->kind);
1250                                                 break;
1251                                 }
1252                                 break;
1253                         }
1254                         break;
1255
1256                 case T_CreateConversionStmt:
1257                         CreateConversionCommand((CreateConversionStmt *) parsetree);
1258                         break;
1259
1260                 case T_CreateCastStmt:
1261                         CreateCast((CreateCastStmt *) parsetree);
1262                         break;
1263
1264                 case T_DropCastStmt:
1265                         DropCast((DropCastStmt *) parsetree);
1266                         break;
1267
1268                 case T_CreateOpClassStmt:
1269                         DefineOpClass((CreateOpClassStmt *) parsetree);
1270                         break;
1271
1272                 case T_CreateOpFamilyStmt:
1273                         DefineOpFamily((CreateOpFamilyStmt *) parsetree);
1274                         break;
1275
1276                 case T_AlterOpFamilyStmt:
1277                         AlterOpFamily((AlterOpFamilyStmt *) parsetree);
1278                         break;
1279
1280                 case T_RemoveOpClassStmt:
1281                         RemoveOpClass((RemoveOpClassStmt *) parsetree);
1282                         break;
1283
1284                 case T_RemoveOpFamilyStmt:
1285                         RemoveOpFamily((RemoveOpFamilyStmt *) parsetree);
1286                         break;
1287
1288                 case T_AlterTSDictionaryStmt:
1289                         AlterTSDictionary((AlterTSDictionaryStmt *) parsetree);
1290                         break;
1291
1292                 case T_AlterTSConfigurationStmt:
1293                         AlterTSConfiguration((AlterTSConfigurationStmt *) parsetree);
1294                         break;
1295
1296                 default:
1297                         elog(ERROR, "unrecognized node type: %d",
1298                                  (int) nodeTag(parsetree));
1299                         break;
1300         }
1301 }
1302
1303 /*
1304  * UtilityReturnsTuples
1305  *              Return "true" if this utility statement will send output to the
1306  *              destination.
1307  *
1308  * Generally, there should be a case here for each case in ProcessUtility
1309  * where "dest" is passed on.
1310  */
1311 bool
1312 UtilityReturnsTuples(Node *parsetree)
1313 {
1314         switch (nodeTag(parsetree))
1315         {
1316                 case T_FetchStmt:
1317                         {
1318                                 FetchStmt  *stmt = (FetchStmt *) parsetree;
1319                                 Portal          portal;
1320
1321                                 if (stmt->ismove)
1322                                         return false;
1323                                 portal = GetPortalByName(stmt->portalname);
1324                                 if (!PortalIsValid(portal))
1325                                         return false;           /* not our business to raise error */
1326                                 return portal->tupDesc ? true : false;
1327                         }
1328
1329                 case T_ExecuteStmt:
1330                         {
1331                                 ExecuteStmt *stmt = (ExecuteStmt *) parsetree;
1332                                 PreparedStatement *entry;
1333
1334                                 if (stmt->into)
1335                                         return false;
1336                                 entry = FetchPreparedStatement(stmt->name, false);
1337                                 if (!entry)
1338                                         return false;           /* not our business to raise error */
1339                                 if (entry->plansource->resultDesc)
1340                                         return true;
1341                                 return false;
1342                         }
1343
1344                 case T_ExplainStmt:
1345                         return true;
1346
1347                 case T_VariableShowStmt:
1348                         return true;
1349
1350                 default:
1351                         return false;
1352         }
1353 }
1354
1355 /*
1356  * UtilityTupleDescriptor
1357  *              Fetch the actual output tuple descriptor for a utility statement
1358  *              for which UtilityReturnsTuples() previously returned "true".
1359  *
1360  * The returned descriptor is created in (or copied into) the current memory
1361  * context.
1362  */
1363 TupleDesc
1364 UtilityTupleDescriptor(Node *parsetree)
1365 {
1366         switch (nodeTag(parsetree))
1367         {
1368                 case T_FetchStmt:
1369                         {
1370                                 FetchStmt  *stmt = (FetchStmt *) parsetree;
1371                                 Portal          portal;
1372
1373                                 if (stmt->ismove)
1374                                         return NULL;
1375                                 portal = GetPortalByName(stmt->portalname);
1376                                 if (!PortalIsValid(portal))
1377                                         return NULL;    /* not our business to raise error */
1378                                 return CreateTupleDescCopy(portal->tupDesc);
1379                         }
1380
1381                 case T_ExecuteStmt:
1382                         {
1383                                 ExecuteStmt *stmt = (ExecuteStmt *) parsetree;
1384                                 PreparedStatement *entry;
1385
1386                                 if (stmt->into)
1387                                         return NULL;
1388                                 entry = FetchPreparedStatement(stmt->name, false);
1389                                 if (!entry)
1390                                         return NULL;    /* not our business to raise error */
1391                                 return FetchPreparedStatementResultDesc(entry);
1392                         }
1393
1394                 case T_ExplainStmt:
1395                         return ExplainResultDesc((ExplainStmt *) parsetree);
1396
1397                 case T_VariableShowStmt:
1398                         {
1399                                 VariableShowStmt *n = (VariableShowStmt *) parsetree;
1400
1401                                 return GetPGVariableResultDesc(n->name);
1402                         }
1403
1404                 default:
1405                         return NULL;
1406         }
1407 }
1408
1409
1410 /*
1411  * QueryReturnsTuples
1412  *              Return "true" if this Query will send output to the destination.
1413  */
1414 #ifdef NOT_USED
1415 bool
1416 QueryReturnsTuples(Query *parsetree)
1417 {
1418         switch (parsetree->commandType)
1419         {
1420                 case CMD_SELECT:
1421                         /* returns tuples ... unless it's DECLARE CURSOR or SELECT INTO */
1422                         if (parsetree->utilityStmt == NULL &&
1423                                 parsetree->intoClause == NULL)
1424                                 return true;
1425                         break;
1426                 case CMD_INSERT:
1427                 case CMD_UPDATE:
1428                 case CMD_DELETE:
1429                         /* the forms with RETURNING return tuples */
1430                         if (parsetree->returningList)
1431                                 return true;
1432                         break;
1433                 case CMD_UTILITY:
1434                         return UtilityReturnsTuples(parsetree->utilityStmt);
1435                 case CMD_UNKNOWN:
1436                 case CMD_NOTHING:
1437                         /* probably shouldn't get here */
1438                         break;
1439         }
1440         return false;                           /* default */
1441 }
1442 #endif
1443
1444
1445 /*
1446  * AlterObjectTypeCommandTag
1447  *              helper function for CreateCommandTag
1448  *
1449  * This covers most cases where ALTER is used with an ObjectType enum.
1450  */
1451 static const char *
1452 AlterObjectTypeCommandTag(ObjectType objtype)
1453 {
1454         const char *tag;
1455
1456         switch (objtype)
1457         {
1458                 case OBJECT_AGGREGATE:
1459                         tag = "ALTER AGGREGATE";
1460                         break;
1461                 case OBJECT_ATTRIBUTE:
1462                         tag = "ALTER TYPE";
1463                         break;
1464                 case OBJECT_CAST:
1465                         tag = "ALTER CAST";
1466                         break;
1467                 case OBJECT_COLLATION:
1468                         tag = "ALTER COLLATION";
1469                         break;
1470                 case OBJECT_COLUMN:
1471                         tag = "ALTER TABLE";
1472                         break;
1473                 case OBJECT_CONSTRAINT:
1474                         tag = "ALTER TABLE";
1475                         break;
1476                 case OBJECT_CONVERSION:
1477                         tag = "ALTER CONVERSION";
1478                         break;
1479                 case OBJECT_DATABASE:
1480                         tag = "ALTER DATABASE";
1481                         break;
1482                 case OBJECT_DOMAIN:
1483                         tag = "ALTER DOMAIN";
1484                         break;
1485                 case OBJECT_EXTENSION:
1486                         tag = "ALTER EXTENSION";
1487                         break;
1488                 case OBJECT_FDW:
1489                         tag = "ALTER FOREIGN DATA WRAPPER";
1490                         break;
1491                 case OBJECT_FOREIGN_SERVER:
1492                         tag = "ALTER SERVER";
1493                         break;
1494                 case OBJECT_FOREIGN_TABLE:
1495                         tag = "ALTER FOREIGN TABLE";
1496                         break;
1497                 case OBJECT_FUNCTION:
1498                         tag = "ALTER FUNCTION";
1499                         break;
1500                 case OBJECT_INDEX:
1501                         tag = "ALTER INDEX";
1502                         break;
1503                 case OBJECT_LANGUAGE:
1504                         tag = "ALTER LANGUAGE";
1505                         break;
1506                 case OBJECT_LARGEOBJECT:
1507                         tag = "ALTER LARGE OBJECT";
1508                         break;
1509                 case OBJECT_OPCLASS:
1510                         tag = "ALTER OPERATOR CLASS";
1511                         break;
1512                 case OBJECT_OPERATOR:
1513                         tag = "ALTER OPERATOR";
1514                         break;
1515                 case OBJECT_OPFAMILY:
1516                         tag = "ALTER OPERATOR FAMILY";
1517                         break;
1518                 case OBJECT_ROLE:
1519                         tag = "ALTER ROLE";
1520                         break;
1521                 case OBJECT_RULE:
1522                         tag = "ALTER RULE";
1523                         break;
1524                 case OBJECT_SCHEMA:
1525                         tag = "ALTER SCHEMA";
1526                         break;
1527                 case OBJECT_SEQUENCE:
1528                         tag = "ALTER SEQUENCE";
1529                         break;
1530                 case OBJECT_TABLE:
1531                         tag = "ALTER TABLE";
1532                         break;
1533                 case OBJECT_TABLESPACE:
1534                         tag = "ALTER TABLESPACE";
1535                         break;
1536                 case OBJECT_TRIGGER:
1537                         tag = "ALTER TRIGGER";
1538                         break;
1539                 case OBJECT_TSCONFIGURATION:
1540                         tag = "ALTER TEXT SEARCH CONFIGURATION";
1541                         break;
1542                 case OBJECT_TSDICTIONARY:
1543                         tag = "ALTER TEXT SEARCH DICTIONARY";
1544                         break;
1545                 case OBJECT_TSPARSER:
1546                         tag = "ALTER TEXT SEARCH PARSER";
1547                         break;
1548                 case OBJECT_TSTEMPLATE:
1549                         tag = "ALTER TEXT SEARCH TEMPLATE";
1550                         break;
1551                 case OBJECT_TYPE:
1552                         tag = "ALTER TYPE";
1553                         break;
1554                 case OBJECT_VIEW:
1555                         tag = "ALTER VIEW";
1556                         break;
1557                 default:
1558                         tag = "???";
1559                         break;
1560         }
1561
1562         return tag;
1563 }
1564
1565 /*
1566  * CreateCommandTag
1567  *              utility to get a string representation of the command operation,
1568  *              given either a raw (un-analyzed) parsetree or a planned query.
1569  *
1570  * This must handle all command types, but since the vast majority
1571  * of 'em are utility commands, it seems sensible to keep it here.
1572  *
1573  * NB: all result strings must be shorter than COMPLETION_TAG_BUFSIZE.
1574  * Also, the result must point at a true constant (permanent storage).
1575  */
1576 const char *
1577 CreateCommandTag(Node *parsetree)
1578 {
1579         const char *tag;
1580
1581         switch (nodeTag(parsetree))
1582         {
1583                         /* raw plannable queries */
1584                 case T_InsertStmt:
1585                         tag = "INSERT";
1586                         break;
1587
1588                 case T_DeleteStmt:
1589                         tag = "DELETE";
1590                         break;
1591
1592                 case T_UpdateStmt:
1593                         tag = "UPDATE";
1594                         break;
1595
1596                 case T_SelectStmt:
1597                         tag = "SELECT";
1598                         break;
1599
1600                         /* utility statements --- same whether raw or cooked */
1601                 case T_TransactionStmt:
1602                         {
1603                                 TransactionStmt *stmt = (TransactionStmt *) parsetree;
1604
1605                                 switch (stmt->kind)
1606                                 {
1607                                         case TRANS_STMT_BEGIN:
1608                                                 tag = "BEGIN";
1609                                                 break;
1610
1611                                         case TRANS_STMT_START:
1612                                                 tag = "START TRANSACTION";
1613                                                 break;
1614
1615                                         case TRANS_STMT_COMMIT:
1616                                                 tag = "COMMIT";
1617                                                 break;
1618
1619                                         case TRANS_STMT_ROLLBACK:
1620                                         case TRANS_STMT_ROLLBACK_TO:
1621                                                 tag = "ROLLBACK";
1622                                                 break;
1623
1624                                         case TRANS_STMT_SAVEPOINT:
1625                                                 tag = "SAVEPOINT";
1626                                                 break;
1627
1628                                         case TRANS_STMT_RELEASE:
1629                                                 tag = "RELEASE";
1630                                                 break;
1631
1632                                         case TRANS_STMT_PREPARE:
1633                                                 tag = "PREPARE TRANSACTION";
1634                                                 break;
1635
1636                                         case TRANS_STMT_COMMIT_PREPARED:
1637                                                 tag = "COMMIT PREPARED";
1638                                                 break;
1639
1640                                         case TRANS_STMT_ROLLBACK_PREPARED:
1641                                                 tag = "ROLLBACK PREPARED";
1642                                                 break;
1643
1644                                         default:
1645                                                 tag = "???";
1646                                                 break;
1647                                 }
1648                         }
1649                         break;
1650
1651                 case T_DeclareCursorStmt:
1652                         tag = "DECLARE CURSOR";
1653                         break;
1654
1655                 case T_ClosePortalStmt:
1656                         {
1657                                 ClosePortalStmt *stmt = (ClosePortalStmt *) parsetree;
1658
1659                                 if (stmt->portalname == NULL)
1660                                         tag = "CLOSE CURSOR ALL";
1661                                 else
1662                                         tag = "CLOSE CURSOR";
1663                         }
1664                         break;
1665
1666                 case T_FetchStmt:
1667                         {
1668                                 FetchStmt  *stmt = (FetchStmt *) parsetree;
1669
1670                                 tag = (stmt->ismove) ? "MOVE" : "FETCH";
1671                         }
1672                         break;
1673
1674                 case T_CreateDomainStmt:
1675                         tag = "CREATE DOMAIN";
1676                         break;
1677
1678                 case T_CreateSchemaStmt:
1679                         tag = "CREATE SCHEMA";
1680                         break;
1681
1682                 case T_CreateStmt:
1683                         tag = "CREATE TABLE";
1684                         break;
1685
1686                 case T_CreateTableSpaceStmt:
1687                         tag = "CREATE TABLESPACE";
1688                         break;
1689
1690                 case T_DropTableSpaceStmt:
1691                         tag = "DROP TABLESPACE";
1692                         break;
1693
1694                 case T_AlterTableSpaceOptionsStmt:
1695                         tag = "ALTER TABLESPACE";
1696                         break;
1697
1698                 case T_CreateExtensionStmt:
1699                         tag = "CREATE EXTENSION";
1700                         break;
1701
1702                 case T_AlterExtensionStmt:
1703                         tag = "ALTER EXTENSION";
1704                         break;
1705
1706                 case T_AlterExtensionContentsStmt:
1707                         tag = "ALTER EXTENSION";
1708                         break;
1709
1710                 case T_CreateFdwStmt:
1711                         tag = "CREATE FOREIGN DATA WRAPPER";
1712                         break;
1713
1714                 case T_AlterFdwStmt:
1715                         tag = "ALTER FOREIGN DATA WRAPPER";
1716                         break;
1717
1718                 case T_DropFdwStmt:
1719                         tag = "DROP FOREIGN DATA WRAPPER";
1720                         break;
1721
1722                 case T_CreateForeignServerStmt:
1723                         tag = "CREATE SERVER";
1724                         break;
1725
1726                 case T_AlterForeignServerStmt:
1727                         tag = "ALTER SERVER";
1728                         break;
1729
1730                 case T_DropForeignServerStmt:
1731                         tag = "DROP SERVER";
1732                         break;
1733
1734                 case T_CreateUserMappingStmt:
1735                         tag = "CREATE USER MAPPING";
1736                         break;
1737
1738                 case T_AlterUserMappingStmt:
1739                         tag = "ALTER USER MAPPING";
1740                         break;
1741
1742                 case T_DropUserMappingStmt:
1743                         tag = "DROP USER MAPPING";
1744                         break;
1745
1746                 case T_CreateForeignTableStmt:
1747                         tag = "CREATE FOREIGN TABLE";
1748                         break;
1749
1750                 case T_DropStmt:
1751                         switch (((DropStmt *) parsetree)->removeType)
1752                         {
1753                                 case OBJECT_TABLE:
1754                                         tag = "DROP TABLE";
1755                                         break;
1756                                 case OBJECT_SEQUENCE:
1757                                         tag = "DROP SEQUENCE";
1758                                         break;
1759                                 case OBJECT_VIEW:
1760                                         tag = "DROP VIEW";
1761                                         break;
1762                                 case OBJECT_INDEX:
1763                                         tag = "DROP INDEX";
1764                                         break;
1765                                 case OBJECT_TYPE:
1766                                         tag = "DROP TYPE";
1767                                         break;
1768                                 case OBJECT_DOMAIN:
1769                                         tag = "DROP DOMAIN";
1770                                         break;
1771                                 case OBJECT_COLLATION:
1772                                         tag = "DROP COLLATION";
1773                                         break;
1774                                 case OBJECT_CONVERSION:
1775                                         tag = "DROP CONVERSION";
1776                                         break;
1777                                 case OBJECT_SCHEMA:
1778                                         tag = "DROP SCHEMA";
1779                                         break;
1780                                 case OBJECT_TSPARSER:
1781                                         tag = "DROP TEXT SEARCH PARSER";
1782                                         break;
1783                                 case OBJECT_TSDICTIONARY:
1784                                         tag = "DROP TEXT SEARCH DICTIONARY";
1785                                         break;
1786                                 case OBJECT_TSTEMPLATE:
1787                                         tag = "DROP TEXT SEARCH TEMPLATE";
1788                                         break;
1789                                 case OBJECT_TSCONFIGURATION:
1790                                         tag = "DROP TEXT SEARCH CONFIGURATION";
1791                                         break;
1792                                 case OBJECT_FOREIGN_TABLE:
1793                                         tag = "DROP FOREIGN TABLE";
1794                                         break;
1795                                 case OBJECT_EXTENSION:
1796                                         tag = "DROP EXTENSION";
1797                                         break;
1798                                 default:
1799                                         tag = "???";
1800                         }
1801                         break;
1802
1803                 case T_TruncateStmt:
1804                         tag = "TRUNCATE TABLE";
1805                         break;
1806
1807                 case T_CommentStmt:
1808                         tag = "COMMENT";
1809                         break;
1810
1811                 case T_SecLabelStmt:
1812                         tag = "SECURITY LABEL";
1813                         break;
1814
1815                 case T_CopyStmt:
1816                         tag = "COPY";
1817                         break;
1818
1819                 case T_RenameStmt:
1820                         tag = AlterObjectTypeCommandTag(((RenameStmt *) parsetree)->renameType);
1821                         break;
1822
1823                 case T_AlterObjectSchemaStmt:
1824                         tag = AlterObjectTypeCommandTag(((AlterObjectSchemaStmt *) parsetree)->objectType);
1825                         break;
1826
1827                 case T_AlterOwnerStmt:
1828                         tag = AlterObjectTypeCommandTag(((AlterOwnerStmt *) parsetree)->objectType);
1829                         break;
1830
1831                 case T_AlterTableStmt:
1832                         tag = AlterObjectTypeCommandTag(((AlterTableStmt *) parsetree)->relkind);
1833                         break;
1834
1835                 case T_AlterDomainStmt:
1836                         tag = "ALTER DOMAIN";
1837                         break;
1838
1839                 case T_AlterFunctionStmt:
1840                         tag = "ALTER FUNCTION";
1841                         break;
1842
1843                 case T_GrantStmt:
1844                         {
1845                                 GrantStmt  *stmt = (GrantStmt *) parsetree;
1846
1847                                 tag = (stmt->is_grant) ? "GRANT" : "REVOKE";
1848                         }
1849                         break;
1850
1851                 case T_GrantRoleStmt:
1852                         {
1853                                 GrantRoleStmt *stmt = (GrantRoleStmt *) parsetree;
1854
1855                                 tag = (stmt->is_grant) ? "GRANT ROLE" : "REVOKE ROLE";
1856                         }
1857                         break;
1858
1859                 case T_AlterDefaultPrivilegesStmt:
1860                         tag = "ALTER DEFAULT PRIVILEGES";
1861                         break;
1862
1863                 case T_DefineStmt:
1864                         switch (((DefineStmt *) parsetree)->kind)
1865                         {
1866                                 case OBJECT_AGGREGATE:
1867                                         tag = "CREATE AGGREGATE";
1868                                         break;
1869                                 case OBJECT_OPERATOR:
1870                                         tag = "CREATE OPERATOR";
1871                                         break;
1872                                 case OBJECT_TYPE:
1873                                         tag = "CREATE TYPE";
1874                                         break;
1875                                 case OBJECT_TSPARSER:
1876                                         tag = "CREATE TEXT SEARCH PARSER";
1877                                         break;
1878                                 case OBJECT_TSDICTIONARY:
1879                                         tag = "CREATE TEXT SEARCH DICTIONARY";
1880                                         break;
1881                                 case OBJECT_TSTEMPLATE:
1882                                         tag = "CREATE TEXT SEARCH TEMPLATE";
1883                                         break;
1884                                 case OBJECT_TSCONFIGURATION:
1885                                         tag = "CREATE TEXT SEARCH CONFIGURATION";
1886                                         break;
1887                                 case OBJECT_COLLATION:
1888                                         tag = "CREATE COLLATION";
1889                                         break;
1890                                 default:
1891                                         tag = "???";
1892                         }
1893                         break;
1894
1895                 case T_CompositeTypeStmt:
1896                         tag = "CREATE TYPE";
1897                         break;
1898
1899                 case T_CreateEnumStmt:
1900                         tag = "CREATE TYPE";
1901                         break;
1902
1903                 case T_AlterEnumStmt:
1904                         tag = "ALTER TYPE";
1905                         break;
1906
1907                 case T_ViewStmt:
1908                         tag = "CREATE VIEW";
1909                         break;
1910
1911                 case T_CreateFunctionStmt:
1912                         tag = "CREATE FUNCTION";
1913                         break;
1914
1915                 case T_IndexStmt:
1916                         tag = "CREATE INDEX";
1917                         break;
1918
1919                 case T_RuleStmt:
1920                         tag = "CREATE RULE";
1921                         break;
1922
1923                 case T_CreateSeqStmt:
1924                         tag = "CREATE SEQUENCE";
1925                         break;
1926
1927                 case T_AlterSeqStmt:
1928                         tag = "ALTER SEQUENCE";
1929                         break;
1930
1931                 case T_RemoveFuncStmt:
1932                         switch (((RemoveFuncStmt *) parsetree)->kind)
1933                         {
1934                                 case OBJECT_FUNCTION:
1935                                         tag = "DROP FUNCTION";
1936                                         break;
1937                                 case OBJECT_AGGREGATE:
1938                                         tag = "DROP AGGREGATE";
1939                                         break;
1940                                 case OBJECT_OPERATOR:
1941                                         tag = "DROP OPERATOR";
1942                                         break;
1943                                 default:
1944                                         tag = "???";
1945                         }
1946                         break;
1947
1948                 case T_DoStmt:
1949                         tag = "DO";
1950                         break;
1951
1952                 case T_CreatedbStmt:
1953                         tag = "CREATE DATABASE";
1954                         break;
1955
1956                 case T_AlterDatabaseStmt:
1957                         tag = "ALTER DATABASE";
1958                         break;
1959
1960                 case T_AlterDatabaseSetStmt:
1961                         tag = "ALTER DATABASE";
1962                         break;
1963
1964                 case T_DropdbStmt:
1965                         tag = "DROP DATABASE";
1966                         break;
1967
1968                 case T_NotifyStmt:
1969                         tag = "NOTIFY";
1970                         break;
1971
1972                 case T_ListenStmt:
1973                         tag = "LISTEN";
1974                         break;
1975
1976                 case T_UnlistenStmt:
1977                         tag = "UNLISTEN";
1978                         break;
1979
1980                 case T_LoadStmt:
1981                         tag = "LOAD";
1982                         break;
1983
1984                 case T_ClusterStmt:
1985                         tag = "CLUSTER";
1986                         break;
1987
1988                 case T_VacuumStmt:
1989                         if (((VacuumStmt *) parsetree)->options & VACOPT_VACUUM)
1990                                 tag = "VACUUM";
1991                         else
1992                                 tag = "ANALYZE";
1993                         break;
1994
1995                 case T_ExplainStmt:
1996                         tag = "EXPLAIN";
1997                         break;
1998
1999                 case T_VariableSetStmt:
2000                         switch (((VariableSetStmt *) parsetree)->kind)
2001                         {
2002                                 case VAR_SET_VALUE:
2003                                 case VAR_SET_CURRENT:
2004                                 case VAR_SET_DEFAULT:
2005                                 case VAR_SET_MULTI:
2006                                         tag = "SET";
2007                                         break;
2008                                 case VAR_RESET:
2009                                 case VAR_RESET_ALL:
2010                                         tag = "RESET";
2011                                         break;
2012                                 default:
2013                                         tag = "???";
2014                         }
2015                         break;
2016
2017                 case T_VariableShowStmt:
2018                         tag = "SHOW";
2019                         break;
2020
2021                 case T_DiscardStmt:
2022                         switch (((DiscardStmt *) parsetree)->target)
2023                         {
2024                                 case DISCARD_ALL:
2025                                         tag = "DISCARD ALL";
2026                                         break;
2027                                 case DISCARD_PLANS:
2028                                         tag = "DISCARD PLANS";
2029                                         break;
2030                                 case DISCARD_TEMP:
2031                                         tag = "DISCARD TEMP";
2032                                         break;
2033                                 default:
2034                                         tag = "???";
2035                         }
2036                         break;
2037
2038                 case T_CreateTrigStmt:
2039                         tag = "CREATE TRIGGER";
2040                         break;
2041
2042                 case T_DropPropertyStmt:
2043                         switch (((DropPropertyStmt *) parsetree)->removeType)
2044                         {
2045                                 case OBJECT_TRIGGER:
2046                                         tag = "DROP TRIGGER";
2047                                         break;
2048                                 case OBJECT_RULE:
2049                                         tag = "DROP RULE";
2050                                         break;
2051                                 default:
2052                                         tag = "???";
2053                         }
2054                         break;
2055
2056                 case T_CreatePLangStmt:
2057                         tag = "CREATE LANGUAGE";
2058                         break;
2059
2060                 case T_DropPLangStmt:
2061                         tag = "DROP LANGUAGE";
2062                         break;
2063
2064                 case T_CreateRoleStmt:
2065                         tag = "CREATE ROLE";
2066                         break;
2067
2068                 case T_AlterRoleStmt:
2069                         tag = "ALTER ROLE";
2070                         break;
2071
2072                 case T_AlterRoleSetStmt:
2073                         tag = "ALTER ROLE";
2074                         break;
2075
2076                 case T_DropRoleStmt:
2077                         tag = "DROP ROLE";
2078                         break;
2079
2080                 case T_DropOwnedStmt:
2081                         tag = "DROP OWNED";
2082                         break;
2083
2084                 case T_ReassignOwnedStmt:
2085                         tag = "REASSIGN OWNED";
2086                         break;
2087
2088                 case T_LockStmt:
2089                         tag = "LOCK TABLE";
2090                         break;
2091
2092                 case T_ConstraintsSetStmt:
2093                         tag = "SET CONSTRAINTS";
2094                         break;
2095
2096                 case T_CheckPointStmt:
2097                         tag = "CHECKPOINT";
2098                         break;
2099
2100                 case T_ReindexStmt:
2101                         tag = "REINDEX";
2102                         break;
2103
2104                 case T_CreateConversionStmt:
2105                         tag = "CREATE CONVERSION";
2106                         break;
2107
2108                 case T_CreateCastStmt:
2109                         tag = "CREATE CAST";
2110                         break;
2111
2112                 case T_DropCastStmt:
2113                         tag = "DROP CAST";
2114                         break;
2115
2116                 case T_CreateOpClassStmt:
2117                         tag = "CREATE OPERATOR CLASS";
2118                         break;
2119
2120                 case T_CreateOpFamilyStmt:
2121                         tag = "CREATE OPERATOR FAMILY";
2122                         break;
2123
2124                 case T_AlterOpFamilyStmt:
2125                         tag = "ALTER OPERATOR FAMILY";
2126                         break;
2127
2128                 case T_RemoveOpClassStmt:
2129                         tag = "DROP OPERATOR CLASS";
2130                         break;
2131
2132                 case T_RemoveOpFamilyStmt:
2133                         tag = "DROP OPERATOR FAMILY";
2134                         break;
2135
2136                 case T_AlterTSDictionaryStmt:
2137                         tag = "ALTER TEXT SEARCH DICTIONARY";
2138                         break;
2139
2140                 case T_AlterTSConfigurationStmt:
2141                         tag = "ALTER TEXT SEARCH CONFIGURATION";
2142                         break;
2143
2144                 case T_PrepareStmt:
2145                         tag = "PREPARE";
2146                         break;
2147
2148                 case T_ExecuteStmt:
2149                         tag = "EXECUTE";
2150                         break;
2151
2152                 case T_DeallocateStmt:
2153                         {
2154                                 DeallocateStmt *stmt = (DeallocateStmt *) parsetree;
2155
2156                                 if (stmt->name == NULL)
2157                                         tag = "DEALLOCATE ALL";
2158                                 else
2159                                         tag = "DEALLOCATE";
2160                         }
2161                         break;
2162
2163                         /* already-planned queries */
2164                 case T_PlannedStmt:
2165                         {
2166                                 PlannedStmt *stmt = (PlannedStmt *) parsetree;
2167
2168                                 switch (stmt->commandType)
2169                                 {
2170                                         case CMD_SELECT:
2171
2172                                                 /*
2173                                                  * We take a little extra care here so that the result
2174                                                  * will be useful for complaints about read-only
2175                                                  * statements
2176                                                  */
2177                                                 if (stmt->utilityStmt != NULL)
2178                                                 {
2179                                                         Assert(IsA(stmt->utilityStmt, DeclareCursorStmt));
2180                                                         tag = "DECLARE CURSOR";
2181                                                 }
2182                                                 else if (stmt->intoClause != NULL)
2183                                                         tag = "SELECT INTO";
2184                                                 else if (stmt->rowMarks != NIL)
2185                                                 {
2186                                                         /* not 100% but probably close enough */
2187                                                         if (((PlanRowMark *) linitial(stmt->rowMarks))->markType == ROW_MARK_EXCLUSIVE)
2188                                                                 tag = "SELECT FOR UPDATE";
2189                                                         else
2190                                                                 tag = "SELECT FOR SHARE";
2191                                                 }
2192                                                 else
2193                                                         tag = "SELECT";
2194                                                 break;
2195                                         case CMD_UPDATE:
2196                                                 tag = "UPDATE";
2197                                                 break;
2198                                         case CMD_INSERT:
2199                                                 tag = "INSERT";
2200                                                 break;
2201                                         case CMD_DELETE:
2202                                                 tag = "DELETE";
2203                                                 break;
2204                                         default:
2205                                                 elog(WARNING, "unrecognized commandType: %d",
2206                                                          (int) stmt->commandType);
2207                                                 tag = "???";
2208                                                 break;
2209                                 }
2210                         }
2211                         break;
2212
2213                         /* parsed-and-rewritten-but-not-planned queries */
2214                 case T_Query:
2215                         {
2216                                 Query      *stmt = (Query *) parsetree;
2217
2218                                 switch (stmt->commandType)
2219                                 {
2220                                         case CMD_SELECT:
2221
2222                                                 /*
2223                                                  * We take a little extra care here so that the result
2224                                                  * will be useful for complaints about read-only
2225                                                  * statements
2226                                                  */
2227                                                 if (stmt->utilityStmt != NULL)
2228                                                 {
2229                                                         Assert(IsA(stmt->utilityStmt, DeclareCursorStmt));
2230                                                         tag = "DECLARE CURSOR";
2231                                                 }
2232                                                 else if (stmt->intoClause != NULL)
2233                                                         tag = "SELECT INTO";
2234                                                 else if (stmt->rowMarks != NIL)
2235                                                 {
2236                                                         /* not 100% but probably close enough */
2237                                                         if (((RowMarkClause *) linitial(stmt->rowMarks))->forUpdate)
2238                                                                 tag = "SELECT FOR UPDATE";
2239                                                         else
2240                                                                 tag = "SELECT FOR SHARE";
2241                                                 }
2242                                                 else
2243                                                         tag = "SELECT";
2244                                                 break;
2245                                         case CMD_UPDATE:
2246                                                 tag = "UPDATE";
2247                                                 break;
2248                                         case CMD_INSERT:
2249                                                 tag = "INSERT";
2250                                                 break;
2251                                         case CMD_DELETE:
2252                                                 tag = "DELETE";
2253                                                 break;
2254                                         case CMD_UTILITY:
2255                                                 tag = CreateCommandTag(stmt->utilityStmt);
2256                                                 break;
2257                                         default:
2258                                                 elog(WARNING, "unrecognized commandType: %d",
2259                                                          (int) stmt->commandType);
2260                                                 tag = "???";
2261                                                 break;
2262                                 }
2263                         }
2264                         break;
2265
2266                 default:
2267                         elog(WARNING, "unrecognized node type: %d",
2268                                  (int) nodeTag(parsetree));
2269                         tag = "???";
2270                         break;
2271         }
2272
2273         return tag;
2274 }
2275
2276
2277 /*
2278  * GetCommandLogLevel
2279  *              utility to get the minimum log_statement level for a command,
2280  *              given either a raw (un-analyzed) parsetree or a planned query.
2281  *
2282  * This must handle all command types, but since the vast majority
2283  * of 'em are utility commands, it seems sensible to keep it here.
2284  */
2285 LogStmtLevel
2286 GetCommandLogLevel(Node *parsetree)
2287 {
2288         LogStmtLevel lev;
2289
2290         switch (nodeTag(parsetree))
2291         {
2292                         /* raw plannable queries */
2293                 case T_InsertStmt:
2294                 case T_DeleteStmt:
2295                 case T_UpdateStmt:
2296                         lev = LOGSTMT_MOD;
2297                         break;
2298
2299                 case T_SelectStmt:
2300                         if (((SelectStmt *) parsetree)->intoClause)
2301                                 lev = LOGSTMT_DDL;              /* CREATE AS, SELECT INTO */
2302                         else
2303                                 lev = LOGSTMT_ALL;
2304                         break;
2305
2306                         /* utility statements --- same whether raw or cooked */
2307                 case T_TransactionStmt:
2308                         lev = LOGSTMT_ALL;
2309                         break;
2310
2311                 case T_DeclareCursorStmt:
2312                         lev = LOGSTMT_ALL;
2313                         break;
2314
2315                 case T_ClosePortalStmt:
2316                         lev = LOGSTMT_ALL;
2317                         break;
2318
2319                 case T_FetchStmt:
2320                         lev = LOGSTMT_ALL;
2321                         break;
2322
2323                 case T_CreateSchemaStmt:
2324                         lev = LOGSTMT_DDL;
2325                         break;
2326
2327                 case T_CreateStmt:
2328                 case T_CreateForeignTableStmt:
2329                         lev = LOGSTMT_DDL;
2330                         break;
2331
2332                 case T_CreateTableSpaceStmt:
2333                 case T_DropTableSpaceStmt:
2334                 case T_AlterTableSpaceOptionsStmt:
2335                         lev = LOGSTMT_DDL;
2336                         break;
2337
2338                 case T_CreateExtensionStmt:
2339                 case T_AlterExtensionStmt:
2340                 case T_AlterExtensionContentsStmt:
2341                         lev = LOGSTMT_DDL;
2342                         break;
2343
2344                 case T_CreateFdwStmt:
2345                 case T_AlterFdwStmt:
2346                 case T_DropFdwStmt:
2347                 case T_CreateForeignServerStmt:
2348                 case T_AlterForeignServerStmt:
2349                 case T_DropForeignServerStmt:
2350                 case T_CreateUserMappingStmt:
2351                 case T_AlterUserMappingStmt:
2352                 case T_DropUserMappingStmt:
2353                         lev = LOGSTMT_DDL;
2354                         break;
2355
2356                 case T_DropStmt:
2357                         lev = LOGSTMT_DDL;
2358                         break;
2359
2360                 case T_TruncateStmt:
2361                         lev = LOGSTMT_MOD;
2362                         break;
2363
2364                 case T_CommentStmt:
2365                         lev = LOGSTMT_DDL;
2366                         break;
2367
2368                 case T_SecLabelStmt:
2369                         lev = LOGSTMT_DDL;
2370                         break;
2371
2372                 case T_CopyStmt:
2373                         if (((CopyStmt *) parsetree)->is_from)
2374                                 lev = LOGSTMT_MOD;
2375                         else
2376                                 lev = LOGSTMT_ALL;
2377                         break;
2378
2379                 case T_PrepareStmt:
2380                         {
2381                                 PrepareStmt *stmt = (PrepareStmt *) parsetree;
2382
2383                                 /* Look through a PREPARE to the contained stmt */
2384                                 lev = GetCommandLogLevel(stmt->query);
2385                         }
2386                         break;
2387
2388                 case T_ExecuteStmt:
2389                         {
2390                                 ExecuteStmt *stmt = (ExecuteStmt *) parsetree;
2391                                 PreparedStatement *ps;
2392
2393                                 /* Look through an EXECUTE to the referenced stmt */
2394                                 ps = FetchPreparedStatement(stmt->name, false);
2395                                 if (ps)
2396                                         lev = GetCommandLogLevel(ps->plansource->raw_parse_tree);
2397                                 else
2398                                         lev = LOGSTMT_ALL;
2399                         }
2400                         break;
2401
2402                 case T_DeallocateStmt:
2403                         lev = LOGSTMT_ALL;
2404                         break;
2405
2406                 case T_RenameStmt:
2407                         lev = LOGSTMT_DDL;
2408                         break;
2409
2410                 case T_AlterObjectSchemaStmt:
2411                         lev = LOGSTMT_DDL;
2412                         break;
2413
2414                 case T_AlterOwnerStmt:
2415                         lev = LOGSTMT_DDL;
2416                         break;
2417
2418                 case T_AlterTableStmt:
2419                         lev = LOGSTMT_DDL;
2420                         break;
2421
2422                 case T_AlterDomainStmt:
2423                         lev = LOGSTMT_DDL;
2424                         break;
2425
2426                 case T_GrantStmt:
2427                         lev = LOGSTMT_DDL;
2428                         break;
2429
2430                 case T_GrantRoleStmt:
2431                         lev = LOGSTMT_DDL;
2432                         break;
2433
2434                 case T_AlterDefaultPrivilegesStmt:
2435                         lev = LOGSTMT_DDL;
2436                         break;
2437
2438                 case T_DefineStmt:
2439                         lev = LOGSTMT_DDL;
2440                         break;
2441
2442                 case T_CompositeTypeStmt:
2443                         lev = LOGSTMT_DDL;
2444                         break;
2445
2446                 case T_CreateEnumStmt:
2447                         lev = LOGSTMT_DDL;
2448                         break;
2449
2450                 case T_AlterEnumStmt:
2451                         lev = LOGSTMT_DDL;
2452                         break;
2453
2454                 case T_ViewStmt:
2455                         lev = LOGSTMT_DDL;
2456                         break;
2457
2458                 case T_CreateFunctionStmt:
2459                         lev = LOGSTMT_DDL;
2460                         break;
2461
2462                 case T_AlterFunctionStmt:
2463                         lev = LOGSTMT_DDL;
2464                         break;
2465
2466                 case T_IndexStmt:
2467                         lev = LOGSTMT_DDL;
2468                         break;
2469
2470                 case T_RuleStmt:
2471                         lev = LOGSTMT_DDL;
2472                         break;
2473
2474                 case T_CreateSeqStmt:
2475                         lev = LOGSTMT_DDL;
2476                         break;
2477
2478                 case T_AlterSeqStmt:
2479                         lev = LOGSTMT_DDL;
2480                         break;
2481
2482                 case T_RemoveFuncStmt:
2483                         lev = LOGSTMT_DDL;
2484                         break;
2485
2486                 case T_DoStmt:
2487                         lev = LOGSTMT_ALL;
2488                         break;
2489
2490                 case T_CreatedbStmt:
2491                         lev = LOGSTMT_DDL;
2492                         break;
2493
2494                 case T_AlterDatabaseStmt:
2495                         lev = LOGSTMT_DDL;
2496                         break;
2497
2498                 case T_AlterDatabaseSetStmt:
2499                         lev = LOGSTMT_DDL;
2500                         break;
2501
2502                 case T_DropdbStmt:
2503                         lev = LOGSTMT_DDL;
2504                         break;
2505
2506                 case T_NotifyStmt:
2507                         lev = LOGSTMT_ALL;
2508                         break;
2509
2510                 case T_ListenStmt:
2511                         lev = LOGSTMT_ALL;
2512                         break;
2513
2514                 case T_UnlistenStmt:
2515                         lev = LOGSTMT_ALL;
2516                         break;
2517
2518                 case T_LoadStmt:
2519                         lev = LOGSTMT_ALL;
2520                         break;
2521
2522                 case T_ClusterStmt:
2523                         lev = LOGSTMT_DDL;
2524                         break;
2525
2526                 case T_VacuumStmt:
2527                         lev = LOGSTMT_ALL;
2528                         break;
2529
2530                 case T_ExplainStmt:
2531                         {
2532                                 ExplainStmt *stmt = (ExplainStmt *) parsetree;
2533                                 bool            analyze = false;
2534                                 ListCell   *lc;
2535
2536                                 /* Look through an EXPLAIN ANALYZE to the contained stmt */
2537                                 foreach(lc, stmt->options)
2538                                 {
2539                                         DefElem    *opt = (DefElem *) lfirst(lc);
2540
2541                                         if (strcmp(opt->defname, "analyze") == 0)
2542                                                 analyze = defGetBoolean(opt);
2543                                         /* don't "break", as explain.c will use the last value */
2544                                 }
2545                                 if (analyze)
2546                                         return GetCommandLogLevel(stmt->query);
2547
2548                                 /* Plain EXPLAIN isn't so interesting */
2549                                 lev = LOGSTMT_ALL;
2550                         }
2551                         break;
2552
2553                 case T_VariableSetStmt:
2554                         lev = LOGSTMT_ALL;
2555                         break;
2556
2557                 case T_VariableShowStmt:
2558                         lev = LOGSTMT_ALL;
2559                         break;
2560
2561                 case T_DiscardStmt:
2562                         lev = LOGSTMT_ALL;
2563                         break;
2564
2565                 case T_CreateTrigStmt:
2566                         lev = LOGSTMT_DDL;
2567                         break;
2568
2569                 case T_DropPropertyStmt:
2570                         lev = LOGSTMT_DDL;
2571                         break;
2572
2573                 case T_CreatePLangStmt:
2574                         lev = LOGSTMT_DDL;
2575                         break;
2576
2577                 case T_DropPLangStmt:
2578                         lev = LOGSTMT_DDL;
2579                         break;
2580
2581                 case T_CreateDomainStmt:
2582                         lev = LOGSTMT_DDL;
2583                         break;
2584
2585                 case T_CreateRoleStmt:
2586                         lev = LOGSTMT_DDL;
2587                         break;
2588
2589                 case T_AlterRoleStmt:
2590                         lev = LOGSTMT_DDL;
2591                         break;
2592
2593                 case T_AlterRoleSetStmt:
2594                         lev = LOGSTMT_DDL;
2595                         break;
2596
2597                 case T_DropRoleStmt:
2598                         lev = LOGSTMT_DDL;
2599                         break;
2600
2601                 case T_DropOwnedStmt:
2602                         lev = LOGSTMT_DDL;
2603                         break;
2604
2605                 case T_ReassignOwnedStmt:
2606                         lev = LOGSTMT_DDL;
2607                         break;
2608
2609                 case T_LockStmt:
2610                         lev = LOGSTMT_ALL;
2611                         break;
2612
2613                 case T_ConstraintsSetStmt:
2614                         lev = LOGSTMT_ALL;
2615                         break;
2616
2617                 case T_CheckPointStmt:
2618                         lev = LOGSTMT_ALL;
2619                         break;
2620
2621                 case T_ReindexStmt:
2622                         lev = LOGSTMT_ALL;      /* should this be DDL? */
2623                         break;
2624
2625                 case T_CreateConversionStmt:
2626                         lev = LOGSTMT_DDL;
2627                         break;
2628
2629                 case T_CreateCastStmt:
2630                         lev = LOGSTMT_DDL;
2631                         break;
2632
2633                 case T_DropCastStmt:
2634                         lev = LOGSTMT_DDL;
2635                         break;
2636
2637                 case T_CreateOpClassStmt:
2638                         lev = LOGSTMT_DDL;
2639                         break;
2640
2641                 case T_CreateOpFamilyStmt:
2642                         lev = LOGSTMT_DDL;
2643                         break;
2644
2645                 case T_AlterOpFamilyStmt:
2646                         lev = LOGSTMT_DDL;
2647                         break;
2648
2649                 case T_RemoveOpClassStmt:
2650                         lev = LOGSTMT_DDL;
2651                         break;
2652
2653                 case T_RemoveOpFamilyStmt:
2654                         lev = LOGSTMT_DDL;
2655                         break;
2656
2657                 case T_AlterTSDictionaryStmt:
2658                         lev = LOGSTMT_DDL;
2659                         break;
2660
2661                 case T_AlterTSConfigurationStmt:
2662                         lev = LOGSTMT_DDL;
2663                         break;
2664
2665                         /* already-planned queries */
2666                 case T_PlannedStmt:
2667                         {
2668                                 PlannedStmt *stmt = (PlannedStmt *) parsetree;
2669
2670                                 switch (stmt->commandType)
2671                                 {
2672                                         case CMD_SELECT:
2673                                                 if (stmt->intoClause != NULL)
2674                                                         lev = LOGSTMT_DDL;      /* CREATE AS, SELECT INTO */
2675                                                 else
2676                                                         lev = LOGSTMT_ALL;      /* SELECT or DECLARE CURSOR */
2677                                                 break;
2678
2679                                         case CMD_UPDATE:
2680                                         case CMD_INSERT:
2681                                         case CMD_DELETE:
2682                                                 lev = LOGSTMT_MOD;
2683                                                 break;
2684
2685                                         default:
2686                                                 elog(WARNING, "unrecognized commandType: %d",
2687                                                          (int) stmt->commandType);
2688                                                 lev = LOGSTMT_ALL;
2689                                                 break;
2690                                 }
2691                         }
2692                         break;
2693
2694                         /* parsed-and-rewritten-but-not-planned queries */
2695                 case T_Query:
2696                         {
2697                                 Query      *stmt = (Query *) parsetree;
2698
2699                                 switch (stmt->commandType)
2700                                 {
2701                                         case CMD_SELECT:
2702                                                 if (stmt->intoClause != NULL)
2703                                                         lev = LOGSTMT_DDL;      /* CREATE AS, SELECT INTO */
2704                                                 else
2705                                                         lev = LOGSTMT_ALL;      /* SELECT or DECLARE CURSOR */
2706                                                 break;
2707
2708                                         case CMD_UPDATE:
2709                                         case CMD_INSERT:
2710                                         case CMD_DELETE:
2711                                                 lev = LOGSTMT_MOD;
2712                                                 break;
2713
2714                                         case CMD_UTILITY:
2715                                                 lev = GetCommandLogLevel(stmt->utilityStmt);
2716                                                 break;
2717
2718                                         default:
2719                                                 elog(WARNING, "unrecognized commandType: %d",
2720                                                          (int) stmt->commandType);
2721                                                 lev = LOGSTMT_ALL;
2722                                                 break;
2723                                 }
2724
2725                         }
2726                         break;
2727
2728                 default:
2729                         elog(WARNING, "unrecognized node type: %d",
2730                                  (int) nodeTag(parsetree));
2731                         lev = LOGSTMT_ALL;
2732                         break;
2733         }
2734
2735         return lev;
2736 }