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