web-dev-qa-db-fra.com

SQL Server prend-il en charge les domaines personnalisés?

PostgreSQL prend en charge la spécification DOMAIN , à partir de SQL 2011 Spec Spec,

Un domaine est un objet désigné par l'utilisateur qui peut être spécifié comme alternative à un type de données dans certains endroits où un type de données peut être spécifié. Un domaine consiste en un type de données, éventuellement une option par défaut et des contraintes zéro ou plus (domaine).

Cela nous permet de faire des trucs vraiment cool comme mettre en œuvre un domaine pour la spécification HTML5 pour le courrier électronique sur un texte insensible à une casse Type . Cela garantit que tous les clients accédant à la base de données ont une vérification d'intégrité sur les données insérées.

CREATE DOMAIN email AS citext
  CHECK ( value ~ '^[a-zA-Z0-9.!#$%&''*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$' );

SQL Server prend-il en charge une telle fonctionnalité en dehors du système de déclenchement?

8
Evan Carroll

SQLCLR présente une surface pour créer des types de données entièrement personnalisés. En fait, c'est ainsi que SQL Server prend en charge les types de données géométriques et hiérarchies.

Étant donné que SQLCLR est basé sur le langage commun-intermédiaire Microsoft.Net, une grande variété de contraintes sont possibles pour un type de données SQLCLR. Par exemple, vous pouvez facilement vous assurer qu'une adresse e-mail provient d'un domaine valide en interrogeant DNS pour l'enregistrement MX dans le cadre du code de validation des données.

SQL Server peut indexer un CLR UDT tant que IsByteOrdered:=True est défini. Il existe une tonne de propriétés comme celle-là, que vous pouvez modifier pour affecter la manière dont SQL Server utilise l'UDT. Pour une correspondance d'égalité comme celle requise par un index, SQL Server examine simplement la valeur binaire stockée dans la page I.E. Il n'a pas besoin de regarder le code UDT du tout.

À titre d'exemple d'un type défini par l'utilisateur SQLCLR qui vérifie un espace de domaine pour la validité, j'ai écrit le code de la preuve terrible suivant VB.NET CODE:

Imports System
Imports System.Data
Imports System.Data.SqlClient
Imports System.Data.SqlTypes
Imports Microsoft.SqlServer.Server

<Serializable()> _
<Microsoft.SqlServer.Server.SqlUserDefinedType(Format.UserDefined, IsByteOrdered:=True, MaxByteSize:=320, ValidationMethodName:="ValidateEmailAddress")> _
Public Structure EmailType
    Implements INullable
    Implements IBinarySerialize

    Private m_Null As Boolean
    Private m_EmailAddress As String

    Public Function ValidateEmailAddress() As Boolean
        'is the email address valid?
        If Me.IsValidDomain Then
            Return True
        Else
            Return False
        End If
    End Function

    Public Overrides Function ToString() As String
        Return Me.m_EmailAddress
    End Function

    Public ReadOnly Property IsNull() As Boolean Implements INullable.IsNull
        Get
            ' Put your code here
            If Me.m_EmailAddress Is Nothing Then
                Me.m_Null = True
            Else
                Me.m_Null = False
            End If
            Return m_Null
        End Get
    End Property

    Public Shared ReadOnly Property Null As EmailType
        Get
            Dim h As New EmailType
            h.m_Null = True
            Return h
        End Get
    End Property

    'called when SQL Server passes in a SqlString value to the UDT
    Public Shared Function Parse(ByVal s As SqlString) As EmailType
        If s.IsNull Then
            Return Null
        End If

        Dim u As New EmailType

        u.m_EmailAddress = CType(s, String)
        If u.ValidateEmailAddress = False Then
            Throw New Exception("Invalid Email Address")
        End If
        Return u
    End Function

    Public Function IsValidDomain() As Boolean
        Dim iAtSign As Int32 = Microsoft.VisualBasic.Strings.InStr(Me.m_EmailAddress, "@")
        Dim iDomainLength As Int32 = Microsoft.VisualBasic.Strings.Len(Me.m_EmailAddress) - iAtSign
        Dim sDomain As String = Microsoft.VisualBasic.Strings.Right(Me.m_EmailAddress, iDomainLength)
        Dim bResolvable As Boolean = False
        Try
            Dim ip As System.Net.IPHostEntry = System.Net.Dns.GetHostEntry(sDomain)
            bResolvable = True
        Catch ex As Exception
            Throw New Exception(Me.m_EmailAddress & " is not from a resolvable domain.")
        End Try
        Return bResolvable
    End Function

    ' save the value to the database
    Public Sub Write(w As System.IO.BinaryWriter) Implements IBinarySerialize.Write
        w.Write(Me.m_EmailAddress)
    End Sub

    ' retrieve the value from the database
    Public Sub Read(r As System.IO.BinaryReader) Implements IBinarySerialize.Read
        Dim sTemp As String = r.ReadString
        Dim sTemp1 As String = ""
        For Each n As Char In sTemp.ToCharArray
            sTemp1 = sTemp1 & n.ToString
        Next
        Me.m_EmailAddress = sTemp
    End Sub

