Header And Logo

PostgreSQL
| The world's most advanced open source database.

utility.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * utility.c
00004  *    Contains functions which control the execution of the POSTGRES utility
00005  *    commands.  At one time acted as an interface between the Lisp and C
00006  *    systems.
00007  *
00008  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00009  * Portions Copyright (c) 1994, Regents of the University of California
00010  *
00011  *
00012  * IDENTIFICATION
00013  *    src/backend/tcop/utility.c
00014  *
00015  *-------------------------------------------------------------------------
00016  */
00017 #include "postgres.h"
00018 
00019 #include "access/htup_details.h"
00020 #include "access/reloptions.h"
00021 #include "access/twophase.h"
00022 #include "access/xact.h"
00023 #include "catalog/catalog.h"
00024 #include "catalog/namespace.h"
00025 #include "catalog/toasting.h"
00026 #include "commands/alter.h"
00027 #include "commands/async.h"
00028 #include "commands/cluster.h"
00029 #include "commands/comment.h"
00030 #include "commands/collationcmds.h"
00031 #include "commands/conversioncmds.h"
00032 #include "commands/copy.h"
00033 #include "commands/createas.h"
00034 #include "commands/dbcommands.h"
00035 #include "commands/defrem.h"
00036 #include "commands/discard.h"
00037 #include "commands/event_trigger.h"
00038 #include "commands/explain.h"
00039 #include "commands/extension.h"
00040 #include "commands/matview.h"
00041 #include "commands/lockcmds.h"
00042 #include "commands/portalcmds.h"
00043 #include "commands/prepare.h"
00044 #include "commands/proclang.h"
00045 #include "commands/schemacmds.h"
00046 #include "commands/seclabel.h"
00047 #include "commands/sequence.h"
00048 #include "commands/tablecmds.h"
00049 #include "commands/tablespace.h"
00050 #include "commands/trigger.h"
00051 #include "commands/typecmds.h"
00052 #include "commands/user.h"
00053 #include "commands/vacuum.h"
00054 #include "commands/view.h"
00055 #include "miscadmin.h"
00056 #include "parser/parse_utilcmd.h"
00057 #include "postmaster/bgwriter.h"
00058 #include "rewrite/rewriteDefine.h"
00059 #include "rewrite/rewriteRemove.h"
00060 #include "storage/fd.h"
00061 #include "tcop/pquery.h"
00062 #include "tcop/utility.h"
00063 #include "utils/acl.h"
00064 #include "utils/guc.h"
00065 #include "utils/syscache.h"
00066 
00067 
00068 /* Hook for plugins to get control in ProcessUtility() */
00069 ProcessUtility_hook_type ProcessUtility_hook = NULL;
00070 
00071 /* local function declarations */
00072 static void ProcessUtilitySlow(Node *parsetree,
00073                    const char *queryString,
00074                    ProcessUtilityContext context,
00075                    ParamListInfo params,
00076                    DestReceiver *dest,
00077                    char *completionTag);
00078 static void ExecDropStmt(DropStmt *stmt, bool isTopLevel);
00079 
00080 
00081 /*
00082  * Verify user has ownership of specified relation, else ereport.
00083  *
00084  * If noCatalogs is true then we also deny access to system catalogs,
00085  * except when allowSystemTableMods is true.
00086  */
00087 void
00088 CheckRelationOwnership(RangeVar *rel, bool noCatalogs)
00089 {
00090     Oid         relOid;
00091     HeapTuple   tuple;
00092 
00093     /*
00094      * XXX: This is unsafe in the presence of concurrent DDL, since it is
00095      * called before acquiring any lock on the target relation.  However,
00096      * locking the target relation (especially using something like
00097      * AccessExclusiveLock) before verifying that the user has permissions is
00098      * not appealing either.
00099      */
00100     relOid = RangeVarGetRelid(rel, NoLock, false);
00101 
00102     tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
00103     if (!HeapTupleIsValid(tuple))       /* should not happen */
00104         elog(ERROR, "cache lookup failed for relation %u", relOid);
00105 
00106     if (!pg_class_ownercheck(relOid, GetUserId()))
00107         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
00108                        rel->relname);
00109 
00110     if (noCatalogs)
00111     {
00112         if (!allowSystemTableMods &&
00113             IsSystemClass((Form_pg_class) GETSTRUCT(tuple)))
00114             ereport(ERROR,
00115                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00116                      errmsg("permission denied: \"%s\" is a system catalog",
00117                             rel->relname)));
00118     }
00119 
00120     ReleaseSysCache(tuple);
00121 }
00122 
00123 
00124 /*
00125  * CommandIsReadOnly: is an executable query read-only?
00126  *
00127  * This is a much stricter test than we apply for XactReadOnly mode;
00128  * the query must be *in truth* read-only, because the caller wishes
00129  * not to do CommandCounterIncrement for it.
00130  *
00131  * Note: currently no need to support Query nodes here
00132  */
00133 bool
00134 CommandIsReadOnly(Node *parsetree)
00135 {
00136     if (IsA(parsetree, PlannedStmt))
00137     {
00138         PlannedStmt *stmt = (PlannedStmt *) parsetree;
00139 
00140         switch (stmt->commandType)
00141         {
00142             case CMD_SELECT:
00143                 if (stmt->rowMarks != NIL)
00144                     return false;       /* SELECT FOR [KEY] UPDATE/SHARE */
00145                 else if (stmt->hasModifyingCTE)
00146                     return false;       /* data-modifying CTE */
00147                 else
00148                     return true;
00149             case CMD_UPDATE:
00150             case CMD_INSERT:
00151             case CMD_DELETE:
00152                 return false;
00153             default:
00154                 elog(WARNING, "unrecognized commandType: %d",
00155                      (int) stmt->commandType);
00156                 break;
00157         }
00158     }
00159     /* For now, treat all utility commands as read/write */
00160     return false;
00161 }
00162 
00163 /*
00164  * check_xact_readonly: is a utility command read-only?
00165  *
00166  * Here we use the loose rules of XactReadOnly mode: no permanent effects
00167  * on the database are allowed.
00168  */
00169 static void
00170 check_xact_readonly(Node *parsetree)
00171 {
00172     if (!XactReadOnly)
00173         return;
00174 
00175     /*
00176      * Note: Commands that need to do more complicated checking are handled
00177      * elsewhere, in particular COPY and plannable statements do their own
00178      * checking.  However they should all call PreventCommandIfReadOnly to
00179      * actually throw the error.
00180      */
00181 
00182     switch (nodeTag(parsetree))
00183     {
00184         case T_AlterDatabaseStmt:
00185         case T_AlterDatabaseSetStmt:
00186         case T_AlterDomainStmt:
00187         case T_AlterFunctionStmt:
00188         case T_AlterRoleStmt:
00189         case T_AlterRoleSetStmt:
00190         case T_AlterObjectSchemaStmt:
00191         case T_AlterOwnerStmt:
00192         case T_AlterSeqStmt:
00193         case T_AlterTableStmt:
00194         case T_RenameStmt:
00195         case T_CommentStmt:
00196         case T_DefineStmt:
00197         case T_CreateCastStmt:
00198         case T_CreateEventTrigStmt:
00199         case T_AlterEventTrigStmt:
00200         case T_CreateConversionStmt:
00201         case T_CreatedbStmt:
00202         case T_CreateDomainStmt:
00203         case T_CreateFunctionStmt:
00204         case T_CreateRoleStmt:
00205         case T_IndexStmt:
00206         case T_CreatePLangStmt:
00207         case T_CreateOpClassStmt:
00208         case T_CreateOpFamilyStmt:
00209         case T_AlterOpFamilyStmt:
00210         case T_RuleStmt:
00211         case T_CreateSchemaStmt:
00212         case T_CreateSeqStmt:
00213         case T_CreateStmt:
00214         case T_CreateTableAsStmt:
00215         case T_RefreshMatViewStmt:
00216         case T_CreateTableSpaceStmt:
00217         case T_CreateTrigStmt:
00218         case T_CompositeTypeStmt:
00219         case T_CreateEnumStmt:
00220         case T_CreateRangeStmt:
00221         case T_AlterEnumStmt:
00222         case T_ViewStmt:
00223         case T_DropStmt:
00224         case T_DropdbStmt:
00225         case T_DropTableSpaceStmt:
00226         case T_DropRoleStmt:
00227         case T_GrantStmt:
00228         case T_GrantRoleStmt:
00229         case T_AlterDefaultPrivilegesStmt:
00230         case T_TruncateStmt:
00231         case T_DropOwnedStmt:
00232         case T_ReassignOwnedStmt:
00233         case T_AlterTSDictionaryStmt:
00234         case T_AlterTSConfigurationStmt:
00235         case T_CreateExtensionStmt:
00236         case T_AlterExtensionStmt:
00237         case T_AlterExtensionContentsStmt:
00238         case T_CreateFdwStmt:
00239         case T_AlterFdwStmt:
00240         case T_CreateForeignServerStmt:
00241         case T_AlterForeignServerStmt:
00242         case T_CreateUserMappingStmt:
00243         case T_AlterUserMappingStmt:
00244         case T_DropUserMappingStmt:
00245         case T_AlterTableSpaceOptionsStmt:
00246         case T_CreateForeignTableStmt:
00247         case T_SecLabelStmt:
00248             PreventCommandIfReadOnly(CreateCommandTag(parsetree));
00249             break;
00250         default:
00251             /* do nothing */
00252             break;
00253     }
00254 }
00255 
00256 /*
00257  * PreventCommandIfReadOnly: throw error if XactReadOnly
00258  *
00259  * This is useful mainly to ensure consistency of the error message wording;
00260  * most callers have checked XactReadOnly for themselves.
00261  */
00262 void
00263 PreventCommandIfReadOnly(const char *cmdname)
00264 {
00265     if (XactReadOnly)
00266         ereport(ERROR,
00267                 (errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),
00268         /* translator: %s is name of a SQL command, eg CREATE */
00269                  errmsg("cannot execute %s in a read-only transaction",
00270                         cmdname)));
00271 }
00272 
00273 /*
00274  * PreventCommandDuringRecovery: throw error if RecoveryInProgress
00275  *
00276  * The majority of operations that are unsafe in a Hot Standby slave
00277  * will be rejected by XactReadOnly tests.  However there are a few
00278  * commands that are allowed in "read-only" xacts but cannot be allowed
00279  * in Hot Standby mode.  Those commands should call this function.
00280  */
00281 void
00282 PreventCommandDuringRecovery(const char *cmdname)
00283 {
00284     if (RecoveryInProgress())
00285         ereport(ERROR,
00286                 (errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),
00287         /* translator: %s is name of a SQL command, eg CREATE */
00288                  errmsg("cannot execute %s during recovery",
00289                         cmdname)));
00290 }
00291 
00292 /*
00293  * CheckRestrictedOperation: throw error for hazardous command if we're
00294  * inside a security restriction context.
00295  *
00296  * This is needed to protect session-local state for which there is not any
00297  * better-defined protection mechanism, such as ownership.
00298  */
00299 static void
00300 CheckRestrictedOperation(const char *cmdname)
00301 {
00302     if (InSecurityRestrictedOperation())
00303         ereport(ERROR,
00304                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00305         /* translator: %s is name of a SQL command, eg PREPARE */
00306              errmsg("cannot execute %s within security-restricted operation",
00307                     cmdname)));
00308 }
00309 
00310 
00311 /*
00312  * ProcessUtility
00313  *      general utility function invoker
00314  *
00315  *  parsetree: the parse tree for the utility statement
00316  *  queryString: original source text of command
00317  *  context: identifies source of statement (toplevel client command,
00318  *      non-toplevel client command, subcommand of a larger utility command)
00319  *  params: parameters to use during execution
00320  *  dest: where to send results
00321  *  completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
00322  *      in which to store a command completion status string.
00323  *
00324  * Notes: as of PG 8.4, caller MUST supply a queryString; it is not
00325  * allowed anymore to pass NULL.  (If you really don't have source text,
00326  * you can pass a constant string, perhaps "(query not available)".)
00327  *
00328  * completionTag is only set nonempty if we want to return a nondefault status.
00329  *
00330  * completionTag may be NULL if caller doesn't want a status string.
00331  */
00332 void
00333 ProcessUtility(Node *parsetree,
00334                const char *queryString,
00335                ProcessUtilityContext context,
00336                ParamListInfo params,
00337                DestReceiver *dest,
00338                char *completionTag)
00339 {
00340     Assert(queryString != NULL);    /* required as of 8.4 */
00341 
00342     /*
00343      * We provide a function hook variable that lets loadable plugins get
00344      * control when ProcessUtility is called.  Such a plugin would normally
00345      * call standard_ProcessUtility().
00346      */
00347     if (ProcessUtility_hook)
00348         (*ProcessUtility_hook) (parsetree, queryString,
00349                                 context, params,
00350                                 dest, completionTag);
00351     else
00352         standard_ProcessUtility(parsetree, queryString,
00353                                 context, params,
00354                                 dest, completionTag);
00355 }
00356 
00357 /*
00358  * standard_ProcessUtility itself deals only with utility commands for
00359  * which we do not provide event trigger support.  Commands that do have
00360  * such support are passed down to ProcessUtilitySlow, which contains the
00361  * necessary infrastructure for such triggers.
00362  *
00363  * This division is not just for performance: it's critical that the
00364  * event trigger code not be invoked when doing START TRANSACTION for
00365  * example, because we might need to refresh the event trigger cache,
00366  * which requires being in a valid transaction.
00367  */
00368 void
00369 standard_ProcessUtility(Node *parsetree,
00370                         const char *queryString,
00371                         ProcessUtilityContext context,
00372                         ParamListInfo params,
00373                         DestReceiver *dest,
00374                         char *completionTag)
00375 {
00376     bool        isTopLevel = (context == PROCESS_UTILITY_TOPLEVEL);
00377 
00378     check_xact_readonly(parsetree);
00379 
00380     if (completionTag)
00381         completionTag[0] = '\0';
00382 
00383     switch (nodeTag(parsetree))
00384     {
00385             /*
00386              * ******************** transactions ********************
00387              */
00388         case T_TransactionStmt:
00389             {
00390                 TransactionStmt *stmt = (TransactionStmt *) parsetree;
00391 
00392                 switch (stmt->kind)
00393                 {
00394                         /*
00395                          * START TRANSACTION, as defined by SQL99: Identical
00396                          * to BEGIN.  Same code for both.
00397                          */
00398                     case TRANS_STMT_BEGIN:
00399                     case TRANS_STMT_START:
00400                         {
00401                             ListCell   *lc;
00402 
00403                             BeginTransactionBlock();
00404                             foreach(lc, stmt->options)
00405                             {
00406                                 DefElem    *item = (DefElem *) lfirst(lc);
00407 
00408                                 if (strcmp(item->defname, "transaction_isolation") == 0)
00409                                     SetPGVariable("transaction_isolation",
00410                                                   list_make1(item->arg),
00411                                                   true);
00412                                 else if (strcmp(item->defname, "transaction_read_only") == 0)
00413                                     SetPGVariable("transaction_read_only",
00414                                                   list_make1(item->arg),
00415                                                   true);
00416                                 else if (strcmp(item->defname, "transaction_deferrable") == 0)
00417                                     SetPGVariable("transaction_deferrable",
00418                                                   list_make1(item->arg),
00419                                                   true);
00420                             }
00421                         }
00422                         break;
00423 
00424                     case TRANS_STMT_COMMIT:
00425                         if (!EndTransactionBlock())
00426                         {
00427                             /* report unsuccessful commit in completionTag */
00428                             if (completionTag)
00429                                 strcpy(completionTag, "ROLLBACK");
00430                         }
00431                         break;
00432 
00433                     case TRANS_STMT_PREPARE:
00434                         PreventCommandDuringRecovery("PREPARE TRANSACTION");
00435                         if (!PrepareTransactionBlock(stmt->gid))
00436                         {
00437                             /* report unsuccessful commit in completionTag */
00438                             if (completionTag)
00439                                 strcpy(completionTag, "ROLLBACK");
00440                         }
00441                         break;
00442 
00443                     case TRANS_STMT_COMMIT_PREPARED:
00444                         PreventTransactionChain(isTopLevel, "COMMIT PREPARED");
00445                         PreventCommandDuringRecovery("COMMIT PREPARED");
00446                         FinishPreparedTransaction(stmt->gid, true);
00447                         break;
00448 
00449                     case TRANS_STMT_ROLLBACK_PREPARED:
00450                         PreventTransactionChain(isTopLevel, "ROLLBACK PREPARED");
00451                         PreventCommandDuringRecovery("ROLLBACK PREPARED");
00452                         FinishPreparedTransaction(stmt->gid, false);
00453                         break;
00454 
00455                     case TRANS_STMT_ROLLBACK:
00456                         UserAbortTransactionBlock();
00457                         break;
00458 
00459                     case TRANS_STMT_SAVEPOINT:
00460                         {
00461                             ListCell   *cell;
00462                             char       *name = NULL;
00463 
00464                             RequireTransactionChain(isTopLevel, "SAVEPOINT");
00465 
00466                             foreach(cell, stmt->options)
00467                             {
00468                                 DefElem    *elem = lfirst(cell);
00469 
00470                                 if (strcmp(elem->defname, "savepoint_name") == 0)
00471                                     name = strVal(elem->arg);
00472                             }
00473 
00474                             Assert(PointerIsValid(name));
00475 
00476                             DefineSavepoint(name);
00477                         }
00478                         break;
00479 
00480                     case TRANS_STMT_RELEASE:
00481                         RequireTransactionChain(isTopLevel, "RELEASE SAVEPOINT");
00482                         ReleaseSavepoint(stmt->options);
00483                         break;
00484 
00485                     case TRANS_STMT_ROLLBACK_TO:
00486                         RequireTransactionChain(isTopLevel, "ROLLBACK TO SAVEPOINT");
00487                         RollbackToSavepoint(stmt->options);
00488 
00489                         /*
00490                          * CommitTransactionCommand is in charge of
00491                          * re-defining the savepoint again
00492                          */
00493                         break;
00494                 }
00495             }
00496             break;
00497 
00498             /*
00499              * Portal (cursor) manipulation
00500              *
00501              * Note: DECLARE CURSOR is processed mostly as a SELECT, and
00502              * therefore what we will get here is a PlannedStmt not a bare
00503              * DeclareCursorStmt.
00504              */
00505         case T_PlannedStmt:
00506             {
00507                 PlannedStmt *stmt = (PlannedStmt *) parsetree;
00508 
00509                 if (stmt->utilityStmt == NULL ||
00510                     !IsA(stmt->utilityStmt, DeclareCursorStmt))
00511                     elog(ERROR, "non-DECLARE CURSOR PlannedStmt passed to ProcessUtility");
00512                 PerformCursorOpen(stmt, params, queryString, isTopLevel);
00513             }
00514             break;
00515 
00516         case T_ClosePortalStmt:
00517             {
00518                 ClosePortalStmt *stmt = (ClosePortalStmt *) parsetree;
00519 
00520                 CheckRestrictedOperation("CLOSE");
00521                 PerformPortalClose(stmt->portalname);
00522             }
00523             break;
00524 
00525         case T_FetchStmt:
00526             PerformPortalFetch((FetchStmt *) parsetree, dest,
00527                                completionTag);
00528             break;
00529 
00530         case T_DoStmt:
00531             ExecuteDoStmt((DoStmt *) parsetree);
00532             break;
00533 
00534         case T_CreateTableSpaceStmt:
00535             /* no event triggers for global objects */
00536             PreventTransactionChain(isTopLevel, "CREATE TABLESPACE");
00537             CreateTableSpace((CreateTableSpaceStmt *) parsetree);
00538             break;
00539 
00540         case T_DropTableSpaceStmt:
00541             /* no event triggers for global objects */
00542             PreventTransactionChain(isTopLevel, "DROP TABLESPACE");
00543             DropTableSpace((DropTableSpaceStmt *) parsetree);
00544             break;
00545 
00546         case T_AlterTableSpaceOptionsStmt:
00547             /* no event triggers for global objects */
00548             AlterTableSpaceOptions((AlterTableSpaceOptionsStmt *) parsetree);
00549             break;
00550 
00551         case T_TruncateStmt:
00552             ExecuteTruncate((TruncateStmt *) parsetree);
00553             break;
00554 
00555         case T_CommentStmt:
00556             CommentObject((CommentStmt *) parsetree);
00557             break;
00558 
00559         case T_SecLabelStmt:
00560             ExecSecLabelStmt((SecLabelStmt *) parsetree);
00561             break;
00562 
00563         case T_CopyStmt:
00564             {
00565                 uint64      processed;
00566 
00567                 DoCopy((CopyStmt *) parsetree, queryString, &processed);
00568                 if (completionTag)
00569                     snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
00570                              "COPY " UINT64_FORMAT, processed);
00571             }
00572             break;
00573 
00574         case T_PrepareStmt:
00575             CheckRestrictedOperation("PREPARE");
00576             PrepareQuery((PrepareStmt *) parsetree, queryString);
00577             break;
00578 
00579         case T_ExecuteStmt:
00580             ExecuteQuery((ExecuteStmt *) parsetree, NULL,
00581                          queryString, params,
00582                          dest, completionTag);
00583             break;
00584 
00585         case T_DeallocateStmt:
00586             CheckRestrictedOperation("DEALLOCATE");
00587             DeallocateQuery((DeallocateStmt *) parsetree);
00588             break;
00589 
00590         case T_GrantStmt:
00591             /* no event triggers for global objects */
00592             ExecuteGrantStmt((GrantStmt *) parsetree);
00593             break;
00594 
00595         case T_GrantRoleStmt:
00596             /* no event triggers for global objects */
00597             GrantRole((GrantRoleStmt *) parsetree);
00598             break;
00599 
00600         case T_CreatedbStmt:
00601             /* no event triggers for global objects */
00602             PreventTransactionChain(isTopLevel, "CREATE DATABASE");
00603             createdb((CreatedbStmt *) parsetree);
00604             break;
00605 
00606         case T_AlterDatabaseStmt:
00607             /* no event triggers for global objects */
00608             AlterDatabase((AlterDatabaseStmt *) parsetree, isTopLevel);
00609             break;
00610 
00611         case T_AlterDatabaseSetStmt:
00612             /* no event triggers for global objects */
00613             AlterDatabaseSet((AlterDatabaseSetStmt *) parsetree);
00614             break;
00615 
00616         case T_DropdbStmt:
00617             {
00618                 DropdbStmt *stmt = (DropdbStmt *) parsetree;
00619 
00620                 /* no event triggers for global objects */
00621                 PreventTransactionChain(isTopLevel, "DROP DATABASE");
00622                 dropdb(stmt->dbname, stmt->missing_ok);
00623             }
00624             break;
00625 
00626             /* Query-level asynchronous notification */
00627         case T_NotifyStmt:
00628             {
00629                 NotifyStmt *stmt = (NotifyStmt *) parsetree;
00630 
00631                 PreventCommandDuringRecovery("NOTIFY");
00632                 Async_Notify(stmt->conditionname, stmt->payload);
00633             }
00634             break;
00635 
00636         case T_ListenStmt:
00637             {
00638                 ListenStmt *stmt = (ListenStmt *) parsetree;
00639 
00640                 PreventCommandDuringRecovery("LISTEN");
00641                 CheckRestrictedOperation("LISTEN");
00642                 Async_Listen(stmt->conditionname);
00643             }
00644             break;
00645 
00646         case T_UnlistenStmt:
00647             {
00648                 UnlistenStmt *stmt = (UnlistenStmt *) parsetree;
00649 
00650                 PreventCommandDuringRecovery("UNLISTEN");
00651                 CheckRestrictedOperation("UNLISTEN");
00652                 if (stmt->conditionname)
00653                     Async_Unlisten(stmt->conditionname);
00654                 else
00655                     Async_UnlistenAll();
00656             }
00657             break;
00658 
00659         case T_LoadStmt:
00660             {
00661                 LoadStmt   *stmt = (LoadStmt *) parsetree;
00662 
00663                 closeAllVfds(); /* probably not necessary... */
00664                 /* Allowed names are restricted if you're not superuser */
00665                 load_file(stmt->filename, !superuser());
00666             }
00667             break;
00668 
00669         case T_ClusterStmt:
00670             /* we choose to allow this during "read only" transactions */
00671             PreventCommandDuringRecovery("CLUSTER");
00672             cluster((ClusterStmt *) parsetree, isTopLevel);
00673             break;
00674 
00675         case T_VacuumStmt:
00676             {
00677                 VacuumStmt *stmt = (VacuumStmt *) parsetree;
00678 
00679                 /* we choose to allow this during "read only" transactions */
00680                 PreventCommandDuringRecovery((stmt->options & VACOPT_VACUUM) ?
00681                                              "VACUUM" : "ANALYZE");
00682                 vacuum(stmt, InvalidOid, true, NULL, false, isTopLevel);
00683             }
00684             break;
00685 
00686         case T_ExplainStmt:
00687             ExplainQuery((ExplainStmt *) parsetree, queryString, params, dest);
00688             break;
00689 
00690         case T_VariableSetStmt:
00691             ExecSetVariableStmt((VariableSetStmt *) parsetree);
00692             break;
00693 
00694         case T_VariableShowStmt:
00695             {
00696                 VariableShowStmt *n = (VariableShowStmt *) parsetree;
00697 
00698                 GetPGVariable(n->name, dest);
00699             }
00700             break;
00701 
00702         case T_DiscardStmt:
00703             /* should we allow DISCARD PLANS? */
00704             CheckRestrictedOperation("DISCARD");
00705             DiscardCommand((DiscardStmt *) parsetree, isTopLevel);
00706             break;
00707 
00708         case T_CreateEventTrigStmt:
00709             /* no event triggers on event triggers */
00710             CreateEventTrigger((CreateEventTrigStmt *) parsetree);
00711             break;
00712 
00713         case T_AlterEventTrigStmt:
00714             /* no event triggers on event triggers */
00715             AlterEventTrigger((AlterEventTrigStmt *) parsetree);
00716             break;
00717 
00718             /*
00719              * ******************************** ROLE statements ****
00720              */
00721         case T_CreateRoleStmt:
00722             /* no event triggers for global objects */
00723             CreateRole((CreateRoleStmt *) parsetree);
00724             break;
00725 
00726         case T_AlterRoleStmt:
00727             /* no event triggers for global objects */
00728             AlterRole((AlterRoleStmt *) parsetree);
00729             break;
00730 
00731         case T_AlterRoleSetStmt:
00732             /* no event triggers for global objects */
00733             AlterRoleSet((AlterRoleSetStmt *) parsetree);
00734             break;
00735 
00736         case T_DropRoleStmt:
00737             /* no event triggers for global objects */
00738             DropRole((DropRoleStmt *) parsetree);
00739             break;
00740 
00741         case T_ReassignOwnedStmt:
00742             /* no event triggers for global objects */
00743             ReassignOwnedObjects((ReassignOwnedStmt *) parsetree);
00744             break;
00745 
00746         case T_LockStmt:
00747 
00748             /*
00749              * Since the lock would just get dropped immediately, LOCK TABLE
00750              * outside a transaction block is presumed to be user error.
00751              */
00752             RequireTransactionChain(isTopLevel, "LOCK TABLE");
00753             LockTableCommand((LockStmt *) parsetree);
00754             break;
00755 
00756         case T_ConstraintsSetStmt:
00757             AfterTriggerSetState((ConstraintsSetStmt *) parsetree);
00758             break;
00759 
00760         case T_CheckPointStmt:
00761             if (!superuser())
00762                 ereport(ERROR,
00763                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00764                          errmsg("must be superuser to do CHECKPOINT")));
00765 
00766             /*
00767              * You might think we should have a PreventCommandDuringRecovery()
00768              * here, but we interpret a CHECKPOINT command during recovery as
00769              * a request for a restartpoint instead. We allow this since it
00770              * can be a useful way of reducing switchover time when using
00771              * various forms of replication.
00772              */
00773             RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_WAIT |
00774                               (RecoveryInProgress() ? 0 : CHECKPOINT_FORCE));
00775             break;
00776 
00777         case T_ReindexStmt:
00778             {
00779                 ReindexStmt *stmt = (ReindexStmt *) parsetree;
00780 
00781                 /* we choose to allow this during "read only" transactions */
00782                 PreventCommandDuringRecovery("REINDEX");
00783                 switch (stmt->kind)
00784                 {
00785                     case OBJECT_INDEX:
00786                         ReindexIndex(stmt->relation);
00787                         break;
00788                     case OBJECT_TABLE:
00789                     case OBJECT_MATVIEW:
00790                         ReindexTable(stmt->relation);
00791                         break;
00792                     case OBJECT_DATABASE:
00793 
00794                         /*
00795                          * This cannot run inside a user transaction block; if
00796                          * we were inside a transaction, then its commit- and
00797                          * start-transaction-command calls would not have the
00798                          * intended effect!
00799                          */
00800                         PreventTransactionChain(isTopLevel,
00801                                                 "REINDEX DATABASE");
00802                         ReindexDatabase(stmt->name,
00803                                         stmt->do_system, stmt->do_user);
00804                         break;
00805                     default:
00806                         elog(ERROR, "unrecognized object type: %d",
00807                              (int) stmt->kind);
00808                         break;
00809                 }
00810             }
00811             break;
00812 
00813             /*
00814              * The following statements are supported by Event Triggers only
00815              * in some cases, so we "fast path" them in the other cases.
00816              */
00817 
00818         case T_DropStmt:
00819             {
00820                 DropStmt   *stmt = (DropStmt *) parsetree;
00821 
00822                 if (EventTriggerSupportsObjectType(stmt->removeType))
00823                     ProcessUtilitySlow(parsetree, queryString,
00824                                        context, params,
00825                                        dest, completionTag);
00826                 else
00827                     ExecDropStmt(stmt, isTopLevel);
00828             }
00829             break;
00830 
00831         case T_RenameStmt:
00832             {
00833                 RenameStmt *stmt = (RenameStmt *) parsetree;
00834 
00835                 if (EventTriggerSupportsObjectType(stmt->renameType))
00836                     ProcessUtilitySlow(parsetree, queryString,
00837                                        context, params,
00838                                        dest, completionTag);
00839                 else
00840                     ExecRenameStmt(stmt);
00841             }
00842             break;
00843 
00844         case T_AlterObjectSchemaStmt:
00845             {
00846                 AlterObjectSchemaStmt *stmt = (AlterObjectSchemaStmt *) parsetree;
00847 
00848                 if (EventTriggerSupportsObjectType(stmt->objectType))
00849                     ProcessUtilitySlow(parsetree, queryString,
00850                                        context, params,
00851                                        dest, completionTag);
00852                 else
00853                     ExecAlterObjectSchemaStmt(stmt);
00854             }
00855             break;
00856 
00857         case T_AlterOwnerStmt:
00858             {
00859                 AlterOwnerStmt *stmt = (AlterOwnerStmt *) parsetree;
00860 
00861                 if (EventTriggerSupportsObjectType(stmt->objectType))
00862                     ProcessUtilitySlow(parsetree, queryString,
00863                                        context, params,
00864                                        dest, completionTag);
00865                 else
00866                     ExecAlterOwnerStmt(stmt);
00867             }
00868             break;
00869 
00870         default:
00871             /* All other statement types have event trigger support */
00872             ProcessUtilitySlow(parsetree, queryString,
00873                                context, params,
00874                                dest, completionTag);
00875             break;
00876     }
00877 }
00878 
00879 /*
00880  * The "Slow" variant of ProcessUtility should only receive statements
00881  * supported by the event triggers facility.  Therefore, we always
00882  * perform the trigger support calls if the context allows it.
00883  */
00884 static void
00885 ProcessUtilitySlow(Node *parsetree,
00886                    const char *queryString,
00887                    ProcessUtilityContext context,
00888                    ParamListInfo params,
00889                    DestReceiver *dest,
00890                    char *completionTag)
00891 {
00892     bool        isTopLevel = (context == PROCESS_UTILITY_TOPLEVEL);
00893     bool        isCompleteQuery = (context <= PROCESS_UTILITY_QUERY);
00894     bool        needCleanup;
00895 
00896     /* All event trigger calls are done only when isCompleteQuery is true */
00897     needCleanup = isCompleteQuery && EventTriggerBeginCompleteQuery();
00898 
00899     /* PG_TRY block is to ensure we call EventTriggerEndCompleteQuery */
00900     PG_TRY();
00901     {
00902         if (isCompleteQuery)
00903             EventTriggerDDLCommandStart(parsetree);
00904 
00905         switch (nodeTag(parsetree))
00906         {
00907                 /*
00908                  * relation and attribute manipulation
00909                  */
00910             case T_CreateSchemaStmt:
00911                 CreateSchemaCommand((CreateSchemaStmt *) parsetree,
00912                                     queryString);
00913                 break;
00914 
00915             case T_CreateStmt:
00916             case T_CreateForeignTableStmt:
00917                 {
00918                     List       *stmts;
00919                     ListCell   *l;
00920                     Oid         relOid;
00921 
00922                     /* Run parse analysis ... */
00923                     stmts = transformCreateStmt((CreateStmt *) parsetree,
00924                                                 queryString);
00925 
00926                     /* ... and do it */
00927                     foreach(l, stmts)
00928                     {
00929                         Node       *stmt = (Node *) lfirst(l);
00930 
00931                         if (IsA(stmt, CreateStmt))
00932                         {
00933                             Datum       toast_options;
00934                             static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
00935 
00936                             /* Create the table itself */
00937                             relOid = DefineRelation((CreateStmt *) stmt,
00938                                                     RELKIND_RELATION,
00939                                                     InvalidOid);
00940 
00941                             /*
00942                              * Let AlterTableCreateToastTable decide if this
00943                              * one needs a secondary relation too.
00944                              */
00945                             CommandCounterIncrement();
00946 
00947                             /*
00948                              * parse and validate reloptions for the toast
00949                              * table
00950                              */
00951                             toast_options = transformRelOptions((Datum) 0,
00952                                               ((CreateStmt *) stmt)->options,
00953                                                                 "toast",
00954                                                                 validnsps,
00955                                                                 true,
00956                                                                 false);
00957                             (void) heap_reloptions(RELKIND_TOASTVALUE,
00958                                                    toast_options,
00959                                                    true);
00960 
00961                             AlterTableCreateToastTable(relOid, toast_options);
00962                         }
00963                         else if (IsA(stmt, CreateForeignTableStmt))
00964                         {
00965                             /* Create the table itself */
00966                             relOid = DefineRelation((CreateStmt *) stmt,
00967                                                     RELKIND_FOREIGN_TABLE,
00968                                                     InvalidOid);
00969                             CreateForeignTable((CreateForeignTableStmt *) stmt,
00970                                                relOid);
00971                         }
00972                         else
00973                         {
00974                             /* Recurse for anything else */
00975                             ProcessUtility(stmt,
00976                                            queryString,
00977                                            PROCESS_UTILITY_SUBCOMMAND,
00978                                            params,
00979                                            None_Receiver,
00980                                            NULL);
00981                         }
00982 
00983                         /* Need CCI between commands */
00984                         if (lnext(l) != NULL)
00985                             CommandCounterIncrement();
00986                     }
00987                 }
00988                 break;
00989 
00990             case T_AlterTableStmt:
00991                 {
00992                     AlterTableStmt *atstmt = (AlterTableStmt *) parsetree;
00993                     Oid         relid;
00994                     List       *stmts;
00995                     ListCell   *l;
00996                     LOCKMODE    lockmode;
00997 
00998                     /*
00999                      * Figure out lock mode, and acquire lock.  This also does
01000                      * basic permissions checks, so that we won't wait for a
01001                      * lock on (for example) a relation on which we have no
01002                      * permissions.
01003                      */
01004                     lockmode = AlterTableGetLockLevel(atstmt->cmds);
01005                     relid = AlterTableLookupRelation(atstmt, lockmode);
01006 
01007                     if (OidIsValid(relid))
01008                     {
01009                         /* Run parse analysis ... */
01010                         stmts = transformAlterTableStmt(atstmt, queryString);
01011 
01012                         /* ... and do it */
01013                         foreach(l, stmts)
01014                         {
01015                             Node       *stmt = (Node *) lfirst(l);
01016 
01017                             if (IsA(stmt, AlterTableStmt))
01018                             {
01019                                 /* Do the table alteration proper */
01020                                 AlterTable(relid, lockmode,
01021                                            (AlterTableStmt *) stmt);
01022                             }
01023                             else
01024                             {
01025                                 /* Recurse for anything else */
01026                                 ProcessUtility(stmt,
01027                                                queryString,
01028                                                PROCESS_UTILITY_SUBCOMMAND,
01029                                                params,
01030                                                None_Receiver,
01031                                                NULL);
01032                             }
01033 
01034                             /* Need CCI between commands */
01035                             if (lnext(l) != NULL)
01036                                 CommandCounterIncrement();
01037                         }
01038                     }
01039                     else
01040                         ereport(NOTICE,
01041                           (errmsg("relation \"%s\" does not exist, skipping",
01042                                   atstmt->relation->relname)));
01043                 }
01044                 break;
01045 
01046             case T_AlterDomainStmt:
01047                 {
01048                     AlterDomainStmt *stmt = (AlterDomainStmt *) parsetree;
01049 
01050                     /*
01051                      * Some or all of these functions are recursive to cover
01052                      * inherited things, so permission checks are done there.
01053                      */
01054                     switch (stmt->subtype)
01055                     {
01056                         case 'T':       /* ALTER DOMAIN DEFAULT */
01057 
01058                             /*
01059                              * Recursively alter column default for table and,
01060                              * if requested, for descendants
01061                              */
01062                             AlterDomainDefault(stmt->typeName,
01063                                                stmt->def);
01064                             break;
01065                         case 'N':       /* ALTER DOMAIN DROP NOT NULL */
01066                             AlterDomainNotNull(stmt->typeName,
01067                                                false);
01068                             break;
01069                         case 'O':       /* ALTER DOMAIN SET NOT NULL */
01070                             AlterDomainNotNull(stmt->typeName,
01071                                                true);
01072                             break;
01073                         case 'C':       /* ADD CONSTRAINT */
01074                             AlterDomainAddConstraint(stmt->typeName,
01075                                                      stmt->def);
01076                             break;
01077                         case 'X':       /* DROP CONSTRAINT */
01078                             AlterDomainDropConstraint(stmt->typeName,
01079                                                       stmt->name,
01080                                                       stmt->behavior,
01081                                                       stmt->missing_ok);
01082                             break;
01083                         case 'V':       /* VALIDATE CONSTRAINT */
01084                             AlterDomainValidateConstraint(stmt->typeName,
01085                                                           stmt->name);
01086                             break;
01087                         default:        /* oops */
01088                             elog(ERROR, "unrecognized alter domain type: %d",
01089                                  (int) stmt->subtype);
01090                             break;
01091                     }
01092                 }
01093                 break;
01094 
01095                 /*
01096                  * ************* object creation / destruction **************
01097                  */
01098             case T_DefineStmt:
01099                 {
01100                     DefineStmt *stmt = (DefineStmt *) parsetree;
01101 
01102                     switch (stmt->kind)
01103                     {
01104                         case OBJECT_AGGREGATE:
01105                             DefineAggregate(stmt->defnames, stmt->args,
01106                                             stmt->oldstyle, stmt->definition);
01107                             break;
01108                         case OBJECT_OPERATOR:
01109                             Assert(stmt->args == NIL);
01110                             DefineOperator(stmt->defnames, stmt->definition);
01111                             break;
01112                         case OBJECT_TYPE:
01113                             Assert(stmt->args == NIL);
01114                             DefineType(stmt->defnames, stmt->definition);
01115                             break;
01116                         case OBJECT_TSPARSER:
01117                             Assert(stmt->args == NIL);
01118                             DefineTSParser(stmt->defnames, stmt->definition);
01119                             break;
01120                         case OBJECT_TSDICTIONARY:
01121                             Assert(stmt->args == NIL);
01122                             DefineTSDictionary(stmt->defnames,
01123                                                stmt->definition);
01124                             break;
01125                         case OBJECT_TSTEMPLATE:
01126                             Assert(stmt->args == NIL);
01127                             DefineTSTemplate(stmt->defnames,
01128                                              stmt->definition);
01129                             break;
01130                         case OBJECT_TSCONFIGURATION:
01131                             Assert(stmt->args == NIL);
01132                             DefineTSConfiguration(stmt->defnames,
01133                                                   stmt->definition);
01134                             break;
01135                         case OBJECT_COLLATION:
01136                             Assert(stmt->args == NIL);
01137                             DefineCollation(stmt->defnames, stmt->definition);
01138                             break;
01139                         default:
01140                             elog(ERROR, "unrecognized define stmt type: %d",
01141                                  (int) stmt->kind);
01142                             break;
01143                     }
01144                 }
01145                 break;
01146 
01147             case T_IndexStmt:   /* CREATE INDEX */
01148                 {
01149                     IndexStmt  *stmt = (IndexStmt *) parsetree;
01150 
01151                     if (stmt->concurrent)
01152                         PreventTransactionChain(isTopLevel,
01153                                                 "CREATE INDEX CONCURRENTLY");
01154 
01155                     CheckRelationOwnership(stmt->relation, true);
01156 
01157                     /* Run parse analysis ... */
01158                     stmt = transformIndexStmt(stmt, queryString);
01159 
01160                     /* ... and do it */
01161                     DefineIndex(stmt,
01162                                 InvalidOid,     /* no predefined OID */
01163                                 false,  /* is_alter_table */
01164                                 true,   /* check_rights */
01165                                 false,  /* skip_build */
01166                                 false); /* quiet */
01167                 }
01168                 break;
01169 
01170             case T_CreateExtensionStmt:
01171                 CreateExtension((CreateExtensionStmt *) parsetree);
01172                 break;
01173 
01174             case T_AlterExtensionStmt:
01175                 ExecAlterExtensionStmt((AlterExtensionStmt *) parsetree);
01176                 break;
01177 
01178             case T_AlterExtensionContentsStmt:
01179                 ExecAlterExtensionContentsStmt((AlterExtensionContentsStmt *) parsetree);
01180                 break;
01181 
01182             case T_CreateFdwStmt:
01183                 CreateForeignDataWrapper((CreateFdwStmt *) parsetree);
01184                 break;
01185 
01186             case T_AlterFdwStmt:
01187                 AlterForeignDataWrapper((AlterFdwStmt *) parsetree);
01188                 break;
01189 
01190             case T_CreateForeignServerStmt:
01191                 CreateForeignServer((CreateForeignServerStmt *) parsetree);
01192                 break;
01193 
01194             case T_AlterForeignServerStmt:
01195                 AlterForeignServer((AlterForeignServerStmt *) parsetree);
01196                 break;
01197 
01198             case T_CreateUserMappingStmt:
01199                 CreateUserMapping((CreateUserMappingStmt *) parsetree);
01200                 break;
01201 
01202             case T_AlterUserMappingStmt:
01203                 AlterUserMapping((AlterUserMappingStmt *) parsetree);
01204                 break;
01205 
01206             case T_DropUserMappingStmt:
01207                 RemoveUserMapping((DropUserMappingStmt *) parsetree);
01208                 break;
01209 
01210             case T_CompositeTypeStmt:   /* CREATE TYPE (composite) */
01211                 {
01212                     CompositeTypeStmt *stmt = (CompositeTypeStmt *) parsetree;
01213 
01214                     DefineCompositeType(stmt->typevar, stmt->coldeflist);
01215                 }
01216                 break;
01217 
01218             case T_CreateEnumStmt:      /* CREATE TYPE AS ENUM */
01219                 DefineEnum((CreateEnumStmt *) parsetree);
01220                 break;
01221 
01222             case T_CreateRangeStmt:     /* CREATE TYPE AS RANGE */
01223                 DefineRange((CreateRangeStmt *) parsetree);
01224                 break;
01225 
01226             case T_AlterEnumStmt:       /* ALTER TYPE (enum) */
01227                 AlterEnum((AlterEnumStmt *) parsetree, isTopLevel);
01228                 break;
01229 
01230             case T_ViewStmt:    /* CREATE VIEW */
01231                 DefineView((ViewStmt *) parsetree, queryString);
01232                 break;
01233 
01234             case T_CreateFunctionStmt:  /* CREATE FUNCTION */
01235                 CreateFunction((CreateFunctionStmt *) parsetree, queryString);
01236                 break;
01237 
01238             case T_AlterFunctionStmt:   /* ALTER FUNCTION */
01239                 AlterFunction((AlterFunctionStmt *) parsetree);
01240                 break;
01241 
01242             case T_RuleStmt:    /* CREATE RULE */
01243                 DefineRule((RuleStmt *) parsetree, queryString);
01244                 break;
01245 
01246             case T_CreateSeqStmt:
01247                 DefineSequence((CreateSeqStmt *) parsetree);
01248                 break;
01249 
01250             case T_AlterSeqStmt:
01251                 AlterSequence((AlterSeqStmt *) parsetree);
01252                 break;
01253 
01254             case T_CreateTableAsStmt:
01255                 ExecCreateTableAs((CreateTableAsStmt *) parsetree,
01256                                   queryString, params, completionTag);
01257                 break;
01258 
01259             case T_RefreshMatViewStmt:
01260                 ExecRefreshMatView((RefreshMatViewStmt *) parsetree,
01261                                    queryString, params, completionTag);
01262                 break;
01263 
01264             case T_CreateTrigStmt:
01265                 (void) CreateTrigger((CreateTrigStmt *) parsetree, queryString,
01266                                      InvalidOid, InvalidOid, false);
01267                 break;
01268 
01269             case T_CreatePLangStmt:
01270                 CreateProceduralLanguage((CreatePLangStmt *) parsetree);
01271                 break;
01272 
01273             case T_CreateDomainStmt:
01274                 DefineDomain((CreateDomainStmt *) parsetree);
01275                 break;
01276 
01277             case T_CreateConversionStmt:
01278                 CreateConversionCommand((CreateConversionStmt *) parsetree);
01279                 break;
01280 
01281             case T_CreateCastStmt:
01282                 CreateCast((CreateCastStmt *) parsetree);
01283                 break;
01284 
01285             case T_CreateOpClassStmt:
01286                 DefineOpClass((CreateOpClassStmt *) parsetree);
01287                 break;
01288 
01289             case T_CreateOpFamilyStmt:
01290                 DefineOpFamily((CreateOpFamilyStmt *) parsetree);
01291                 break;
01292 
01293             case T_AlterOpFamilyStmt:
01294                 AlterOpFamily((AlterOpFamilyStmt *) parsetree);
01295                 break;
01296 
01297             case T_AlterTSDictionaryStmt:
01298                 AlterTSDictionary((AlterTSDictionaryStmt *) parsetree);
01299                 break;
01300 
01301             case T_AlterTSConfigurationStmt:
01302                 AlterTSConfiguration((AlterTSConfigurationStmt *) parsetree);
01303                 break;
01304 
01305             case T_DropStmt:
01306                 ExecDropStmt((DropStmt *) parsetree, isTopLevel);
01307                 break;
01308 
01309             case T_RenameStmt:
01310                 ExecRenameStmt((RenameStmt *) parsetree);
01311                 break;
01312 
01313             case T_AlterObjectSchemaStmt:
01314                 ExecAlterObjectSchemaStmt((AlterObjectSchemaStmt *) parsetree);
01315                 break;
01316 
01317             case T_AlterOwnerStmt:
01318                 ExecAlterOwnerStmt((AlterOwnerStmt *) parsetree);
01319                 break;
01320 
01321             case T_DropOwnedStmt:
01322                 DropOwnedObjects((DropOwnedStmt *) parsetree);
01323                 break;
01324 
01325             case T_AlterDefaultPrivilegesStmt:
01326                 ExecAlterDefaultPrivilegesStmt((AlterDefaultPrivilegesStmt *) parsetree);
01327                 break;
01328 
01329             default:
01330                 elog(ERROR, "unrecognized node type: %d",
01331                      (int) nodeTag(parsetree));
01332                 break;
01333         }
01334 
01335         if (isCompleteQuery)
01336         {
01337             EventTriggerSQLDrop(parsetree);
01338             EventTriggerDDLCommandEnd(parsetree);
01339         }
01340     }
01341     PG_CATCH();
01342     {
01343         if (needCleanup)
01344             EventTriggerEndCompleteQuery();
01345         PG_RE_THROW();
01346     }
01347     PG_END_TRY();
01348 
01349     if (needCleanup)
01350         EventTriggerEndCompleteQuery();
01351 }
01352 
01353 /*
01354  * Dispatch function for DropStmt
01355  */
01356 static void
01357 ExecDropStmt(DropStmt *stmt, bool isTopLevel)
01358 {
01359     switch (stmt->removeType)
01360     {
01361         case OBJECT_INDEX:
01362             if (stmt->concurrent)
01363                 PreventTransactionChain(isTopLevel,
01364                                         "DROP INDEX CONCURRENTLY");
01365             /* fall through */
01366 
01367         case OBJECT_TABLE:
01368         case OBJECT_SEQUENCE:
01369         case OBJECT_VIEW:
01370         case OBJECT_MATVIEW:
01371         case OBJECT_FOREIGN_TABLE:
01372             RemoveRelations(stmt);
01373             break;
01374         default:
01375             RemoveObjects(stmt);
01376             break;
01377     }
01378 }
01379 
01380 
01381 /*
01382  * UtilityReturnsTuples
01383  *      Return "true" if this utility statement will send output to the
01384  *      destination.
01385  *
01386  * Generally, there should be a case here for each case in ProcessUtility
01387  * where "dest" is passed on.
01388  */
01389 bool
01390 UtilityReturnsTuples(Node *parsetree)
01391 {
01392     switch (nodeTag(parsetree))
01393     {
01394         case T_FetchStmt:
01395             {
01396                 FetchStmt  *stmt = (FetchStmt *) parsetree;
01397                 Portal      portal;
01398 
01399                 if (stmt->ismove)
01400                     return false;
01401                 portal = GetPortalByName(stmt->portalname);
01402                 if (!PortalIsValid(portal))
01403                     return false;       /* not our business to raise error */
01404                 return portal->tupDesc ? true : false;
01405             }
01406 
01407         case T_ExecuteStmt:
01408             {
01409                 ExecuteStmt *stmt = (ExecuteStmt *) parsetree;
01410                 PreparedStatement *entry;
01411 
01412                 entry = FetchPreparedStatement(stmt->name, false);
01413                 if (!entry)
01414                     return false;       /* not our business to raise error */
01415                 if (entry->plansource->resultDesc)
01416                     return true;
01417                 return false;
01418             }
01419 
01420         case T_ExplainStmt:
01421             return true;
01422 
01423         case T_VariableShowStmt:
01424             return true;
01425 
01426         default:
01427             return false;
01428     }
01429 }
01430 
01431 /*
01432  * UtilityTupleDescriptor
01433  *      Fetch the actual output tuple descriptor for a utility statement
01434  *      for which UtilityReturnsTuples() previously returned "true".
01435  *
01436  * The returned descriptor is created in (or copied into) the current memory
01437  * context.
01438  */
01439 TupleDesc
01440 UtilityTupleDescriptor(Node *parsetree)
01441 {
01442     switch (nodeTag(parsetree))
01443     {
01444         case T_FetchStmt:
01445             {
01446                 FetchStmt  *stmt = (FetchStmt *) parsetree;
01447                 Portal      portal;
01448 
01449                 if (stmt->ismove)
01450                     return NULL;
01451                 portal = GetPortalByName(stmt->portalname);
01452                 if (!PortalIsValid(portal))
01453                     return NULL;    /* not our business to raise error */
01454                 return CreateTupleDescCopy(portal->tupDesc);
01455             }
01456 
01457         case T_ExecuteStmt:
01458             {
01459                 ExecuteStmt *stmt = (ExecuteStmt *) parsetree;
01460                 PreparedStatement *entry;
01461 
01462                 entry = FetchPreparedStatement(stmt->name, false);
01463                 if (!entry)
01464                     return NULL;    /* not our business to raise error */
01465                 return FetchPreparedStatementResultDesc(entry);
01466             }
01467 
01468         case T_ExplainStmt:
01469             return ExplainResultDesc((ExplainStmt *) parsetree);
01470 
01471         case T_VariableShowStmt:
01472             {
01473                 VariableShowStmt *n = (VariableShowStmt *) parsetree;
01474 
01475                 return GetPGVariableResultDesc(n->name);
01476             }
01477 
01478         default:
01479             return NULL;
01480     }
01481 }
01482 
01483 
01484 /*
01485  * QueryReturnsTuples
01486  *      Return "true" if this Query will send output to the destination.
01487  */
01488 #ifdef NOT_USED
01489 bool
01490 QueryReturnsTuples(Query *parsetree)
01491 {
01492     switch (parsetree->commandType)
01493     {
01494         case CMD_SELECT:
01495             /* returns tuples ... unless it's DECLARE CURSOR */
01496             if (parsetree->utilityStmt == NULL)
01497                 return true;
01498             break;
01499         case CMD_INSERT:
01500         case CMD_UPDATE:
01501         case CMD_DELETE:
01502             /* the forms with RETURNING return tuples */
01503             if (parsetree->returningList)
01504                 return true;
01505             break;
01506         case CMD_UTILITY:
01507             return UtilityReturnsTuples(parsetree->utilityStmt);
01508         case CMD_UNKNOWN:
01509         case CMD_NOTHING:
01510             /* probably shouldn't get here */
01511             break;
01512     }
01513     return false;               /* default */
01514 }
01515 #endif
01516 
01517 
01518 /*
01519  * UtilityContainsQuery
01520  *      Return the contained Query, or NULL if there is none
01521  *
01522  * Certain utility statements, such as EXPLAIN, contain a plannable Query.
01523  * This function encapsulates knowledge of exactly which ones do.
01524  * We assume it is invoked only on already-parse-analyzed statements
01525  * (else the contained parsetree isn't a Query yet).
01526  *
01527  * In some cases (currently, only EXPLAIN of CREATE TABLE AS/SELECT INTO and
01528  * CREATE MATERIALIZED VIEW), potentially Query-containing utility statements
01529  * can be nested.  This function will drill down to a non-utility Query, or
01530  * return NULL if none.
01531  */
01532 Query *
01533 UtilityContainsQuery(Node *parsetree)
01534 {
01535     Query      *qry;
01536 
01537     switch (nodeTag(parsetree))
01538     {
01539         case T_ExplainStmt:
01540             qry = (Query *) ((ExplainStmt *) parsetree)->query;
01541             Assert(IsA(qry, Query));
01542             if (qry->commandType == CMD_UTILITY)
01543                 return UtilityContainsQuery(qry->utilityStmt);
01544             return qry;
01545 
01546         case T_CreateTableAsStmt:
01547             qry = (Query *) ((CreateTableAsStmt *) parsetree)->query;
01548             Assert(IsA(qry, Query));
01549             if (qry->commandType == CMD_UTILITY)
01550                 return UtilityContainsQuery(qry->utilityStmt);
01551             return qry;
01552 
01553         default:
01554             return NULL;
01555     }
01556 }
01557 
01558 
01559 /*
01560  * AlterObjectTypeCommandTag
01561  *      helper function for CreateCommandTag
01562  *
01563  * This covers most cases where ALTER is used with an ObjectType enum.
01564  */
01565 static const char *
01566 AlterObjectTypeCommandTag(ObjectType objtype)
01567 {
01568     const char *tag;
01569 
01570     switch (objtype)
01571     {
01572         case OBJECT_AGGREGATE:
01573             tag = "ALTER AGGREGATE";
01574             break;
01575         case OBJECT_ATTRIBUTE:
01576             tag = "ALTER TYPE";
01577             break;
01578         case OBJECT_CAST:
01579             tag = "ALTER CAST";
01580             break;
01581         case OBJECT_COLLATION:
01582             tag = "ALTER COLLATION";
01583             break;
01584         case OBJECT_COLUMN:
01585             tag = "ALTER TABLE";
01586             break;
01587         case OBJECT_CONSTRAINT:
01588             tag = "ALTER TABLE";
01589             break;
01590         case OBJECT_CONVERSION:
01591             tag = "ALTER CONVERSION";
01592             break;
01593         case OBJECT_DATABASE:
01594             tag = "ALTER DATABASE";
01595             break;
01596         case OBJECT_DOMAIN:
01597             tag = "ALTER DOMAIN";
01598             break;
01599         case OBJECT_EXTENSION:
01600             tag = "ALTER EXTENSION";
01601             break;
01602         case OBJECT_FDW:
01603             tag = "ALTER FOREIGN DATA WRAPPER";
01604             break;
01605         case OBJECT_FOREIGN_SERVER:
01606             tag = "ALTER SERVER";
01607             break;
01608         case OBJECT_FOREIGN_TABLE:
01609             tag = "ALTER FOREIGN TABLE";
01610             break;
01611         case OBJECT_FUNCTION:
01612             tag = "ALTER FUNCTION";
01613             break;
01614         case OBJECT_INDEX:
01615             tag = "ALTER INDEX";
01616             break;
01617         case OBJECT_LANGUAGE:
01618             tag = "ALTER LANGUAGE";
01619             break;
01620         case OBJECT_LARGEOBJECT:
01621             tag = "ALTER LARGE OBJECT";
01622             break;
01623         case OBJECT_OPCLASS:
01624             tag = "ALTER OPERATOR CLASS";
01625             break;
01626         case OBJECT_OPERATOR:
01627             tag = "ALTER OPERATOR";
01628             break;
01629         case OBJECT_OPFAMILY:
01630             tag = "ALTER OPERATOR FAMILY";
01631             break;
01632         case OBJECT_ROLE:
01633             tag = "ALTER ROLE";
01634             break;
01635         case OBJECT_RULE:
01636             tag = "ALTER RULE";
01637             break;
01638         case OBJECT_SCHEMA:
01639             tag = "ALTER SCHEMA";
01640             break;
01641         case OBJECT_SEQUENCE:
01642             tag = "ALTER SEQUENCE";
01643             break;
01644         case OBJECT_TABLE:
01645             tag = "ALTER TABLE";
01646             break;
01647         case OBJECT_TABLESPACE:
01648             tag = "ALTER TABLESPACE";
01649             break;
01650         case OBJECT_TRIGGER:
01651             tag = "ALTER TRIGGER";
01652             break;
01653         case OBJECT_EVENT_TRIGGER:
01654             tag = "ALTER EVENT TRIGGER";
01655             break;
01656         case OBJECT_TSCONFIGURATION:
01657             tag = "ALTER TEXT SEARCH CONFIGURATION";
01658             break;
01659         case OBJECT_TSDICTIONARY:
01660             tag = "ALTER TEXT SEARCH DICTIONARY";
01661             break;
01662         case OBJECT_TSPARSER:
01663             tag = "ALTER TEXT SEARCH PARSER";
01664             break;
01665         case OBJECT_TSTEMPLATE:
01666             tag = "ALTER TEXT SEARCH TEMPLATE";
01667             break;
01668         case OBJECT_TYPE:
01669             tag = "ALTER TYPE";
01670             break;
01671         case OBJECT_VIEW:
01672             tag = "ALTER VIEW";
01673             break;
01674         case OBJECT_MATVIEW:
01675             tag = "ALTER MATERIALIZED VIEW";
01676             break;
01677         default:
01678             tag = "???";
01679             break;
01680     }
01681 
01682     return tag;
01683 }
01684 
01685 /*
01686  * CreateCommandTag
01687  *      utility to get a string representation of the command operation,
01688  *      given either a raw (un-analyzed) parsetree or a planned query.
01689  *
01690  * This must handle all command types, but since the vast majority
01691  * of 'em are utility commands, it seems sensible to keep it here.
01692  *
01693  * NB: all result strings must be shorter than COMPLETION_TAG_BUFSIZE.
01694  * Also, the result must point at a true constant (permanent storage).
01695  */
01696 const char *
01697 CreateCommandTag(Node *parsetree)
01698 {
01699     const char *tag;
01700 
01701     switch (nodeTag(parsetree))
01702     {
01703             /* raw plannable queries */
01704         case T_InsertStmt:
01705             tag = "INSERT";
01706             break;
01707 
01708         case T_DeleteStmt:
01709             tag = "DELETE";
01710             break;
01711 
01712         case T_UpdateStmt:
01713             tag = "UPDATE";
01714             break;
01715 
01716         case T_SelectStmt:
01717             tag = "SELECT";
01718             break;
01719 
01720             /* utility statements --- same whether raw or cooked */
01721         case T_TransactionStmt:
01722             {
01723                 TransactionStmt *stmt = (TransactionStmt *) parsetree;
01724 
01725                 switch (stmt->kind)
01726                 {
01727                     case TRANS_STMT_BEGIN:
01728                         tag = "BEGIN";
01729                         break;
01730 
01731                     case TRANS_STMT_START:
01732                         tag = "START TRANSACTION";
01733                         break;
01734 
01735                     case TRANS_STMT_COMMIT:
01736                         tag = "COMMIT";
01737                         break;
01738 
01739                     case TRANS_STMT_ROLLBACK:
01740                     case TRANS_STMT_ROLLBACK_TO:
01741                         tag = "ROLLBACK";
01742                         break;
01743 
01744                     case TRANS_STMT_SAVEPOINT:
01745                         tag = "SAVEPOINT";
01746                         break;
01747 
01748                     case TRANS_STMT_RELEASE:
01749                         tag = "RELEASE";
01750                         break;
01751 
01752                     case TRANS_STMT_PREPARE:
01753                         tag = "PREPARE TRANSACTION";
01754                         break;
01755 
01756                     case TRANS_STMT_COMMIT_PREPARED:
01757                         tag = "COMMIT PREPARED";
01758                         break;
01759 
01760                     case TRANS_STMT_ROLLBACK_PREPARED:
01761                         tag = "ROLLBACK PREPARED";
01762                         break;
01763 
01764                     default:
01765                         tag = "???";
01766                         break;
01767                 }
01768             }
01769             break;
01770 
01771         case T_DeclareCursorStmt:
01772             tag = "DECLARE CURSOR";
01773             break;
01774 
01775         case T_ClosePortalStmt:
01776             {
01777                 ClosePortalStmt *stmt = (ClosePortalStmt *) parsetree;
01778 
01779                 if (stmt->portalname == NULL)
01780                     tag = "CLOSE CURSOR ALL";
01781                 else
01782                     tag = "CLOSE CURSOR";
01783             }
01784             break;
01785 
01786         case T_FetchStmt:
01787             {
01788                 FetchStmt  *stmt = (FetchStmt *) parsetree;
01789 
01790                 tag = (stmt->ismove) ? "MOVE" : "FETCH";
01791             }
01792             break;
01793 
01794         case T_CreateDomainStmt:
01795             tag = "CREATE DOMAIN";
01796             break;
01797 
01798         case T_CreateSchemaStmt:
01799             tag = "CREATE SCHEMA";
01800             break;
01801 
01802         case T_CreateStmt:
01803             tag = "CREATE TABLE";
01804             break;
01805 
01806         case T_CreateTableSpaceStmt:
01807             tag = "CREATE TABLESPACE";
01808             break;
01809 
01810         case T_DropTableSpaceStmt:
01811             tag = "DROP TABLESPACE";
01812             break;
01813 
01814         case T_AlterTableSpaceOptionsStmt:
01815             tag = "ALTER TABLESPACE";
01816             break;
01817 
01818         case T_CreateExtensionStmt:
01819             tag = "CREATE EXTENSION";
01820             break;
01821 
01822         case T_AlterExtensionStmt:
01823             tag = "ALTER EXTENSION";
01824             break;
01825 
01826         case T_AlterExtensionContentsStmt:
01827             tag = "ALTER EXTENSION";
01828             break;
01829 
01830         case T_CreateFdwStmt:
01831             tag = "CREATE FOREIGN DATA WRAPPER";
01832             break;
01833 
01834         case T_AlterFdwStmt:
01835             tag = "ALTER FOREIGN DATA WRAPPER";
01836             break;
01837 
01838         case T_CreateForeignServerStmt:
01839             tag = "CREATE SERVER";
01840             break;
01841 
01842         case T_AlterForeignServerStmt:
01843             tag = "ALTER SERVER";
01844             break;
01845 
01846         case T_CreateUserMappingStmt:
01847             tag = "CREATE USER MAPPING";
01848             break;
01849 
01850         case T_AlterUserMappingStmt:
01851             tag = "ALTER USER MAPPING";
01852             break;
01853 
01854         case T_DropUserMappingStmt:
01855             tag = "DROP USER MAPPING";
01856             break;
01857 
01858         case T_CreateForeignTableStmt:
01859             tag = "CREATE FOREIGN TABLE";
01860             break;
01861 
01862         case T_DropStmt:
01863             switch (((DropStmt *) parsetree)->removeType)
01864             {
01865                 case OBJECT_TABLE:
01866                     tag = "DROP TABLE";
01867                     break;
01868                 case OBJECT_SEQUENCE:
01869                     tag = "DROP SEQUENCE";
01870                     break;
01871                 case OBJECT_VIEW:
01872                     tag = "DROP VIEW";
01873                     break;
01874                 case OBJECT_MATVIEW:
01875                     tag = "DROP MATERIALIZED VIEW";
01876                     break;
01877                 case OBJECT_INDEX:
01878                     tag = "DROP INDEX";
01879                     break;
01880                 case OBJECT_TYPE:
01881                     tag = "DROP TYPE";
01882                     break;
01883                 case OBJECT_DOMAIN:
01884                     tag = "DROP DOMAIN";
01885                     break;
01886                 case OBJECT_COLLATION:
01887                     tag = "DROP COLLATION";
01888                     break;
01889                 case OBJECT_CONVERSION:
01890                     tag = "DROP CONVERSION";
01891                     break;
01892                 case OBJECT_SCHEMA:
01893                     tag = "DROP SCHEMA";
01894                     break;
01895                 case OBJECT_TSPARSER:
01896                     tag = "DROP TEXT SEARCH PARSER";
01897                     break;
01898                 case OBJECT_TSDICTIONARY:
01899                     tag = "DROP TEXT SEARCH DICTIONARY";
01900                     break;
01901                 case OBJECT_TSTEMPLATE:
01902                     tag = "DROP TEXT SEARCH TEMPLATE";
01903                     break;
01904                 case OBJECT_TSCONFIGURATION:
01905                     tag = "DROP TEXT SEARCH CONFIGURATION";
01906                     break;
01907                 case OBJECT_FOREIGN_TABLE:
01908                     tag = "DROP FOREIGN TABLE";
01909                     break;
01910                 case OBJECT_EXTENSION:
01911                     tag = "DROP EXTENSION";
01912                     break;
01913                 case OBJECT_FUNCTION:
01914                     tag = "DROP FUNCTION";
01915                     break;
01916                 case OBJECT_AGGREGATE:
01917                     tag = "DROP AGGREGATE";
01918                     break;
01919                 case OBJECT_OPERATOR:
01920                     tag = "DROP OPERATOR";
01921                     break;
01922                 case OBJECT_LANGUAGE:
01923                     tag = "DROP LANGUAGE";
01924                     break;
01925                 case OBJECT_CAST:
01926                     tag = "DROP CAST";
01927                     break;
01928                 case OBJECT_TRIGGER:
01929                     tag = "DROP TRIGGER";
01930                     break;
01931                 case OBJECT_EVENT_TRIGGER:
01932                     tag = "DROP EVENT TRIGGER";
01933                     break;
01934                 case OBJECT_RULE:
01935                     tag = "DROP RULE";
01936                     break;
01937                 case OBJECT_FDW:
01938                     tag = "DROP FOREIGN DATA WRAPPER";
01939                     break;
01940                 case OBJECT_FOREIGN_SERVER:
01941                     tag = "DROP SERVER";
01942                     break;
01943                 case OBJECT_OPCLASS:
01944                     tag = "DROP OPERATOR CLASS";
01945                     break;
01946                 case OBJECT_OPFAMILY:
01947                     tag = "DROP OPERATOR FAMILY";
01948                     break;
01949                 default:
01950                     tag = "???";
01951             }
01952             break;
01953 
01954         case T_TruncateStmt:
01955             tag = "TRUNCATE TABLE";
01956             break;
01957 
01958         case T_CommentStmt:
01959             tag = "COMMENT";
01960             break;
01961 
01962         case T_SecLabelStmt:
01963             tag = "SECURITY LABEL";
01964             break;
01965 
01966         case T_CopyStmt:
01967             tag = "COPY";
01968             break;
01969 
01970         case T_RenameStmt:
01971             tag = AlterObjectTypeCommandTag(((RenameStmt *) parsetree)->renameType);
01972             break;
01973 
01974         case T_AlterObjectSchemaStmt:
01975             tag = AlterObjectTypeCommandTag(((AlterObjectSchemaStmt *) parsetree)->objectType);
01976             break;
01977 
01978         case T_AlterOwnerStmt:
01979             tag = AlterObjectTypeCommandTag(((AlterOwnerStmt *) parsetree)->objectType);
01980             break;
01981 
01982         case T_AlterTableStmt:
01983             tag = AlterObjectTypeCommandTag(((AlterTableStmt *) parsetree)->relkind);
01984             break;
01985 
01986         case T_AlterDomainStmt:
01987             tag = "ALTER DOMAIN";
01988             break;
01989 
01990         case T_AlterFunctionStmt:
01991             tag = "ALTER FUNCTION";
01992             break;
01993 
01994         case T_GrantStmt:
01995             {
01996                 GrantStmt  *stmt = (GrantStmt *) parsetree;
01997 
01998                 tag = (stmt->is_grant) ? "GRANT" : "REVOKE";
01999             }
02000             break;
02001 
02002         case T_GrantRoleStmt:
02003             {
02004                 GrantRoleStmt *stmt = (GrantRoleStmt *) parsetree;
02005 
02006                 tag = (stmt->is_grant) ? "GRANT ROLE" : "REVOKE ROLE";
02007             }
02008             break;
02009 
02010         case T_AlterDefaultPrivilegesStmt:
02011             tag = "ALTER DEFAULT PRIVILEGES";
02012             break;
02013 
02014         case T_DefineStmt:
02015             switch (((DefineStmt *) parsetree)->kind)
02016             {
02017                 case OBJECT_AGGREGATE:
02018                     tag = "CREATE AGGREGATE";
02019                     break;
02020                 case OBJECT_OPERATOR:
02021                     tag = "CREATE OPERATOR";
02022                     break;
02023                 case OBJECT_TYPE:
02024                     tag = "CREATE TYPE";
02025                     break;
02026                 case OBJECT_TSPARSER:
02027                     tag = "CREATE TEXT SEARCH PARSER";
02028                     break;
02029                 case OBJECT_TSDICTIONARY:
02030                     tag = "CREATE TEXT SEARCH DICTIONARY";
02031                     break;
02032                 case OBJECT_TSTEMPLATE:
02033                     tag = "CREATE TEXT SEARCH TEMPLATE";
02034                     break;
02035                 case OBJECT_TSCONFIGURATION:
02036                     tag = "CREATE TEXT SEARCH CONFIGURATION";
02037                     break;
02038                 case OBJECT_COLLATION:
02039                     tag = "CREATE COLLATION";
02040                     break;
02041                 default:
02042                     tag = "???";
02043             }
02044             break;
02045 
02046         case T_CompositeTypeStmt:
02047             tag = "CREATE TYPE";
02048             break;
02049 
02050         case T_CreateEnumStmt:
02051             tag = "CREATE TYPE";
02052             break;
02053 
02054         case T_CreateRangeStmt:
02055             tag = "CREATE TYPE";
02056             break;
02057 
02058         case T_AlterEnumStmt:
02059             tag = "ALTER TYPE";
02060             break;
02061 
02062         case T_ViewStmt:
02063             tag = "CREATE VIEW";
02064             break;
02065 
02066         case T_CreateFunctionStmt:
02067             tag = "CREATE FUNCTION";
02068             break;
02069 
02070         case T_IndexStmt:
02071             tag = "CREATE INDEX";
02072             break;
02073 
02074         case T_RuleStmt:
02075             tag = "CREATE RULE";
02076             break;
02077 
02078         case T_CreateSeqStmt:
02079             tag = "CREATE SEQUENCE";
02080             break;
02081 
02082         case T_AlterSeqStmt:
02083             tag = "ALTER SEQUENCE";
02084             break;
02085 
02086         case T_DoStmt:
02087             tag = "DO";
02088             break;
02089 
02090         case T_CreatedbStmt:
02091             tag = "CREATE DATABASE";
02092             break;
02093 
02094         case T_AlterDatabaseStmt:
02095             tag = "ALTER DATABASE";
02096             break;
02097 
02098         case T_AlterDatabaseSetStmt:
02099             tag = "ALTER DATABASE";
02100             break;
02101 
02102         case T_DropdbStmt:
02103             tag = "DROP DATABASE";
02104             break;
02105 
02106         case T_NotifyStmt:
02107             tag = "NOTIFY";
02108             break;
02109 
02110         case T_ListenStmt:
02111             tag = "LISTEN";
02112             break;
02113 
02114         case T_UnlistenStmt:
02115             tag = "UNLISTEN";
02116             break;
02117 
02118         case T_LoadStmt:
02119             tag = "LOAD";
02120             break;
02121 
02122         case T_ClusterStmt:
02123             tag = "CLUSTER";
02124             break;
02125 
02126         case T_VacuumStmt:
02127             if (((VacuumStmt *) parsetree)->options & VACOPT_VACUUM)
02128                 tag = "VACUUM";
02129             else
02130                 tag = "ANALYZE";
02131             break;
02132 
02133         case T_ExplainStmt:
02134             tag = "EXPLAIN";
02135             break;
02136 
02137         case T_CreateTableAsStmt:
02138             switch (((CreateTableAsStmt *) parsetree)->relkind)
02139             {
02140                 case OBJECT_TABLE:
02141                     if (((CreateTableAsStmt *) parsetree)->is_select_into)
02142                         tag = "SELECT INTO";
02143                     else
02144                         tag = "CREATE TABLE AS";
02145                     break;
02146                 case OBJECT_MATVIEW:
02147                     tag = "CREATE MATERIALIZED VIEW";
02148                     break;
02149                 default:
02150                     tag = "???";
02151             }
02152             break;
02153 
02154         case T_RefreshMatViewStmt:
02155             tag = "REFRESH MATERIALIZED VIEW";
02156             break;
02157 
02158         case T_VariableSetStmt:
02159             switch (((VariableSetStmt *) parsetree)->kind)
02160             {
02161                 case VAR_SET_VALUE:
02162                 case VAR_SET_CURRENT:
02163                 case VAR_SET_DEFAULT:
02164                 case VAR_SET_MULTI:
02165                     tag = "SET";
02166                     break;
02167                 case VAR_RESET:
02168                 case VAR_RESET_ALL:
02169                     tag = "RESET";
02170                     break;
02171                 default:
02172                     tag = "???";
02173             }
02174             break;
02175 
02176         case T_VariableShowStmt:
02177             tag = "SHOW";
02178             break;
02179 
02180         case T_DiscardStmt:
02181             switch (((DiscardStmt *) parsetree)->target)
02182             {
02183                 case DISCARD_ALL:
02184                     tag = "DISCARD ALL";
02185                     break;
02186                 case DISCARD_PLANS:
02187                     tag = "DISCARD PLANS";
02188                     break;
02189                 case DISCARD_TEMP:
02190                     tag = "DISCARD TEMP";
02191                     break;
02192                 default:
02193                     tag = "???";
02194             }
02195             break;
02196 
02197         case T_CreateTrigStmt:
02198             tag = "CREATE TRIGGER";
02199             break;
02200 
02201         case T_CreateEventTrigStmt:
02202             tag = "CREATE EVENT TRIGGER";
02203             break;
02204 
02205         case T_AlterEventTrigStmt:
02206             tag = "ALTER EVENT TRIGGER";
02207             break;
02208 
02209         case T_CreatePLangStmt:
02210             tag = "CREATE LANGUAGE";
02211             break;
02212 
02213         case T_CreateRoleStmt:
02214             tag = "CREATE ROLE";
02215             break;
02216 
02217         case T_AlterRoleStmt:
02218             tag = "ALTER ROLE";
02219             break;
02220 
02221         case T_AlterRoleSetStmt:
02222             tag = "ALTER ROLE";
02223             break;
02224 
02225         case T_DropRoleStmt:
02226             tag = "DROP ROLE";
02227             break;
02228 
02229         case T_DropOwnedStmt:
02230             tag = "DROP OWNED";
02231             break;
02232 
02233         case T_ReassignOwnedStmt:
02234             tag = "REASSIGN OWNED";
02235             break;
02236 
02237         case T_LockStmt:
02238             tag = "LOCK TABLE";
02239             break;
02240 
02241         case T_ConstraintsSetStmt:
02242             tag = "SET CONSTRAINTS";
02243             break;
02244 
02245         case T_CheckPointStmt:
02246             tag = "CHECKPOINT";
02247             break;
02248 
02249         case T_ReindexStmt:
02250             tag = "REINDEX";
02251             break;
02252 
02253         case T_CreateConversionStmt:
02254             tag = "CREATE CONVERSION";
02255             break;
02256 
02257         case T_CreateCastStmt:
02258             tag = "CREATE CAST";
02259             break;
02260 
02261         case T_CreateOpClassStmt:
02262             tag = "CREATE OPERATOR CLASS";
02263             break;
02264 
02265         case T_CreateOpFamilyStmt:
02266             tag = "CREATE OPERATOR FAMILY";
02267             break;
02268 
02269         case T_AlterOpFamilyStmt:
02270             tag = "ALTER OPERATOR FAMILY";
02271             break;
02272 
02273         case T_AlterTSDictionaryStmt:
02274             tag = "ALTER TEXT SEARCH DICTIONARY";
02275             break;
02276 
02277         case T_AlterTSConfigurationStmt:
02278             tag = "ALTER TEXT SEARCH CONFIGURATION";
02279             break;
02280 
02281         case T_PrepareStmt:
02282             tag = "PREPARE";
02283             break;
02284 
02285         case T_ExecuteStmt:
02286             tag = "EXECUTE";
02287             break;
02288 
02289         case T_DeallocateStmt:
02290             {
02291                 DeallocateStmt *stmt = (DeallocateStmt *) parsetree;
02292 
02293                 if (stmt->name == NULL)
02294                     tag = "DEALLOCATE ALL";
02295                 else
02296                     tag = "DEALLOCATE";
02297             }
02298             break;
02299 
02300             /* already-planned queries */
02301         case T_PlannedStmt:
02302             {
02303                 PlannedStmt *stmt = (PlannedStmt *) parsetree;
02304 
02305                 switch (stmt->commandType)
02306                 {
02307                     case CMD_SELECT:
02308 
02309                         /*
02310                          * We take a little extra care here so that the result
02311                          * will be useful for complaints about read-only
02312                          * statements
02313                          */
02314                         if (stmt->utilityStmt != NULL)
02315                         {
02316                             Assert(IsA(stmt->utilityStmt, DeclareCursorStmt));
02317                             tag = "DECLARE CURSOR";
02318                         }
02319                         else if (stmt->rowMarks != NIL)
02320                         {
02321                             /* not 100% but probably close enough */
02322                             switch (((PlanRowMark *) linitial(stmt->rowMarks))->markType)
02323                             {
02324                                 case ROW_MARK_EXCLUSIVE:
02325                                     tag = "SELECT FOR UPDATE";
02326                                     break;
02327                                 case ROW_MARK_NOKEYEXCLUSIVE:
02328                                     tag = "SELECT FOR NO KEY UPDATE";
02329                                     break;
02330                                 case ROW_MARK_SHARE:
02331                                     tag = "SELECT FOR SHARE";
02332                                     break;
02333                                 case ROW_MARK_KEYSHARE:
02334                                     tag = "SELECT FOR KEY SHARE";
02335                                     break;
02336                                 case ROW_MARK_REFERENCE:
02337                                 case ROW_MARK_COPY:
02338                                     tag = "SELECT";
02339                                     break;
02340                                 default:
02341                                     tag = "???";
02342                                     break;
02343                             }
02344                         }
02345                         else
02346                             tag = "SELECT";
02347                         break;
02348                     case CMD_UPDATE:
02349                         tag = "UPDATE";
02350                         break;
02351                     case CMD_INSERT:
02352                         tag = "INSERT";
02353                         break;
02354                     case CMD_DELETE:
02355                         tag = "DELETE";
02356                         break;
02357                     default:
02358                         elog(WARNING, "unrecognized commandType: %d",
02359                              (int) stmt->commandType);
02360                         tag = "???";
02361                         break;
02362                 }
02363             }
02364             break;
02365 
02366             /* parsed-and-rewritten-but-not-planned queries */
02367         case T_Query:
02368             {
02369                 Query      *stmt = (Query *) parsetree;
02370 
02371                 switch (stmt->commandType)
02372                 {
02373                     case CMD_SELECT:
02374 
02375                         /*
02376                          * We take a little extra care here so that the result
02377                          * will be useful for complaints about read-only
02378                          * statements
02379                          */
02380                         if (stmt->utilityStmt != NULL)
02381                         {
02382                             Assert(IsA(stmt->utilityStmt, DeclareCursorStmt));
02383                             tag = "DECLARE CURSOR";
02384                         }
02385                         else if (stmt->rowMarks != NIL)
02386                         {
02387                             /* not 100% but probably close enough */
02388                             switch (((RowMarkClause *) linitial(stmt->rowMarks))->strength)
02389                             {
02390                                 case LCS_FORKEYSHARE:
02391                                     tag = "SELECT FOR KEY SHARE";
02392                                     break;
02393                                 case LCS_FORSHARE:
02394                                     tag = "SELECT FOR SHARE";
02395                                     break;
02396                                 case LCS_FORNOKEYUPDATE:
02397                                     tag = "SELECT FOR NO KEY UPDATE";
02398                                     break;
02399                                 case LCS_FORUPDATE:
02400                                     tag = "SELECT FOR UPDATE";
02401                                     break;
02402                                 default:
02403                                     tag = "???";
02404                                     break;
02405                             }
02406                         }
02407                         else
02408                             tag = "SELECT";
02409                         break;
02410                     case CMD_UPDATE:
02411                         tag = "UPDATE";
02412                         break;
02413                     case CMD_INSERT:
02414                         tag = "INSERT";
02415                         break;
02416                     case CMD_DELETE:
02417                         tag = "DELETE";
02418                         break;
02419                     case CMD_UTILITY:
02420                         tag = CreateCommandTag(stmt->utilityStmt);
02421                         break;
02422                     default:
02423                         elog(WARNING, "unrecognized commandType: %d",
02424                              (int) stmt->commandType);
02425                         tag = "???";
02426                         break;
02427                 }
02428             }
02429             break;
02430 
02431         default:
02432             elog(WARNING, "unrecognized node type: %d",
02433                  (int) nodeTag(parsetree));
02434             tag = "???";
02435             break;
02436     }
02437 
02438     return tag;
02439 }
02440 
02441 
02442 /*
02443  * GetCommandLogLevel
02444  *      utility to get the minimum log_statement level for a command,
02445  *      given either a raw (un-analyzed) parsetree or a planned query.
02446  *
02447  * This must handle all command types, but since the vast majority
02448  * of 'em are utility commands, it seems sensible to keep it here.
02449  */
02450 LogStmtLevel
02451 GetCommandLogLevel(Node *parsetree)
02452 {
02453     LogStmtLevel lev;
02454 
02455     switch (nodeTag(parsetree))
02456     {
02457             /* raw plannable queries */
02458         case T_InsertStmt:
02459         case T_DeleteStmt:
02460         case T_UpdateStmt:
02461             lev = LOGSTMT_MOD;
02462             break;
02463 
02464         case T_SelectStmt:
02465             if (((SelectStmt *) parsetree)->intoClause)
02466                 lev = LOGSTMT_DDL;      /* SELECT INTO */
02467             else
02468                 lev = LOGSTMT_ALL;
02469             break;
02470 
02471             /* utility statements --- same whether raw or cooked */
02472         case T_TransactionStmt:
02473             lev = LOGSTMT_ALL;
02474             break;
02475 
02476         case T_DeclareCursorStmt:
02477             lev = LOGSTMT_ALL;
02478             break;
02479 
02480         case T_ClosePortalStmt:
02481             lev = LOGSTMT_ALL;
02482             break;
02483 
02484         case T_FetchStmt:
02485             lev = LOGSTMT_ALL;
02486             break;
02487 
02488         case T_CreateSchemaStmt:
02489             lev = LOGSTMT_DDL;
02490             break;
02491 
02492         case T_CreateStmt:
02493         case T_CreateForeignTableStmt:
02494             lev = LOGSTMT_DDL;
02495             break;
02496 
02497         case T_CreateTableSpaceStmt:
02498         case T_DropTableSpaceStmt:
02499         case T_AlterTableSpaceOptionsStmt:
02500             lev = LOGSTMT_DDL;
02501             break;
02502 
02503         case T_CreateExtensionStmt:
02504         case T_AlterExtensionStmt:
02505         case T_AlterExtensionContentsStmt:
02506             lev = LOGSTMT_DDL;
02507             break;
02508 
02509         case T_CreateFdwStmt:
02510         case T_AlterFdwStmt:
02511         case T_CreateForeignServerStmt:
02512         case T_AlterForeignServerStmt:
02513         case T_CreateUserMappingStmt:
02514         case T_AlterUserMappingStmt:
02515         case T_DropUserMappingStmt:
02516             lev = LOGSTMT_DDL;
02517             break;
02518 
02519         case T_DropStmt:
02520             lev = LOGSTMT_DDL;
02521             break;
02522 
02523         case T_TruncateStmt:
02524             lev = LOGSTMT_MOD;
02525             break;
02526 
02527         case T_CommentStmt:
02528             lev = LOGSTMT_DDL;
02529             break;
02530 
02531         case T_SecLabelStmt:
02532             lev = LOGSTMT_DDL;
02533             break;
02534 
02535         case T_CopyStmt:
02536             if (((CopyStmt *) parsetree)->is_from)
02537                 lev = LOGSTMT_MOD;
02538             else
02539                 lev = LOGSTMT_ALL;
02540             break;
02541 
02542         case T_PrepareStmt:
02543             {
02544                 PrepareStmt *stmt = (PrepareStmt *) parsetree;
02545 
02546                 /* Look through a PREPARE to the contained stmt */
02547                 lev = GetCommandLogLevel(stmt->query);
02548             }
02549             break;
02550 
02551         case T_ExecuteStmt:
02552             {
02553                 ExecuteStmt *stmt = (ExecuteStmt *) parsetree;
02554                 PreparedStatement *ps;
02555 
02556                 /* Look through an EXECUTE to the referenced stmt */
02557                 ps = FetchPreparedStatement(stmt->name, false);
02558                 if (ps)
02559                     lev = GetCommandLogLevel(ps->plansource->raw_parse_tree);
02560                 else
02561                     lev = LOGSTMT_ALL;
02562             }
02563             break;
02564 
02565         case T_DeallocateStmt:
02566             lev = LOGSTMT_ALL;
02567             break;
02568 
02569         case T_RenameStmt:
02570             lev = LOGSTMT_DDL;
02571             break;
02572 
02573         case T_AlterObjectSchemaStmt:
02574             lev = LOGSTMT_DDL;
02575             break;
02576 
02577         case T_AlterOwnerStmt:
02578             lev = LOGSTMT_DDL;
02579             break;
02580 
02581         case T_AlterTableStmt:
02582             lev = LOGSTMT_DDL;
02583             break;
02584 
02585         case T_AlterDomainStmt:
02586             lev = LOGSTMT_DDL;
02587             break;
02588 
02589         case T_GrantStmt:
02590             lev = LOGSTMT_DDL;
02591             break;
02592 
02593         case T_GrantRoleStmt:
02594             lev = LOGSTMT_DDL;
02595             break;
02596 
02597         case T_AlterDefaultPrivilegesStmt:
02598             lev = LOGSTMT_DDL;
02599             break;
02600 
02601         case T_DefineStmt:
02602             lev = LOGSTMT_DDL;
02603             break;
02604 
02605         case T_CompositeTypeStmt:
02606             lev = LOGSTMT_DDL;
02607             break;
02608 
02609         case T_CreateEnumStmt:
02610             lev = LOGSTMT_DDL;
02611             break;
02612 
02613         case T_CreateRangeStmt:
02614             lev = LOGSTMT_DDL;
02615             break;
02616 
02617         case T_AlterEnumStmt:
02618             lev = LOGSTMT_DDL;
02619             break;
02620 
02621         case T_ViewStmt:
02622             lev = LOGSTMT_DDL;
02623             break;
02624 
02625         case T_CreateFunctionStmt:
02626             lev = LOGSTMT_DDL;
02627             break;
02628 
02629         case T_AlterFunctionStmt:
02630             lev = LOGSTMT_DDL;
02631             break;
02632 
02633         case T_IndexStmt:
02634             lev = LOGSTMT_DDL;
02635             break;
02636 
02637         case T_RuleStmt:
02638             lev = LOGSTMT_DDL;
02639             break;
02640 
02641         case T_CreateSeqStmt:
02642             lev = LOGSTMT_DDL;
02643             break;
02644 
02645         case T_AlterSeqStmt:
02646             lev = LOGSTMT_DDL;
02647             break;
02648 
02649         case T_DoStmt:
02650             lev = LOGSTMT_ALL;
02651             break;
02652 
02653         case T_CreatedbStmt:
02654             lev = LOGSTMT_DDL;
02655             break;
02656 
02657         case T_AlterDatabaseStmt:
02658             lev = LOGSTMT_DDL;
02659             break;
02660 
02661         case T_AlterDatabaseSetStmt:
02662             lev = LOGSTMT_DDL;
02663             break;
02664 
02665         case T_DropdbStmt:
02666             lev = LOGSTMT_DDL;
02667             break;
02668 
02669         case T_NotifyStmt:
02670             lev = LOGSTMT_ALL;
02671             break;
02672 
02673         case T_ListenStmt:
02674             lev = LOGSTMT_ALL;
02675             break;
02676 
02677         case T_UnlistenStmt:
02678             lev = LOGSTMT_ALL;
02679             break;
02680 
02681         case T_LoadStmt:
02682             lev = LOGSTMT_ALL;
02683             break;
02684 
02685         case T_ClusterStmt:
02686             lev = LOGSTMT_DDL;
02687             break;
02688 
02689         case T_VacuumStmt:
02690             lev = LOGSTMT_ALL;
02691             break;
02692 
02693         case T_ExplainStmt:
02694             {
02695                 ExplainStmt *stmt = (ExplainStmt *) parsetree;
02696                 bool        analyze = false;
02697                 ListCell   *lc;
02698 
02699                 /* Look through an EXPLAIN ANALYZE to the contained stmt */
02700                 foreach(lc, stmt->options)
02701                 {
02702                     DefElem    *opt = (DefElem *) lfirst(lc);
02703 
02704                     if (strcmp(opt->defname, "analyze") == 0)
02705                         analyze = defGetBoolean(opt);
02706                     /* don't "break", as explain.c will use the last value */
02707                 }
02708                 if (analyze)
02709                     return GetCommandLogLevel(stmt->query);
02710 
02711                 /* Plain EXPLAIN isn't so interesting */
02712                 lev = LOGSTMT_ALL;
02713             }
02714             break;
02715 
02716         case T_CreateTableAsStmt:
02717             lev = LOGSTMT_DDL;
02718             break;
02719 
02720         case T_RefreshMatViewStmt:
02721             lev = LOGSTMT_DDL;
02722             break;
02723 
02724         case T_VariableSetStmt:
02725             lev = LOGSTMT_ALL;
02726             break;
02727 
02728         case T_VariableShowStmt:
02729             lev = LOGSTMT_ALL;
02730             break;
02731 
02732         case T_DiscardStmt:
02733             lev = LOGSTMT_ALL;
02734             break;
02735 
02736         case T_CreateTrigStmt:
02737             lev = LOGSTMT_DDL;
02738             break;
02739 
02740         case T_CreateEventTrigStmt:
02741             lev = LOGSTMT_DDL;
02742             break;
02743 
02744         case T_AlterEventTrigStmt:
02745             lev = LOGSTMT_DDL;
02746             break;
02747 
02748         case T_CreatePLangStmt:
02749             lev = LOGSTMT_DDL;
02750             break;
02751 
02752         case T_CreateDomainStmt:
02753             lev = LOGSTMT_DDL;
02754             break;
02755 
02756         case T_CreateRoleStmt:
02757             lev = LOGSTMT_DDL;
02758             break;
02759 
02760         case T_AlterRoleStmt:
02761             lev = LOGSTMT_DDL;
02762             break;
02763 
02764         case T_AlterRoleSetStmt:
02765             lev = LOGSTMT_DDL;
02766             break;
02767 
02768         case T_DropRoleStmt:
02769             lev = LOGSTMT_DDL;
02770             break;
02771 
02772         case T_DropOwnedStmt:
02773             lev = LOGSTMT_DDL;
02774             break;
02775 
02776         case T_ReassignOwnedStmt:
02777             lev = LOGSTMT_DDL;
02778             break;
02779 
02780         case T_LockStmt:
02781             lev = LOGSTMT_ALL;
02782             break;
02783 
02784         case T_ConstraintsSetStmt:
02785             lev = LOGSTMT_ALL;
02786             break;
02787 
02788         case T_CheckPointStmt:
02789             lev = LOGSTMT_ALL;
02790             break;
02791 
02792         case T_ReindexStmt:
02793             lev = LOGSTMT_ALL;  /* should this be DDL? */
02794             break;
02795 
02796         case T_CreateConversionStmt:
02797             lev = LOGSTMT_DDL;
02798             break;
02799 
02800         case T_CreateCastStmt:
02801             lev = LOGSTMT_DDL;
02802             break;
02803 
02804         case T_CreateOpClassStmt:
02805             lev = LOGSTMT_DDL;
02806             break;
02807 
02808         case T_CreateOpFamilyStmt:
02809             lev = LOGSTMT_DDL;
02810             break;
02811 
02812         case T_AlterOpFamilyStmt:
02813             lev = LOGSTMT_DDL;
02814             break;
02815 
02816         case T_AlterTSDictionaryStmt:
02817             lev = LOGSTMT_DDL;
02818             break;
02819 
02820         case T_AlterTSConfigurationStmt:
02821             lev = LOGSTMT_DDL;
02822             break;
02823 
02824             /* already-planned queries */
02825         case T_PlannedStmt:
02826             {
02827                 PlannedStmt *stmt = (PlannedStmt *) parsetree;
02828 
02829                 switch (stmt->commandType)
02830                 {
02831                     case CMD_SELECT:
02832                         lev = LOGSTMT_ALL;
02833                         break;
02834 
02835                     case CMD_UPDATE:
02836                     case CMD_INSERT:
02837                     case CMD_DELETE:
02838                         lev = LOGSTMT_MOD;
02839                         break;
02840 
02841                     default:
02842                         elog(WARNING, "unrecognized commandType: %d",
02843                              (int) stmt->commandType);
02844                         lev = LOGSTMT_ALL;
02845                         break;
02846                 }
02847             }
02848             break;
02849 
02850             /* parsed-and-rewritten-but-not-planned queries */
02851         case T_Query:
02852             {
02853                 Query      *stmt = (Query *) parsetree;
02854 
02855                 switch (stmt->commandType)
02856                 {
02857                     case CMD_SELECT:
02858                         lev = LOGSTMT_ALL;
02859                         break;
02860 
02861                     case CMD_UPDATE:
02862                     case CMD_INSERT:
02863                     case CMD_DELETE:
02864                         lev = LOGSTMT_MOD;
02865                         break;
02866 
02867                     case CMD_UTILITY:
02868                         lev = GetCommandLogLevel(stmt->utilityStmt);
02869                         break;
02870 
02871                     default:
02872                         elog(WARNING, "unrecognized commandType: %d",
02873                              (int) stmt->commandType);
02874                         lev = LOGSTMT_ALL;
02875                         break;
02876                 }
02877 
02878             }
02879             break;
02880 
02881         default:
02882             elog(WARNING, "unrecognized node type: %d",
02883                  (int) nodeTag(parsetree));
02884             lev = LOGSTMT_ALL;
02885             break;
02886     }
02887 
02888     return lev;
02889 }