OSDN Git Service

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