postgresql/src/backend/tcop/utility.c
Alvaro Herrera 58b088a9b3
Fix DDL deparse of CREATE OPERATOR CLASS
When an implicit operator family is created, it wasn't getting reported.
Make it do so.

This has always been missing.  Backpatch to 10.

Author: Masahiko Sawada <sawada.mshk@gmail.com>
Reported-by: Leslie LEMAIRE <leslie.lemaire@developpement-durable.gouv.fr>
Reviewed-by: Amit Kapila <amit.kapila16@gmail.com>
Reviewed-by: Michael Paquiër <michael@paquier.xyz>
Discussion: https://postgr.es/m/f74d69e151b22171e8829551b1159e77@developpement-durable.gouv.fr
2022-05-20 18:52:55 +02:00

3742 lines
90 KiB
C

/*-------------------------------------------------------------------------
*
* utility.c
* Contains functions which control the execution of the POSTGRES utility
* commands. At one time acted as an interface between the Lisp and C
* systems.
*
* Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* src/backend/tcop/utility.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/htup_details.h"
#include "access/reloptions.h"
#include "access/twophase.h"
#include "access/xact.h"
#include "access/xlog.h"
#include "catalog/catalog.h"
#include "catalog/index.h"
#include "catalog/namespace.h"
#include "catalog/pg_inherits.h"
#include "catalog/toasting.h"
#include "commands/alter.h"
#include "commands/async.h"
#include "commands/cluster.h"
#include "commands/collationcmds.h"
#include "commands/comment.h"
#include "commands/conversioncmds.h"
#include "commands/copy.h"
#include "commands/createas.h"
#include "commands/dbcommands.h"
#include "commands/defrem.h"
#include "commands/discard.h"
#include "commands/event_trigger.h"
#include "commands/explain.h"
#include "commands/extension.h"
#include "commands/lockcmds.h"
#include "commands/matview.h"
#include "commands/policy.h"
#include "commands/portalcmds.h"
#include "commands/prepare.h"
#include "commands/proclang.h"
#include "commands/publicationcmds.h"
#include "commands/schemacmds.h"
#include "commands/seclabel.h"
#include "commands/sequence.h"
#include "commands/subscriptioncmds.h"
#include "commands/tablecmds.h"
#include "commands/tablespace.h"
#include "commands/trigger.h"
#include "commands/typecmds.h"
#include "commands/user.h"
#include "commands/vacuum.h"
#include "commands/view.h"
#include "miscadmin.h"
#include "parser/parse_utilcmd.h"
#include "postmaster/bgwriter.h"
#include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteRemove.h"
#include "storage/fd.h"
#include "tcop/pquery.h"
#include "tcop/utility.h"
#include "utils/acl.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/syscache.h"
/* Hook for plugins to get control in ProcessUtility() */
ProcessUtility_hook_type ProcessUtility_hook = NULL;
/* local function declarations */
static int ClassifyUtilityCommandAsReadOnly(Node *parsetree);
static void ProcessUtilitySlow(ParseState *pstate,
PlannedStmt *pstmt,
const char *queryString,
ProcessUtilityContext context,
ParamListInfo params,
QueryEnvironment *queryEnv,
DestReceiver *dest,
QueryCompletion *qc);
static void ExecDropStmt(DropStmt *stmt, bool isTopLevel);
/*
* CommandIsReadOnly: is an executable query read-only?
*
* This is a much stricter test than we apply for XactReadOnly mode;
* the query must be *in truth* read-only, because the caller wishes
* not to do CommandCounterIncrement for it.
*
* Note: currently no need to support raw or analyzed queries here
*/
bool
CommandIsReadOnly(PlannedStmt *pstmt)
{
Assert(IsA(pstmt, PlannedStmt));
switch (pstmt->commandType)
{
case CMD_SELECT:
if (pstmt->rowMarks != NIL)
return false; /* SELECT FOR [KEY] UPDATE/SHARE */
else if (pstmt->hasModifyingCTE)
return false; /* data-modifying CTE */
else
return true;
case CMD_UPDATE:
case CMD_INSERT:
case CMD_DELETE:
return false;
case CMD_UTILITY:
/* For now, treat all utility commands as read/write */
return false;
default:
elog(WARNING, "unrecognized commandType: %d",
(int) pstmt->commandType);
break;
}
return false;
}
/*
* Determine the degree to which a utility command is read only.
*
* Note the definitions of the relevant flags in src/include/utility/tcop.h.
*/
static int
ClassifyUtilityCommandAsReadOnly(Node *parsetree)
{
switch (nodeTag(parsetree))
{
case T_AlterCollationStmt:
case T_AlterDatabaseSetStmt:
case T_AlterDatabaseStmt:
case T_AlterDefaultPrivilegesStmt:
case T_AlterDomainStmt:
case T_AlterEnumStmt:
case T_AlterEventTrigStmt:
case T_AlterExtensionContentsStmt:
case T_AlterExtensionStmt:
case T_AlterFdwStmt:
case T_AlterForeignServerStmt:
case T_AlterFunctionStmt:
case T_AlterObjectDependsStmt:
case T_AlterObjectSchemaStmt:
case T_AlterOpFamilyStmt:
case T_AlterOperatorStmt:
case T_AlterOwnerStmt:
case T_AlterPolicyStmt:
case T_AlterPublicationStmt:
case T_AlterRoleSetStmt:
case T_AlterRoleStmt:
case T_AlterSeqStmt:
case T_AlterStatsStmt:
case T_AlterSubscriptionStmt:
case T_AlterTSConfigurationStmt:
case T_AlterTSDictionaryStmt:
case T_AlterTableMoveAllStmt:
case T_AlterTableSpaceOptionsStmt:
case T_AlterTableStmt:
case T_AlterTypeStmt:
case T_AlterUserMappingStmt:
case T_CommentStmt:
case T_CompositeTypeStmt:
case T_CreateAmStmt:
case T_CreateCastStmt:
case T_CreateConversionStmt:
case T_CreateDomainStmt:
case T_CreateEnumStmt:
case T_CreateEventTrigStmt:
case T_CreateExtensionStmt:
case T_CreateFdwStmt:
case T_CreateForeignServerStmt:
case T_CreateForeignTableStmt:
case T_CreateFunctionStmt:
case T_CreateOpClassStmt:
case T_CreateOpFamilyStmt:
case T_CreatePLangStmt:
case T_CreatePolicyStmt:
case T_CreatePublicationStmt:
case T_CreateRangeStmt:
case T_CreateRoleStmt:
case T_CreateSchemaStmt:
case T_CreateSeqStmt:
case T_CreateStatsStmt:
case T_CreateStmt:
case T_CreateSubscriptionStmt:
case T_CreateTableAsStmt:
case T_CreateTableSpaceStmt:
case T_CreateTransformStmt:
case T_CreateTrigStmt:
case T_CreateUserMappingStmt:
case T_CreatedbStmt:
case T_DefineStmt:
case T_DropOwnedStmt:
case T_DropRoleStmt:
case T_DropStmt:
case T_DropSubscriptionStmt:
case T_DropTableSpaceStmt:
case T_DropUserMappingStmt:
case T_DropdbStmt:
case T_GrantRoleStmt:
case T_GrantStmt:
case T_ImportForeignSchemaStmt:
case T_IndexStmt:
case T_ReassignOwnedStmt:
case T_RefreshMatViewStmt:
case T_RenameStmt:
case T_RuleStmt:
case T_SecLabelStmt:
case T_TruncateStmt:
case T_ViewStmt:
{
/* DDL is not read-only, and neither is TRUNCATE. */
return COMMAND_IS_NOT_READ_ONLY;
}
case T_AlterSystemStmt:
{
/*
* Surprisingly, ALTER SYSTEM meets all our definitions of
* read-only: it changes nothing that affects the output of
* pg_dump, it doesn't write WAL or imperil the application of
* future WAL, and it doesn't depend on any state that needs
* to be synchronized with parallel workers.
*
* So, despite the fact that it writes to a file, it's read
* only!
*/
return COMMAND_IS_STRICTLY_READ_ONLY;
}
case T_CallStmt:
case T_DoStmt:
{
/*
* Commands inside the DO block or the called procedure might
* not be read only, but they'll be checked separately when we
* try to execute them. Here we only need to worry about the
* DO or CALL command itself.
*/
return COMMAND_IS_STRICTLY_READ_ONLY;
}
case T_CheckPointStmt:
{
/*
* You might think that this should not be permitted in
* recovery, but we interpret a CHECKPOINT command during
* recovery as a request for a restartpoint instead. We allow
* this since it can be a useful way of reducing switchover
* time when using various forms of replication.
*/
return COMMAND_IS_STRICTLY_READ_ONLY;
}
case T_ClosePortalStmt:
case T_ConstraintsSetStmt:
case T_DeallocateStmt:
case T_DeclareCursorStmt:
case T_DiscardStmt:
case T_ExecuteStmt:
case T_FetchStmt:
case T_LoadStmt:
case T_PrepareStmt:
case T_UnlistenStmt:
case T_VariableSetStmt:
{
/*
* These modify only backend-local state, so they're OK to run
* in a read-only transaction or on a standby. However, they
* are disallowed in parallel mode, because they either rely
* upon or modify backend-local state that might not be
* synchronized among cooperating backends.
*/
return COMMAND_OK_IN_RECOVERY | COMMAND_OK_IN_READ_ONLY_TXN;
}
case T_ClusterStmt:
case T_ReindexStmt:
case T_VacuumStmt:
{
/*
* These commands write WAL, so they're not strictly
* read-only, and running them in parallel workers isn't
* supported.
*
* However, they don't change the database state in a way that
* would affect pg_dump output, so it's fine to run them in a
* read-only transaction. (CLUSTER might change the order of
* rows on disk, which could affect the ordering of pg_dump
* output, but that's not semantically significant.)
*/
return COMMAND_OK_IN_READ_ONLY_TXN;
}
case T_CopyStmt:
{
CopyStmt *stmt = (CopyStmt *) parsetree;
/*
* You might think that COPY FROM is not at all read only, but
* it's OK to copy into a temporary table, because that
* wouldn't change the output of pg_dump. If the target table
* turns out to be non-temporary, DoCopy itself will call
* PreventCommandIfReadOnly.
*/
if (stmt->is_from)
return COMMAND_OK_IN_READ_ONLY_TXN;
else
return COMMAND_IS_STRICTLY_READ_ONLY;
}
case T_ExplainStmt:
case T_VariableShowStmt:
{
/*
* These commands don't modify any data and are safe to run in
* a parallel worker.
*/
return COMMAND_IS_STRICTLY_READ_ONLY;
}
case T_ListenStmt:
case T_NotifyStmt:
{
/*
* NOTIFY requires an XID assignment, so it can't be permitted
* on a standby. Perhaps LISTEN could, since without NOTIFY it
* would be OK to just do nothing, at least until promotion,
* but we currently prohibit it lest the user get the wrong
* idea.
*
* (We do allow T_UnlistenStmt on a standby, though, because
* it's a no-op.)
*/
return COMMAND_OK_IN_READ_ONLY_TXN;
}
case T_LockStmt:
{
LockStmt *stmt = (LockStmt *) parsetree;
/*
* Only weaker locker modes are allowed during recovery. The
* restrictions here must match those in
* LockAcquireExtended().
*/
if (stmt->mode > RowExclusiveLock)
return COMMAND_OK_IN_READ_ONLY_TXN;
else
return COMMAND_IS_STRICTLY_READ_ONLY;
}
case T_TransactionStmt:
{
TransactionStmt *stmt = (TransactionStmt *) parsetree;
/*
* PREPARE, COMMIT PREPARED, and ROLLBACK PREPARED all write
* WAL, so they're not read-only in the strict sense; but the
* first and third do not change pg_dump output, so they're OK
* in a read-only transactions.
*
* We also consider COMMIT PREPARED to be OK in a read-only
* transaction environment, by way of exception.
*/
switch (stmt->kind)
{
case TRANS_STMT_BEGIN:
case TRANS_STMT_START:
case TRANS_STMT_COMMIT:
case TRANS_STMT_ROLLBACK:
case TRANS_STMT_SAVEPOINT:
case TRANS_STMT_RELEASE:
case TRANS_STMT_ROLLBACK_TO:
return COMMAND_IS_STRICTLY_READ_ONLY;
case TRANS_STMT_PREPARE:
case TRANS_STMT_COMMIT_PREPARED:
case TRANS_STMT_ROLLBACK_PREPARED:
return COMMAND_OK_IN_READ_ONLY_TXN;
}
elog(ERROR, "unrecognized TransactionStmtKind: %d",
(int) stmt->kind);
return 0; /* silence stupider compilers */
}
default:
elog(ERROR, "unrecognized node type: %d",
(int) nodeTag(parsetree));
return 0; /* silence stupider compilers */
}
}
/*
* PreventCommandIfReadOnly: throw error if XactReadOnly
*
* This is useful partly to ensure consistency of the error message wording;
* some callers have checked XactReadOnly for themselves.
*/
void
PreventCommandIfReadOnly(const char *cmdname)
{
if (XactReadOnly)
ereport(ERROR,
(errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),
/* translator: %s is name of a SQL command, eg CREATE */
errmsg("cannot execute %s in a read-only transaction",
cmdname)));
}
/*
* PreventCommandIfParallelMode: throw error if current (sub)transaction is
* in parallel mode.
*
* This is useful partly to ensure consistency of the error message wording;
* some callers have checked IsInParallelMode() for themselves.
*/
void
PreventCommandIfParallelMode(const char *cmdname)
{
if (IsInParallelMode())
ereport(ERROR,
(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
/* translator: %s is name of a SQL command, eg CREATE */
errmsg("cannot execute %s during a parallel operation",
cmdname)));
}
/*
* PreventCommandDuringRecovery: throw error if RecoveryInProgress
*
* The majority of operations that are unsafe in a Hot Standby
* will be rejected by XactReadOnly tests. However there are a few
* commands that are allowed in "read-only" xacts but cannot be allowed
* in Hot Standby mode. Those commands should call this function.
*/
void
PreventCommandDuringRecovery(const char *cmdname)
{
if (RecoveryInProgress())
ereport(ERROR,
(errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),
/* translator: %s is name of a SQL command, eg CREATE */
errmsg("cannot execute %s during recovery",
cmdname)));
}
/*
* CheckRestrictedOperation: throw error for hazardous command if we're
* inside a security restriction context.
*
* This is needed to protect session-local state for which there is not any
* better-defined protection mechanism, such as ownership.
*/
static void
CheckRestrictedOperation(const char *cmdname)
{
if (InSecurityRestrictedOperation())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
/* translator: %s is name of a SQL command, eg PREPARE */
errmsg("cannot execute %s within security-restricted operation",
cmdname)));
}
/*
* ProcessUtility
* general utility function invoker
*
* pstmt: PlannedStmt wrapper for the utility statement
* queryString: original source text of command
* readOnlyTree: if true, pstmt's node tree must not be modified
* context: identifies source of statement (toplevel client command,
* non-toplevel client command, subcommand of a larger utility command)
* params: parameters to use during execution
* queryEnv: environment for parse through execution (e.g., ephemeral named
* tables like trigger transition tables). May be NULL.
* dest: where to send results
* qc: where to store command completion status data. May be NULL,
* but if not, then caller must have initialized it.
*
* Caller MUST supply a queryString; it is not allowed (anymore) to pass NULL.
* If you really don't have source text, you can pass a constant string,
* perhaps "(query not available)".
*
* Note for users of ProcessUtility_hook: the same queryString may be passed
* to multiple invocations of ProcessUtility when processing a query string
* containing multiple semicolon-separated statements. One should use
* pstmt->stmt_location and pstmt->stmt_len to identify the substring
* containing the current statement. Keep in mind also that some utility
* statements (e.g., CREATE SCHEMA) will recurse to ProcessUtility to process
* sub-statements, often passing down the same queryString, stmt_location,
* and stmt_len that were given for the whole statement.
*/
void
ProcessUtility(PlannedStmt *pstmt,
const char *queryString,
bool readOnlyTree,
ProcessUtilityContext context,
ParamListInfo params,
QueryEnvironment *queryEnv,
DestReceiver *dest,
QueryCompletion *qc)
{
Assert(IsA(pstmt, PlannedStmt));
Assert(pstmt->commandType == CMD_UTILITY);
Assert(queryString != NULL); /* required as of 8.4 */
Assert(qc == NULL || qc->commandTag == CMDTAG_UNKNOWN);
/*
* We provide a function hook variable that lets loadable plugins get
* control when ProcessUtility is called. Such a plugin would normally
* call standard_ProcessUtility().
*/
if (ProcessUtility_hook)
(*ProcessUtility_hook) (pstmt, queryString, readOnlyTree,
context, params, queryEnv,
dest, qc);
else
standard_ProcessUtility(pstmt, queryString, readOnlyTree,
context, params, queryEnv,
dest, qc);
}
/*
* standard_ProcessUtility itself deals only with utility commands for
* which we do not provide event trigger support. Commands that do have
* such support are passed down to ProcessUtilitySlow, which contains the
* necessary infrastructure for such triggers.
*
* This division is not just for performance: it's critical that the
* event trigger code not be invoked when doing START TRANSACTION for
* example, because we might need to refresh the event trigger cache,
* which requires being in a valid transaction.
*/
void
standard_ProcessUtility(PlannedStmt *pstmt,
const char *queryString,
bool readOnlyTree,
ProcessUtilityContext context,
ParamListInfo params,
QueryEnvironment *queryEnv,
DestReceiver *dest,
QueryCompletion *qc)
{
Node *parsetree;
bool isTopLevel = (context == PROCESS_UTILITY_TOPLEVEL);
bool isAtomicContext = (!(context == PROCESS_UTILITY_TOPLEVEL || context == PROCESS_UTILITY_QUERY_NONATOMIC) || IsTransactionBlock());
ParseState *pstate;
int readonly_flags;
/* This can recurse, so check for excessive recursion */
check_stack_depth();
/*
* If the given node tree is read-only, make a copy to ensure that parse
* transformations don't damage the original tree. This could be
* refactored to avoid making unnecessary copies in more cases, but it's
* not clear that it's worth a great deal of trouble over. Statements
* that are complex enough to be expensive to copy are exactly the ones
* we'd need to copy, so that only marginal savings seem possible.
*/
if (readOnlyTree)
pstmt = copyObject(pstmt);
parsetree = pstmt->utilityStmt;
/* Prohibit read/write commands in read-only states. */
readonly_flags = ClassifyUtilityCommandAsReadOnly(parsetree);
if (readonly_flags != COMMAND_IS_STRICTLY_READ_ONLY &&
(XactReadOnly || IsInParallelMode()))
{
CommandTag commandtag = CreateCommandTag(parsetree);
if ((readonly_flags & COMMAND_OK_IN_READ_ONLY_TXN) == 0)
PreventCommandIfReadOnly(GetCommandTagName(commandtag));
if ((readonly_flags & COMMAND_OK_IN_PARALLEL_MODE) == 0)
PreventCommandIfParallelMode(GetCommandTagName(commandtag));
if ((readonly_flags & COMMAND_OK_IN_RECOVERY) == 0)
PreventCommandDuringRecovery(GetCommandTagName(commandtag));
}
pstate = make_parsestate(NULL);
pstate->p_sourcetext = queryString;
pstate->p_queryEnv = queryEnv;
switch (nodeTag(parsetree))
{
/*
* ******************** transactions ********************
*/
case T_TransactionStmt:
{
TransactionStmt *stmt = (TransactionStmt *) parsetree;
switch (stmt->kind)
{
/*
* START TRANSACTION, as defined by SQL99: Identical
* to BEGIN. Same code for both.
*/
case TRANS_STMT_BEGIN:
case TRANS_STMT_START:
{
ListCell *lc;
BeginTransactionBlock();
foreach(lc, stmt->options)
{
DefElem *item = (DefElem *) lfirst(lc);
if (strcmp(item->defname, "transaction_isolation") == 0)
SetPGVariable("transaction_isolation",
list_make1(item->arg),
true);
else if (strcmp(item->defname, "transaction_read_only") == 0)
SetPGVariable("transaction_read_only",
list_make1(item->arg),
true);
else if (strcmp(item->defname, "transaction_deferrable") == 0)
SetPGVariable("transaction_deferrable",
list_make1(item->arg),
true);
}
}
break;
case TRANS_STMT_COMMIT:
if (!EndTransactionBlock(stmt->chain))
{
/* report unsuccessful commit in qc */
if (qc)
SetQueryCompletion(qc, CMDTAG_ROLLBACK, 0);
}
break;
case TRANS_STMT_PREPARE:
if (!PrepareTransactionBlock(stmt->gid))
{
/* report unsuccessful commit in qc */
if (qc)
SetQueryCompletion(qc, CMDTAG_ROLLBACK, 0);
}
break;
case TRANS_STMT_COMMIT_PREPARED:
PreventInTransactionBlock(isTopLevel, "COMMIT PREPARED");
FinishPreparedTransaction(stmt->gid, true);
break;
case TRANS_STMT_ROLLBACK_PREPARED:
PreventInTransactionBlock(isTopLevel, "ROLLBACK PREPARED");
FinishPreparedTransaction(stmt->gid, false);
break;
case TRANS_STMT_ROLLBACK:
UserAbortTransactionBlock(stmt->chain);
break;
case TRANS_STMT_SAVEPOINT:
RequireTransactionBlock(isTopLevel, "SAVEPOINT");
DefineSavepoint(stmt->savepoint_name);
break;
case TRANS_STMT_RELEASE:
RequireTransactionBlock(isTopLevel, "RELEASE SAVEPOINT");
ReleaseSavepoint(stmt->savepoint_name);
break;
case TRANS_STMT_ROLLBACK_TO:
RequireTransactionBlock(isTopLevel, "ROLLBACK TO SAVEPOINT");
RollbackToSavepoint(stmt->savepoint_name);
/*
* CommitTransactionCommand is in charge of
* re-defining the savepoint again
*/
break;
}
}
break;
/*
* Portal (cursor) manipulation
*/
case T_DeclareCursorStmt:
PerformCursorOpen(pstate, (DeclareCursorStmt *) parsetree, params,
isTopLevel);
break;
case T_ClosePortalStmt:
{
ClosePortalStmt *stmt = (ClosePortalStmt *) parsetree;
CheckRestrictedOperation("CLOSE");
PerformPortalClose(stmt->portalname);
}
break;
case T_FetchStmt:
PerformPortalFetch((FetchStmt *) parsetree, dest, qc);
break;
case T_DoStmt:
ExecuteDoStmt((DoStmt *) parsetree, isAtomicContext);
break;
case T_CreateTableSpaceStmt:
/* no event triggers for global objects */
PreventInTransactionBlock(isTopLevel, "CREATE TABLESPACE");
CreateTableSpace((CreateTableSpaceStmt *) parsetree);
break;
case T_DropTableSpaceStmt:
/* no event triggers for global objects */
PreventInTransactionBlock(isTopLevel, "DROP TABLESPACE");
DropTableSpace((DropTableSpaceStmt *) parsetree);
break;
case T_AlterTableSpaceOptionsStmt:
/* no event triggers for global objects */
AlterTableSpaceOptions((AlterTableSpaceOptionsStmt *) parsetree);
break;
case T_TruncateStmt:
ExecuteTruncate((TruncateStmt *) parsetree);
break;
case T_CopyStmt:
{
uint64 processed;
DoCopy(pstate, (CopyStmt *) parsetree,
pstmt->stmt_location, pstmt->stmt_len,
&processed);
if (qc)
SetQueryCompletion(qc, CMDTAG_COPY, processed);
}
break;
case T_PrepareStmt:
CheckRestrictedOperation("PREPARE");
PrepareQuery(pstate, (PrepareStmt *) parsetree,
pstmt->stmt_location, pstmt->stmt_len);
break;
case T_ExecuteStmt:
ExecuteQuery(pstate,
(ExecuteStmt *) parsetree, NULL,
params,
dest, qc);
break;
case T_DeallocateStmt:
CheckRestrictedOperation("DEALLOCATE");
DeallocateQuery((DeallocateStmt *) parsetree);
break;
case T_GrantRoleStmt:
/* no event triggers for global objects */
GrantRole((GrantRoleStmt *) parsetree);
break;
case T_CreatedbStmt:
/* no event triggers for global objects */
PreventInTransactionBlock(isTopLevel, "CREATE DATABASE");
createdb(pstate, (CreatedbStmt *) parsetree);
break;
case T_AlterDatabaseStmt:
/* no event triggers for global objects */
AlterDatabase(pstate, (AlterDatabaseStmt *) parsetree, isTopLevel);
break;
case T_AlterDatabaseSetStmt:
/* no event triggers for global objects */
AlterDatabaseSet((AlterDatabaseSetStmt *) parsetree);
break;
case T_DropdbStmt:
/* no event triggers for global objects */
PreventInTransactionBlock(isTopLevel, "DROP DATABASE");
DropDatabase(pstate, (DropdbStmt *) parsetree);
break;
/* Query-level asynchronous notification */
case T_NotifyStmt:
{
NotifyStmt *stmt = (NotifyStmt *) parsetree;
Async_Notify(stmt->conditionname, stmt->payload);
}
break;
case T_ListenStmt:
{
ListenStmt *stmt = (ListenStmt *) parsetree;
CheckRestrictedOperation("LISTEN");
/*
* We don't allow LISTEN in background processes, as there is
* no mechanism for them to collect NOTIFY messages, so they'd
* just block cleanout of the async SLRU indefinitely.
* (Authors of custom background workers could bypass this
* restriction by calling Async_Listen directly, but then it's
* on them to provide some mechanism to process the message
* queue.) Note there seems no reason to forbid UNLISTEN.
*/
if (MyBackendType != B_BACKEND)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
/* translator: %s is name of a SQL command, eg LISTEN */
errmsg("cannot execute %s within a background process",
"LISTEN")));
Async_Listen(stmt->conditionname);
}
break;
case T_UnlistenStmt:
{
UnlistenStmt *stmt = (UnlistenStmt *) parsetree;
CheckRestrictedOperation("UNLISTEN");
if (stmt->conditionname)
Async_Unlisten(stmt->conditionname);
else
Async_UnlistenAll();
}
break;
case T_LoadStmt:
{
LoadStmt *stmt = (LoadStmt *) parsetree;
closeAllVfds(); /* probably not necessary... */
/* Allowed names are restricted if you're not superuser */
load_file(stmt->filename, !superuser());
}
break;
case T_CallStmt:
ExecuteCallStmt(castNode(CallStmt, parsetree), params, isAtomicContext, dest);
break;
case T_ClusterStmt:
cluster(pstate, (ClusterStmt *) parsetree, isTopLevel);
break;
case T_VacuumStmt:
ExecVacuum(pstate, (VacuumStmt *) parsetree, isTopLevel);
break;
case T_ExplainStmt:
ExplainQuery(pstate, (ExplainStmt *) parsetree, params, dest);
break;
case T_AlterSystemStmt:
PreventInTransactionBlock(isTopLevel, "ALTER SYSTEM");
AlterSystemSetConfigFile((AlterSystemStmt *) parsetree);
break;
case T_VariableSetStmt:
ExecSetVariableStmt((VariableSetStmt *) parsetree, isTopLevel);
break;
case T_VariableShowStmt:
{
VariableShowStmt *n = (VariableShowStmt *) parsetree;
GetPGVariable(n->name, dest);
}
break;
case T_DiscardStmt:
/* should we allow DISCARD PLANS? */
CheckRestrictedOperation("DISCARD");
DiscardCommand((DiscardStmt *) parsetree, isTopLevel);
break;
case T_CreateEventTrigStmt:
/* no event triggers on event triggers */
CreateEventTrigger((CreateEventTrigStmt *) parsetree);
break;
case T_AlterEventTrigStmt:
/* no event triggers on event triggers */
AlterEventTrigger((AlterEventTrigStmt *) parsetree);
break;
/*
* ******************************** ROLE statements ****
*/
case T_CreateRoleStmt:
/* no event triggers for global objects */
CreateRole(pstate, (CreateRoleStmt *) parsetree);
break;
case T_AlterRoleStmt:
/* no event triggers for global objects */
AlterRole((AlterRoleStmt *) parsetree);
break;
case T_AlterRoleSetStmt:
/* no event triggers for global objects */
AlterRoleSet((AlterRoleSetStmt *) parsetree);
break;
case T_DropRoleStmt:
/* no event triggers for global objects */
DropRole((DropRoleStmt *) parsetree);
break;
case T_ReassignOwnedStmt:
/* no event triggers for global objects */
ReassignOwnedObjects((ReassignOwnedStmt *) parsetree);
break;
case T_LockStmt:
/*
* Since the lock would just get dropped immediately, LOCK TABLE
* outside a transaction block is presumed to be user error.
*/
RequireTransactionBlock(isTopLevel, "LOCK TABLE");
LockTableCommand((LockStmt *) parsetree);
break;
case T_ConstraintsSetStmt:
WarnNoTransactionBlock(isTopLevel, "SET CONSTRAINTS");
AfterTriggerSetState((ConstraintsSetStmt *) parsetree);
break;
case T_CheckPointStmt:
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to do CHECKPOINT")));
RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_WAIT |
(RecoveryInProgress() ? 0 : CHECKPOINT_FORCE));
break;
case T_ReindexStmt:
ExecReindex(pstate, (ReindexStmt *) parsetree, isTopLevel);
break;
/*
* The following statements are supported by Event Triggers only
* in some cases, so we "fast path" them in the other cases.
*/
case T_GrantStmt:
{
GrantStmt *stmt = (GrantStmt *) parsetree;
if (EventTriggerSupportsObjectType(stmt->objtype))
ProcessUtilitySlow(pstate, pstmt, queryString,
context, params, queryEnv,
dest, qc);
else
ExecuteGrantStmt(stmt);
}
break;
case T_DropStmt:
{
DropStmt *stmt = (DropStmt *) parsetree;
if (EventTriggerSupportsObjectType(stmt->removeType))
ProcessUtilitySlow(pstate, pstmt, queryString,
context, params, queryEnv,
dest, qc);
else
ExecDropStmt(stmt, isTopLevel);
}
break;
case T_RenameStmt:
{
RenameStmt *stmt = (RenameStmt *) parsetree;
if (EventTriggerSupportsObjectType(stmt->renameType))
ProcessUtilitySlow(pstate, pstmt, queryString,
context, params, queryEnv,
dest, qc);
else
ExecRenameStmt(stmt);
}
break;
case T_AlterObjectDependsStmt:
{
AlterObjectDependsStmt *stmt = (AlterObjectDependsStmt *) parsetree;
if (EventTriggerSupportsObjectType(stmt->objectType))
ProcessUtilitySlow(pstate, pstmt, queryString,
context, params, queryEnv,
dest, qc);
else
ExecAlterObjectDependsStmt(stmt, NULL);
}
break;
case T_AlterObjectSchemaStmt:
{
AlterObjectSchemaStmt *stmt = (AlterObjectSchemaStmt *) parsetree;
if (EventTriggerSupportsObjectType(stmt->objectType))
ProcessUtilitySlow(pstate, pstmt, queryString,
context, params, queryEnv,
dest, qc);
else
ExecAlterObjectSchemaStmt(stmt, NULL);
}
break;
case T_AlterOwnerStmt:
{
AlterOwnerStmt *stmt = (AlterOwnerStmt *) parsetree;
if (EventTriggerSupportsObjectType(stmt->objectType))
ProcessUtilitySlow(pstate, pstmt, queryString,
context, params, queryEnv,
dest, qc);
else
ExecAlterOwnerStmt(stmt);
}
break;
case T_CommentStmt:
{
CommentStmt *stmt = (CommentStmt *) parsetree;
if (EventTriggerSupportsObjectType(stmt->objtype))
ProcessUtilitySlow(pstate, pstmt, queryString,
context, params, queryEnv,
dest, qc);
else
CommentObject(stmt);
break;
}
case T_SecLabelStmt:
{
SecLabelStmt *stmt = (SecLabelStmt *) parsetree;
if (EventTriggerSupportsObjectType(stmt->objtype))
ProcessUtilitySlow(pstate, pstmt, queryString,
context, params, queryEnv,
dest, qc);
else
ExecSecLabelStmt(stmt);
break;
}
default:
/* All other statement types have event trigger support */
ProcessUtilitySlow(pstate, pstmt, queryString,
context, params, queryEnv,
dest, qc);
break;
}
free_parsestate(pstate);
/*
* Make effects of commands visible, for instance so that
* PreCommit_on_commit_actions() can see them (see for example bug
* #15631).
*/
CommandCounterIncrement();
}
/*
* The "Slow" variant of ProcessUtility should only receive statements
* supported by the event triggers facility. Therefore, we always
* perform the trigger support calls if the context allows it.
*/
static void
ProcessUtilitySlow(ParseState *pstate,
PlannedStmt *pstmt,
const char *queryString,
ProcessUtilityContext context,
ParamListInfo params,
QueryEnvironment *queryEnv,
DestReceiver *dest,
QueryCompletion *qc)
{
Node *parsetree = pstmt->utilityStmt;
bool isTopLevel = (context == PROCESS_UTILITY_TOPLEVEL);
bool isCompleteQuery = (context != PROCESS_UTILITY_SUBCOMMAND);
bool needCleanup;
bool commandCollected = false;
ObjectAddress address;
ObjectAddress secondaryObject = InvalidObjectAddress;
/* All event trigger calls are done only when isCompleteQuery is true */
needCleanup = isCompleteQuery && EventTriggerBeginCompleteQuery();
/* PG_TRY block is to ensure we call EventTriggerEndCompleteQuery */
PG_TRY();
{
if (isCompleteQuery)
EventTriggerDDLCommandStart(parsetree);
switch (nodeTag(parsetree))
{
/*
* relation and attribute manipulation
*/
case T_CreateSchemaStmt:
CreateSchemaCommand((CreateSchemaStmt *) parsetree,
queryString,
pstmt->stmt_location,
pstmt->stmt_len);
/*
* EventTriggerCollectSimpleCommand called by
* CreateSchemaCommand
*/
commandCollected = true;
break;
case T_CreateStmt:
case T_CreateForeignTableStmt:
{
List *stmts;
RangeVar *table_rv = NULL;
/* Run parse analysis ... */
stmts = transformCreateStmt((CreateStmt *) parsetree,
queryString);
/*
* ... and do it. We can't use foreach() because we may
* modify the list midway through, so pick off the
* elements one at a time, the hard way.
*/
while (stmts != NIL)
{
Node *stmt = (Node *) linitial(stmts);
stmts = list_delete_first(stmts);
if (IsA(stmt, CreateStmt))
{
CreateStmt *cstmt = (CreateStmt *) stmt;
Datum toast_options;
static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
/* Remember transformed RangeVar for LIKE */
table_rv = cstmt->relation;
/* Create the table itself */
address = DefineRelation(cstmt,
RELKIND_RELATION,
InvalidOid, NULL,
queryString);
EventTriggerCollectSimpleCommand(address,
secondaryObject,
stmt);
/*
* Let NewRelationCreateToastTable decide if this
* one needs a secondary relation too.
*/
CommandCounterIncrement();
/*
* parse and validate reloptions for the toast
* table
*/
toast_options = transformRelOptions((Datum) 0,
cstmt->options,
"toast",
validnsps,
true,
false);
(void) heap_reloptions(RELKIND_TOASTVALUE,
toast_options,
true);
NewRelationCreateToastTable(address.objectId,
toast_options);
}
else if (IsA(stmt, CreateForeignTableStmt))
{
CreateForeignTableStmt *cstmt = (CreateForeignTableStmt *) stmt;
/* Remember transformed RangeVar for LIKE */
table_rv = cstmt->base.relation;
/* Create the table itself */
address = DefineRelation(&cstmt->base,
RELKIND_FOREIGN_TABLE,
InvalidOid, NULL,
queryString);
CreateForeignTable(cstmt,
address.objectId);
EventTriggerCollectSimpleCommand(address,
secondaryObject,
stmt);
}
else if (IsA(stmt, TableLikeClause))
{
/*
* Do delayed processing of LIKE options. This
* will result in additional sub-statements for us
* to process. Those should get done before any
* remaining actions, so prepend them to "stmts".
*/
TableLikeClause *like = (TableLikeClause *) stmt;
List *morestmts;
Assert(table_rv != NULL);
morestmts = expandTableLikeClause(table_rv, like);
stmts = list_concat(morestmts, stmts);
}
else
{
/*
* Recurse for anything else. Note the recursive
* call will stash the objects so created into our
* event trigger context.
*/
PlannedStmt *wrapper;
wrapper = makeNode(PlannedStmt);
wrapper->commandType = CMD_UTILITY;
wrapper->canSetTag = false;
wrapper->utilityStmt = stmt;
wrapper->stmt_location = pstmt->stmt_location;
wrapper->stmt_len = pstmt->stmt_len;
ProcessUtility(wrapper,
queryString,
false,
PROCESS_UTILITY_SUBCOMMAND,
params,
NULL,
None_Receiver,
NULL);
}
/* Need CCI between commands */
if (stmts != NIL)
CommandCounterIncrement();
}
/*
* The multiple commands generated here are stashed
* individually, so disable collection below.
*/
commandCollected = true;
}
break;
case T_AlterTableStmt:
{
AlterTableStmt *atstmt = (AlterTableStmt *) parsetree;
Oid relid;
LOCKMODE lockmode;
ListCell *cell;
/*
* Disallow ALTER TABLE .. DETACH CONCURRENTLY in a
* transaction block or function. (Perhaps it could be
* allowed in a procedure, but don't hold your breath.)
*/
foreach(cell, atstmt->cmds)
{
AlterTableCmd *cmd = (AlterTableCmd *) lfirst(cell);
/* Disallow DETACH CONCURRENTLY in a transaction block */
if (cmd->subtype == AT_DetachPartition)
{
if (((PartitionCmd *) cmd->def)->concurrent)
PreventInTransactionBlock(isTopLevel,
"ALTER TABLE ... DETACH CONCURRENTLY");
}
}
/*
* Figure out lock mode, and acquire lock. This also does
* basic permissions checks, so that we won't wait for a
* lock on (for example) a relation on which we have no
* permissions.
*/
lockmode = AlterTableGetLockLevel(atstmt->cmds);
relid = AlterTableLookupRelation(atstmt, lockmode);
if (OidIsValid(relid))
{
AlterTableUtilityContext atcontext;
/* Set up info needed for recursive callbacks ... */
atcontext.pstmt = pstmt;
atcontext.queryString = queryString;
atcontext.relid = relid;
atcontext.params = params;
atcontext.queryEnv = queryEnv;
/* ... ensure we have an event trigger context ... */
EventTriggerAlterTableStart(parsetree);
EventTriggerAlterTableRelid(relid);
/* ... and do it */
AlterTable(atstmt, lockmode, &atcontext);
/* done */
EventTriggerAlterTableEnd();
}
else
ereport(NOTICE,
(errmsg("relation \"%s\" does not exist, skipping",
atstmt->relation->relname)));
}
/* ALTER TABLE stashes commands internally */
commandCollected = true;
break;
case T_AlterDomainStmt:
{
AlterDomainStmt *stmt = (AlterDomainStmt *) parsetree;
/*
* Some or all of these functions are recursive to cover
* inherited things, so permission checks are done there.
*/
switch (stmt->subtype)
{
case 'T': /* ALTER DOMAIN DEFAULT */
/*
* Recursively alter column default for table and,
* if requested, for descendants
*/
address =
AlterDomainDefault(stmt->typeName,
stmt->def);
break;
case 'N': /* ALTER DOMAIN DROP NOT NULL */
address =
AlterDomainNotNull(stmt->typeName,
false);
break;
case 'O': /* ALTER DOMAIN SET NOT NULL */
address =
AlterDomainNotNull(stmt->typeName,
true);
break;
case 'C': /* ADD CONSTRAINT */
address =
AlterDomainAddConstraint(stmt->typeName,
stmt->def,
&secondaryObject);
break;
case 'X': /* DROP CONSTRAINT */
address =
AlterDomainDropConstraint(stmt->typeName,
stmt->name,
stmt->behavior,
stmt->missing_ok);
break;
case 'V': /* VALIDATE CONSTRAINT */
address =
AlterDomainValidateConstraint(stmt->typeName,
stmt->name);
break;
default: /* oops */
elog(ERROR, "unrecognized alter domain type: %d",
(int) stmt->subtype);
break;
}
}
break;
/*
* ************* object creation / destruction **************
*/
case T_DefineStmt:
{
DefineStmt *stmt = (DefineStmt *) parsetree;
switch (stmt->kind)
{
case OBJECT_AGGREGATE:
address =
DefineAggregate(pstate, stmt->defnames, stmt->args,
stmt->oldstyle,
stmt->definition,
stmt->replace);
break;
case OBJECT_OPERATOR:
Assert(stmt->args == NIL);
address = DefineOperator(stmt->defnames,
stmt->definition);
break;
case OBJECT_TYPE:
Assert(stmt->args == NIL);
address = DefineType(pstate,
stmt->defnames,
stmt->definition);
break;
case OBJECT_TSPARSER:
Assert(stmt->args == NIL);
address = DefineTSParser(stmt->defnames,
stmt->definition);
break;
case OBJECT_TSDICTIONARY:
Assert(stmt->args == NIL);
address = DefineTSDictionary(stmt->defnames,
stmt->definition);
break;
case OBJECT_TSTEMPLATE:
Assert(stmt->args == NIL);
address = DefineTSTemplate(stmt->defnames,
stmt->definition);
break;
case OBJECT_TSCONFIGURATION:
Assert(stmt->args == NIL);
address = DefineTSConfiguration(stmt->defnames,
stmt->definition,
&secondaryObject);
break;
case OBJECT_COLLATION:
Assert(stmt->args == NIL);
address = DefineCollation(pstate,
stmt->defnames,
stmt->definition,
stmt->if_not_exists);
break;
default:
elog(ERROR, "unrecognized define stmt type: %d",
(int) stmt->kind);
break;
}
}
break;
case T_IndexStmt: /* CREATE INDEX */
{
IndexStmt *stmt = (IndexStmt *) parsetree;
Oid relid;
LOCKMODE lockmode;
bool is_alter_table;
if (stmt->concurrent)
PreventInTransactionBlock(isTopLevel,
"CREATE INDEX CONCURRENTLY");
/*
* Look up the relation OID just once, right here at the
* beginning, so that we don't end up repeating the name
* lookup later and latching onto a different relation
* partway through. To avoid lock upgrade hazards, it's
* important that we take the strongest lock that will
* eventually be needed here, so the lockmode calculation
* needs to match what DefineIndex() does.
*/
lockmode = stmt->concurrent ? ShareUpdateExclusiveLock
: ShareLock;
relid =
RangeVarGetRelidExtended(stmt->relation, lockmode,
0,
RangeVarCallbackOwnsRelation,
NULL);
/*
* CREATE INDEX on partitioned tables (but not regular
* inherited tables) recurses to partitions, so we must
* acquire locks early to avoid deadlocks.
*
* We also take the opportunity to verify that all
* partitions are something we can put an index on, to
* avoid building some indexes only to fail later.
*/
if (stmt->relation->inh &&
get_rel_relkind(relid) == RELKIND_PARTITIONED_TABLE)
{
ListCell *lc;
List *inheritors = NIL;
inheritors = find_all_inheritors(relid, lockmode, NULL);
foreach(lc, inheritors)
{
char relkind = get_rel_relkind(lfirst_oid(lc));
if (relkind != RELKIND_RELATION &&
relkind != RELKIND_MATVIEW &&
relkind != RELKIND_PARTITIONED_TABLE &&
relkind != RELKIND_FOREIGN_TABLE)
elog(ERROR, "unexpected relkind \"%c\" on partition \"%s\"",
relkind, stmt->relation->relname);
if (relkind == RELKIND_FOREIGN_TABLE &&
(stmt->unique || stmt->primary))
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("cannot create unique index on partitioned table \"%s\"",
stmt->relation->relname),
errdetail("Table \"%s\" contains partitions that are foreign tables.",
stmt->relation->relname)));
}
list_free(inheritors);
}
/*
* If the IndexStmt is already transformed, it must have
* come from generateClonedIndexStmt, which in current
* usage means it came from expandTableLikeClause rather
* than from original parse analysis. And that means we
* must treat it like ALTER TABLE ADD INDEX, not CREATE.
* (This is a bit grotty, but currently it doesn't seem
* worth adding a separate bool field for the purpose.)
*/
is_alter_table = stmt->transformed;
/* Run parse analysis ... */
stmt = transformIndexStmt(relid, stmt, queryString);
/* ... and do it */
EventTriggerAlterTableStart(parsetree);
address =
DefineIndex(relid, /* OID of heap relation */
stmt,
InvalidOid, /* no predefined OID */
InvalidOid, /* no parent index */
InvalidOid, /* no parent constraint */
is_alter_table,
true, /* check_rights */
true, /* check_not_in_use */
false, /* skip_build */
false); /* quiet */
/*
* Add the CREATE INDEX node itself to stash right away;
* if there were any commands stashed in the ALTER TABLE
* code, we need them to appear after this one.
*/
EventTriggerCollectSimpleCommand(address, secondaryObject,
parsetree);
commandCollected = true;
EventTriggerAlterTableEnd();
}
break;
case T_CreateExtensionStmt:
address = CreateExtension(pstate, (CreateExtensionStmt *) parsetree);
break;
case T_AlterExtensionStmt:
address = ExecAlterExtensionStmt(pstate, (AlterExtensionStmt *) parsetree);
break;
case T_AlterExtensionContentsStmt:
address = ExecAlterExtensionContentsStmt((AlterExtensionContentsStmt *) parsetree,
&secondaryObject);
break;
case T_CreateFdwStmt:
address = CreateForeignDataWrapper((CreateFdwStmt *) parsetree);
break;
case T_AlterFdwStmt:
address = AlterForeignDataWrapper((AlterFdwStmt *) parsetree);
break;
case T_CreateForeignServerStmt:
address = CreateForeignServer((CreateForeignServerStmt *) parsetree);
break;
case T_AlterForeignServerStmt:
address = AlterForeignServer((AlterForeignServerStmt *) parsetree);
break;
case T_CreateUserMappingStmt:
address = CreateUserMapping((CreateUserMappingStmt *) parsetree);
break;
case T_AlterUserMappingStmt:
address = AlterUserMapping((AlterUserMappingStmt *) parsetree);
break;
case T_DropUserMappingStmt:
RemoveUserMapping((DropUserMappingStmt *) parsetree);
/* no commands stashed for DROP */
commandCollected = true;
break;
case T_ImportForeignSchemaStmt:
ImportForeignSchema((ImportForeignSchemaStmt *) parsetree);
/* commands are stashed inside ImportForeignSchema */
commandCollected = true;
break;
case T_CompositeTypeStmt: /* CREATE TYPE (composite) */
{
CompositeTypeStmt *stmt = (CompositeTypeStmt *) parsetree;
address = DefineCompositeType(stmt->typevar,
stmt->coldeflist);
}
break;
case T_CreateEnumStmt: /* CREATE TYPE AS ENUM */
address = DefineEnum((CreateEnumStmt *) parsetree);
break;
case T_CreateRangeStmt: /* CREATE TYPE AS RANGE */
address = DefineRange((CreateRangeStmt *) parsetree);
break;
case T_AlterEnumStmt: /* ALTER TYPE (enum) */
address = AlterEnum((AlterEnumStmt *) parsetree);
break;
case T_ViewStmt: /* CREATE VIEW */
EventTriggerAlterTableStart(parsetree);
address = DefineView((ViewStmt *) parsetree, queryString,
pstmt->stmt_location, pstmt->stmt_len);
EventTriggerCollectSimpleCommand(address, secondaryObject,
parsetree);
/* stashed internally */
commandCollected = true;
EventTriggerAlterTableEnd();
break;
case T_CreateFunctionStmt: /* CREATE FUNCTION */
address = CreateFunction(pstate, (CreateFunctionStmt *) parsetree);
break;
case T_AlterFunctionStmt: /* ALTER FUNCTION */
address = AlterFunction(pstate, (AlterFunctionStmt *) parsetree);
break;
case T_RuleStmt: /* CREATE RULE */
address = DefineRule((RuleStmt *) parsetree, queryString);
break;
case T_CreateSeqStmt:
address = DefineSequence(pstate, (CreateSeqStmt *) parsetree);
break;
case T_AlterSeqStmt:
address = AlterSequence(pstate, (AlterSeqStmt *) parsetree);
break;
case T_CreateTableAsStmt:
address = ExecCreateTableAs(pstate, (CreateTableAsStmt *) parsetree,
params, queryEnv, qc);
break;
case T_RefreshMatViewStmt:
/*
* REFRESH CONCURRENTLY executes some DDL commands internally.
* Inhibit DDL command collection here to avoid those commands
* from showing up in the deparsed command queue. The refresh
* command itself is queued, which is enough.
*/
EventTriggerInhibitCommandCollection();
PG_TRY();
{
address = ExecRefreshMatView((RefreshMatViewStmt *) parsetree,
queryString, params, qc);
}
PG_FINALLY();
{
EventTriggerUndoInhibitCommandCollection();
}
PG_END_TRY();
break;
case T_CreateTrigStmt:
address = CreateTrigger((CreateTrigStmt *) parsetree,
queryString, InvalidOid, InvalidOid,
InvalidOid, InvalidOid, InvalidOid,
InvalidOid, NULL, false, false);
break;
case T_CreatePLangStmt:
address = CreateProceduralLanguage((CreatePLangStmt *) parsetree);
break;
case T_CreateDomainStmt:
address = DefineDomain((CreateDomainStmt *) parsetree);
break;
case T_CreateConversionStmt:
address = CreateConversionCommand((CreateConversionStmt *) parsetree);
break;
case T_CreateCastStmt:
address = CreateCast((CreateCastStmt *) parsetree);
break;
case T_CreateOpClassStmt:
DefineOpClass((CreateOpClassStmt *) parsetree);
/* command is stashed in DefineOpClass */
commandCollected = true;
break;
case T_CreateOpFamilyStmt:
address = DefineOpFamily((CreateOpFamilyStmt *) parsetree);
/*
* DefineOpFamily calls EventTriggerCollectSimpleCommand
* directly.
*/
commandCollected = true;
break;
case T_CreateTransformStmt:
address = CreateTransform((CreateTransformStmt *) parsetree);
break;
case T_AlterOpFamilyStmt:
AlterOpFamily((AlterOpFamilyStmt *) parsetree);
/* commands are stashed in AlterOpFamily */
commandCollected = true;
break;
case T_AlterTSDictionaryStmt:
address = AlterTSDictionary((AlterTSDictionaryStmt *) parsetree);
break;
case T_AlterTSConfigurationStmt:
AlterTSConfiguration((AlterTSConfigurationStmt *) parsetree);
/*
* Commands are stashed in MakeConfigurationMapping and
* DropConfigurationMapping, which are called from
* AlterTSConfiguration
*/
commandCollected = true;
break;
case T_AlterTableMoveAllStmt:
AlterTableMoveAll((AlterTableMoveAllStmt *) parsetree);
/* commands are stashed in AlterTableMoveAll */
commandCollected = true;
break;
case T_DropStmt:
ExecDropStmt((DropStmt *) parsetree, isTopLevel);
/* no commands stashed for DROP */
commandCollected = true;
break;
case T_RenameStmt:
address = ExecRenameStmt((RenameStmt *) parsetree);
break;
case T_AlterObjectDependsStmt:
address =
ExecAlterObjectDependsStmt((AlterObjectDependsStmt *) parsetree,
&secondaryObject);
break;
case T_AlterObjectSchemaStmt:
address =
ExecAlterObjectSchemaStmt((AlterObjectSchemaStmt *) parsetree,
&secondaryObject);
break;
case T_AlterOwnerStmt:
address = ExecAlterOwnerStmt((AlterOwnerStmt *) parsetree);
break;
case T_AlterOperatorStmt:
address = AlterOperator((AlterOperatorStmt *) parsetree);
break;
case T_AlterTypeStmt:
address = AlterType((AlterTypeStmt *) parsetree);
break;
case T_CommentStmt:
address = CommentObject((CommentStmt *) parsetree);
break;
case T_GrantStmt:
ExecuteGrantStmt((GrantStmt *) parsetree);
/* commands are stashed in ExecGrantStmt_oids */
commandCollected = true;
break;
case T_DropOwnedStmt:
DropOwnedObjects((DropOwnedStmt *) parsetree);
/* no commands stashed for DROP */
commandCollected = true;
break;
case T_AlterDefaultPrivilegesStmt:
ExecAlterDefaultPrivilegesStmt(pstate, (AlterDefaultPrivilegesStmt *) parsetree);
EventTriggerCollectAlterDefPrivs((AlterDefaultPrivilegesStmt *) parsetree);
commandCollected = true;
break;
case T_CreatePolicyStmt: /* CREATE POLICY */
address = CreatePolicy((CreatePolicyStmt *) parsetree);
break;
case T_AlterPolicyStmt: /* ALTER POLICY */
address = AlterPolicy((AlterPolicyStmt *) parsetree);
break;
case T_SecLabelStmt:
address = ExecSecLabelStmt((SecLabelStmt *) parsetree);
break;
case T_CreateAmStmt:
address = CreateAccessMethod((CreateAmStmt *) parsetree);
break;
case T_CreatePublicationStmt:
address = CreatePublication((CreatePublicationStmt *) parsetree);
break;
case T_AlterPublicationStmt:
AlterPublication((AlterPublicationStmt *) parsetree);
/*
* AlterPublication calls EventTriggerCollectSimpleCommand
* directly
*/
commandCollected = true;
break;
case T_CreateSubscriptionStmt:
address = CreateSubscription((CreateSubscriptionStmt *) parsetree,
isTopLevel);
break;
case T_AlterSubscriptionStmt:
address = AlterSubscription((AlterSubscriptionStmt *) parsetree,
isTopLevel);
break;
case T_DropSubscriptionStmt:
DropSubscription((DropSubscriptionStmt *) parsetree, isTopLevel);
/* no commands stashed for DROP */
commandCollected = true;
break;
case T_CreateStatsStmt:
{
Oid relid;
CreateStatsStmt *stmt = (CreateStatsStmt *) parsetree;
RangeVar *rel = (RangeVar *) linitial(stmt->relations);
if (!IsA(rel, RangeVar))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("only a single relation is allowed in CREATE STATISTICS")));
/*
* CREATE STATISTICS will influence future execution plans
* but does not interfere with currently executing plans.
* So it should be enough to take ShareUpdateExclusiveLock
* on relation, conflicting with ANALYZE and other DDL
* that sets statistical information, but not with normal
* queries.
*
* XXX RangeVarCallbackOwnsRelation not needed here, to
* keep the same behavior as before.
*/
relid = RangeVarGetRelid(rel, ShareUpdateExclusiveLock, false);
/* Run parse analysis ... */
stmt = transformStatsStmt(relid, stmt, queryString);
address = CreateStatistics(stmt);
}
break;
case T_AlterStatsStmt:
address = AlterStatistics((AlterStatsStmt *) parsetree);
break;
case T_AlterCollationStmt:
address = AlterCollation((AlterCollationStmt *) parsetree);
break;
default:
elog(ERROR, "unrecognized node type: %d",
(int) nodeTag(parsetree));
break;
}
/*
* Remember the object so that ddl_command_end event triggers have
* access to it.
*/
if (!commandCollected)
EventTriggerCollectSimpleCommand(address, secondaryObject,
parsetree);
if (isCompleteQuery)
{
EventTriggerSQLDrop(parsetree);
EventTriggerDDLCommandEnd(parsetree);
}
}
PG_FINALLY();
{
if (needCleanup)
EventTriggerEndCompleteQuery();
}
PG_END_TRY();
}
/*
* ProcessUtilityForAlterTable
* Recursive entry from ALTER TABLE
*
* ALTER TABLE sometimes generates subcommands such as CREATE INDEX.
* It calls this, not the main entry point ProcessUtility, to execute
* such subcommands.
*
* stmt: the utility command to execute
* context: opaque passthrough struct with the info we need
*
* It's caller's responsibility to do CommandCounterIncrement after
* calling this, if needed.
*/
void
ProcessUtilityForAlterTable(Node *stmt, AlterTableUtilityContext *context)
{
PlannedStmt *wrapper;
/*
* For event triggers, we must "close" the current complex-command set,
* and start a new one afterwards; this is needed to ensure the ordering
* of command events is consistent with the way they were executed.
*/
EventTriggerAlterTableEnd();
/* Create a suitable wrapper */
wrapper = makeNode(PlannedStmt);
wrapper->commandType = CMD_UTILITY;
wrapper->canSetTag = false;
wrapper->utilityStmt = stmt;
wrapper->stmt_location = context->pstmt->stmt_location;
wrapper->stmt_len = context->pstmt->stmt_len;
ProcessUtility(wrapper,
context->queryString,
false,
PROCESS_UTILITY_SUBCOMMAND,
context->params,
context->queryEnv,
None_Receiver,
NULL);
EventTriggerAlterTableStart(context->pstmt->utilityStmt);
EventTriggerAlterTableRelid(context->relid);
}
/*
* Dispatch function for DropStmt
*/
static void
ExecDropStmt(DropStmt *stmt, bool isTopLevel)
{
switch (stmt->removeType)
{
case OBJECT_INDEX:
if (stmt->concurrent)
PreventInTransactionBlock(isTopLevel,
"DROP INDEX CONCURRENTLY");
/* fall through */
case OBJECT_TABLE:
case OBJECT_SEQUENCE:
case OBJECT_VIEW:
case OBJECT_MATVIEW:
case OBJECT_FOREIGN_TABLE:
RemoveRelations(stmt);
break;
default:
RemoveObjects(stmt);
break;
}
}
/*
* UtilityReturnsTuples
* Return "true" if this utility statement will send output to the
* destination.
*
* Generally, there should be a case here for each case in ProcessUtility
* where "dest" is passed on.
*/
bool
UtilityReturnsTuples(Node *parsetree)
{
switch (nodeTag(parsetree))
{
case T_CallStmt:
{
CallStmt *stmt = (CallStmt *) parsetree;
return (stmt->funcexpr->funcresulttype == RECORDOID);
}
case T_FetchStmt:
{
FetchStmt *stmt = (FetchStmt *) parsetree;
Portal portal;
if (stmt->ismove)
return false;
portal = GetPortalByName(stmt->portalname);
if (!PortalIsValid(portal))
return false; /* not our business to raise error */
return portal->tupDesc ? true : false;
}
case T_ExecuteStmt:
{
ExecuteStmt *stmt = (ExecuteStmt *) parsetree;
PreparedStatement *entry;
entry = FetchPreparedStatement(stmt->name, false);
if (!entry)
return false; /* not our business to raise error */
if (entry->plansource->resultDesc)
return true;
return false;
}
case T_ExplainStmt:
return true;
case T_VariableShowStmt:
return true;
default:
return false;
}
}
/*
* UtilityTupleDescriptor
* Fetch the actual output tuple descriptor for a utility statement
* for which UtilityReturnsTuples() previously returned "true".
*
* The returned descriptor is created in (or copied into) the current memory
* context.
*/
TupleDesc
UtilityTupleDescriptor(Node *parsetree)
{
switch (nodeTag(parsetree))
{
case T_CallStmt:
return CallStmtResultDesc((CallStmt *) parsetree);
case T_FetchStmt:
{
FetchStmt *stmt = (FetchStmt *) parsetree;
Portal portal;
if (stmt->ismove)
return NULL;
portal = GetPortalByName(stmt->portalname);
if (!PortalIsValid(portal))
return NULL; /* not our business to raise error */
return CreateTupleDescCopy(portal->tupDesc);
}
case T_ExecuteStmt:
{
ExecuteStmt *stmt = (ExecuteStmt *) parsetree;
PreparedStatement *entry;
entry = FetchPreparedStatement(stmt->name, false);
if (!entry)
return NULL; /* not our business to raise error */
return FetchPreparedStatementResultDesc(entry);
}
case T_ExplainStmt:
return ExplainResultDesc((ExplainStmt *) parsetree);
case T_VariableShowStmt:
{
VariableShowStmt *n = (VariableShowStmt *) parsetree;
return GetPGVariableResultDesc(n->name);
}
default:
return NULL;
}
}
/*
* QueryReturnsTuples
* Return "true" if this Query will send output to the destination.
*/
#ifdef NOT_USED
bool
QueryReturnsTuples(Query *parsetree)
{
switch (parsetree->commandType)
{
case CMD_SELECT:
/* returns tuples */
return true;
case CMD_INSERT:
case CMD_UPDATE:
case CMD_DELETE:
/* the forms with RETURNING return tuples */
if (parsetree->returningList)
return true;
break;
case CMD_UTILITY:
return UtilityReturnsTuples(parsetree->utilityStmt);
case CMD_UNKNOWN:
case CMD_NOTHING:
/* probably shouldn't get here */
break;
}
return false; /* default */
}
#endif
/*
* UtilityContainsQuery
* Return the contained Query, or NULL if there is none
*
* Certain utility statements, such as EXPLAIN, contain a plannable Query.
* This function encapsulates knowledge of exactly which ones do.
* We assume it is invoked only on already-parse-analyzed statements
* (else the contained parsetree isn't a Query yet).
*
* In some cases (currently, only EXPLAIN of CREATE TABLE AS/SELECT INTO and
* CREATE MATERIALIZED VIEW), potentially Query-containing utility statements
* can be nested. This function will drill down to a non-utility Query, or
* return NULL if none.
*/
Query *
UtilityContainsQuery(Node *parsetree)
{
Query *qry;
switch (nodeTag(parsetree))
{
case T_DeclareCursorStmt:
qry = castNode(Query, ((DeclareCursorStmt *) parsetree)->query);
if (qry->commandType == CMD_UTILITY)
return UtilityContainsQuery(qry->utilityStmt);
return qry;
case T_ExplainStmt:
qry = castNode(Query, ((ExplainStmt *) parsetree)->query);
if (qry->commandType == CMD_UTILITY)
return UtilityContainsQuery(qry->utilityStmt);
return qry;
case T_CreateTableAsStmt:
qry = castNode(Query, ((CreateTableAsStmt *) parsetree)->query);
if (qry->commandType == CMD_UTILITY)
return UtilityContainsQuery(qry->utilityStmt);
return qry;
default:
return NULL;
}
}
/*
* AlterObjectTypeCommandTag
* helper function for CreateCommandTag
*
* This covers most cases where ALTER is used with an ObjectType enum.
*/
static CommandTag
AlterObjectTypeCommandTag(ObjectType objtype)
{
CommandTag tag;
switch (objtype)
{
case OBJECT_AGGREGATE:
tag = CMDTAG_ALTER_AGGREGATE;
break;
case OBJECT_ATTRIBUTE:
tag = CMDTAG_ALTER_TYPE;
break;
case OBJECT_CAST:
tag = CMDTAG_ALTER_CAST;
break;
case OBJECT_COLLATION:
tag = CMDTAG_ALTER_COLLATION;
break;
case OBJECT_COLUMN:
tag = CMDTAG_ALTER_TABLE;
break;
case OBJECT_CONVERSION:
tag = CMDTAG_ALTER_CONVERSION;
break;
case OBJECT_DATABASE:
tag = CMDTAG_ALTER_DATABASE;
break;
case OBJECT_DOMAIN:
case OBJECT_DOMCONSTRAINT:
tag = CMDTAG_ALTER_DOMAIN;
break;
case OBJECT_EXTENSION:
tag = CMDTAG_ALTER_EXTENSION;
break;
case OBJECT_FDW:
tag = CMDTAG_ALTER_FOREIGN_DATA_WRAPPER;
break;
case OBJECT_FOREIGN_SERVER:
tag = CMDTAG_ALTER_SERVER;
break;
case OBJECT_FOREIGN_TABLE:
tag = CMDTAG_ALTER_FOREIGN_TABLE;
break;
case OBJECT_FUNCTION:
tag = CMDTAG_ALTER_FUNCTION;
break;
case OBJECT_INDEX:
tag = CMDTAG_ALTER_INDEX;
break;
case OBJECT_LANGUAGE:
tag = CMDTAG_ALTER_LANGUAGE;
break;
case OBJECT_LARGEOBJECT:
tag = CMDTAG_ALTER_LARGE_OBJECT;
break;
case OBJECT_OPCLASS:
tag = CMDTAG_ALTER_OPERATOR_CLASS;
break;
case OBJECT_OPERATOR:
tag = CMDTAG_ALTER_OPERATOR;
break;
case OBJECT_OPFAMILY:
tag = CMDTAG_ALTER_OPERATOR_FAMILY;
break;
case OBJECT_POLICY:
tag = CMDTAG_ALTER_POLICY;
break;
case OBJECT_PROCEDURE:
tag = CMDTAG_ALTER_PROCEDURE;
break;
case OBJECT_ROLE:
tag = CMDTAG_ALTER_ROLE;
break;
case OBJECT_ROUTINE:
tag = CMDTAG_ALTER_ROUTINE;
break;
case OBJECT_RULE:
tag = CMDTAG_ALTER_RULE;
break;
case OBJECT_SCHEMA:
tag = CMDTAG_ALTER_SCHEMA;
break;
case OBJECT_SEQUENCE:
tag = CMDTAG_ALTER_SEQUENCE;
break;
case OBJECT_TABLE:
case OBJECT_TABCONSTRAINT:
tag = CMDTAG_ALTER_TABLE;
break;
case OBJECT_TABLESPACE:
tag = CMDTAG_ALTER_TABLESPACE;
break;
case OBJECT_TRIGGER:
tag = CMDTAG_ALTER_TRIGGER;
break;
case OBJECT_EVENT_TRIGGER:
tag = CMDTAG_ALTER_EVENT_TRIGGER;
break;
case OBJECT_TSCONFIGURATION:
tag = CMDTAG_ALTER_TEXT_SEARCH_CONFIGURATION;
break;
case OBJECT_TSDICTIONARY:
tag = CMDTAG_ALTER_TEXT_SEARCH_DICTIONARY;
break;
case OBJECT_TSPARSER:
tag = CMDTAG_ALTER_TEXT_SEARCH_PARSER;
break;
case OBJECT_TSTEMPLATE:
tag = CMDTAG_ALTER_TEXT_SEARCH_TEMPLATE;
break;
case OBJECT_TYPE:
tag = CMDTAG_ALTER_TYPE;
break;
case OBJECT_VIEW:
tag = CMDTAG_ALTER_VIEW;
break;
case OBJECT_MATVIEW:
tag = CMDTAG_ALTER_MATERIALIZED_VIEW;
break;
case OBJECT_PUBLICATION:
tag = CMDTAG_ALTER_PUBLICATION;
break;
case OBJECT_SUBSCRIPTION:
tag = CMDTAG_ALTER_SUBSCRIPTION;
break;
case OBJECT_STATISTIC_EXT:
tag = CMDTAG_ALTER_STATISTICS;
break;
default:
tag = CMDTAG_UNKNOWN;
break;
}
return tag;
}
/*
* CreateCommandTag
* utility to get a CommandTag for the command operation,
* given either a raw (un-analyzed) parsetree, an analyzed Query,
* or a PlannedStmt.
*
* This must handle all command types, but since the vast majority
* of 'em are utility commands, it seems sensible to keep it here.
*/
CommandTag
CreateCommandTag(Node *parsetree)
{
CommandTag tag;
switch (nodeTag(parsetree))
{
/* recurse if we're given a RawStmt */
case T_RawStmt:
tag = CreateCommandTag(((RawStmt *) parsetree)->stmt);
break;
/* raw plannable queries */
case T_InsertStmt:
tag = CMDTAG_INSERT;
break;
case T_DeleteStmt:
tag = CMDTAG_DELETE;
break;
case T_UpdateStmt:
tag = CMDTAG_UPDATE;
break;
case T_SelectStmt:
tag = CMDTAG_SELECT;
break;
case T_PLAssignStmt:
tag = CMDTAG_SELECT;
break;
/* utility statements --- same whether raw or cooked */
case T_TransactionStmt:
{
TransactionStmt *stmt = (TransactionStmt *) parsetree;
switch (stmt->kind)
{
case TRANS_STMT_BEGIN:
tag = CMDTAG_BEGIN;
break;
case TRANS_STMT_START:
tag = CMDTAG_START_TRANSACTION;
break;
case TRANS_STMT_COMMIT:
tag = CMDTAG_COMMIT;
break;
case TRANS_STMT_ROLLBACK:
case TRANS_STMT_ROLLBACK_TO:
tag = CMDTAG_ROLLBACK;
break;
case TRANS_STMT_SAVEPOINT:
tag = CMDTAG_SAVEPOINT;
break;
case TRANS_STMT_RELEASE:
tag = CMDTAG_RELEASE;
break;
case TRANS_STMT_PREPARE:
tag = CMDTAG_PREPARE_TRANSACTION;
break;
case TRANS_STMT_COMMIT_PREPARED:
tag = CMDTAG_COMMIT_PREPARED;
break;
case TRANS_STMT_ROLLBACK_PREPARED:
tag = CMDTAG_ROLLBACK_PREPARED;
break;
default:
tag = CMDTAG_UNKNOWN;
break;
}
}
break;
case T_DeclareCursorStmt:
tag = CMDTAG_DECLARE_CURSOR;
break;
case T_ClosePortalStmt:
{
ClosePortalStmt *stmt = (ClosePortalStmt *) parsetree;
if (stmt->portalname == NULL)
tag = CMDTAG_CLOSE_CURSOR_ALL;
else
tag = CMDTAG_CLOSE_CURSOR;
}
break;
case T_FetchStmt:
{
FetchStmt *stmt = (FetchStmt *) parsetree;
tag = (stmt->ismove) ? CMDTAG_MOVE : CMDTAG_FETCH;
}
break;
case T_CreateDomainStmt:
tag = CMDTAG_CREATE_DOMAIN;
break;
case T_CreateSchemaStmt:
tag = CMDTAG_CREATE_SCHEMA;
break;
case T_CreateStmt:
tag = CMDTAG_CREATE_TABLE;
break;
case T_CreateTableSpaceStmt:
tag = CMDTAG_CREATE_TABLESPACE;
break;
case T_DropTableSpaceStmt:
tag = CMDTAG_DROP_TABLESPACE;
break;
case T_AlterTableSpaceOptionsStmt:
tag = CMDTAG_ALTER_TABLESPACE;
break;
case T_CreateExtensionStmt:
tag = CMDTAG_CREATE_EXTENSION;
break;
case T_AlterExtensionStmt:
tag = CMDTAG_ALTER_EXTENSION;
break;
case T_AlterExtensionContentsStmt:
tag = CMDTAG_ALTER_EXTENSION;
break;
case T_CreateFdwStmt:
tag = CMDTAG_CREATE_FOREIGN_DATA_WRAPPER;
break;
case T_AlterFdwStmt:
tag = CMDTAG_ALTER_FOREIGN_DATA_WRAPPER;
break;
case T_CreateForeignServerStmt:
tag = CMDTAG_CREATE_SERVER;
break;
case T_AlterForeignServerStmt:
tag = CMDTAG_ALTER_SERVER;
break;
case T_CreateUserMappingStmt:
tag = CMDTAG_CREATE_USER_MAPPING;
break;
case T_AlterUserMappingStmt:
tag = CMDTAG_ALTER_USER_MAPPING;
break;
case T_DropUserMappingStmt:
tag = CMDTAG_DROP_USER_MAPPING;
break;
case T_CreateForeignTableStmt:
tag = CMDTAG_CREATE_FOREIGN_TABLE;
break;
case T_ImportForeignSchemaStmt:
tag = CMDTAG_IMPORT_FOREIGN_SCHEMA;
break;
case T_DropStmt:
switch (((DropStmt *) parsetree)->removeType)
{
case OBJECT_TABLE:
tag = CMDTAG_DROP_TABLE;
break;
case OBJECT_SEQUENCE:
tag = CMDTAG_DROP_SEQUENCE;
break;
case OBJECT_VIEW:
tag = CMDTAG_DROP_VIEW;
break;
case OBJECT_MATVIEW:
tag = CMDTAG_DROP_MATERIALIZED_VIEW;
break;
case OBJECT_INDEX:
tag = CMDTAG_DROP_INDEX;
break;
case OBJECT_TYPE:
tag = CMDTAG_DROP_TYPE;
break;
case OBJECT_DOMAIN:
tag = CMDTAG_DROP_DOMAIN;
break;
case OBJECT_COLLATION:
tag = CMDTAG_DROP_COLLATION;
break;
case OBJECT_CONVERSION:
tag = CMDTAG_DROP_CONVERSION;
break;
case OBJECT_SCHEMA:
tag = CMDTAG_DROP_SCHEMA;
break;
case OBJECT_TSPARSER:
tag = CMDTAG_DROP_TEXT_SEARCH_PARSER;
break;
case OBJECT_TSDICTIONARY:
tag = CMDTAG_DROP_TEXT_SEARCH_DICTIONARY;
break;
case OBJECT_TSTEMPLATE:
tag = CMDTAG_DROP_TEXT_SEARCH_TEMPLATE;
break;
case OBJECT_TSCONFIGURATION:
tag = CMDTAG_DROP_TEXT_SEARCH_CONFIGURATION;
break;
case OBJECT_FOREIGN_TABLE:
tag = CMDTAG_DROP_FOREIGN_TABLE;
break;
case OBJECT_EXTENSION:
tag = CMDTAG_DROP_EXTENSION;
break;
case OBJECT_FUNCTION:
tag = CMDTAG_DROP_FUNCTION;
break;
case OBJECT_PROCEDURE:
tag = CMDTAG_DROP_PROCEDURE;
break;
case OBJECT_ROUTINE:
tag = CMDTAG_DROP_ROUTINE;
break;
case OBJECT_AGGREGATE:
tag = CMDTAG_DROP_AGGREGATE;
break;
case OBJECT_OPERATOR:
tag = CMDTAG_DROP_OPERATOR;
break;
case OBJECT_LANGUAGE:
tag = CMDTAG_DROP_LANGUAGE;
break;
case OBJECT_CAST:
tag = CMDTAG_DROP_CAST;
break;
case OBJECT_TRIGGER:
tag = CMDTAG_DROP_TRIGGER;
break;
case OBJECT_EVENT_TRIGGER:
tag = CMDTAG_DROP_EVENT_TRIGGER;
break;
case OBJECT_RULE:
tag = CMDTAG_DROP_RULE;
break;
case OBJECT_FDW:
tag = CMDTAG_DROP_FOREIGN_DATA_WRAPPER;
break;
case OBJECT_FOREIGN_SERVER:
tag = CMDTAG_DROP_SERVER;
break;
case OBJECT_OPCLASS:
tag = CMDTAG_DROP_OPERATOR_CLASS;
break;
case OBJECT_OPFAMILY:
tag = CMDTAG_DROP_OPERATOR_FAMILY;
break;
case OBJECT_POLICY:
tag = CMDTAG_DROP_POLICY;
break;
case OBJECT_TRANSFORM:
tag = CMDTAG_DROP_TRANSFORM;
break;
case OBJECT_ACCESS_METHOD:
tag = CMDTAG_DROP_ACCESS_METHOD;
break;
case OBJECT_PUBLICATION:
tag = CMDTAG_DROP_PUBLICATION;
break;
case OBJECT_STATISTIC_EXT:
tag = CMDTAG_DROP_STATISTICS;
break;
default:
tag = CMDTAG_UNKNOWN;
}
break;
case T_TruncateStmt:
tag = CMDTAG_TRUNCATE_TABLE;
break;
case T_CommentStmt:
tag = CMDTAG_COMMENT;
break;
case T_SecLabelStmt:
tag = CMDTAG_SECURITY_LABEL;
break;
case T_CopyStmt:
tag = CMDTAG_COPY;
break;
case T_RenameStmt:
/*
* When the column is renamed, the command tag is created from its
* relation type
*/
tag = AlterObjectTypeCommandTag(((RenameStmt *) parsetree)->renameType == OBJECT_COLUMN ?
((RenameStmt *) parsetree)->relationType :
((RenameStmt *) parsetree)->renameType);
break;
case T_AlterObjectDependsStmt:
tag = AlterObjectTypeCommandTag(((AlterObjectDependsStmt *) parsetree)->objectType);
break;
case T_AlterObjectSchemaStmt:
tag = AlterObjectTypeCommandTag(((AlterObjectSchemaStmt *) parsetree)->objectType);
break;
case T_AlterOwnerStmt:
tag = AlterObjectTypeCommandTag(((AlterOwnerStmt *) parsetree)->objectType);
break;
case T_AlterTableMoveAllStmt:
tag = AlterObjectTypeCommandTag(((AlterTableMoveAllStmt *) parsetree)->objtype);
break;
case T_AlterTableStmt:
tag = AlterObjectTypeCommandTag(((AlterTableStmt *) parsetree)->objtype);
break;
case T_AlterDomainStmt:
tag = CMDTAG_ALTER_DOMAIN;
break;
case T_AlterFunctionStmt:
switch (((AlterFunctionStmt *) parsetree)->objtype)
{
case OBJECT_FUNCTION:
tag = CMDTAG_ALTER_FUNCTION;
break;
case OBJECT_PROCEDURE:
tag = CMDTAG_ALTER_PROCEDURE;
break;
case OBJECT_ROUTINE:
tag = CMDTAG_ALTER_ROUTINE;
break;
default:
tag = CMDTAG_UNKNOWN;
}
break;
case T_GrantStmt:
{
GrantStmt *stmt = (GrantStmt *) parsetree;
tag = (stmt->is_grant) ? CMDTAG_GRANT : CMDTAG_REVOKE;
}
break;
case T_GrantRoleStmt:
{
GrantRoleStmt *stmt = (GrantRoleStmt *) parsetree;
tag = (stmt->is_grant) ? CMDTAG_GRANT_ROLE : CMDTAG_REVOKE_ROLE;
}
break;
case T_AlterDefaultPrivilegesStmt:
tag = CMDTAG_ALTER_DEFAULT_PRIVILEGES;
break;
case T_DefineStmt:
switch (((DefineStmt *) parsetree)->kind)
{
case OBJECT_AGGREGATE:
tag = CMDTAG_CREATE_AGGREGATE;
break;
case OBJECT_OPERATOR:
tag = CMDTAG_CREATE_OPERATOR;
break;
case OBJECT_TYPE:
tag = CMDTAG_CREATE_TYPE;
break;
case OBJECT_TSPARSER:
tag = CMDTAG_CREATE_TEXT_SEARCH_PARSER;
break;
case OBJECT_TSDICTIONARY:
tag = CMDTAG_CREATE_TEXT_SEARCH_DICTIONARY;
break;
case OBJECT_TSTEMPLATE:
tag = CMDTAG_CREATE_TEXT_SEARCH_TEMPLATE;
break;
case OBJECT_TSCONFIGURATION:
tag = CMDTAG_CREATE_TEXT_SEARCH_CONFIGURATION;
break;
case OBJECT_COLLATION:
tag = CMDTAG_CREATE_COLLATION;
break;
case OBJECT_ACCESS_METHOD:
tag = CMDTAG_CREATE_ACCESS_METHOD;
break;
default:
tag = CMDTAG_UNKNOWN;
}
break;
case T_CompositeTypeStmt:
tag = CMDTAG_CREATE_TYPE;
break;
case T_CreateEnumStmt:
tag = CMDTAG_CREATE_TYPE;
break;
case T_CreateRangeStmt:
tag = CMDTAG_CREATE_TYPE;
break;
case T_AlterEnumStmt:
tag = CMDTAG_ALTER_TYPE;
break;
case T_ViewStmt:
tag = CMDTAG_CREATE_VIEW;
break;
case T_CreateFunctionStmt:
if (((CreateFunctionStmt *) parsetree)->is_procedure)
tag = CMDTAG_CREATE_PROCEDURE;
else
tag = CMDTAG_CREATE_FUNCTION;
break;
case T_IndexStmt:
tag = CMDTAG_CREATE_INDEX;
break;
case T_RuleStmt:
tag = CMDTAG_CREATE_RULE;
break;
case T_CreateSeqStmt:
tag = CMDTAG_CREATE_SEQUENCE;
break;
case T_AlterSeqStmt:
tag = CMDTAG_ALTER_SEQUENCE;
break;
case T_DoStmt:
tag = CMDTAG_DO;
break;
case T_CreatedbStmt:
tag = CMDTAG_CREATE_DATABASE;
break;
case T_AlterDatabaseStmt:
tag = CMDTAG_ALTER_DATABASE;
break;
case T_AlterDatabaseSetStmt:
tag = CMDTAG_ALTER_DATABASE;
break;
case T_DropdbStmt:
tag = CMDTAG_DROP_DATABASE;
break;
case T_NotifyStmt:
tag = CMDTAG_NOTIFY;
break;
case T_ListenStmt:
tag = CMDTAG_LISTEN;
break;
case T_UnlistenStmt:
tag = CMDTAG_UNLISTEN;
break;
case T_LoadStmt:
tag = CMDTAG_LOAD;
break;
case T_CallStmt:
tag = CMDTAG_CALL;
break;
case T_ClusterStmt:
tag = CMDTAG_CLUSTER;
break;
case T_VacuumStmt:
if (((VacuumStmt *) parsetree)->is_vacuumcmd)
tag = CMDTAG_VACUUM;
else
tag = CMDTAG_ANALYZE;
break;
case T_ExplainStmt:
tag = CMDTAG_EXPLAIN;
break;
case T_CreateTableAsStmt:
switch (((CreateTableAsStmt *) parsetree)->objtype)
{
case OBJECT_TABLE:
if (((CreateTableAsStmt *) parsetree)->is_select_into)
tag = CMDTAG_SELECT_INTO;
else
tag = CMDTAG_CREATE_TABLE_AS;
break;
case OBJECT_MATVIEW:
tag = CMDTAG_CREATE_MATERIALIZED_VIEW;
break;
default:
tag = CMDTAG_UNKNOWN;
}
break;
case T_RefreshMatViewStmt:
tag = CMDTAG_REFRESH_MATERIALIZED_VIEW;
break;
case T_AlterSystemStmt:
tag = CMDTAG_ALTER_SYSTEM;
break;
case T_VariableSetStmt:
switch (((VariableSetStmt *) parsetree)->kind)
{
case VAR_SET_VALUE:
case VAR_SET_CURRENT:
case VAR_SET_DEFAULT:
case VAR_SET_MULTI:
tag = CMDTAG_SET;
break;
case VAR_RESET:
case VAR_RESET_ALL:
tag = CMDTAG_RESET;
break;
default:
tag = CMDTAG_UNKNOWN;
}
break;
case T_VariableShowStmt:
tag = CMDTAG_SHOW;
break;
case T_DiscardStmt:
switch (((DiscardStmt *) parsetree)->target)
{
case DISCARD_ALL:
tag = CMDTAG_DISCARD_ALL;
break;
case DISCARD_PLANS:
tag = CMDTAG_DISCARD_PLANS;
break;
case DISCARD_TEMP:
tag = CMDTAG_DISCARD_TEMP;
break;
case DISCARD_SEQUENCES:
tag = CMDTAG_DISCARD_SEQUENCES;
break;
default:
tag = CMDTAG_UNKNOWN;
}
break;
case T_CreateTransformStmt:
tag = CMDTAG_CREATE_TRANSFORM;
break;
case T_CreateTrigStmt:
tag = CMDTAG_CREATE_TRIGGER;
break;
case T_CreateEventTrigStmt:
tag = CMDTAG_CREATE_EVENT_TRIGGER;
break;
case T_AlterEventTrigStmt:
tag = CMDTAG_ALTER_EVENT_TRIGGER;
break;
case T_CreatePLangStmt:
tag = CMDTAG_CREATE_LANGUAGE;
break;
case T_CreateRoleStmt:
tag = CMDTAG_CREATE_ROLE;
break;
case T_AlterRoleStmt:
tag = CMDTAG_ALTER_ROLE;
break;
case T_AlterRoleSetStmt:
tag = CMDTAG_ALTER_ROLE;
break;
case T_DropRoleStmt:
tag = CMDTAG_DROP_ROLE;
break;
case T_DropOwnedStmt:
tag = CMDTAG_DROP_OWNED;
break;
case T_ReassignOwnedStmt:
tag = CMDTAG_REASSIGN_OWNED;
break;
case T_LockStmt:
tag = CMDTAG_LOCK_TABLE;
break;
case T_ConstraintsSetStmt:
tag = CMDTAG_SET_CONSTRAINTS;
break;
case T_CheckPointStmt:
tag = CMDTAG_CHECKPOINT;
break;
case T_ReindexStmt:
tag = CMDTAG_REINDEX;
break;
case T_CreateConversionStmt:
tag = CMDTAG_CREATE_CONVERSION;
break;
case T_CreateCastStmt:
tag = CMDTAG_CREATE_CAST;
break;
case T_CreateOpClassStmt:
tag = CMDTAG_CREATE_OPERATOR_CLASS;
break;
case T_CreateOpFamilyStmt:
tag = CMDTAG_CREATE_OPERATOR_FAMILY;
break;
case T_AlterOpFamilyStmt:
tag = CMDTAG_ALTER_OPERATOR_FAMILY;
break;
case T_AlterOperatorStmt:
tag = CMDTAG_ALTER_OPERATOR;
break;
case T_AlterTypeStmt:
tag = CMDTAG_ALTER_TYPE;
break;
case T_AlterTSDictionaryStmt:
tag = CMDTAG_ALTER_TEXT_SEARCH_DICTIONARY;
break;
case T_AlterTSConfigurationStmt:
tag = CMDTAG_ALTER_TEXT_SEARCH_CONFIGURATION;
break;
case T_CreatePolicyStmt:
tag = CMDTAG_CREATE_POLICY;
break;
case T_AlterPolicyStmt:
tag = CMDTAG_ALTER_POLICY;
break;
case T_CreateAmStmt:
tag = CMDTAG_CREATE_ACCESS_METHOD;
break;
case T_CreatePublicationStmt:
tag = CMDTAG_CREATE_PUBLICATION;
break;
case T_AlterPublicationStmt:
tag = CMDTAG_ALTER_PUBLICATION;
break;
case T_CreateSubscriptionStmt:
tag = CMDTAG_CREATE_SUBSCRIPTION;
break;
case T_AlterSubscriptionStmt:
tag = CMDTAG_ALTER_SUBSCRIPTION;
break;
case T_DropSubscriptionStmt:
tag = CMDTAG_DROP_SUBSCRIPTION;
break;
case T_AlterCollationStmt:
tag = CMDTAG_ALTER_COLLATION;
break;
case T_PrepareStmt:
tag = CMDTAG_PREPARE;
break;
case T_ExecuteStmt:
tag = CMDTAG_EXECUTE;
break;
case T_CreateStatsStmt:
tag = CMDTAG_CREATE_STATISTICS;
break;
case T_AlterStatsStmt:
tag = CMDTAG_ALTER_STATISTICS;
break;
case T_DeallocateStmt:
{
DeallocateStmt *stmt = (DeallocateStmt *) parsetree;
if (stmt->name == NULL)
tag = CMDTAG_DEALLOCATE_ALL;
else
tag = CMDTAG_DEALLOCATE;
}
break;
/* already-planned queries */
case T_PlannedStmt:
{
PlannedStmt *stmt = (PlannedStmt *) parsetree;
switch (stmt->commandType)
{
case CMD_SELECT:
/*
* We take a little extra care here so that the result
* will be useful for complaints about read-only
* statements
*/
if (stmt->rowMarks != NIL)
{
/* not 100% but probably close enough */
switch (((PlanRowMark *) linitial(stmt->rowMarks))->strength)
{
case LCS_FORKEYSHARE:
tag = CMDTAG_SELECT_FOR_KEY_SHARE;
break;
case LCS_FORSHARE:
tag = CMDTAG_SELECT_FOR_SHARE;
break;
case LCS_FORNOKEYUPDATE:
tag = CMDTAG_SELECT_FOR_NO_KEY_UPDATE;
break;
case LCS_FORUPDATE:
tag = CMDTAG_SELECT_FOR_UPDATE;
break;
default:
tag = CMDTAG_SELECT;
break;
}
}
else
tag = CMDTAG_SELECT;
break;
case CMD_UPDATE:
tag = CMDTAG_UPDATE;
break;
case CMD_INSERT:
tag = CMDTAG_INSERT;
break;
case CMD_DELETE:
tag = CMDTAG_DELETE;
break;
case CMD_UTILITY:
tag = CreateCommandTag(stmt->utilityStmt);
break;
default:
elog(WARNING, "unrecognized commandType: %d",
(int) stmt->commandType);
tag = CMDTAG_UNKNOWN;
break;
}
}
break;
/* parsed-and-rewritten-but-not-planned queries */
case T_Query:
{
Query *stmt = (Query *) parsetree;
switch (stmt->commandType)
{
case CMD_SELECT:
/*
* We take a little extra care here so that the result
* will be useful for complaints about read-only
* statements
*/
if (stmt->rowMarks != NIL)
{
/* not 100% but probably close enough */
switch (((RowMarkClause *) linitial(stmt->rowMarks))->strength)
{
case LCS_FORKEYSHARE:
tag = CMDTAG_SELECT_FOR_KEY_SHARE;
break;
case LCS_FORSHARE:
tag = CMDTAG_SELECT_FOR_SHARE;
break;
case LCS_FORNOKEYUPDATE:
tag = CMDTAG_SELECT_FOR_NO_KEY_UPDATE;
break;
case LCS_FORUPDATE:
tag = CMDTAG_SELECT_FOR_UPDATE;
break;
default:
tag = CMDTAG_UNKNOWN;
break;
}
}
else
tag = CMDTAG_SELECT;
break;
case CMD_UPDATE:
tag = CMDTAG_UPDATE;
break;
case CMD_INSERT:
tag = CMDTAG_INSERT;
break;
case CMD_DELETE:
tag = CMDTAG_DELETE;
break;
case CMD_UTILITY:
tag = CreateCommandTag(stmt->utilityStmt);
break;
default:
elog(WARNING, "unrecognized commandType: %d",
(int) stmt->commandType);
tag = CMDTAG_UNKNOWN;
break;
}
}
break;
default:
elog(WARNING, "unrecognized node type: %d",
(int) nodeTag(parsetree));
tag = CMDTAG_UNKNOWN;
break;
}
return tag;
}
/*
* GetCommandLogLevel
* utility to get the minimum log_statement level for a command,
* given either a raw (un-analyzed) parsetree, an analyzed Query,
* or a PlannedStmt.
*
* This must handle all command types, but since the vast majority
* of 'em are utility commands, it seems sensible to keep it here.
*/
LogStmtLevel
GetCommandLogLevel(Node *parsetree)
{
LogStmtLevel lev;
switch (nodeTag(parsetree))
{
/* recurse if we're given a RawStmt */
case T_RawStmt:
lev = GetCommandLogLevel(((RawStmt *) parsetree)->stmt);
break;
/* raw plannable queries */
case T_InsertStmt:
case T_DeleteStmt:
case T_UpdateStmt:
lev = LOGSTMT_MOD;
break;
case T_SelectStmt:
if (((SelectStmt *) parsetree)->intoClause)
lev = LOGSTMT_DDL; /* SELECT INTO */
else
lev = LOGSTMT_ALL;
break;
case T_PLAssignStmt:
lev = LOGSTMT_ALL;
break;
/* utility statements --- same whether raw or cooked */
case T_TransactionStmt:
lev = LOGSTMT_ALL;
break;
case T_DeclareCursorStmt:
lev = LOGSTMT_ALL;
break;
case T_ClosePortalStmt:
lev = LOGSTMT_ALL;
break;
case T_FetchStmt:
lev = LOGSTMT_ALL;
break;
case T_CreateSchemaStmt:
lev = LOGSTMT_DDL;
break;
case T_CreateStmt:
case T_CreateForeignTableStmt:
lev = LOGSTMT_DDL;
break;
case T_CreateTableSpaceStmt:
case T_DropTableSpaceStmt:
case T_AlterTableSpaceOptionsStmt:
lev = LOGSTMT_DDL;
break;
case T_CreateExtensionStmt:
case T_AlterExtensionStmt:
case T_AlterExtensionContentsStmt:
lev = LOGSTMT_DDL;
break;
case T_CreateFdwStmt:
case T_AlterFdwStmt:
case T_CreateForeignServerStmt:
case T_AlterForeignServerStmt:
case T_CreateUserMappingStmt:
case T_AlterUserMappingStmt:
case T_DropUserMappingStmt:
case T_ImportForeignSchemaStmt:
lev = LOGSTMT_DDL;
break;
case T_DropStmt:
lev = LOGSTMT_DDL;
break;
case T_TruncateStmt:
lev = LOGSTMT_MOD;
break;
case T_CommentStmt:
lev = LOGSTMT_DDL;
break;
case T_SecLabelStmt:
lev = LOGSTMT_DDL;
break;
case T_CopyStmt:
if (((CopyStmt *) parsetree)->is_from)
lev = LOGSTMT_MOD;
else
lev = LOGSTMT_ALL;
break;
case T_PrepareStmt:
{
PrepareStmt *stmt = (PrepareStmt *) parsetree;
/* Look through a PREPARE to the contained stmt */
lev = GetCommandLogLevel(stmt->query);
}
break;
case T_ExecuteStmt:
{
ExecuteStmt *stmt = (ExecuteStmt *) parsetree;
PreparedStatement *ps;
/* Look through an EXECUTE to the referenced stmt */
ps = FetchPreparedStatement(stmt->name, false);
if (ps && ps->plansource->raw_parse_tree)
lev = GetCommandLogLevel(ps->plansource->raw_parse_tree->stmt);
else
lev = LOGSTMT_ALL;
}
break;
case T_DeallocateStmt:
lev = LOGSTMT_ALL;
break;
case T_RenameStmt:
lev = LOGSTMT_DDL;
break;
case T_AlterObjectDependsStmt:
lev = LOGSTMT_DDL;
break;
case T_AlterObjectSchemaStmt:
lev = LOGSTMT_DDL;
break;
case T_AlterOwnerStmt:
lev = LOGSTMT_DDL;
break;
case T_AlterOperatorStmt:
lev = LOGSTMT_DDL;
break;
case T_AlterTypeStmt:
lev = LOGSTMT_DDL;
break;
case T_AlterTableMoveAllStmt:
case T_AlterTableStmt:
lev = LOGSTMT_DDL;
break;
case T_AlterDomainStmt:
lev = LOGSTMT_DDL;
break;
case T_GrantStmt:
lev = LOGSTMT_DDL;
break;
case T_GrantRoleStmt:
lev = LOGSTMT_DDL;
break;
case T_AlterDefaultPrivilegesStmt:
lev = LOGSTMT_DDL;
break;
case T_DefineStmt:
lev = LOGSTMT_DDL;
break;
case T_CompositeTypeStmt:
lev = LOGSTMT_DDL;
break;
case T_CreateEnumStmt:
lev = LOGSTMT_DDL;
break;
case T_CreateRangeStmt:
lev = LOGSTMT_DDL;
break;
case T_AlterEnumStmt:
lev = LOGSTMT_DDL;
break;
case T_ViewStmt:
lev = LOGSTMT_DDL;
break;
case T_CreateFunctionStmt:
lev = LOGSTMT_DDL;
break;
case T_AlterFunctionStmt:
lev = LOGSTMT_DDL;
break;
case T_IndexStmt:
lev = LOGSTMT_DDL;
break;
case T_RuleStmt:
lev = LOGSTMT_DDL;
break;
case T_CreateSeqStmt:
lev = LOGSTMT_DDL;
break;
case T_AlterSeqStmt:
lev = LOGSTMT_DDL;
break;
case T_DoStmt:
lev = LOGSTMT_ALL;
break;
case T_CreatedbStmt:
lev = LOGSTMT_DDL;
break;
case T_AlterDatabaseStmt:
lev = LOGSTMT_DDL;
break;
case T_AlterDatabaseSetStmt:
lev = LOGSTMT_DDL;
break;
case T_DropdbStmt:
lev = LOGSTMT_DDL;
break;
case T_NotifyStmt:
lev = LOGSTMT_ALL;
break;
case T_ListenStmt:
lev = LOGSTMT_ALL;
break;
case T_UnlistenStmt:
lev = LOGSTMT_ALL;
break;
case T_LoadStmt:
lev = LOGSTMT_ALL;
break;
case T_CallStmt:
lev = LOGSTMT_ALL;
break;
case T_ClusterStmt:
lev = LOGSTMT_DDL;
break;
case T_VacuumStmt:
lev = LOGSTMT_ALL;
break;
case T_ExplainStmt:
{
ExplainStmt *stmt = (ExplainStmt *) parsetree;
bool analyze = false;
ListCell *lc;
/* Look through an EXPLAIN ANALYZE to the contained stmt */
foreach(lc, stmt->options)
{
DefElem *opt = (DefElem *) lfirst(lc);
if (strcmp(opt->defname, "analyze") == 0)
analyze = defGetBoolean(opt);
/* don't "break", as explain.c will use the last value */
}
if (analyze)
return GetCommandLogLevel(stmt->query);
/* Plain EXPLAIN isn't so interesting */
lev = LOGSTMT_ALL;
}
break;
case T_CreateTableAsStmt:
lev = LOGSTMT_DDL;
break;
case T_RefreshMatViewStmt:
lev = LOGSTMT_DDL;
break;
case T_AlterSystemStmt:
lev = LOGSTMT_DDL;
break;
case T_VariableSetStmt:
lev = LOGSTMT_ALL;
break;
case T_VariableShowStmt:
lev = LOGSTMT_ALL;
break;
case T_DiscardStmt:
lev = LOGSTMT_ALL;
break;
case T_CreateTrigStmt:
lev = LOGSTMT_DDL;
break;
case T_CreateEventTrigStmt:
lev = LOGSTMT_DDL;
break;
case T_AlterEventTrigStmt:
lev = LOGSTMT_DDL;
break;
case T_CreatePLangStmt:
lev = LOGSTMT_DDL;
break;
case T_CreateDomainStmt:
lev = LOGSTMT_DDL;
break;
case T_CreateRoleStmt:
lev = LOGSTMT_DDL;
break;
case T_AlterRoleStmt:
lev = LOGSTMT_DDL;
break;
case T_AlterRoleSetStmt:
lev = LOGSTMT_DDL;
break;
case T_DropRoleStmt:
lev = LOGSTMT_DDL;
break;
case T_DropOwnedStmt:
lev = LOGSTMT_DDL;
break;
case T_ReassignOwnedStmt:
lev = LOGSTMT_DDL;
break;
case T_LockStmt:
lev = LOGSTMT_ALL;
break;
case T_ConstraintsSetStmt:
lev = LOGSTMT_ALL;
break;
case T_CheckPointStmt:
lev = LOGSTMT_ALL;
break;
case T_ReindexStmt:
lev = LOGSTMT_ALL; /* should this be DDL? */
break;
case T_CreateConversionStmt:
lev = LOGSTMT_DDL;
break;
case T_CreateCastStmt:
lev = LOGSTMT_DDL;
break;
case T_CreateOpClassStmt:
lev = LOGSTMT_DDL;
break;
case T_CreateOpFamilyStmt:
lev = LOGSTMT_DDL;
break;
case T_CreateTransformStmt:
lev = LOGSTMT_DDL;
break;
case T_AlterOpFamilyStmt:
lev = LOGSTMT_DDL;
break;
case T_CreatePolicyStmt:
lev = LOGSTMT_DDL;
break;
case T_AlterPolicyStmt:
lev = LOGSTMT_DDL;
break;
case T_AlterTSDictionaryStmt:
lev = LOGSTMT_DDL;
break;
case T_AlterTSConfigurationStmt:
lev = LOGSTMT_DDL;
break;
case T_CreateAmStmt:
lev = LOGSTMT_DDL;
break;
case T_CreatePublicationStmt:
lev = LOGSTMT_DDL;
break;
case T_AlterPublicationStmt:
lev = LOGSTMT_DDL;
break;
case T_CreateSubscriptionStmt:
lev = LOGSTMT_DDL;
break;
case T_AlterSubscriptionStmt:
lev = LOGSTMT_DDL;
break;
case T_DropSubscriptionStmt:
lev = LOGSTMT_DDL;
break;
case T_CreateStatsStmt:
lev = LOGSTMT_DDL;
break;
case T_AlterStatsStmt:
lev = LOGSTMT_DDL;
break;
case T_AlterCollationStmt:
lev = LOGSTMT_DDL;
break;
/* already-planned queries */
case T_PlannedStmt:
{
PlannedStmt *stmt = (PlannedStmt *) parsetree;
switch (stmt->commandType)
{
case CMD_SELECT:
lev = LOGSTMT_ALL;
break;
case CMD_UPDATE:
case CMD_INSERT:
case CMD_DELETE:
lev = LOGSTMT_MOD;
break;
case CMD_UTILITY:
lev = GetCommandLogLevel(stmt->utilityStmt);
break;
default:
elog(WARNING, "unrecognized commandType: %d",
(int) stmt->commandType);
lev = LOGSTMT_ALL;
break;
}
}
break;
/* parsed-and-rewritten-but-not-planned queries */
case T_Query:
{
Query *stmt = (Query *) parsetree;
switch (stmt->commandType)
{
case CMD_SELECT:
lev = LOGSTMT_ALL;
break;
case CMD_UPDATE:
case CMD_INSERT:
case CMD_DELETE:
lev = LOGSTMT_MOD;
break;
case CMD_UTILITY:
lev = GetCommandLogLevel(stmt->utilityStmt);
break;
default:
elog(WARNING, "unrecognized commandType: %d",
(int) stmt->commandType);
lev = LOGSTMT_ALL;
break;
}
}
break;
default:
elog(WARNING, "unrecognized node type: %d",
(int) nodeTag(parsetree));
lev = LOGSTMT_ALL;
break;
}
return lev;
}