XQuery und statische Typisierung

Gilt für:SQL Server

XQuery in SQL Server ist eine statisch typisierte Sprache. Sie gibt bei der Abfragekompilierung einen Typfehler aus, wenn ein Ausdruck einen Wert zurückliefert, dessen Typ oder Kardinalität von einer bestimmten Funktion oder einem Operator nicht angenommen wird. Darüber hinaus kann eine Überprüfung des statischen Typs auch erkennen, ob ein Pfadausdruck eines typisierten XML-Dokuments falsch typisiert ist. Der XQuery-Compiler realisiert zuerst die Normalisierungsphase, in der die impliziten Vorgänge, wie die Atomisierung, hinzugefügt werden. Anschließend erfolgen die Inferenz und die Überprüfung des statischen Typs.

Inferenz des statischen Typs

Die Inferenz des statischen Typs ermittelt den Rückgabetyp eines Ausdrucks. Hierbei wird aus den statischen Typen der Eingabeparameter und aus der statischen Semantik des Vorgangs der statische Typ des Ergebnisses abgeleitet. Beispiel: Der statische Typ des Ausdrucks 1 + 2,3 wird wie folgt abgeleitet:

  • Der statische Typ von 1 ist xs:integer und der statische Typ von 2.3 ist xs:decimal. Basierend auf der dynamischen Semantik konvertiert die statische Semantik des + Vorgangs die ganze Zahl in eine Dezimalzahl und gibt dann eine Dezimalzahl zurück. Der abgeleitete statische Typ wäre dann xs:decimal.

Für nicht typisierte XML-Instanzen gibt es spezielle Typen, mit deren Hilfe angegeben wird, dass die Daten nicht typisiert sind. Diese Information wird bei der Überprüfung des statischen Typs und zur Durchführung bestimmter impliziter Datentypkonvertierungen verwendet.

Bei typisierten Daten wird der Eingabetyp aus der XML-Schemaauflistung abgeleitet, die die XML-Datentypinstanz einschränkt. Wenn das Schema beispielsweise nur Elemente vom Typ xs:integer zulässt, sind die Ergebnisse eines Pfadausdrucks, der dieses Element verwendet, null oder mehr Elemente des Typs xs:integer. Dies wird derzeit mithilfe eines Ausdrucks ausgedrückt, z element(age,xs:integer)* . B. bei dem das Sternchen (*) die Kardinalität des resultierenden Typs angibt. In diesem Beispiel kann der Ausdruck zu null oder mehr Elementen des Namens "age" und des Typs xs:integer führen. Andere Kardinalitäten sind genau eins und werden durch die Verwendung des Typnamens allein, null oder eins ausgedrückt und mit einem Fragezeichen (?) und 1 oder mehr ausgedrückt und mit einem Pluszeichen (+) ausgedrückt.

In manchen Fällen kann die Inferenz des statischen Typs ableiten, dass ein Ausdruck immer eine leere Zeichenfolge zurückliefert. Wenn beispielsweise ein Pfadausdruck für einen typisierten XML-Datentyp nach einem <Namenselement> in einem <Kundenelement> (/Customer/Name) sucht, das Schema jedoch keinen Namen> innerhalb eines <Kunden> zulässt<, wird aus dem statischen Typrückschluss abgeleitet, dass das Ergebnis leer ist. Dies wird verwendet, um falsche Abfragen zu erkennen und wird als statischer Fehler gemeldet, es sei denn, der Ausdruck war () oder data( () ).

Die detaillierten Inferenzregeln werden in der formalen Semantik der XQuery-Spezifikation angegeben. Microsoft hat diese nur geringfügig für typisierte XML-Datentypinstanzen angepasst. Die wichtigste Änderung zum Standard besteht darin, dass der implizite Dokumentknoten den Typ der XML-Datentypinstanz kennt. Aus diesem Grund wird ein Pfadausdruck der Form /age auf der Grundlage dieser Information exakt typisiert.

