diff --git a/pkg/sql/alter_schema.go b/pkg/sql/alter_schema.go index e0d4ab2d412a..ba9e22a608e6 100644 --- a/pkg/sql/alter_schema.go +++ b/pkg/sql/alter_schema.go @@ -78,11 +78,44 @@ func (p *planner) AlterSchema(ctx context.Context, n *tree.AlterSchema) (planNod func (n *alterSchemaNode) startExec(params runParams) error { switch t := n.n.Cmd.(type) { case *tree.AlterSchemaRename: - return params.p.renameSchema( - params.ctx, n.db, n.desc, string(t.NewName), tree.AsStringWithFQNames(n.n, params.Ann())) + oldName := n.desc.Name + newName := string(t.NewName) + if err := params.p.renameSchema( + params.ctx, n.db, n.desc, newName, tree.AsStringWithFQNames(n.n, params.Ann()), + ); err != nil { + return err + } + return MakeEventLogger(params.extendedEvalCtx.ExecCfg).InsertEventRecord( + params.ctx, + params.p.txn, + EventLogRenameSchema, + int32(n.desc.ID), + int32(params.extendedEvalCtx.NodeID.SQLInstanceID()), + struct { + SchemaName string + NewSchemaName string + User string + }{oldName, newName, params.p.SessionData().User}, + ) case *tree.AlterSchemaOwner: - return params.p.alterSchemaOwner( - params.ctx, n.desc, string(t.Owner), tree.AsStringWithFQNames(n.n, params.Ann())) + newOwner := string(t.Owner) + if err := params.p.alterSchemaOwner( + params.ctx, n.desc, newOwner, tree.AsStringWithFQNames(n.n, params.Ann()), + ); err != nil { + return err + } + return MakeEventLogger(params.extendedEvalCtx.ExecCfg).InsertEventRecord( + params.ctx, + params.p.txn, + EventLogAlterSchemaOwner, + int32(n.desc.ID), + int32(params.extendedEvalCtx.NodeID.SQLInstanceID()), + struct { + SchemaName string + Owner string + User string + }{n.desc.Name, newOwner, params.p.SessionData().User}, + ) default: return errors.AssertionFailedf("unknown schema cmd %T", t) } diff --git a/pkg/sql/create_schema.go b/pkg/sql/create_schema.go index f53bf6400b32..98352e6edeb5 100644 --- a/pkg/sql/create_schema.go +++ b/pkg/sql/create_schema.go @@ -141,13 +141,27 @@ func (p *planner) createUserDefinedSchema(params runParams, n *tree.CreateSchema } // Finally create the schema on disk. - return p.createDescriptorWithID( + if err := p.createDescriptorWithID( params.ctx, catalogkeys.NewSchemaKey(db.ID, schemaName).Key(p.ExecCfg().Codec), id, desc, params.ExecCfg().Settings, tree.AsStringWithFQNames(n, params.Ann()), + ); err != nil { + return err + } + return MakeEventLogger(params.extendedEvalCtx.ExecCfg).InsertEventRecord( + params.ctx, + params.p.txn, + EventLogCreateSchema, + int32(desc.GetID()), + int32(params.extendedEvalCtx.NodeID.SQLInstanceID()), + struct { + SchemaName string + Owner string + User string + }{schemaName, privs.Owner, params.SessionData().User}, ) } diff --git a/pkg/sql/event_log.go b/pkg/sql/event_log.go index 9000f23a2325..222432746bc9 100644 --- a/pkg/sql/event_log.go +++ b/pkg/sql/event_log.go @@ -32,8 +32,14 @@ const ( // EventLogRenameDatabase is recorded when a database is renamed. EventLogRenameDatabase EventLogType = "rename_database" + // EventLogCreateSchema is recorded when a schema is created. + EventLogCreateSchema EventLogType = "create_schema" // EventLogDropSchema is recorded when a schema is dropped. EventLogDropSchema EventLogType = "drop_schema" + // EventLogRenameSchema is recorded when a schema is renamed. + EventLogRenameSchema EventLogType = "rename_schema" + // EventLogChangeSchemaOwner is recorded when a schema's owner is changed. + EventLogAlterSchemaOwner EventLogType = "alter_schema_owner" // EventLogCreateTable is recorded when a table is created. EventLogCreateTable EventLogType = "create_table" diff --git a/pkg/sql/logictest/testdata/logic_test/event_log b/pkg/sql/logictest/testdata/logic_test/event_log index 6e488c24fddc..e87d78c73877 100644 --- a/pkg/sql/logictest/testdata/logic_test/event_log +++ b/pkg/sql/logictest/testdata/logic_test/event_log @@ -534,3 +534,57 @@ DROP USER u statement ok DROP USER v + + +# Schema events +################## + +statement ok +CREATE SCHEMA s + +statement ok +CREATE USER u + +statement ok +CREATE SCHEMA AUTHORIZATION u + +query ITT +SELECT "reportingID", info::JSONB->>'SchemaName', info::JSONB->>'Owner' +FROM system.eventlog +WHERE "eventType" = 'create_schema' +ORDER BY 2 +---- +1 s root +1 u u + +statement ok +ALTER SCHEMA u RENAME TO t + +query ITT +SELECT "reportingID", info::JSONB->>'SchemaName', info::JSONB->>'NewSchemaName' +FROM system.eventlog +WHERE "eventType" = 'rename_schema' +---- +1 u t + +statement ok +ALTER SCHEMA t OWNER TO root + +query ITT +SELECT "reportingID", info::JSONB->>'SchemaName', info::JSONB->>'Owner' +FROM system.eventlog +WHERE "eventType" = 'alter_schema_owner' +---- +1 t root + +statement ok +DROP SCHEMA s, t + +query IT +SELECT "reportingID", info::JSONB->>'SchemaName' +FROM system.eventlog +WHERE "eventType" = 'drop_schema' +ORDER BY 2 +---- +1 s +1 t diff --git a/pkg/ui/src/util/eventTypes.ts b/pkg/ui/src/util/eventTypes.ts index 5685e44562c2..4210e9c86d64 100644 --- a/pkg/ui/src/util/eventTypes.ts +++ b/pkg/ui/src/util/eventTypes.ts @@ -77,6 +77,14 @@ export const CREATE_STATISTICS = "create_statistics"; export const GRANT_PRIVILEGE = "grant_privilege"; // Recorded when privileges are removed from a user(s). export const REVOKE_PRIVILEGE = "revoke_privilege"; +// Recorded when a schema is created. +export const CREATE_SCHEMA = "create_schema"; +// Recorded when a schema is dropped. +export const DROP_SCHEMA = "drop_schema"; +// Recorded when a schema is renamed. +export const RENAME_SCHEMA = "rename_schema"; +// Recorded when a schema's owner is changed. +export const ALTER_SCHEMA_OWNER = "alter_schema_owner"; // Node Event Types export const nodeEvents = [NODE_JOIN, NODE_RESTART, NODE_DECOMMISSIONING, NODE_DECOMMISSIONED, NODE_RECOMMISSIONED]; diff --git a/pkg/ui/src/util/events.ts b/pkg/ui/src/util/events.ts index 7e8cedbcba18..7cae1782db8d 100644 --- a/pkg/ui/src/util/events.ts +++ b/pkg/ui/src/util/events.ts @@ -87,6 +87,14 @@ export function getEventDescription(e: Event$Properties): string { return `Privileges granted: User ${info.User} granted ${info.Privileges} to ${info.Grantees} on ${info.Target}`; case eventTypes.REVOKE_PRIVILEGE: return `Privileges revoked: User ${info.User} revoked ${info.Privileges} from ${info.Grantees} on ${info.Target}`; + case eventTypes.CREATE_SCHEMA: + return `Schema Created: User ${info.User} created schema ${info.SchemaName} with owner ${info.Owner}`; + case eventTypes.DROP_SCHEMA: + return `Schema Dropped: User ${info.User} dropped schema ${info.SchemaName}`; + case eventTypes.RENAME_SCHEMA: + return `Schema Renamed: User ${info.User} renamed schema ${info.SchemaName} to ${info.NewSchemaName}`; + case eventTypes.ALTER_SCHEMA_OWNER: + return `Schema Owner Altered: User ${info.User} altered the owner of schema ${info.SchemaName} to ${info.Owner}`; default: return `Unknown Event Type: ${e.event_type}, content: ${JSON.stringify(info, null, 2)}`; } @@ -111,6 +119,9 @@ export interface EventInfo { Statement?: string; Grantees?: string; Privileges?: string; + SchemaName?: string; + NewSchemaName?: string; + Owner?: string; // The following are three names for the same key (it was renamed twice). // All ar included for backwards compatibility. DroppedTables?: string[];