Wenn Ihre Benutzer über Erstellungsberechtigungen in ihrem eigenen Schema verfügen, können Sie einen DDL-Trigger einrichten, um die Tabellenerstellung zu erfassen, die in einer anderen Dateigruppe als der mit diesem Benutzer verknüpften erfolgt. Sie können nicht verhindern, dass die Tabelle erstellt wird, aber Sie können sie zurücksetzen und eine Fehlermeldung zurückgeben.
Fügen wir zunächst einer vorhandenen Datenbank eine Dateigruppe und eine Datei mit maximaler Größe hinzu:
USE [master];
GO
ALTER DATABASE floob ADD FILEGROUP SomeUser;
GO
ALTER DATABASE floob ADD FILE
(
NAME = SomeUser,
FILENAME = 'C:\...wherever...\floob_SomeUser.mdf',
MAXSIZE = 20MB -- your quota, this part is important!
) TO FILEGROUP SomeUser; -- this part is also important!
GO
Erstellen wir nun ein Schema und eine Anmeldung, die dieses Schema steuern können:
CREATE SCHEMA SomeUser;
GO
CREATE LOGIN SomeUser WITH PASSWORD = 'foo', CHECK_POLICY = OFF;
GO
USE floob;
GO
CREATE USER SomeUser FROM LOGIN [SomeUser] WITH DEFAULT_SCHEMA = SomeUser;
GO
GRANT CONTROL ON SCHEMA::SomeUser TO dbo;
GRANT CREATE TABLE TO SomeUser;
GO
Erstens kann dieser Benutzer mit diesen Einstellungen keine Tabellen in dbo oder einem anderen Schema als dem eigenen erstellen. Dies bedeutet, dass er standardmäßig nur Tabellen in seiner begrenzten Datei [Gruppe] erstellen kann. Wenn Sie als dieser Benutzer eine Verbindung zum Datenbank-Floob herstellen und versuchen, eine Tabelle in dbo zu erstellen:
CREATE TABLE dbo.foo(id INT);
Sie erhalten diesen Fehler:
Nachricht 2760, Ebene 16,
Status 1, Zeile 1 Der angegebene Schemaname "dbo" ist entweder nicht vorhanden oder Sie haben keine Berechtigung, ihn zu verwenden.
Und aufgrund des Standardschemas dieses Benutzers wird bei Nichtangabe des SomeUser-Schemas immer noch eine in SomeUser erstellte Tabelle angezeigt (obwohl Sie hier, insbesondere in diesem Fall, unbedingt auf bewährte Methoden drängen und beim Erstellen oder Referenzieren von Objekten immer den Schemanamen angeben sollten ).
Jetzt können wir einen Trigger wie diesen erstellen, der den gesamten Stapel zurücksetzt, falls keine Dateigruppe angegeben ist:
CREATE TRIGGER EnsureFilegroup
ON DATABASE
FOR CREATE_TABLE
AS
BEGIN
DECLARE @e XML = EVENTDATA();
IF @e.value('(/EVENT_INSTANCE/SchemaName)[1]', 'NVARCHAR(128)') = N'SomeUser'
AND NOT EXISTS (SELECT 1 FROM sys.indexes AS i INNER JOIN sys.data_spaces AS d
ON i.data_space_id = d.data_space_id
WHERE d.name = N'SomeUser'
AND i.[object_id] = OBJECT_ID(
QUOTENAME(@e.value('(/EVENT_INSTANCE/SchemaName)[1]', 'NVARCHAR(128)'))
+ '.' + QUOTENAME(@e.value('(/EVENT_INSTANCE/ObjectName)[1]', 'NVARCHAR(128)')))
AND i.index_id IN (0,1))
BEGIN
RAISERROR('You must place your objects on the SomeUser filegroup.', 11, 1);
ROLLBACK TRANSACTION;
END
END
GO
Es ist besonders praktisch, die Namen von Benutzer, Schema und Dateigruppe gleich zu halten, was es einfacher macht, dies als programmatisch zu verwenden. Sie können zunächst überprüfen, ob das verwendete Schema nicht zu Ihren "umlimited" -Schemas gehört, und dann eine Prüfung durchführen, bei der der Schemaname mit dem Namen der Dateigruppe verglichen wird. Wenn es nicht übereinstimmt, hat dieser Benutzer Rechte für das falsche Schema und versucht, Objekte am falschen Ort zu erstellen. Es wird ein Fehler ausgegeben:
ALTER TRIGGER EnsureFilegroup
ON DATABASE
FOR CREATE_TABLE
AS
BEGIN
DECLARE @e XML = EVENTDATA();
IF @e.value('(/EVENT_INSTANCE/SchemaName)[1]', 'NVARCHAR(128)') <> N'dbo'
-- or NOT IN (N'dbo', N'other unlimited schemas')
BEGIN
IF NOT EXISTS (SELECT 1 FROM sys.indexes AS i INNER JOIN sys.data_spaces AS d
ON i.data_space_id = d.data_space_id
WHERE d.name = @e.value('(/EVENT_INSTANCE/SchemaName)[1]', 'NVARCHAR(128)')
AND i.[object_id] = OBJECT_ID(
QUOTENAME(@e.value('(/EVENT_INSTANCE/SchemaName)[1]', 'NVARCHAR(128)'))
+ '.' + QUOTENAME(@e.value('(/EVENT_INSTANCE/ObjectName)[1]', 'NVARCHAR(128)')))
AND i.index_id IN (0,1))
BEGIN
RAISERROR('You must place your objects on your own filegroup.', 11, 1);
ROLLBACK TRANSACTION;
END
END
END
GO