* commands. At one time acted as an interface between the Lisp and C
* systems.
*
- * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
ProcessUtility_hook_type ProcessUtility_hook = NULL;
/* local function declarations */
-static void ProcessUtilitySlow(Node *parsetree,
+static void ProcessUtilitySlow(ParseState *pstate,
+ PlannedStmt *pstmt,
const char *queryString,
ProcessUtilityContext context,
ParamListInfo params,
* 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->rowMarks != NIL)
- return false; /* SELECT FOR [KEY] 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;
}
/*
* 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
- * or PreventCommandIfParallelMode 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:
* 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)
* 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,
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,
+ (*ProcessUtility_hook) (pstmt, queryString,
context, params,
dest, completionTag);
else
- standard_ProcessUtility(parsetree, queryString,
+ standard_ProcessUtility(pstmt, queryString,
context, params,
dest, completionTag);
}
* which requires being in a valid transaction.
*/
void
-standard_ProcessUtility(Node *parsetree,
+standard_ProcessUtility(PlannedStmt *pstmt,
const char *queryString,
ProcessUtilityContext context,
ParamListInfo params,
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:
{
uint64 processed;
- DoCopy((CopyStmt *) parsetree, queryString, &processed);
+ DoCopy(pstate, (CopyStmt *) parsetree,
+ pstmt->stmt_location, pstmt->stmt_len,
+ &processed);
if (completionTag)
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
"COPY " UINT64_FORMAT, processed);
case T_PrepareStmt:
CheckRestrictedOperation("PREPARE");
- PrepareQuery((PrepareStmt *) parsetree, queryString);
+ PrepareQuery((PrepareStmt *) parsetree, queryString,
+ pstmt->stmt_location, pstmt->stmt_len);
break;
case T_ExecuteStmt:
case T_CreatedbStmt:
/* no event triggers for global objects */
PreventTransactionChain(isTopLevel, "CREATE DATABASE");
- createdb((CreatedbStmt *) parsetree);
+ createdb(pstate, (CreatedbStmt *) parsetree);
break;
case T_AlterDatabaseStmt:
/* no event triggers for global objects */
- AlterDatabase((AlterDatabaseStmt *) parsetree, isTopLevel);
+ AlterDatabase(pstate, (AlterDatabaseStmt *) parsetree, isTopLevel);
break;
case T_AlterDatabaseSetStmt:
break;
case T_ExplainStmt:
- ExplainQuery((ExplainStmt *) parsetree, queryString, params, dest);
+ ExplainQuery(pstate, (ExplainStmt *) parsetree, queryString, params, dest);
break;
case T_AlterSystemStmt:
*/
case T_CreateRoleStmt:
/* no event triggers for global objects */
- CreateRole((CreateRoleStmt *) parsetree);
+ CreateRole(pstate, (CreateRoleStmt *) parsetree);
break;
case T_AlterRoleStmt:
switch (stmt->kind)
{
case REINDEX_OBJECT_INDEX:
- ReindexIndex(stmt->relation);
+ ReindexIndex(stmt->relation, stmt->options);
break;
case REINDEX_OBJECT_TABLE:
- ReindexTable(stmt->relation);
+ ReindexTable(stmt->relation, stmt->options);
break;
case REINDEX_OBJECT_SCHEMA:
case REINDEX_OBJECT_SYSTEM:
(stmt->kind == REINDEX_OBJECT_SCHEMA) ? "REINDEX SCHEMA" :
(stmt->kind == REINDEX_OBJECT_SYSTEM) ? "REINDEX SYSTEM" :
"REINDEX DATABASE");
- ReindexMultipleTables(stmt->name, stmt->kind);
+ ReindexMultipleTables(stmt->name, stmt->kind, stmt->options);
break;
default:
elog(ERROR, "unrecognized object type: %d",
GrantStmt *stmt = (GrantStmt *) parsetree;
if (EventTriggerSupportsGrantObjectType(stmt->objtype))
- ProcessUtilitySlow(parsetree, queryString,
+ ProcessUtilitySlow(pstate, pstmt, queryString,
context, params,
dest, completionTag);
else
- ExecuteGrantStmt((GrantStmt *) parsetree);
+ ExecuteGrantStmt(stmt);
}
break;
DropStmt *stmt = (DropStmt *) parsetree;
if (EventTriggerSupportsObjectType(stmt->removeType))
- ProcessUtilitySlow(parsetree, queryString,
+ ProcessUtilitySlow(pstate, pstmt, queryString,
context, params,
dest, completionTag);
else
RenameStmt *stmt = (RenameStmt *) parsetree;
if (EventTriggerSupportsObjectType(stmt->renameType))
- ProcessUtilitySlow(parsetree, queryString,
+ ProcessUtilitySlow(pstate, pstmt, queryString,
context, params,
dest, completionTag);
else
}
break;
+ 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_AlterObjectSchemaStmt:
{
AlterObjectSchemaStmt *stmt = (AlterObjectSchemaStmt *) parsetree;
if (EventTriggerSupportsObjectType(stmt->objectType))
- ProcessUtilitySlow(parsetree, queryString,
+ ProcessUtilitySlow(pstate, pstmt, queryString,
context, params,
dest, completionTag);
else
AlterOwnerStmt *stmt = (AlterOwnerStmt *) parsetree;
if (EventTriggerSupportsObjectType(stmt->objectType))
- ProcessUtilitySlow(parsetree, queryString,
+ ProcessUtilitySlow(pstate, pstmt, queryString,
context, params,
dest, completionTag);
else
CommentStmt *stmt = (CommentStmt *) parsetree;
if (EventTriggerSupportsObjectType(stmt->objtype))
- ProcessUtilitySlow(parsetree, queryString,
+ ProcessUtilitySlow(pstate, pstmt, queryString,
context, params,
dest, completionTag);
else
- CommentObject((CommentStmt *) parsetree);
+ CommentObject(stmt);
break;
}
SecLabelStmt *stmt = (SecLabelStmt *) parsetree;
if (EventTriggerSupportsObjectType(stmt->objtype))
- ProcessUtilitySlow(parsetree, queryString,
+ ProcessUtilitySlow(pstate, pstmt, queryString,
context, params,
dest, completionTag);
else
default:
/* All other statement types have event trigger support */
- ProcessUtilitySlow(parsetree, queryString,
+ ProcessUtilitySlow(pstate, pstmt, queryString,
context, params,
dest, completionTag);
break;
}
+
+ free_parsestate(pstate);
}
/*
* perform the trigger support calls if the context allows it.
*/
static void
-ProcessUtilitySlow(Node *parsetree,
+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();
*/
case T_CreateSchemaStmt:
CreateSchemaCommand((CreateSchemaStmt *) parsetree,
- queryString);
+ queryString,
+ pstmt->stmt_location,
+ pstmt->stmt_len);
+
+ /*
+ * EventTriggerCollectSimpleCommand called by
+ * CreateSchemaCommand
+ */
+ commandCollected = true;
break;
case T_CreateStmt:
/* Create the table itself */
address = DefineRelation((CreateStmt *) stmt,
RELKIND_RELATION,
- InvalidOid, NULL);
+ InvalidOid, NULL,
+ queryString);
+ EventTriggerCollectSimpleCommand(address,
+ secondaryObject,
+ stmt);
/*
* Let NewRelationCreateToastTable decide if this
/* Create the table itself */
address = DefineRelation((CreateStmt *) stmt,
RELKIND_FOREIGN_TABLE,
- InvalidOid, NULL);
+ InvalidOid, NULL,
+ queryString);
CreateForeignTable((CreateForeignTableStmt *) stmt,
address.objectId);
+ EventTriggerCollectSimpleCommand(address,
+ secondaryObject,
+ stmt);
}
else
{
- /* Recurse for anything else */
- ProcessUtility(stmt,
+ /*
+ * 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,
if (lnext(l) != NULL)
CommandCounterIncrement();
}
+
+ /*
+ * The multiple commands generated here are stashed
+ * individually, so disable collection below.
+ */
+ commandCollected = true;
}
break;
stmts = transformAlterTableStmt(relid, atstmt,
queryString);
+ /* ... ensure we have an event trigger context ... */
+ EventTriggerAlterTableStart(parsetree);
+ EventTriggerAlterTableRelid(relid);
+
/* ... and do it */
foreach(l, stmts)
{
}
else
{
- /* Recurse for anything else */
- ProcessUtility(stmt,
+ /*
+ * 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);
}
/* Need CCI between commands */
if (lnext(l) != NULL)
CommandCounterIncrement();
}
+
+ /* 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:
* Recursively alter column default for table and,
* if requested, for descendants
*/
- AlterDomainDefault(stmt->typeName,
- stmt->def);
+ address =
+ AlterDomainDefault(stmt->typeName,
+ stmt->def);
break;
case 'N': /* ALTER DOMAIN DROP NOT NULL */
- AlterDomainNotNull(stmt->typeName,
- false);
+ address =
+ AlterDomainNotNull(stmt->typeName,
+ false);
break;
case 'O': /* ALTER DOMAIN SET NOT NULL */
- AlterDomainNotNull(stmt->typeName,
- true);
+ address =
+ AlterDomainNotNull(stmt->typeName,
+ true);
break;
case 'C': /* ADD CONSTRAINT */
- AlterDomainAddConstraint(stmt->typeName,
- stmt->def,
- NULL);
+ address =
+ AlterDomainAddConstraint(stmt->typeName,
+ stmt->def,
+ &secondaryObject);
break;
case 'X': /* DROP CONSTRAINT */
- AlterDomainDropConstraint(stmt->typeName,
- stmt->name,
- stmt->behavior,
- stmt->missing_ok);
+ address =
+ AlterDomainDropConstraint(stmt->typeName,
+ stmt->name,
+ stmt->behavior,
+ stmt->missing_ok);
break;
case 'V': /* VALIDATE CONSTRAINT */
- AlterDomainValidateConstraint(stmt->typeName,
- stmt->name);
+ address =
+ AlterDomainValidateConstraint(stmt->typeName,
+ stmt->name);
break;
default: /* oops */
elog(ERROR, "unrecognized alter domain type: %d",
switch (stmt->kind)
{
case OBJECT_AGGREGATE:
- DefineAggregate(stmt->defnames, stmt->args,
- stmt->oldstyle, stmt->definition,
- queryString);
+ address =
+ DefineAggregate(pstate, stmt->defnames, stmt->args,
+ stmt->oldstyle,
+ stmt->definition);
break;
case OBJECT_OPERATOR:
Assert(stmt->args == NIL);
- DefineOperator(stmt->defnames, stmt->definition);
+ address = DefineOperator(stmt->defnames,
+ stmt->definition);
break;
case OBJECT_TYPE:
Assert(stmt->args == NIL);
- DefineType(stmt->defnames, stmt->definition);
+ address = DefineType(pstate,
+ stmt->defnames,
+ stmt->definition);
break;
case OBJECT_TSPARSER:
Assert(stmt->args == NIL);
- DefineTSParser(stmt->defnames, stmt->definition);
+ address = DefineTSParser(stmt->defnames,
+ stmt->definition);
break;
case OBJECT_TSDICTIONARY:
Assert(stmt->args == NIL);
- DefineTSDictionary(stmt->defnames,
- stmt->definition);
+ address = DefineTSDictionary(stmt->defnames,
+ stmt->definition);
break;
case OBJECT_TSTEMPLATE:
Assert(stmt->args == NIL);
- DefineTSTemplate(stmt->defnames,
- stmt->definition);
+ address = DefineTSTemplate(stmt->defnames,
+ stmt->definition);
break;
case OBJECT_TSCONFIGURATION:
Assert(stmt->args == NIL);
- DefineTSConfiguration(stmt->defnames,
- stmt->definition,
- NULL);
+ address = DefineTSConfiguration(stmt->defnames,
+ stmt->definition,
+ &secondaryObject);
break;
case OBJECT_COLLATION:
Assert(stmt->args == NIL);
- DefineCollation(stmt->defnames, stmt->definition);
+ address = DefineCollation(pstate,
+ stmt->defnames,
+ stmt->definition);
break;
default:
elog(ERROR, "unrecognized define stmt type: %d",
stmt = transformIndexStmt(relid, stmt, queryString);
/* ... and do it */
- DefineIndex(relid, /* OID of heap relation */
- stmt,
- InvalidOid, /* no predefined OID */
- false, /* is_alter_table */
- true, /* check_rights */
- false, /* skip_build */
- false); /* quiet */
+ 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;
case T_CreateExtensionStmt:
- CreateExtension((CreateExtensionStmt *) parsetree);
+ address = CreateExtension(pstate, (CreateExtensionStmt *) parsetree);
break;
case T_AlterExtensionStmt:
- ExecAlterExtensionStmt((AlterExtensionStmt *) parsetree);
+ address = ExecAlterExtensionStmt(pstate, (AlterExtensionStmt *) parsetree);
break;
case T_AlterExtensionContentsStmt:
- ExecAlterExtensionContentsStmt((AlterExtensionContentsStmt *) parsetree,
- NULL);
+ address = ExecAlterExtensionContentsStmt((AlterExtensionContentsStmt *) parsetree,
+ &secondaryObject);
break;
case T_CreateFdwStmt:
- CreateForeignDataWrapper((CreateFdwStmt *) parsetree);
+ address = CreateForeignDataWrapper((CreateFdwStmt *) parsetree);
break;
case T_AlterFdwStmt:
- AlterForeignDataWrapper((AlterFdwStmt *) parsetree);
+ address = AlterForeignDataWrapper((AlterFdwStmt *) parsetree);
break;
case T_CreateForeignServerStmt:
- CreateForeignServer((CreateForeignServerStmt *) parsetree);
+ address = CreateForeignServer((CreateForeignServerStmt *) parsetree);
break;
case T_AlterForeignServerStmt:
- AlterForeignServer((AlterForeignServerStmt *) parsetree);
+ address = AlterForeignServer((AlterForeignServerStmt *) parsetree);
break;
case T_CreateUserMappingStmt:
- CreateUserMapping((CreateUserMappingStmt *) parsetree);
+ address = CreateUserMapping((CreateUserMappingStmt *) parsetree);
break;
case T_AlterUserMappingStmt:
- AlterUserMapping((AlterUserMappingStmt *) parsetree);
+ 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;
- DefineCompositeType(stmt->typevar, stmt->coldeflist);
+ address = DefineCompositeType(stmt->typevar,
+ stmt->coldeflist);
}
break;
case T_CreateEnumStmt: /* CREATE TYPE AS ENUM */
- DefineEnum((CreateEnumStmt *) parsetree);
+ address = DefineEnum((CreateEnumStmt *) parsetree);
break;
case T_CreateRangeStmt: /* CREATE TYPE AS RANGE */
- DefineRange((CreateRangeStmt *) parsetree);
+ address = DefineRange((CreateRangeStmt *) parsetree);
break;
case T_AlterEnumStmt: /* ALTER TYPE (enum) */
- AlterEnum((AlterEnumStmt *) parsetree, isTopLevel);
+ address = AlterEnum((AlterEnumStmt *) parsetree);
break;
case T_ViewStmt: /* CREATE VIEW */
- DefineView((ViewStmt *) parsetree, queryString);
+ 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 */
- CreateFunction((CreateFunctionStmt *) parsetree, queryString);
+ address = CreateFunction(pstate, (CreateFunctionStmt *) parsetree);
break;
case T_AlterFunctionStmt: /* ALTER FUNCTION */
- AlterFunction((AlterFunctionStmt *) parsetree);
+ address = AlterFunction(pstate, (AlterFunctionStmt *) parsetree);
break;
case T_RuleStmt: /* CREATE RULE */
- DefineRule((RuleStmt *) parsetree, queryString);
+ address = DefineRule((RuleStmt *) parsetree, queryString);
break;
case T_CreateSeqStmt:
- DefineSequence((CreateSeqStmt *) parsetree);
+ address = DefineSequence(pstate, (CreateSeqStmt *) parsetree);
break;
case T_AlterSeqStmt:
- AlterSequence((AlterSeqStmt *) parsetree);
+ address = AlterSequence(pstate, (AlterSeqStmt *) parsetree);
break;
case T_CreateTableAsStmt:
- ExecCreateTableAs((CreateTableAsStmt *) parsetree,
- queryString, params, completionTag);
+ address = ExecCreateTableAs((CreateTableAsStmt *) parsetree,
+ queryString, params, completionTag);
break;
case T_RefreshMatViewStmt:
- ExecRefreshMatView((RefreshMatViewStmt *) parsetree,
- queryString, params, completionTag);
+
+ /*
+ * 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_CreateTrigStmt:
- (void) CreateTrigger((CreateTrigStmt *) parsetree, queryString,
- InvalidOid, InvalidOid, InvalidOid,
- InvalidOid, false);
+ address = CreateTrigger((CreateTrigStmt *) parsetree,
+ queryString, InvalidOid, InvalidOid,
+ InvalidOid, InvalidOid, false);
break;
case T_CreatePLangStmt:
- CreateProceduralLanguage((CreatePLangStmt *) parsetree);
+ address = CreateProceduralLanguage((CreatePLangStmt *) parsetree);
break;
case T_CreateDomainStmt:
- DefineDomain((CreateDomainStmt *) parsetree);
+ address = DefineDomain((CreateDomainStmt *) parsetree);
break;
case T_CreateConversionStmt:
- CreateConversionCommand((CreateConversionStmt *) parsetree);
+ address = CreateConversionCommand((CreateConversionStmt *) parsetree);
break;
case T_CreateCastStmt:
- CreateCast((CreateCastStmt *) parsetree);
+ address = CreateCast((CreateCastStmt *) parsetree);
break;
case T_CreateOpClassStmt:
DefineOpClass((CreateOpClassStmt *) parsetree);
+ /* command is stashed in DefineOpClass */
+ commandCollected = true;
break;
case T_CreateOpFamilyStmt:
- DefineOpFamily((CreateOpFamilyStmt *) parsetree);
+ address = DefineOpFamily((CreateOpFamilyStmt *) parsetree);
break;
case T_CreateTransformStmt:
- CreateTransform((CreateTransformStmt *) parsetree);
+ address = CreateTransform((CreateTransformStmt *) parsetree);
break;
case T_AlterOpFamilyStmt:
AlterOpFamily((AlterOpFamilyStmt *) parsetree);
+ /* commands are stashed in AlterOpFamily */
+ commandCollected = true;
break;
case T_AlterTSDictionaryStmt:
- AlterTSDictionary((AlterTSDictionaryStmt *) parsetree);
+ 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:
- ExecRenameStmt((RenameStmt *) parsetree);
+ address = ExecRenameStmt((RenameStmt *) parsetree);
+ break;
+
+ case T_AlterObjectDependsStmt:
+ address =
+ ExecAlterObjectDependsStmt((AlterObjectDependsStmt *) parsetree,
+ &secondaryObject);
break;
case T_AlterObjectSchemaStmt:
- ExecAlterObjectSchemaStmt((AlterObjectSchemaStmt *) parsetree,
- NULL);
+ address =
+ ExecAlterObjectSchemaStmt((AlterObjectSchemaStmt *) parsetree,
+ &secondaryObject);
break;
case T_AlterOwnerStmt:
- ExecAlterOwnerStmt((AlterOwnerStmt *) parsetree);
+ address = ExecAlterOwnerStmt((AlterOwnerStmt *) parsetree);
+ break;
+
+ case T_AlterOperatorStmt:
+ address = AlterOperator((AlterOperatorStmt *) parsetree);
break;
case T_CommentStmt:
- CommentObject((CommentStmt *) parsetree);
+ 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((AlterDefaultPrivilegesStmt *) parsetree);
+ ExecAlterDefaultPrivilegesStmt(pstate, (AlterDefaultPrivilegesStmt *) parsetree);
+ EventTriggerCollectAlterDefPrivs((AlterDefaultPrivilegesStmt *) parsetree);
+ commandCollected = true;
break;
case T_CreatePolicyStmt: /* CREATE POLICY */
- CreatePolicy((CreatePolicyStmt *) parsetree);
+ address = CreatePolicy((CreatePolicyStmt *) parsetree);
break;
case T_AlterPolicyStmt: /* ALTER POLICY */
- AlterPolicy((AlterPolicyStmt *) parsetree);
+ address = AlterPolicy((AlterPolicyStmt *) parsetree);
break;
case T_SecLabelStmt:
- ExecSecLabelStmt((SecLabelStmt *) parsetree);
+ address = ExecSecLabelStmt((SecLabelStmt *) parsetree);
+ break;
+
+ case T_CreateAmStmt:
+ address = CreateAccessMethod((CreateAmStmt *) parsetree);
break;
default:
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);
switch (parsetree->commandType)
{
case CMD_SELECT:
- /* returns tuples ... unless it's DECLARE CURSOR */
- if (parsetree->utilityStmt == NULL)
- return true;
- break;
+ /* returns tuples */
+ return true;
case CMD_INSERT:
case CMD_UPDATE:
case CMD_DELETE:
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));
/*
* 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";
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;
case OBJECT_COLLATION:
tag = "CREATE COLLATION";
break;
+ case OBJECT_ACCESS_METHOD:
+ tag = "CREATE ACCESS METHOD";
+ break;
default:
tag = "???";
}
tag = "ALTER OPERATOR FAMILY";
break;
+ case T_AlterOperatorStmt:
+ tag = "ALTER OPERATOR";
+ break;
+
case T_AlterTSDictionaryStmt:
tag = "ALTER TEXT SEARCH DICTIONARY";
break;
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->rowMarks != NIL)
+ if (stmt->rowMarks != NIL)
{
/* not 100% but probably close enough */
switch (((PlanRowMark *) linitial(stmt->rowMarks))->strength)
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->rowMarks != NIL)
+ if (stmt->rowMarks != NIL)
{
/* not 100% but probably close enough */
switch (((RowMarkClause *) linitial(stmt->rowMarks))->strength)
/*
* 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:
/* 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);
+ 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_CreateAmStmt:
+ lev = LOGSTMT_DDL;
+ break;
+
/* already-planned queries */
case T_PlannedStmt:
{
lev = LOGSTMT_MOD;
break;
+ case CMD_UTILITY:
+ lev = GetCommandLogLevel(stmt->utilityStmt);
+ break;
+
default:
elog(WARNING, "unrecognized commandType: %d",
(int) stmt->commandType);