Mithilfe SQL Server Profiler Vorlagen und Berechtigungen können Sie die statischen Typen sehen, die als Teil von Abfragekompilierungen zurückgegeben werden. Dazu muss die Ablaufverfolgung das XQuery Static Type-Ereignis in der TSQL-Ereigniskategorie aufweisen.

Überprüfung des statischen Typs

Die Überprüfung des statischen Typs stellt sicher, dass bei der Ausführung zur Laufzeit nur Werte des für den Vorgang passenden Typs empfangen werden. Da die Typen nicht zur Laufzeit geprüft werden müssen, können potenzielle Fehler zu einem frühen Zeitpunkt der Kompilierung festgestellt werden. Dies verbessert die Leistung. Die statische Typisierung setzt jedoch voraus, dass der Verfasser der Abfrage diese sorgfältiger formuliert.

Folgende Typen können verwendet werden:

  • Typen, die durch eine Funktion oder einen Vorgang explizit zugelassen werden.

  • Ein Untertyp eines explizit zugelassenen Typs.

Untertypen werden auf der Grundlage der Untertypisierungsregeln definiert, um Ableitungen durch Beschränkung oder Erweiterung des XML-Schemas zu verwenden. Ein Typ S ist beispielsweise ein Untertyp von T, wenn alle Werte, die den Typ S besitzen, auch Instanzen des Typs T sind.

Darüber hinaus sind alle Ganzzahlwerte auf der Grundlage der Typhierarchie des XML-Schemas auch Dezimalwerte. Nicht alle Dezimalwerte sind allerdings ganze Zahlen. Aus diesem Grund ist eine ganze Zahl ein Untertyp einer Dezimalzahl, aber nicht umgekehrt. Der Vorgang lässt beispielsweise + nur Werte bestimmter Typen zu, z. B. die numerischen Typen xs:integer, xs:decimal, xs:float und xs:double. Wenn Werte anderer Typen, z. B . xs:string, übergeben werden, löst der Vorgang einen Typfehler aus. Dies wird als strenge Typisierung bezeichnet. Werte anderer Typen, wie der Typ atomic, der untypisiertes XML kennzeichnet, können implizit in einen Wert eines Typs konvertiert werden, den die Operation zulässt. Dies wird als schwache Typisierung bezeichnet.

Wenn eine implizite Konvertierung notwendig ist, stellt eine anschließende Überprüfung des statischen Typs sicher, dass an eine Operation nur Werte des zugelassenen Typs mit der richtigen Kardinalität übergeben werden. Für "Zeichenfolge" + 1 wird erkannt, dass der statische Typ von "string" xs:string ist. Da dies kein zulässiger Typ für den + Vorgang ist, wird ein Typfehler ausgelöst.

Wenn das Ergebnis eines beliebigen Ausdrucks E1 zu einem beliebigen Ausdruck E2 addiert wird (E1 + E2), bestimmt die Inferenz des statischen Typs zuerst die statischen Typen von E1 und E2 und prüft diese dann gegen die für den Vorgang zulässigen statischen Typen. Wenn der statische Typ von E1 beispielsweise ein xs:string oder ein xs:integer sein kann, löst die statische Typprüfung einen Typfehler aus, auch wenn einige Werte zur Laufzeit ganze Zahlen sein können. Das gleiche wäre der Fall, wenn der statische Typ von E1 xs:integer* wäre. Da der + Vorgang nur genau einen ganzzahligen Wert akzeptiert und E1 null oder mehr als 1 zurückgeben kann, löst die statische Typprüfung einen Fehler aus.

Wie zuvor erwähnt, ermittelt die Typinferenz häufig einen Typ, der breiter angelegt ist, als dies dem Benutzer hinsichtlich des zu übergebenden Datentyps bekannt ist. In diesen Fällen muss der Benutzer die Abfrage neu schreiben. Zu den typischen Fällen zählen die folgenden:

  • Der Typ folgert einen allgemeineren Typ, wie einen Untertyp oder eine Typvereinigung. Wenn der Typ atomic ist, müssen Sie den Datentypkonvertierungsausdruck oder die Konstruktorfunktion verwenden, um den tatsächlichen statischen Typ anzugeben. Wenn der abgeleitete Typ des Ausdrucks E1 beispielsweise eine Wahl zwischen xs:string oder xs:integer ist und die Addition xs:integer erfordert, sollten Sie anstelle von E1+E2schreibenxs:integer(E1) + E2. Dieser Ausdruck schlägt möglicherweise zur Laufzeit fehl, wenn ein Zeichenfolgenwert gefunden wird, der nicht in xs:integer umgewandelt werden kann. Der Ausdruck wird jetzt jedoch die Überprüfung des statischen Typs durchlaufen. Dieser Ausdruck wird der leeren Sequenz zugeordnet.

  • Aus dem Typ wird eine höhere Kardinalität abgeleitet, als die tatsächlich in den Daten enthaltene. Dies tritt häufig auf, da der xml-Datentyp mehr als ein Element der obersten Ebene enthalten kann und eine XML-Schemaauflistung dies nicht einschränken kann. Um den statischen Typ zu reduzieren und sicherzustellen, dass stattdessen maximal ein Wert übergeben wird, müssen Sie das Positionsprädikat [1] verwenden. Beispiel: Um 1 zum Wert des Attributs c des Elements b unter dem Element der obersten Ebene zu addieren, müssen Sie write (/a/b/@c)[1]+1 angeben. Zusätzlich können Sie mit einer XML-Schemaauflistung das Schlüsselwort DOCUMENT verwenden.

  • Bei einigen Vorgängen geht bei der Inferenz die Typinformation verloren. Wenn beispielsweise der Typ eines Knotens nicht bestimmt werden kann, wird er zu anyType. Dieser wird nicht implizit in irgendeinen anderen Typ umgewandelt. Das tritt am deutlichsten während der Navigation mithilfe der übergeordneten Achse auf. Sie sollten die Verwendung solcher Vorgänge vermeiden und die Abfrage neu schreiben, falls der Ausdruck einen statischen Typfehler erzeugt.

Typüberprüfung von Union-Typen

Union-Typen erfordern aufgrund der Typüberprüfung eine sorgfältige Handhabung. In den folgenden Beispielen sind zwei der Probleme dargestellt.

Beispiel: Funktion für Union-Typ

Betrachten Sie eine Elementdefinition für <r> einen Union-Typ:

<xs:element name="r">  
<xs:simpleType>  
   <xs:union memberTypes="xs:int xs:float xs:double"/>  
</xs:simpleType>  
</xs:element>  

Im XQuery-Kontext gibt die "average"-Funktion fn:avg (//r) einen statischen Fehler zurück, da der XQuery-Compiler keine Werte unterschiedlicher Typen (xs:int, xs:float oder xs:double) für die <r> Elemente im Argument fn:avg() hinzufügen kann. Um dies zu beheben, schreiben Sie den Funktionsaufruf in fn:avg(for $r in //r return $r cast as xs:double ?)um.

Beispiel: Operator für Union-Typ

Die Additionsoperation ('+') erfordert präzise Typen der Operanden. Daher gibt der Ausdruck (//r)[1] + 1 einen statischen Fehler zurück, der die zuvor beschriebene Typdefinition für das -Element <r>aufweist. Eine mögliche Lösung besteht im Umschreiben des Ausdrucks als as (//r)[1] cast as xs:int? +1, wobei das "?" das Auftreten von 0 oder 1 anzeigt. SQL Server erfordert "cast as" mit "?", da jede Umwandlung die leere Sequenz aufgrund von Laufzeitfehlern verursachen kann.

Weitere Informationen

XQuery-Sprachreferenz (SQL Server)