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