* commands. At one time acted as an interface between the Lisp and C
* systems.
*
- * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
*/
#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/namespace.h"
#include "catalog/toasting.h"
#include "commands/collationcmds.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/matview.h"
#include "commands/lockcmds.h"
+#include "commands/policy.h"
#include "commands/portalcmds.h"
#include "commands/prepare.h"
#include "commands/proclang.h"
/* Hook for plugins to get control in ProcessUtility() */
ProcessUtility_hook_type ProcessUtility_hook = NULL;
-
-/*
- * Verify user has ownership of specified relation, else ereport.
- *
- * If noCatalogs is true then we also deny access to system catalogs,
- * except when allowSystemTableMods is true.
- */
-void
-CheckRelationOwnership(RangeVar *rel, bool noCatalogs)
-{
- Oid relOid;
- HeapTuple tuple;
-
- /*
- * XXX: This is unsafe in the presence of concurrent DDL, since it is
- * called before acquiring any lock on the target relation. However,
- * locking the target relation (especially using something like
- * AccessExclusiveLock) before verifying that the user has permissions
- * is not appealing either.
- */
- relOid = RangeVarGetRelid(rel, NoLock, false, false);
-
- tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
- if (!HeapTupleIsValid(tuple)) /* should not happen */
- elog(ERROR, "cache lookup failed for relation %u", relOid);
-
- if (!pg_class_ownercheck(relOid, GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
- rel->relname);
-
- if (noCatalogs)
- {
- if (!allowSystemTableMods &&
- IsSystemClass((Form_pg_class) GETSTRUCT(tuple)))
- ereport(ERROR,
- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("permission denied: \"%s\" is a system catalog",
- rel->relname)));
- }
-
- ReleaseSysCache(tuple);
-}
+/* local function declarations */
+static void ProcessUtilitySlow(ParseState *pstate,
+ PlannedStmt *pstmt,
+ const char *queryString,
+ ProcessUtilityContext context,
+ ParamListInfo params,
+ DestReceiver *dest,
+ char *completionTag);
+static void ExecDropStmt(DropStmt *stmt, bool isTopLevel);
/*
* the query must be *in truth* read-only, because the caller wishes
* not to do CommandCounterIncrement for it.
*
- * Note: currently no need to support Query nodes here
+ * Note: currently no need to support raw or analyzed queries here
*/
bool
-CommandIsReadOnly(Node *parsetree)
+CommandIsReadOnly(PlannedStmt *pstmt)
{
- if (IsA(parsetree, PlannedStmt))
+ Assert(IsA(pstmt, PlannedStmt));
+ switch (pstmt->commandType)
{
- PlannedStmt *stmt = (PlannedStmt *) parsetree;
-
- switch (stmt->commandType)
- {
- case CMD_SELECT:
- if (stmt->intoClause != NULL)
- return false; /* SELECT INTO */
- else if (stmt->rowMarks != NIL)
- return false; /* SELECT FOR UPDATE/SHARE */
- else if (stmt->hasModifyingCTE)
- return false; /* data-modifying CTE */
- else
- return true;
- case CMD_UPDATE:
- case CMD_INSERT:
- case CMD_DELETE:
- return false;
- default:
- elog(WARNING, "unrecognized commandType: %d",
- (int) stmt->commandType);
- break;
- }
+ 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;
}
- /* For now, treat all utility commands as read/write */
return false;
}
static void
check_xact_readonly(Node *parsetree)
{
- if (!XactReadOnly)
+ /* Only perform the check if we have a reason to do so. */
+ if (!XactReadOnly && !IsInParallelMode())
return;
/*
* Note: Commands that need to do more complicated checking are handled
* elsewhere, in particular COPY and plannable statements do their own
- * checking. However they should all call PreventCommandIfReadOnly to
- * actually throw the error.
+ * checking. However they should all call PreventCommandIfReadOnly or
+ * PreventCommandIfParallelMode to actually throw the error.
*/
switch (nodeTag(parsetree))
case T_AlterFunctionStmt:
case T_AlterRoleStmt:
case T_AlterRoleSetStmt:
+ case T_AlterObjectDependsStmt:
case T_AlterObjectSchemaStmt:
case T_AlterOwnerStmt:
+ case T_AlterOperatorStmt:
case T_AlterSeqStmt:
+ case T_AlterTableMoveAllStmt:
case T_AlterTableStmt:
case T_RenameStmt:
case T_CommentStmt:
case T_DefineStmt:
case T_CreateCastStmt:
+ case T_CreateEventTrigStmt:
+ case T_AlterEventTrigStmt:
case T_CreateConversionStmt:
case T_CreatedbStmt:
case T_CreateDomainStmt:
case T_CreateSchemaStmt:
case T_CreateSeqStmt:
case T_CreateStmt:
+ case T_CreateTableAsStmt:
+ case T_RefreshMatViewStmt:
case T_CreateTableSpaceStmt:
+ case T_CreateTransformStmt:
case T_CreateTrigStmt:
case T_CompositeTypeStmt:
case T_CreateEnumStmt:
+ case T_CreateRangeStmt:
case T_AlterEnumStmt:
case T_ViewStmt:
- case T_DropCastStmt:
case T_DropStmt:
case T_DropdbStmt:
case T_DropTableSpaceStmt:
- case T_RemoveFuncStmt:
case T_DropRoleStmt:
- case T_DropPLangStmt:
- case T_RemoveOpClassStmt:
- case T_RemoveOpFamilyStmt:
- case T_DropPropertyStmt:
case T_GrantStmt:
case T_GrantRoleStmt:
case T_AlterDefaultPrivilegesStmt:
case T_AlterExtensionContentsStmt:
case T_CreateFdwStmt:
case T_AlterFdwStmt:
- case T_DropFdwStmt:
case T_CreateForeignServerStmt:
case T_AlterForeignServerStmt:
- case T_DropForeignServerStmt:
case T_CreateUserMappingStmt:
case T_AlterUserMappingStmt:
case T_DropUserMappingStmt:
case T_AlterTableSpaceOptionsStmt:
case T_CreateForeignTableStmt:
+ case T_ImportForeignSchemaStmt:
case T_SecLabelStmt:
PreventCommandIfReadOnly(CreateCommandTag(parsetree));
+ PreventCommandIfParallelMode(CreateCommandTag(parsetree));
break;
default:
/* do nothing */
cmdname)));
}
+/*
+ * PreventCommandIfParallelMode: throw error if current (sub)transaction is
+ * in parallel mode.
+ *
+ * This is useful mainly to ensure consistency of the error message wording;
+ * most 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 slave
- * will be rejected by XactReadOnly tests. However there are a few
+ * 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.
*/
* ProcessUtility
* general utility function invoker
*
- * parsetree: the parse tree for the utility statement
+ * pstmt: PlannedStmt wrapper for the utility statement
* queryString: original source text of command
+ * context: identifies source of statement (toplevel client command,
+ * non-toplevel client command, subcommand of a larger utility command)
* params: parameters to use during execution
- * isTopLevel: true if executing a "top level" (interactively issued) command
* dest: where to send results
* completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
* in which to store a command completion status string.
* completionTag may be NULL if caller doesn't want a status string.
*/
void
-ProcessUtility(Node *parsetree,
+ProcessUtility(PlannedStmt *pstmt,
const char *queryString,
+ ProcessUtilityContext context,
ParamListInfo params,
- bool isTopLevel,
DestReceiver *dest,
char *completionTag)
{
+ Assert(IsA(pstmt, PlannedStmt));
+ Assert(pstmt->commandType == CMD_UTILITY);
Assert(queryString != NULL); /* required as of 8.4 */
/*
* call standard_ProcessUtility().
*/
if (ProcessUtility_hook)
- (*ProcessUtility_hook) (parsetree, queryString, params,
- isTopLevel, dest, completionTag);
+ (*ProcessUtility_hook) (pstmt, queryString,
+ context, params,
+ dest, completionTag);
else
- standard_ProcessUtility(parsetree, queryString, params,
- isTopLevel, dest, completionTag);
+ standard_ProcessUtility(pstmt, queryString,
+ context, params,
+ dest, completionTag);
}
+/*
+ * 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(Node *parsetree,
+standard_ProcessUtility(PlannedStmt *pstmt,
const char *queryString,
+ ProcessUtilityContext context,
ParamListInfo params,
- bool isTopLevel,
DestReceiver *dest,
char *completionTag)
{
+ Node *parsetree = pstmt->utilityStmt;
+ bool isTopLevel = (context == PROCESS_UTILITY_TOPLEVEL);
+ ParseState *pstate;
+
check_xact_readonly(parsetree);
if (completionTag)
completionTag[0] = '\0';
+ pstate = make_parsestate(NULL);
+ pstate->p_sourcetext = queryString;
+
switch (nodeTag(parsetree))
{
/*
/*
* Portal (cursor) manipulation
- *
- * Note: DECLARE CURSOR is processed mostly as a SELECT, and
- * therefore what we will get here is a PlannedStmt not a bare
- * DeclareCursorStmt.
*/
- case T_PlannedStmt:
- {
- PlannedStmt *stmt = (PlannedStmt *) parsetree;
-
- if (stmt->utilityStmt == NULL ||
- !IsA(stmt->utilityStmt, DeclareCursorStmt))
- elog(ERROR, "non-DECLARE CURSOR PlannedStmt passed to ProcessUtility");
- PerformCursorOpen(stmt, params, queryString, isTopLevel);
- }
+ case T_DeclareCursorStmt:
+ PerformCursorOpen((DeclareCursorStmt *) parsetree, params,
+ queryString, isTopLevel);
break;
case T_ClosePortalStmt:
completionTag);
break;
- /*
- * relation and attribute manipulation
- */
- case T_CreateSchemaStmt:
- CreateSchemaCommand((CreateSchemaStmt *) parsetree,
- queryString);
- break;
-
- case T_CreateStmt:
- case T_CreateForeignTableStmt:
- {
- List *stmts;
- ListCell *l;
- Oid relOid;
-
- /* Run parse analysis ... */
- stmts = transformCreateStmt((CreateStmt *) parsetree,
- queryString);
-
- /* ... and do it */
- foreach(l, stmts)
- {
- Node *stmt = (Node *) lfirst(l);
-
- if (IsA(stmt, CreateStmt))
- {
- Datum toast_options;
- static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
-
- /* Create the table itself */
- relOid = DefineRelation((CreateStmt *) stmt,
- RELKIND_RELATION,
- InvalidOid);
-
- /*
- * Let AlterTableCreateToastTable decide if this one
- * needs a secondary relation too.
- */
- CommandCounterIncrement();
-
- /* parse and validate reloptions for the toast table */
- toast_options = transformRelOptions((Datum) 0,
- ((CreateStmt *) stmt)->options,
- "toast",
- validnsps,
- true, false);
- (void) heap_reloptions(RELKIND_TOASTVALUE, toast_options,
- true);
-
- AlterTableCreateToastTable(relOid, toast_options);
- }
- else if (IsA(stmt, CreateForeignTableStmt))
- {
- /* Create the table itself */
- relOid = DefineRelation((CreateStmt *) stmt,
- RELKIND_FOREIGN_TABLE,
- InvalidOid);
- CreateForeignTable((CreateForeignTableStmt *) stmt,
- relOid);
- }
- else
- {
- /* Recurse for anything else */
- ProcessUtility(stmt,
- queryString,
- params,
- false,
- None_Receiver,
- NULL);
- }
-
- /* Need CCI between commands */
- if (lnext(l) != NULL)
- CommandCounterIncrement();
- }
- }
+ case T_DoStmt:
+ ExecuteDoStmt((DoStmt *) parsetree);
break;
case T_CreateTableSpaceStmt:
+ /* no event triggers for global objects */
PreventTransactionChain(isTopLevel, "CREATE TABLESPACE");
CreateTableSpace((CreateTableSpaceStmt *) parsetree);
break;
case T_DropTableSpaceStmt:
+ /* no event triggers for global objects */
PreventTransactionChain(isTopLevel, "DROP TABLESPACE");
DropTableSpace((DropTableSpaceStmt *) parsetree);
break;
case T_AlterTableSpaceOptionsStmt:
+ /* no event triggers for global objects */
AlterTableSpaceOptions((AlterTableSpaceOptionsStmt *) parsetree);
break;
- case T_CreateExtensionStmt:
- CreateExtension((CreateExtensionStmt *) parsetree);
+ case T_TruncateStmt:
+ ExecuteTruncate((TruncateStmt *) parsetree);
break;
- case T_AlterExtensionStmt:
- ExecAlterExtensionStmt((AlterExtensionStmt *) parsetree);
- break;
+ case T_CopyStmt:
+ {
+ uint64 processed;
- case T_AlterExtensionContentsStmt:
- ExecAlterExtensionContentsStmt((AlterExtensionContentsStmt *) parsetree);
+ DoCopy(pstate, (CopyStmt *) parsetree,
+ pstmt->stmt_location, pstmt->stmt_len,
+ &processed);
+ if (completionTag)
+ snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
+ "COPY " UINT64_FORMAT, processed);
+ }
break;
- case T_CreateFdwStmt:
- CreateForeignDataWrapper((CreateFdwStmt *) parsetree);
+ case T_PrepareStmt:
+ CheckRestrictedOperation("PREPARE");
+ PrepareQuery((PrepareStmt *) parsetree, queryString,
+ pstmt->stmt_location, pstmt->stmt_len);
break;
- case T_AlterFdwStmt:
- AlterForeignDataWrapper((AlterFdwStmt *) parsetree);
+ case T_ExecuteStmt:
+ ExecuteQuery((ExecuteStmt *) parsetree, NULL,
+ queryString, params,
+ dest, completionTag);
break;
- case T_DropFdwStmt:
- RemoveForeignDataWrapper((DropFdwStmt *) parsetree);
+ case T_DeallocateStmt:
+ CheckRestrictedOperation("DEALLOCATE");
+ DeallocateQuery((DeallocateStmt *) parsetree);
break;
- case T_CreateForeignServerStmt:
- CreateForeignServer((CreateForeignServerStmt *) parsetree);
+ case T_GrantRoleStmt:
+ /* no event triggers for global objects */
+ GrantRole((GrantRoleStmt *) parsetree);
break;
- case T_AlterForeignServerStmt:
- AlterForeignServer((AlterForeignServerStmt *) parsetree);
+ case T_CreatedbStmt:
+ /* no event triggers for global objects */
+ PreventTransactionChain(isTopLevel, "CREATE DATABASE");
+ createdb(pstate, (CreatedbStmt *) parsetree);
break;
- case T_DropForeignServerStmt:
- RemoveForeignServer((DropForeignServerStmt *) parsetree);
+ case T_AlterDatabaseStmt:
+ /* no event triggers for global objects */
+ AlterDatabase(pstate, (AlterDatabaseStmt *) parsetree, isTopLevel);
break;
- case T_CreateUserMappingStmt:
- CreateUserMapping((CreateUserMappingStmt *) parsetree);
+ case T_AlterDatabaseSetStmt:
+ /* no event triggers for global objects */
+ AlterDatabaseSet((AlterDatabaseSetStmt *) parsetree);
break;
- case T_AlterUserMappingStmt:
- AlterUserMapping((AlterUserMappingStmt *) parsetree);
- break;
+ case T_DropdbStmt:
+ {
+ DropdbStmt *stmt = (DropdbStmt *) parsetree;
- case T_DropUserMappingStmt:
- RemoveUserMapping((DropUserMappingStmt *) parsetree);
+ /* no event triggers for global objects */
+ PreventTransactionChain(isTopLevel, "DROP DATABASE");
+ dropdb(stmt->dbname, stmt->missing_ok);
+ }
break;
- case T_DropStmt:
+ /* Query-level asynchronous notification */
+ case T_NotifyStmt:
{
- DropStmt *stmt = (DropStmt *) parsetree;
-
- switch (stmt->removeType)
- {
- case OBJECT_TABLE:
- case OBJECT_SEQUENCE:
- case OBJECT_VIEW:
- case OBJECT_INDEX:
- case OBJECT_FOREIGN_TABLE:
- RemoveRelations(stmt);
- break;
+ NotifyStmt *stmt = (NotifyStmt *) parsetree;
- case OBJECT_TYPE:
- case OBJECT_DOMAIN:
- RemoveTypes(stmt);
- break;
+ PreventCommandDuringRecovery("NOTIFY");
+ Async_Notify(stmt->conditionname, stmt->payload);
+ }
+ break;
- case OBJECT_COLLATION:
- DropCollationsCommand(stmt);
- break;
+ case T_ListenStmt:
+ {
+ ListenStmt *stmt = (ListenStmt *) parsetree;
- case OBJECT_CONVERSION:
- DropConversionsCommand(stmt);
- break;
+ PreventCommandDuringRecovery("LISTEN");
+ CheckRestrictedOperation("LISTEN");
+ Async_Listen(stmt->conditionname);
+ }
+ break;
- case OBJECT_SCHEMA:
- RemoveSchemas(stmt);
- break;
+ case T_UnlistenStmt:
+ {
+ UnlistenStmt *stmt = (UnlistenStmt *) parsetree;
- case OBJECT_TSPARSER:
- RemoveTSParsers(stmt);
- break;
+ PreventCommandDuringRecovery("UNLISTEN");
+ CheckRestrictedOperation("UNLISTEN");
+ if (stmt->conditionname)
+ Async_Unlisten(stmt->conditionname);
+ else
+ Async_UnlistenAll();
+ }
+ break;
- case OBJECT_TSDICTIONARY:
- RemoveTSDictionaries(stmt);
- break;
+ case T_LoadStmt:
+ {
+ LoadStmt *stmt = (LoadStmt *) parsetree;
- case OBJECT_TSTEMPLATE:
- RemoveTSTemplates(stmt);
- break;
+ closeAllVfds(); /* probably not necessary... */
+ /* Allowed names are restricted if you're not superuser */
+ load_file(stmt->filename, !superuser());
+ }
+ break;
- case OBJECT_TSCONFIGURATION:
- RemoveTSConfigurations(stmt);
- break;
+ case T_ClusterStmt:
+ /* we choose to allow this during "read only" transactions */
+ PreventCommandDuringRecovery("CLUSTER");
+ /* forbidden in parallel mode due to CommandIsReadOnly */
+ cluster((ClusterStmt *) parsetree, isTopLevel);
+ break;
- case OBJECT_EXTENSION:
- RemoveExtensions(stmt);
- break;
+ case T_VacuumStmt:
+ {
+ VacuumStmt *stmt = (VacuumStmt *) parsetree;
- default:
- elog(ERROR, "unrecognized drop object type: %d",
- (int) stmt->removeType);
- break;
- }
+ /* we choose to allow this during "read only" transactions */
+ PreventCommandDuringRecovery((stmt->options & VACOPT_VACUUM) ?
+ "VACUUM" : "ANALYZE");
+ /* forbidden in parallel mode due to CommandIsReadOnly */
+ ExecVacuum(stmt, isTopLevel);
}
break;
- case T_TruncateStmt:
- ExecuteTruncate((TruncateStmt *) parsetree);
+ case T_ExplainStmt:
+ ExplainQuery(pstate, (ExplainStmt *) parsetree, queryString, params, dest);
break;
- case T_CommentStmt:
- CommentObject((CommentStmt *) parsetree);
+ case T_AlterSystemStmt:
+ PreventTransactionChain(isTopLevel, "ALTER SYSTEM");
+ AlterSystemSetConfigFile((AlterSystemStmt *) parsetree);
break;
- case T_SecLabelStmt:
- ExecSecLabelStmt((SecLabelStmt *) parsetree);
+ case T_VariableSetStmt:
+ ExecSetVariableStmt((VariableSetStmt *) parsetree, isTopLevel);
break;
- case T_CopyStmt:
+ case T_VariableShowStmt:
{
- uint64 processed;
+ VariableShowStmt *n = (VariableShowStmt *) parsetree;
- processed = DoCopy((CopyStmt *) parsetree, queryString);
- if (completionTag)
- snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
- "COPY " UINT64_FORMAT, processed);
+ GetPGVariable(n->name, dest);
}
break;
- case T_PrepareStmt:
- CheckRestrictedOperation("PREPARE");
- PrepareQuery((PrepareStmt *) parsetree, queryString);
+ case T_DiscardStmt:
+ /* should we allow DISCARD PLANS? */
+ CheckRestrictedOperation("DISCARD");
+ DiscardCommand((DiscardStmt *) parsetree, isTopLevel);
break;
- case T_ExecuteStmt:
- ExecuteQuery((ExecuteStmt *) parsetree, queryString, params,
- dest, completionTag);
+ case T_CreateEventTrigStmt:
+ /* no event triggers on event triggers */
+ CreateEventTrigger((CreateEventTrigStmt *) parsetree);
break;
- case T_DeallocateStmt:
- CheckRestrictedOperation("DEALLOCATE");
- DeallocateQuery((DeallocateStmt *) parsetree);
+ case T_AlterEventTrigStmt:
+ /* no event triggers on event triggers */
+ AlterEventTrigger((AlterEventTrigStmt *) parsetree);
break;
/*
- * schema
+ * ******************************** ROLE statements ****
*/
- case T_RenameStmt:
- ExecRenameStmt((RenameStmt *) parsetree);
+ case T_CreateRoleStmt:
+ /* no event triggers for global objects */
+ CreateRole(pstate, (CreateRoleStmt *) parsetree);
break;
- case T_AlterObjectSchemaStmt:
- ExecAlterObjectSchemaStmt((AlterObjectSchemaStmt *) parsetree);
+ case T_AlterRoleStmt:
+ /* no event triggers for global objects */
+ AlterRole((AlterRoleStmt *) parsetree);
break;
- case T_AlterOwnerStmt:
- ExecAlterOwnerStmt((AlterOwnerStmt *) parsetree);
+ case T_AlterRoleSetStmt:
+ /* no event triggers for global objects */
+ AlterRoleSet((AlterRoleSetStmt *) parsetree);
break;
- case T_AlterTableStmt:
- {
- List *stmts;
- ListCell *l;
+ case T_DropRoleStmt:
+ /* no event triggers for global objects */
+ DropRole((DropRoleStmt *) parsetree);
+ break;
- /* Run parse analysis ... */
- stmts = transformAlterTableStmt((AlterTableStmt *) parsetree,
- queryString);
+ case T_ReassignOwnedStmt:
+ /* no event triggers for global objects */
+ ReassignOwnedObjects((ReassignOwnedStmt *) parsetree);
+ break;
- /* ... and do it */
- foreach(l, stmts)
- {
- Node *stmt = (Node *) lfirst(l);
+ case T_LockStmt:
- if (IsA(stmt, AlterTableStmt))
- {
- /* Do the table alteration proper */
- AlterTable((AlterTableStmt *) stmt);
- }
- else
- {
- /* Recurse for anything else */
- ProcessUtility(stmt,
- queryString,
- params,
- false,
- None_Receiver,
- NULL);
- }
+ /*
+ * Since the lock would just get dropped immediately, LOCK TABLE
+ * outside a transaction block is presumed to be user error.
+ */
+ RequireTransactionChain(isTopLevel, "LOCK TABLE");
+ /* forbidden in parallel mode due to CommandIsReadOnly */
+ LockTableCommand((LockStmt *) parsetree);
+ break;
- /* Need CCI between commands */
- if (lnext(l) != NULL)
- CommandCounterIncrement();
- }
- }
+ case T_ConstraintsSetStmt:
+ WarnNoTransactionChain(isTopLevel, "SET CONSTRAINTS");
+ AfterTriggerSetState((ConstraintsSetStmt *) parsetree);
break;
- case T_AlterDomainStmt:
- {
- AlterDomainStmt *stmt = (AlterDomainStmt *) parsetree;
+ case T_CheckPointStmt:
+ if (!superuser())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("must be superuser to do CHECKPOINT")));
- /*
- * Some or all of these functions are recursive to cover
- * inherited things, so permission checks are done there.
- */
- switch (stmt->subtype)
+ /*
+ * You might think we should have a PreventCommandDuringRecovery()
+ * here, 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.
+ */
+ RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_WAIT |
+ (RecoveryInProgress() ? 0 : CHECKPOINT_FORCE));
+ break;
+
+ case T_ReindexStmt:
+ {
+ ReindexStmt *stmt = (ReindexStmt *) parsetree;
+
+ /* we choose to allow this during "read only" transactions */
+ PreventCommandDuringRecovery("REINDEX");
+ /* forbidden in parallel mode due to CommandIsReadOnly */
+ switch (stmt->kind)
{
- case 'T': /* ALTER DOMAIN DEFAULT */
+ case REINDEX_OBJECT_INDEX:
+ ReindexIndex(stmt->relation, stmt->options);
+ break;
+ case REINDEX_OBJECT_TABLE:
+ ReindexTable(stmt->relation, stmt->options);
+ break;
+ case REINDEX_OBJECT_SCHEMA:
+ case REINDEX_OBJECT_SYSTEM:
+ case REINDEX_OBJECT_DATABASE:
/*
- * Recursively alter column default for table and, if
- * requested, for descendants
+ * This cannot run inside a user transaction block; if
+ * we were inside a transaction, then its commit- and
+ * start-transaction-command calls would not have the
+ * intended effect!
*/
- AlterDomainDefault(stmt->typeName,
- stmt->def);
- break;
- case 'N': /* ALTER DOMAIN DROP NOT NULL */
- AlterDomainNotNull(stmt->typeName,
- false);
- break;
- case 'O': /* ALTER DOMAIN SET NOT NULL */
- AlterDomainNotNull(stmt->typeName,
- true);
- break;
- case 'C': /* ADD CONSTRAINT */
- AlterDomainAddConstraint(stmt->typeName,
- stmt->def);
- break;
- case 'X': /* DROP CONSTRAINT */
- AlterDomainDropConstraint(stmt->typeName,
- stmt->name,
- stmt->behavior);
- break;
- case 'V': /* VALIDATE CONSTRAINT */
- AlterDomainValidateConstraint(stmt->typeName,
- stmt->name);
+ PreventTransactionChain(isTopLevel,
+ (stmt->kind == REINDEX_OBJECT_SCHEMA) ? "REINDEX SCHEMA" :
+ (stmt->kind == REINDEX_OBJECT_SYSTEM) ? "REINDEX SYSTEM" :
+ "REINDEX DATABASE");
+ ReindexMultipleTables(stmt->name, stmt->kind, stmt->options);
break;
- default: /* oops */
- elog(ERROR, "unrecognized alter domain type: %d",
- (int) stmt->subtype);
+ default:
+ elog(ERROR, "unrecognized object type: %d",
+ (int) stmt->kind);
break;
}
}
break;
- case T_GrantStmt:
- ExecuteGrantStmt((GrantStmt *) parsetree);
- break;
+ /*
+ * The following statements are supported by Event Triggers only
+ * in some cases, so we "fast path" them in the other cases.
+ */
- case T_GrantRoleStmt:
- GrantRole((GrantRoleStmt *) parsetree);
- break;
+ case T_GrantStmt:
+ {
+ GrantStmt *stmt = (GrantStmt *) parsetree;
- case T_AlterDefaultPrivilegesStmt:
- ExecAlterDefaultPrivilegesStmt((AlterDefaultPrivilegesStmt *) parsetree);
+ if (EventTriggerSupportsGrantObjectType(stmt->objtype))
+ ProcessUtilitySlow(pstate, pstmt, queryString,
+ context, params,
+ dest, completionTag);
+ else
+ ExecuteGrantStmt(stmt);
+ }
break;
- /*
- * **************** object creation / destruction *****************
- */
- case T_DefineStmt:
+ case T_DropStmt:
{
- DefineStmt *stmt = (DefineStmt *) parsetree;
+ DropStmt *stmt = (DropStmt *) parsetree;
- switch (stmt->kind)
- {
- case OBJECT_AGGREGATE:
- DefineAggregate(stmt->defnames, stmt->args,
- stmt->oldstyle, stmt->definition);
- break;
- case OBJECT_OPERATOR:
- Assert(stmt->args == NIL);
- DefineOperator(stmt->defnames, stmt->definition);
- break;
- case OBJECT_TYPE:
- Assert(stmt->args == NIL);
- DefineType(stmt->defnames, stmt->definition);
- break;
- case OBJECT_TSPARSER:
- Assert(stmt->args == NIL);
- DefineTSParser(stmt->defnames, stmt->definition);
- break;
- case OBJECT_TSDICTIONARY:
- Assert(stmt->args == NIL);
- DefineTSDictionary(stmt->defnames, stmt->definition);
- break;
- case OBJECT_TSTEMPLATE:
- Assert(stmt->args == NIL);
- DefineTSTemplate(stmt->defnames, stmt->definition);
- break;
- case OBJECT_TSCONFIGURATION:
- Assert(stmt->args == NIL);
- DefineTSConfiguration(stmt->defnames, stmt->definition);
- break;
- case OBJECT_COLLATION:
- Assert(stmt->args == NIL);
- DefineCollation(stmt->defnames, stmt->definition);
- break;
- default:
- elog(ERROR, "unrecognized define stmt type: %d",
- (int) stmt->kind);
- break;
- }
+ if (EventTriggerSupportsObjectType(stmt->removeType))
+ ProcessUtilitySlow(pstate, pstmt, queryString,
+ context, params,
+ dest, completionTag);
+ else
+ ExecDropStmt(stmt, isTopLevel);
}
break;
- case T_CompositeTypeStmt: /* CREATE TYPE (composite) */
+ case T_RenameStmt:
{
- CompositeTypeStmt *stmt = (CompositeTypeStmt *) parsetree;
+ RenameStmt *stmt = (RenameStmt *) parsetree;
- DefineCompositeType(stmt->typevar, stmt->coldeflist);
+ if (EventTriggerSupportsObjectType(stmt->renameType))
+ ProcessUtilitySlow(pstate, pstmt, queryString,
+ context, params,
+ dest, completionTag);
+ else
+ ExecRenameStmt(stmt);
}
break;
- case T_CreateEnumStmt: /* CREATE TYPE (enum) */
- DefineEnum((CreateEnumStmt *) parsetree);
+ case T_AlterObjectDependsStmt:
+ {
+ AlterObjectDependsStmt *stmt = (AlterObjectDependsStmt *) parsetree;
+
+ if (EventTriggerSupportsObjectType(stmt->objectType))
+ ProcessUtilitySlow(pstate, pstmt, queryString,
+ context, params,
+ dest, completionTag);
+ else
+ ExecAlterObjectDependsStmt(stmt, NULL);
+ }
break;
- case T_AlterEnumStmt: /* ALTER TYPE (enum) */
+ case T_AlterObjectSchemaStmt:
+ {
+ AlterObjectSchemaStmt *stmt = (AlterObjectSchemaStmt *) parsetree;
- /*
- * We disallow this in transaction blocks, because we can't cope
- * with enum OID values getting into indexes and then having their
- * defining pg_enum entries go away.
- */
- PreventTransactionChain(isTopLevel, "ALTER TYPE ... ADD");
- AlterEnum((AlterEnumStmt *) parsetree);
+ if (EventTriggerSupportsObjectType(stmt->objectType))
+ ProcessUtilitySlow(pstate, pstmt, queryString,
+ context, params,
+ dest, completionTag);
+ else
+ ExecAlterObjectSchemaStmt(stmt, NULL);
+ }
break;
- case T_ViewStmt: /* CREATE VIEW */
- DefineView((ViewStmt *) parsetree, queryString);
- break;
+ case T_AlterOwnerStmt:
+ {
+ AlterOwnerStmt *stmt = (AlterOwnerStmt *) parsetree;
- case T_CreateFunctionStmt: /* CREATE FUNCTION */
- CreateFunction((CreateFunctionStmt *) parsetree, queryString);
+ if (EventTriggerSupportsObjectType(stmt->objectType))
+ ProcessUtilitySlow(pstate, pstmt, queryString,
+ context, params,
+ dest, completionTag);
+ else
+ ExecAlterOwnerStmt(stmt);
+ }
break;
- case T_AlterFunctionStmt: /* ALTER FUNCTION */
- AlterFunction((AlterFunctionStmt *) parsetree);
- break;
+ case T_CommentStmt:
+ {
+ CommentStmt *stmt = (CommentStmt *) parsetree;
+
+ if (EventTriggerSupportsObjectType(stmt->objtype))
+ ProcessUtilitySlow(pstate, pstmt, queryString,
+ context, params,
+ dest, completionTag);
+ else
+ CommentObject(stmt);
+ break;
+ }
- case T_IndexStmt: /* CREATE INDEX */
+ case T_SecLabelStmt:
{
- IndexStmt *stmt = (IndexStmt *) parsetree;
-
- if (stmt->concurrent)
- PreventTransactionChain(isTopLevel,
- "CREATE INDEX CONCURRENTLY");
-
- CheckRelationOwnership(stmt->relation, true);
-
- /* Run parse analysis ... */
- stmt = transformIndexStmt(stmt, queryString);
-
- /* ... and do it */
- DefineIndex(stmt->relation, /* relation */
- stmt->idxname, /* index name */
- InvalidOid, /* no predefined OID */
- stmt->accessMethod, /* am name */
- stmt->tableSpace,
- stmt->indexParams, /* parameters */
- (Expr *) stmt->whereClause,
- stmt->options,
- stmt->excludeOpNames,
- stmt->unique,
- stmt->primary,
- stmt->isconstraint,
- stmt->deferrable,
- stmt->initdeferred,
- false, /* is_alter_table */
- true, /* check_rights */
- false, /* skip_build */
- false, /* quiet */
- stmt->concurrent); /* concurrent */
+ SecLabelStmt *stmt = (SecLabelStmt *) parsetree;
+
+ if (EventTriggerSupportsObjectType(stmt->objtype))
+ ProcessUtilitySlow(pstate, pstmt, queryString,
+ context, params,
+ dest, completionTag);
+ else
+ ExecSecLabelStmt(stmt);
+ break;
}
- break;
- case T_RuleStmt: /* CREATE RULE */
- DefineRule((RuleStmt *) parsetree, queryString);
+ default:
+ /* All other statement types have event trigger support */
+ ProcessUtilitySlow(pstate, pstmt, queryString,
+ context, params,
+ dest, completionTag);
break;
+ }
- case T_CreateSeqStmt:
- DefineSequence((CreateSeqStmt *) parsetree);
- break;
+ free_parsestate(pstate);
+}
- case T_AlterSeqStmt:
- AlterSequence((AlterSeqStmt *) parsetree);
- break;
+/*
+ * 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,
+ DestReceiver *dest,
+ char *completionTag)
+{
+ Node *parsetree = pstmt->utilityStmt;
+ bool isTopLevel = (context == PROCESS_UTILITY_TOPLEVEL);
+ bool isCompleteQuery = (context <= PROCESS_UTILITY_QUERY);
+ 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);
- case T_RemoveFuncStmt:
- {
- RemoveFuncStmt *stmt = (RemoveFuncStmt *) parsetree;
+ switch (nodeTag(parsetree))
+ {
+ /*
+ * relation and attribute manipulation
+ */
+ case T_CreateSchemaStmt:
+ CreateSchemaCommand((CreateSchemaStmt *) parsetree,
+ queryString,
+ pstmt->stmt_location,
+ pstmt->stmt_len);
- switch (stmt->kind)
+ /*
+ * EventTriggerCollectSimpleCommand called by
+ * CreateSchemaCommand
+ */
+ commandCollected = true;
+ break;
+
+ case T_CreateStmt:
+ case T_CreateForeignTableStmt:
{
- case OBJECT_FUNCTION:
- RemoveFunction(stmt);
- break;
- case OBJECT_AGGREGATE:
- RemoveAggregate(stmt);
- break;
- case OBJECT_OPERATOR:
- RemoveOperator(stmt);
- break;
- default:
- elog(ERROR, "unrecognized object type: %d",
- (int) stmt->kind);
- break;
+ List *stmts;
+ ListCell *l;
+
+ /* Run parse analysis ... */
+ stmts = transformCreateStmt((CreateStmt *) parsetree,
+ queryString);
+
+ /* ... and do it */
+ foreach(l, stmts)
+ {
+ Node *stmt = (Node *) lfirst(l);
+
+ if (IsA(stmt, CreateStmt))
+ {
+ Datum toast_options;
+ static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
+
+ /* Create the table itself */
+ address = DefineRelation((CreateStmt *) stmt,
+ 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,
+ ((CreateStmt *) stmt)->options,
+ "toast",
+ validnsps,
+ true,
+ false);
+ (void) heap_reloptions(RELKIND_TOASTVALUE,
+ toast_options,
+ true);
+
+ NewRelationCreateToastTable(address.objectId,
+ toast_options);
+ }
+ else if (IsA(stmt, CreateForeignTableStmt))
+ {
+ /* Create the table itself */
+ address = DefineRelation((CreateStmt *) stmt,
+ RELKIND_FOREIGN_TABLE,
+ InvalidOid, NULL,
+ queryString);
+ CreateForeignTable((CreateForeignTableStmt *) stmt,
+ address.objectId);
+ EventTriggerCollectSimpleCommand(address,
+ secondaryObject,
+ stmt);
+ }
+ 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,
+ PROCESS_UTILITY_SUBCOMMAND,
+ params,
+ None_Receiver,
+ NULL);
+ }
+
+ /* Need CCI between commands */
+ if (lnext(l) != NULL)
+ CommandCounterIncrement();
+ }
+
+ /*
+ * The multiple commands generated here are stashed
+ * individually, so disable collection below.
+ */
+ commandCollected = true;
}
- }
- break;
+ break;
- case T_DoStmt:
- ExecuteDoStmt((DoStmt *) parsetree);
- break;
+ case T_AlterTableStmt:
+ {
+ AlterTableStmt *atstmt = (AlterTableStmt *) parsetree;
+ Oid relid;
+ List *stmts;
+ ListCell *l;
+ LOCKMODE lockmode;
+
+ /*
+ * 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))
+ {
+ /* Run parse analysis ... */
+ stmts = transformAlterTableStmt(relid, atstmt,
+ queryString);
- case T_CreatedbStmt:
- PreventTransactionChain(isTopLevel, "CREATE DATABASE");
- createdb((CreatedbStmt *) parsetree);
- break;
+ /* ... ensure we have an event trigger context ... */
+ EventTriggerAlterTableStart(parsetree);
+ EventTriggerAlterTableRelid(relid);
- case T_AlterDatabaseStmt:
- AlterDatabase((AlterDatabaseStmt *) parsetree, isTopLevel);
- break;
+ /* ... and do it */
+ foreach(l, stmts)
+ {
+ Node *stmt = (Node *) lfirst(l);
- case T_AlterDatabaseSetStmt:
- AlterDatabaseSet((AlterDatabaseSetStmt *) parsetree);
- break;
+ if (IsA(stmt, AlterTableStmt))
+ {
+ /* Do the table alteration proper */
+ AlterTable(relid, lockmode,
+ (AlterTableStmt *) stmt);
+ }
+ else
+ {
+ /*
+ * Recurse for anything else. If we need to
+ * do so, "close" the current complex-command
+ * set, and start a new one at the bottom;
+ * this is needed to ensure the ordering of
+ * queued commands is consistent with the way
+ * they are executed here.
+ */
+ PlannedStmt *wrapper;
+
+ EventTriggerAlterTableEnd();
+ 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,
+ PROCESS_UTILITY_SUBCOMMAND,
+ params,
+ None_Receiver,
+ NULL);
+ EventTriggerAlterTableStart(parsetree);
+ EventTriggerAlterTableRelid(relid);
+ }
- case T_DropdbStmt:
- {
- DropdbStmt *stmt = (DropdbStmt *) parsetree;
+ /* Need CCI between commands */
+ if (lnext(l) != NULL)
+ CommandCounterIncrement();
+ }
- PreventTransactionChain(isTopLevel, "DROP DATABASE");
- dropdb(stmt->dbname, stmt->missing_ok);
- }
- break;
+ /* done */
+ EventTriggerAlterTableEnd();
+ }
+ else
+ ereport(NOTICE,
+ (errmsg("relation \"%s\" does not exist, skipping",
+ atstmt->relation->relname)));
+ }
- /* Query-level asynchronous notification */
- case T_NotifyStmt:
- {
- NotifyStmt *stmt = (NotifyStmt *) parsetree;
+ /* ALTER TABLE stashes commands internally */
+ commandCollected = true;
+ break;
- PreventCommandDuringRecovery("NOTIFY");
- Async_Notify(stmt->conditionname, stmt->payload);
- }
- break;
+ case T_AlterDomainStmt:
+ {
+ AlterDomainStmt *stmt = (AlterDomainStmt *) parsetree;
- case T_ListenStmt:
- {
- ListenStmt *stmt = (ListenStmt *) 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;
- PreventCommandDuringRecovery("LISTEN");
- CheckRestrictedOperation("LISTEN");
- Async_Listen(stmt->conditionname);
- }
- break;
+ /*
+ * ************* object creation / destruction **************
+ */
+ case T_DefineStmt:
+ {
+ DefineStmt *stmt = (DefineStmt *) parsetree;
- case T_UnlistenStmt:
- {
- UnlistenStmt *stmt = (UnlistenStmt *) parsetree;
+ switch (stmt->kind)
+ {
+ case OBJECT_AGGREGATE:
+ address =
+ DefineAggregate(pstate, stmt->defnames, stmt->args,
+ stmt->oldstyle,
+ stmt->definition);
+ 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);
+ break;
+ default:
+ elog(ERROR, "unrecognized define stmt type: %d",
+ (int) stmt->kind);
+ break;
+ }
+ }
+ break;
- PreventCommandDuringRecovery("UNLISTEN");
- CheckRestrictedOperation("UNLISTEN");
- if (stmt->conditionname)
- Async_Unlisten(stmt->conditionname);
- else
- Async_UnlistenAll();
- }
- break;
+ case T_IndexStmt: /* CREATE INDEX */
+ {
+ IndexStmt *stmt = (IndexStmt *) parsetree;
+ Oid relid;
+ LOCKMODE lockmode;
- case T_LoadStmt:
- {
- LoadStmt *stmt = (LoadStmt *) parsetree;
+ if (stmt->concurrent)
+ PreventTransactionChain(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,
+ false, false,
+ RangeVarCallbackOwnsRelation,
+ NULL);
+
+ /* 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 */
+ false, /* is_alter_table */
+ true, /* check_rights */
+ 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;
- closeAllVfds(); /* probably not necessary... */
- /* Allowed names are restricted if you're not superuser */
- load_file(stmt->filename, !superuser());
- }
- break;
+ case T_CreateExtensionStmt:
+ address = CreateExtension(pstate, (CreateExtensionStmt *) parsetree);
+ break;
- case T_ClusterStmt:
- /* we choose to allow this during "read only" transactions */
- PreventCommandDuringRecovery("CLUSTER");
- cluster((ClusterStmt *) parsetree, isTopLevel);
- break;
+ case T_AlterExtensionStmt:
+ address = ExecAlterExtensionStmt(pstate, (AlterExtensionStmt *) parsetree);
+ break;
- case T_VacuumStmt:
- /* we choose to allow this during "read only" transactions */
- PreventCommandDuringRecovery("VACUUM");
- vacuum((VacuumStmt *) parsetree, InvalidOid, true, NULL, false,
- isTopLevel);
- break;
+ case T_AlterExtensionContentsStmt:
+ address = ExecAlterExtensionContentsStmt((AlterExtensionContentsStmt *) parsetree,
+ &secondaryObject);
+ break;
- case T_ExplainStmt:
- ExplainQuery((ExplainStmt *) parsetree, queryString, params, dest);
- break;
+ case T_CreateFdwStmt:
+ address = CreateForeignDataWrapper((CreateFdwStmt *) parsetree);
+ break;
- case T_VariableSetStmt:
- ExecSetVariableStmt((VariableSetStmt *) parsetree);
- break;
+ case T_AlterFdwStmt:
+ address = AlterForeignDataWrapper((AlterFdwStmt *) parsetree);
+ break;
- case T_VariableShowStmt:
- {
- VariableShowStmt *n = (VariableShowStmt *) parsetree;
+ case T_CreateForeignServerStmt:
+ address = CreateForeignServer((CreateForeignServerStmt *) parsetree);
+ break;
- GetPGVariable(n->name, dest);
- }
- break;
+ case T_AlterForeignServerStmt:
+ address = AlterForeignServer((AlterForeignServerStmt *) parsetree);
+ break;
- case T_DiscardStmt:
- /* should we allow DISCARD PLANS? */
- CheckRestrictedOperation("DISCARD");
- DiscardCommand((DiscardStmt *) parsetree, isTopLevel);
- break;
+ case T_CreateUserMappingStmt:
+ address = CreateUserMapping((CreateUserMappingStmt *) parsetree);
+ break;
- case T_CreateTrigStmt:
- (void) CreateTrigger((CreateTrigStmt *) parsetree, queryString,
- InvalidOid, InvalidOid, false);
- break;
+ case T_AlterUserMappingStmt:
+ address = AlterUserMapping((AlterUserMappingStmt *) parsetree);
+ break;
- case T_DropPropertyStmt:
- {
- DropPropertyStmt *stmt = (DropPropertyStmt *) parsetree;
+ 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;
- switch (stmt->removeType)
+ case T_CompositeTypeStmt: /* CREATE TYPE (composite) */
{
- case OBJECT_RULE:
- /* RemoveRewriteRule checks permissions */
- RemoveRewriteRule(stmt->relation, stmt->property,
- stmt->behavior, stmt->missing_ok);
- break;
- case OBJECT_TRIGGER:
- /* DropTrigger checks permissions */
- DropTrigger(stmt->relation, stmt->property,
- stmt->behavior, stmt->missing_ok);
- break;
- default:
- elog(ERROR, "unrecognized object type: %d",
- (int) stmt->removeType);
- break;
+ CompositeTypeStmt *stmt = (CompositeTypeStmt *) parsetree;
+
+ address = DefineCompositeType(stmt->typevar,
+ stmt->coldeflist);
}
- }
- break;
+ break;
- case T_CreatePLangStmt:
- CreateProceduralLanguage((CreatePLangStmt *) parsetree);
- break;
+ case T_CreateEnumStmt: /* CREATE TYPE AS ENUM */
+ address = DefineEnum((CreateEnumStmt *) parsetree);
+ break;
- case T_DropPLangStmt:
- DropProceduralLanguage((DropPLangStmt *) parsetree);
- break;
+ case T_CreateRangeStmt: /* CREATE TYPE AS RANGE */
+ address = DefineRange((CreateRangeStmt *) parsetree);
+ break;
- /*
- * ******************************** DOMAIN statements ****
- */
- case T_CreateDomainStmt:
- DefineDomain((CreateDomainStmt *) parsetree);
- break;
+ case T_AlterEnumStmt: /* ALTER TYPE (enum) */
+ address = AlterEnum((AlterEnumStmt *) parsetree);
+ break;
- /*
- * ******************************** ROLE statements ****
- */
- case T_CreateRoleStmt:
- CreateRole((CreateRoleStmt *) 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_AlterRoleStmt:
- AlterRole((AlterRoleStmt *) parsetree);
- break;
+ case T_CreateFunctionStmt: /* CREATE FUNCTION */
+ address = CreateFunction(pstate, (CreateFunctionStmt *) parsetree);
+ break;
- case T_AlterRoleSetStmt:
- AlterRoleSet((AlterRoleSetStmt *) parsetree);
- break;
+ case T_AlterFunctionStmt: /* ALTER FUNCTION */
+ address = AlterFunction(pstate, (AlterFunctionStmt *) parsetree);
+ break;
- case T_DropRoleStmt:
- DropRole((DropRoleStmt *) parsetree);
- break;
+ case T_RuleStmt: /* CREATE RULE */
+ address = DefineRule((RuleStmt *) parsetree, queryString);
+ break;
- case T_DropOwnedStmt:
- DropOwnedObjects((DropOwnedStmt *) parsetree);
- break;
+ case T_CreateSeqStmt:
+ address = DefineSequence(pstate, (CreateSeqStmt *) parsetree);
+ break;
- case T_ReassignOwnedStmt:
- ReassignOwnedObjects((ReassignOwnedStmt *) parsetree);
- break;
+ case T_AlterSeqStmt:
+ address = AlterSequence(pstate, (AlterSeqStmt *) parsetree);
+ break;
- case T_LockStmt:
+ case T_CreateTableAsStmt:
+ address = ExecCreateTableAs((CreateTableAsStmt *) parsetree,
+ queryString, params, completionTag);
+ break;
- /*
- * Since the lock would just get dropped immediately, LOCK TABLE
- * outside a transaction block is presumed to be user error.
- */
- RequireTransactionChain(isTopLevel, "LOCK TABLE");
- LockTableCommand((LockStmt *) parsetree);
- break;
+ case T_RefreshMatViewStmt:
- case T_ConstraintsSetStmt:
- AfterTriggerSetState((ConstraintsSetStmt *) parsetree);
- break;
+ /*
+ * REFRSH 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, completionTag);
+ }
+ PG_CATCH();
+ {
+ EventTriggerUndoInhibitCommandCollection();
+ PG_RE_THROW();
+ }
+ PG_END_TRY();
+ EventTriggerUndoInhibitCommandCollection();
+ break;
- case T_CheckPointStmt:
- if (!superuser())
- ereport(ERROR,
- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be superuser to do CHECKPOINT")));
+ case T_CreateTrigStmt:
+ address = CreateTrigger((CreateTrigStmt *) parsetree,
+ queryString, InvalidOid, InvalidOid,
+ InvalidOid, InvalidOid, false);
+ break;
- /*
- * You might think we should have a PreventCommandDuringRecovery()
- * here, 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.
- */
- RequestCheckpoint(CHECKPOINT_IMMEDIATE | CHECKPOINT_WAIT |
- (RecoveryInProgress() ? 0 : CHECKPOINT_FORCE));
- 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);
+ 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_ReindexStmt:
- {
- ReindexStmt *stmt = (ReindexStmt *) parsetree;
+ case T_AlterObjectDependsStmt:
+ address =
+ ExecAlterObjectDependsStmt((AlterObjectDependsStmt *) parsetree,
+ &secondaryObject);
+ break;
- /* we choose to allow this during "read only" transactions */
- PreventCommandDuringRecovery("REINDEX");
- switch (stmt->kind)
- {
- case OBJECT_INDEX:
- ReindexIndex(stmt->relation);
- break;
- case OBJECT_TABLE:
- ReindexTable(stmt->relation);
- break;
- case OBJECT_DATABASE:
+ case T_AlterObjectSchemaStmt:
+ address =
+ ExecAlterObjectSchemaStmt((AlterObjectSchemaStmt *) parsetree,
+ &secondaryObject);
+ break;
- /*
- * This cannot run inside a user transaction block; if
- * we were inside a transaction, then its commit- and
- * start-transaction-command calls would not have the
- * intended effect!
- */
- PreventTransactionChain(isTopLevel,
- "REINDEX DATABASE");
- ReindexDatabase(stmt->name,
- stmt->do_system, stmt->do_user);
- break;
- default:
- elog(ERROR, "unrecognized object type: %d",
- (int) stmt->kind);
- break;
- }
+ case T_AlterOwnerStmt:
+ address = ExecAlterOwnerStmt((AlterOwnerStmt *) parsetree);
break;
- }
- break;
- case T_CreateConversionStmt:
- CreateConversionCommand((CreateConversionStmt *) parsetree);
- break;
+ case T_AlterOperatorStmt:
+ address = AlterOperator((AlterOperatorStmt *) parsetree);
+ break;
- case T_CreateCastStmt:
- CreateCast((CreateCastStmt *) parsetree);
- break;
+ case T_CommentStmt:
+ address = CommentObject((CommentStmt *) parsetree);
+ break;
- case T_DropCastStmt:
- DropCast((DropCastStmt *) parsetree);
- break;
+ case T_GrantStmt:
+ ExecuteGrantStmt((GrantStmt *) parsetree);
+ /* commands are stashed in ExecGrantStmt_oids */
+ commandCollected = true;
+ break;
- case T_CreateOpClassStmt:
- DefineOpClass((CreateOpClassStmt *) parsetree);
- break;
+ case T_DropOwnedStmt:
+ DropOwnedObjects((DropOwnedStmt *) parsetree);
+ /* no commands stashed for DROP */
+ commandCollected = true;
+ break;
- case T_CreateOpFamilyStmt:
- DefineOpFamily((CreateOpFamilyStmt *) parsetree);
- break;
+ case T_AlterDefaultPrivilegesStmt:
+ ExecAlterDefaultPrivilegesStmt(pstate, (AlterDefaultPrivilegesStmt *) parsetree);
+ EventTriggerCollectAlterDefPrivs((AlterDefaultPrivilegesStmt *) parsetree);
+ commandCollected = true;
+ break;
- case T_AlterOpFamilyStmt:
- AlterOpFamily((AlterOpFamilyStmt *) parsetree);
- break;
+ case T_CreatePolicyStmt: /* CREATE POLICY */
+ address = CreatePolicy((CreatePolicyStmt *) parsetree);
+ break;
- case T_RemoveOpClassStmt:
- RemoveOpClass((RemoveOpClassStmt *) parsetree);
- break;
+ case T_AlterPolicyStmt: /* ALTER POLICY */
+ address = AlterPolicy((AlterPolicyStmt *) parsetree);
+ break;
- case T_RemoveOpFamilyStmt:
- RemoveOpFamily((RemoveOpFamilyStmt *) parsetree);
- break;
+ case T_SecLabelStmt:
+ address = ExecSecLabelStmt((SecLabelStmt *) parsetree);
+ break;
- case T_AlterTSDictionaryStmt:
- AlterTSDictionary((AlterTSDictionaryStmt *) parsetree);
- break;
+ case T_CreateAmStmt:
+ address = CreateAccessMethod((CreateAmStmt *) parsetree);
+ break;
- case T_AlterTSConfigurationStmt:
- AlterTSConfiguration((AlterTSConfigurationStmt *) 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_CATCH();
+ {
+ if (needCleanup)
+ EventTriggerEndCompleteQuery();
+ PG_RE_THROW();
+ }
+ PG_END_TRY();
+
+ if (needCleanup)
+ EventTriggerEndCompleteQuery();
+}
+
+/*
+ * Dispatch function for DropStmt
+ */
+static void
+ExecDropStmt(DropStmt *stmt, bool isTopLevel)
+{
+ switch (stmt->removeType)
+ {
+ case OBJECT_INDEX:
+ if (stmt->concurrent)
+ PreventTransactionChain(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:
- elog(ERROR, "unrecognized node type: %d",
- (int) nodeTag(parsetree));
+ RemoveObjects(stmt);
break;
}
}
+
/*
* UtilityReturnsTuples
* Return "true" if this utility statement will send output to the
ExecuteStmt *stmt = (ExecuteStmt *) parsetree;
PreparedStatement *entry;
- if (stmt->into)
- return false;
entry = FetchPreparedStatement(stmt->name, false);
if (!entry)
return false; /* not our business to raise error */
ExecuteStmt *stmt = (ExecuteStmt *) parsetree;
PreparedStatement *entry;
- if (stmt->into)
- return NULL;
entry = FetchPreparedStatement(stmt->name, false);
if (!entry)
return NULL; /* not our business to raise error */
switch (parsetree->commandType)
{
case CMD_SELECT:
- /* returns tuples ... unless it's DECLARE CURSOR or SELECT INTO */
- if (parsetree->utilityStmt == NULL &&
- parsetree->intoClause == NULL)
- return true;
- break;
+ /* returns tuples */
+ return true;
case CMD_INSERT:
case CMD_UPDATE:
case CMD_DELETE:
#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 = (Query *) ((DeclareCursorStmt *) parsetree)->query;
+ Assert(IsA(qry, Query));
+ if (qry->commandType == CMD_UTILITY)
+ return UtilityContainsQuery(qry->utilityStmt);
+ return qry;
+
+ case T_ExplainStmt:
+ qry = (Query *) ((ExplainStmt *) parsetree)->query;
+ Assert(IsA(qry, Query));
+ if (qry->commandType == CMD_UTILITY)
+ return UtilityContainsQuery(qry->utilityStmt);
+ return qry;
+
+ case T_CreateTableAsStmt:
+ qry = (Query *) ((CreateTableAsStmt *) parsetree)->query;
+ Assert(IsA(qry, Query));
+ if (qry->commandType == CMD_UTILITY)
+ return UtilityContainsQuery(qry->utilityStmt);
+ return qry;
+
+ default:
+ return NULL;
+ }
+}
+
+
/*
* AlterObjectTypeCommandTag
* helper function for CreateCommandTag
case OBJECT_COLUMN:
tag = "ALTER TABLE";
break;
- case OBJECT_CONSTRAINT:
- tag = "ALTER TABLE";
- break;
case OBJECT_CONVERSION:
tag = "ALTER CONVERSION";
break;
tag = "ALTER DATABASE";
break;
case OBJECT_DOMAIN:
+ case OBJECT_DOMCONSTRAINT:
tag = "ALTER DOMAIN";
break;
case OBJECT_EXTENSION:
case OBJECT_OPFAMILY:
tag = "ALTER OPERATOR FAMILY";
break;
+ case OBJECT_POLICY:
+ tag = "ALTER POLICY";
+ break;
case OBJECT_ROLE:
tag = "ALTER ROLE";
break;
tag = "ALTER SEQUENCE";
break;
case OBJECT_TABLE:
+ case OBJECT_TABCONSTRAINT:
tag = "ALTER TABLE";
break;
case OBJECT_TABLESPACE:
case OBJECT_TRIGGER:
tag = "ALTER TRIGGER";
break;
+ case OBJECT_EVENT_TRIGGER:
+ tag = "ALTER EVENT TRIGGER";
+ break;
case OBJECT_TSCONFIGURATION:
tag = "ALTER TEXT SEARCH CONFIGURATION";
break;
case OBJECT_VIEW:
tag = "ALTER VIEW";
break;
+ case OBJECT_MATVIEW:
+ tag = "ALTER MATERIALIZED VIEW";
+ break;
default:
tag = "???";
break;
/*
* CreateCommandTag
* utility to get a string representation of the command operation,
- * given either a raw (un-analyzed) parsetree or a planned query.
+ * 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.
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 = "INSERT";
tag = "ALTER FOREIGN DATA WRAPPER";
break;
- case T_DropFdwStmt:
- tag = "DROP FOREIGN DATA WRAPPER";
- break;
-
case T_CreateForeignServerStmt:
tag = "CREATE SERVER";
break;
tag = "ALTER SERVER";
break;
- case T_DropForeignServerStmt:
- tag = "DROP SERVER";
- break;
-
case T_CreateUserMappingStmt:
tag = "CREATE USER MAPPING";
break;
tag = "CREATE FOREIGN TABLE";
break;
+ case T_ImportForeignSchemaStmt:
+ tag = "IMPORT FOREIGN SCHEMA";
+ break;
+
case T_DropStmt:
switch (((DropStmt *) parsetree)->removeType)
{
case OBJECT_VIEW:
tag = "DROP VIEW";
break;
+ case OBJECT_MATVIEW:
+ tag = "DROP MATERIALIZED VIEW";
+ break;
case OBJECT_INDEX:
tag = "DROP INDEX";
break;
case OBJECT_EXTENSION:
tag = "DROP EXTENSION";
break;
+ case OBJECT_FUNCTION:
+ tag = "DROP FUNCTION";
+ break;
+ case OBJECT_AGGREGATE:
+ tag = "DROP AGGREGATE";
+ break;
+ case OBJECT_OPERATOR:
+ tag = "DROP OPERATOR";
+ break;
+ case OBJECT_LANGUAGE:
+ tag = "DROP LANGUAGE";
+ break;
+ case OBJECT_CAST:
+ tag = "DROP CAST";
+ break;
+ case OBJECT_TRIGGER:
+ tag = "DROP TRIGGER";
+ break;
+ case OBJECT_EVENT_TRIGGER:
+ tag = "DROP EVENT TRIGGER";
+ break;
+ case OBJECT_RULE:
+ tag = "DROP RULE";
+ break;
+ case OBJECT_FDW:
+ tag = "DROP FOREIGN DATA WRAPPER";
+ break;
+ case OBJECT_FOREIGN_SERVER:
+ tag = "DROP SERVER";
+ break;
+ case OBJECT_OPCLASS:
+ tag = "DROP OPERATOR CLASS";
+ break;
+ case OBJECT_OPFAMILY:
+ tag = "DROP OPERATOR FAMILY";
+ break;
+ case OBJECT_POLICY:
+ tag = "DROP POLICY";
+ break;
+ case OBJECT_TRANSFORM:
+ tag = "DROP TRANSFORM";
+ break;
+ case OBJECT_ACCESS_METHOD:
+ tag = "DROP ACCESS METHOD";
+ break;
default:
tag = "???";
}
tag = AlterObjectTypeCommandTag(((RenameStmt *) parsetree)->renameType);
break;
+ case T_AlterObjectDependsStmt:
+ tag = AlterObjectTypeCommandTag(((AlterObjectDependsStmt *) parsetree)->objectType);
+ break;
+
case T_AlterObjectSchemaStmt:
tag = AlterObjectTypeCommandTag(((AlterObjectSchemaStmt *) parsetree)->objectType);
break;
tag = AlterObjectTypeCommandTag(((AlterOwnerStmt *) parsetree)->objectType);
break;
+ case T_AlterTableMoveAllStmt:
+ tag = AlterObjectTypeCommandTag(((AlterTableMoveAllStmt *) parsetree)->objtype);
+ break;
+
case T_AlterTableStmt:
tag = AlterObjectTypeCommandTag(((AlterTableStmt *) parsetree)->relkind);
break;
case OBJECT_COLLATION:
tag = "CREATE COLLATION";
break;
+ case OBJECT_ACCESS_METHOD:
+ tag = "CREATE ACCESS METHOD";
+ break;
default:
tag = "???";
}
tag = "CREATE TYPE";
break;
+ case T_CreateRangeStmt:
+ tag = "CREATE TYPE";
+ break;
+
case T_AlterEnumStmt:
tag = "ALTER TYPE";
break;
tag = "ALTER SEQUENCE";
break;
- case T_RemoveFuncStmt:
- switch (((RemoveFuncStmt *) parsetree)->kind)
- {
- case OBJECT_FUNCTION:
- tag = "DROP FUNCTION";
- break;
- case OBJECT_AGGREGATE:
- tag = "DROP AGGREGATE";
- break;
- case OBJECT_OPERATOR:
- tag = "DROP OPERATOR";
- break;
- default:
- tag = "???";
- }
- break;
-
case T_DoStmt:
tag = "DO";
break;
tag = "EXPLAIN";
break;
+ case T_CreateTableAsStmt:
+ switch (((CreateTableAsStmt *) parsetree)->relkind)
+ {
+ case OBJECT_TABLE:
+ if (((CreateTableAsStmt *) parsetree)->is_select_into)
+ tag = "SELECT INTO";
+ else
+ tag = "CREATE TABLE AS";
+ break;
+ case OBJECT_MATVIEW:
+ tag = "CREATE MATERIALIZED VIEW";
+ break;
+ default:
+ tag = "???";
+ }
+ break;
+
+ case T_RefreshMatViewStmt:
+ tag = "REFRESH MATERIALIZED VIEW";
+ break;
+
+ case T_AlterSystemStmt:
+ tag = "ALTER SYSTEM";
+ break;
+
case T_VariableSetStmt:
switch (((VariableSetStmt *) parsetree)->kind)
{
case DISCARD_TEMP:
tag = "DISCARD TEMP";
break;
+ case DISCARD_SEQUENCES:
+ tag = "DISCARD SEQUENCES";
+ break;
default:
tag = "???";
}
break;
+ case T_CreateTransformStmt:
+ tag = "CREATE TRANSFORM";
+ break;
+
case T_CreateTrigStmt:
tag = "CREATE TRIGGER";
break;
- case T_DropPropertyStmt:
- switch (((DropPropertyStmt *) parsetree)->removeType)
- {
- case OBJECT_TRIGGER:
- tag = "DROP TRIGGER";
- break;
- case OBJECT_RULE:
- tag = "DROP RULE";
- break;
- default:
- tag = "???";
- }
+ case T_CreateEventTrigStmt:
+ tag = "CREATE EVENT TRIGGER";
break;
- case T_CreatePLangStmt:
- tag = "CREATE LANGUAGE";
+ case T_AlterEventTrigStmt:
+ tag = "ALTER EVENT TRIGGER";
break;
- case T_DropPLangStmt:
- tag = "DROP LANGUAGE";
+ case T_CreatePLangStmt:
+ tag = "CREATE LANGUAGE";
break;
case T_CreateRoleStmt:
tag = "CREATE CAST";
break;
- case T_DropCastStmt:
- tag = "DROP CAST";
- break;
-
case T_CreateOpClassStmt:
tag = "CREATE OPERATOR CLASS";
break;
tag = "ALTER OPERATOR FAMILY";
break;
- case T_RemoveOpClassStmt:
- tag = "DROP OPERATOR CLASS";
- break;
-
- case T_RemoveOpFamilyStmt:
- tag = "DROP OPERATOR FAMILY";
+ case T_AlterOperatorStmt:
+ tag = "ALTER OPERATOR";
break;
case T_AlterTSDictionaryStmt:
tag = "ALTER TEXT SEARCH CONFIGURATION";
break;
+ case T_CreatePolicyStmt:
+ tag = "CREATE POLICY";
+ break;
+
+ case T_AlterPolicyStmt:
+ tag = "ALTER POLICY";
+ break;
+
+ case T_CreateAmStmt:
+ tag = "CREATE ACCESS METHOD";
+ break;
+
case T_PrepareStmt:
tag = "PREPARE";
break;
* will be useful for complaints about read-only
* statements
*/
- if (stmt->utilityStmt != NULL)
- {
- Assert(IsA(stmt->utilityStmt, DeclareCursorStmt));
- tag = "DECLARE CURSOR";
- }
- else if (stmt->intoClause != NULL)
- tag = "SELECT INTO";
- else if (stmt->rowMarks != NIL)
+ if (stmt->rowMarks != NIL)
{
/* not 100% but probably close enough */
- if (((PlanRowMark *) linitial(stmt->rowMarks))->markType == ROW_MARK_EXCLUSIVE)
- tag = "SELECT FOR UPDATE";
- else
- tag = "SELECT FOR SHARE";
+ switch (((PlanRowMark *) linitial(stmt->rowMarks))->strength)
+ {
+ case LCS_FORKEYSHARE:
+ tag = "SELECT FOR KEY SHARE";
+ break;
+ case LCS_FORSHARE:
+ tag = "SELECT FOR SHARE";
+ break;
+ case LCS_FORNOKEYUPDATE:
+ tag = "SELECT FOR NO KEY UPDATE";
+ break;
+ case LCS_FORUPDATE:
+ tag = "SELECT FOR UPDATE";
+ break;
+ default:
+ tag = "SELECT";
+ break;
+ }
}
else
tag = "SELECT";
case CMD_DELETE:
tag = "DELETE";
break;
+ case CMD_UTILITY:
+ tag = CreateCommandTag(stmt->utilityStmt);
+ break;
default:
elog(WARNING, "unrecognized commandType: %d",
(int) stmt->commandType);
* will be useful for complaints about read-only
* statements
*/
- if (stmt->utilityStmt != NULL)
- {
- Assert(IsA(stmt->utilityStmt, DeclareCursorStmt));
- tag = "DECLARE CURSOR";
- }
- else if (stmt->intoClause != NULL)
- tag = "SELECT INTO";
- else if (stmt->rowMarks != NIL)
+ if (stmt->rowMarks != NIL)
{
/* not 100% but probably close enough */
- if (((RowMarkClause *) linitial(stmt->rowMarks))->forUpdate)
- tag = "SELECT FOR UPDATE";
- else
- tag = "SELECT FOR SHARE";
+ switch (((RowMarkClause *) linitial(stmt->rowMarks))->strength)
+ {
+ case LCS_FORKEYSHARE:
+ tag = "SELECT FOR KEY SHARE";
+ break;
+ case LCS_FORSHARE:
+ tag = "SELECT FOR SHARE";
+ break;
+ case LCS_FORNOKEYUPDATE:
+ tag = "SELECT FOR NO KEY UPDATE";
+ break;
+ case LCS_FORUPDATE:
+ tag = "SELECT FOR UPDATE";
+ break;
+ default:
+ tag = "???";
+ break;
+ }
}
else
tag = "SELECT";
/*
* GetCommandLogLevel
* utility to get the minimum log_statement level for a command,
- * given either a raw (un-analyzed) parsetree or a planned query.
+ * 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.
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_SelectStmt:
if (((SelectStmt *) parsetree)->intoClause)
- lev = LOGSTMT_DDL; /* CREATE AS, SELECT INTO */
+ lev = LOGSTMT_DDL; /* SELECT INTO */
else
lev = LOGSTMT_ALL;
break;
case T_CreateFdwStmt:
case T_AlterFdwStmt:
- case T_DropFdwStmt:
case T_CreateForeignServerStmt:
case T_AlterForeignServerStmt:
- case T_DropForeignServerStmt:
case T_CreateUserMappingStmt:
case T_AlterUserMappingStmt:
case T_DropUserMappingStmt:
+ case T_ImportForeignSchemaStmt:
lev = LOGSTMT_DDL;
break;
/* Look through an EXECUTE to the referenced stmt */
ps = FetchPreparedStatement(stmt->name, false);
- if (ps)
- lev = GetCommandLogLevel(ps->plansource->raw_parse_tree);
+ if (ps && ps->plansource->raw_parse_tree)
+ lev = GetCommandLogLevel(ps->plansource->raw_parse_tree->stmt);
else
lev = LOGSTMT_ALL;
}
lev = LOGSTMT_DDL;
break;
+ case T_AlterObjectDependsStmt:
+ lev = LOGSTMT_DDL;
+ break;
+
case T_AlterObjectSchemaStmt:
lev = LOGSTMT_DDL;
break;
lev = LOGSTMT_DDL;
break;
+ case T_AlterTableMoveAllStmt:
case T_AlterTableStmt:
lev = LOGSTMT_DDL;
break;
lev = LOGSTMT_DDL;
break;
+ case T_CreateRangeStmt:
+ lev = LOGSTMT_DDL;
+ break;
+
case T_AlterEnumStmt:
lev = LOGSTMT_DDL;
break;
lev = LOGSTMT_DDL;
break;
- case T_RemoveFuncStmt:
- lev = LOGSTMT_DDL;
- break;
-
case T_DoStmt:
lev = LOGSTMT_ALL;
break;
}
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;
lev = LOGSTMT_DDL;
break;
- case T_DropPropertyStmt:
+ case T_CreateEventTrigStmt:
lev = LOGSTMT_DDL;
break;
- case T_CreatePLangStmt:
+ case T_AlterEventTrigStmt:
lev = LOGSTMT_DDL;
break;
- case T_DropPLangStmt:
+ case T_CreatePLangStmt:
lev = LOGSTMT_DDL;
break;
lev = LOGSTMT_DDL;
break;
- case T_DropCastStmt:
+ case T_CreateOpClassStmt:
lev = LOGSTMT_DDL;
break;
- case T_CreateOpClassStmt:
+ case T_CreateOpFamilyStmt:
lev = LOGSTMT_DDL;
break;
- case T_CreateOpFamilyStmt:
+ case T_CreateTransformStmt:
lev = LOGSTMT_DDL;
break;
lev = LOGSTMT_DDL;
break;
- case T_RemoveOpClassStmt:
+ case T_CreatePolicyStmt:
lev = LOGSTMT_DDL;
break;
- case T_RemoveOpFamilyStmt:
+ case T_AlterPolicyStmt:
lev = LOGSTMT_DDL;
break;
lev = LOGSTMT_DDL;
break;
+ case T_CreateAmStmt:
+ lev = LOGSTMT_DDL;
+ break;
+
/* already-planned queries */
case T_PlannedStmt:
{
switch (stmt->commandType)
{
case CMD_SELECT:
- if (stmt->intoClause != NULL)
- lev = LOGSTMT_DDL; /* CREATE AS, SELECT INTO */
- else
- lev = LOGSTMT_ALL; /* SELECT or DECLARE CURSOR */
+ lev = LOGSTMT_ALL;
break;
case CMD_UPDATE:
lev = LOGSTMT_MOD;
break;
+ case CMD_UTILITY:
+ lev = GetCommandLogLevel(stmt->utilityStmt);
+ break;
+
default:
elog(WARNING, "unrecognized commandType: %d",
(int) stmt->commandType);
switch (stmt->commandType)
{
case CMD_SELECT:
- if (stmt->intoClause != NULL)
- lev = LOGSTMT_DDL; /* CREATE AS, SELECT INTO */
- else
- lev = LOGSTMT_ALL; /* SELECT or DECLARE CURSOR */
+ lev = LOGSTMT_ALL;
break;
case CMD_UPDATE: