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