Problema com as convenções de nomenclatura de tabelas e o gerenciamento de políticas no SQL Server 2016

10

No SQL Server 2012, eu tinha uma política definida para não permitir espaços no nome de uma tabela. No entanto, quando uso a mesma política no SQL Server 2016, recebo um erro.

Aqui está o código para a condição:

DECLARE @condition_id INT
EXEC msdb.dbo.sp_syspolicy_add_condition @name=N'No Spaces', @description=N'No spaces in table names.', @facet=N'IMultipartNameFacet', @expression=N'<Operator>
  <TypeClass>Bool</TypeClass>
  <OpType>NOT_LIKE</OpType>
  <Count>2</Count>
  <Attribute>
    <TypeClass>String</TypeClass>
    <Name>Name</Name>
  </Attribute>
  <Constant>
    <TypeClass>String</TypeClass>
    <ObjType>System.String</ObjType>
    <Value>% %</Value>
  </Constant>
</Operator>', @is_name_condition=4, @obj_name=N'% %', @condition_id=@condition_id OUTPUT
SELECT @condition_id

Aqui está o código para a política:

DECLARE @object_set_id INT
EXEC msdb.dbo.sp_syspolicy_add_object_set @object_set_name=N'Table Names_ObjectSet', @facet=N'IMultipartNameFacet', @object_set_id=@object_set_id OUTPUT
SELECT @object_set_id

DECLARE @target_set_id INT
EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'Table Names_ObjectSet', @type_skeleton=N'Server/Database/Sequence', @type=N'SEQUENCE', @enabled=False, @target_set_id=@target_set_id OUTPUT
SELECT @target_set_id

EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Server/Database', @level_name=N'Database', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Server/Database/Sequence', @level_name=N'Sequence', @condition_name=N'', @target_set_level_id=0

EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'Table Names_ObjectSet', @type_skeleton=N'Server/Database/StoredProcedure', @type=N'PROCEDURE', @enabled=False, @target_set_id=@target_set_id OUTPUT
SELECT @target_set_id

EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Server/Database', @level_name=N'Database', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Server/Database/StoredProcedure', @level_name=N'StoredProcedure', @condition_name=N'', @target_set_level_id=0

EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'Table Names_ObjectSet', @type_skeleton=N'Server/Database/Synonym', @type=N'SYNONYM', @enabled=False, @target_set_id=@target_set_id OUTPUT
SELECT @target_set_id

EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Server/Database', @level_name=N'Database', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Server/Database/Synonym', @level_name=N'Synonym', @condition_name=N'', @target_set_level_id=0

EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'Table Names_ObjectSet', @type_skeleton=N'Server/Database/Table', @type=N'TABLE', @enabled=True, @target_set_id=@target_set_id OUTPUT
SELECT @target_set_id

EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Server/Database', @level_name=N'Database', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Server/Database/Table', @level_name=N'Table', @condition_name=N'', @target_set_level_id=0

EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'Table Names_ObjectSet', @type_skeleton=N'Server/Database/UserDefinedFunction', @type=N'FUNCTION', @enabled=False, @target_set_id=@target_set_id OUTPUT
SELECT @target_set_id

EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Server/Database', @level_name=N'Database', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Server/Database/UserDefinedFunction', @level_name=N'UserDefinedFunction', @condition_name=N'', @target_set_level_id=0

EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'Table Names_ObjectSet', @type_skeleton=N'Server/Database/UserDefinedType', @type=N'TYPE', @enabled=False, @target_set_id=@target_set_id OUTPUT
SELECT @target_set_id

EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Server/Database', @level_name=N'Database', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Server/Database/UserDefinedType', @level_name=N'UserDefinedType', @condition_name=N'', @target_set_level_id=0

EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'Table Names_ObjectSet', @type_skeleton=N'Server/Database/View', @type=N'VIEW', @enabled=False, @target_set_id=@target_set_id OUTPUT
SELECT @target_set_id

EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Server/Database', @level_name=N'Database', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Server/Database/View', @level_name=N'View', @condition_name=N'', @target_set_level_id=0

EXEC msdb.dbo.sp_syspolicy_add_target_set @object_set_name=N'Table Names_ObjectSet', @type_skeleton=N'Server/Database/XmlSchemaCollection', @type=N'XMLSCHEMACOLLECTION', @enabled=False, @target_set_id=@target_set_id OUTPUT
SELECT @target_set_id

EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Server/Database', @level_name=N'Database', @condition_name=N'', @target_set_level_id=0
EXEC msdb.dbo.sp_syspolicy_add_target_set_level @target_set_id=@target_set_id, @type_skeleton=N'Server/Database/XmlSchemaCollection', @level_name=N'XmlSchemaCollection', @condition_name=N'', @target_set_level_id=0


GO

DECLARE @policy_id INT
EXEC msdb.dbo.sp_syspolicy_add_policy @name=N'Table Names', @condition_name=N'No Spaces', @policy_category=N'', @description=N'', @help_text=N'', @help_link=N'', @schedule_uid=N'00000000-0000-0000-0000-000000000000', @execution_mode=1, @is_enabled=True, @policy_id=@policy_id OUTPUT, @root_condition_name=N'', @object_set=N'Table Names_ObjectSet'
SELECT @policy_id


GO

No SQL Server 2012 e 2014, isso fornece os resultados esperados:

CREATE TABLE [test table]
(Id INT NULL)

A política 'Nomes da tabela' foi violada por 'SQLSERVER: \ SQL \ LSRSQL07 \ SQL2012 \ Databases \ test \ Tables \ dbo.test table'. Esta transação será revertida. Condição da política: '@Name NOT LIKE'% [-.]% 'AND @Name NOT LIKE'% [^ A-Za-z0-9 [_]]% '' Descrição da política: '' Ajuda adicional: '': Instrução '': 'CREATE TABLE [tabela de teste] (ID INT NULL)'. Msg 3609, Nível 16, Estado 1, Procedimento sp_syspolicy_dispatch_event, Linha 65 [Linha Inicial do Lote 48] A transação terminou no gatilho. O lote foi abortado.

E se eu executar o seguinte código, não recebo erro:

CREATE TABLE [testtable]
(Id INT NULL)

No entanto, se eu executar qualquer CREATE TABLEinstrução, com a política ativada, no SQL Server 2016, recebo o seguinte erro:

A política 'Nomes de tabelas' foi violada por 'SQLSERVER: \ SQL \ LSRSQL07 \ SQL2016 \ Databases \ test \ Tables \ dbo.testtable'. Esta transação será revertida. Condição da política: '@Name NOT LIKE'%% '' Descrição da política: '' Ajuda adicional: '': '' Instrução: 'CREATE TABLE [testtable] (ID INT NULL)'. Mensagem 515, Nível 16, Estado 2, Procedimento sp_syspolicy_execute_policy, Linha 69 [Linha Inicial do Lote 44] Não é possível inserir o valor NULL na coluna 'target_query_expression', tabela 'msdb.dbo.syspolicy_policy_execution_history_details_internal'; A coluna não permite nulos. INSERT falha. A instrução foi encerrada.

No SQL Server 2016, não consigo criar nenhuma tabela , passando ou não a condição.

Este é o SQL Server 2016, SP1, CU3.

Alguma idéia sobre isso?

Editar: estou precisando que o modo de avaliação seja "Em alteração: impedir"

John
fonte

Respostas:

6

Testaram os scripts em uma instância CU2 do SQL Server 2016 SP1 e a diretiva funcionará se o modo Avaliação estiver definido como "Ao alterar: impedir". (existe um erro que não permite avaliar políticas que usam facetas específicas).

Enquanto isso, se você usar apenas a política para nomes de tabelas, também poderá tentar a faceta "Opção de Tabela" em vez de "MultipartName", com a mesma configuração ( @NAME NOT LIKE '% %').

Dragos
fonte
Se eu definir o modo de avaliação como "On Demand", ele funcionará, mas para ser justo, eu não tinha tentado isso anteriormente. Eu preferiria ter essa alteração: impeça a impedir que as pessoas criem tabelas e, em seguida, procs armazenados fazendo referência às tabelas com nomes incorretos.
John
Para mim, não funciona definir o modo de avaliação como "Sob demanda" e avaliar a política manualmente. Mas funciona bem se a avaliação estiver definida como "Ao alterar: impedir" e tentar criar tabelas. Você pode tentar postar o problema no Microsoft Connect para descobrir se é um bug ou não.
Dragos
Obrigado, @Dragos. Está acontecendo em qualquer mesa, mesmo aquelas que devem passar pela condição?
John
As tabelas que não possuem espaços em branco no nome são criadas com êxito e as que possuem espaços em branco falham com um erro de violação da política.
Dragos
Estamos enfrentando o mesmo problema com o procedimento armazenado e as facetas de exibição. Estamos no SQL 2016 SP1 CU3 (mais recente). Como John afirmou, isso parece um bug, mas estava pensando se alguém seria capaz de descobrir uma solução alternativa?
dbauser