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