End Structure

Étant donné que le code ci-dessus n'est pas signé, vous devez le tester uniquement sur une machine de développement où vous pouvez activer le paramètre de base de données TRUSTWORTHY. Une fois le code compilé, vous l'importaez dans SQL Server via ce qui suit:

CREATE Assembly SQLCLREmailType 
AUTHORIZATION dbo 
FROM 'C:\Path\Goes\Here\SQLCLREmailType.dll' 
WITH PERMISSION_SET = UNSAFE;

CREATE TYPE EmailType
EXTERNAL NAME SQLCLREmailType.[SQLCLREmailType.EmailType]

L'UDT peut ensuite être utilisé comme ceci:

DECLARE @t TABLE (
    col EmailType NOT NULL
    );

INSERT INTO @t (col)
VALUES ('[email protected]')
    , ('[email protected]');

SELECT CONVERT(varchar(50), t.col)
FROM @t t
GO

Le code ci-dessus renvoie:

+ ------------------- + 
 | (Pas de nom de colonne) | 
 + ------------------ + 
 | [email protected] | 
 | [email protected] | [.____] + ------------------ + +

Cependant, lorsque vous essayez d'insérer une adresse appartenant à un domaine de messagerie inexistant, comme dans:

DECLARE @t TABLE (
    col EmailType NOT NULL
    );

INSERT INTO @t (col)
VALUES , ('us@asdfasdfasdfasdfasdfasdfasdfasdf90097809878907098908908908908.com');

SELECT CONVERT(varchar(50), t.col)
FROM @t t
GO

Vous voyez une erreur:

MSG 6522, niveau 16, État 2, ligne 27
[.____] Une erreur .NET Framework s'est produite lors de l'exécution de la routine ou de l'agrégat défini par l'utilisateur "EmailType":
[. ____.
System.Exception:
[.____] chez sqlclremailtype.emailype.isvaliddomain ()
[.____] chez sqlclremailtype.emailype.validateMailAmailAddress ()
[.____] à sqlclremailtype.emailype.parse (sqlstring s)

10
Max Vernon

Je ne vais pas marquer cela comme choisi pour le moment, car il y a de mai Soyez un travail autour, mais techniquement, ils ne sont pas pris en charge. Vous pouvez voir le problème sur Microsoft Connect.

Bonjour Erland,

Après avoir soigneusement évalué tous les éléments de suggestion de notre pipeline , nous fermons des articles que nous ne mettrons pas dans un proche avenir en raison des éléments de priorité plus élevés actuels. Nous réévaluerons à nouveau les suggestions fermées à l'avenir sur la base de la feuille de route du produit.

Merci encore d'avoir fourni la suggestion du produit et le soutien continu de notre produit.

- Team Umaachandar, SQL Programmabilité

Le problème a été ouvert en 2012.

3
Evan Carroll