XQuery i statyczne typowanie

Dotyczy:SQL Server

XQuery w SQL Server to język statycznie typowany. Oznacza to, że powoduje błędy typu podczas kompilacji zapytań, gdy wyrażenie zwraca wartość o typie lub wartości, której nie akceptuje dana funkcja lub operator. Dodatkowo statyczne sprawdzanie typów może również wykryć, jeśli wyrażenie ścieżki w typowanym dokumencie XML zostało błędnie wpisane. Kompilator XQuery najpierw stosuje fazę normalizacji, która dodaje operacje domyślne, takie jak atomizacja, a następnie wykonuje statyczne wnioskowanie typów oraz statyczne sprawdzanie typów.

Statyczne wnioskowanie typu

Statyczne wnioskowanie typu określa typ zwrotu wyrażenia. Określa to, biorąc statyczne typy parametrów wejściowych oraz statyczną semantykę operacji i wyciągając z wniosku statyczny typ wyniku. Na przykład statyczny typ wyrażenia 1 + 2.3 jest określany w następujący sposób:

  • Statyczny typ 1 to xs:liczba całkowita , a statyczny typ 2.3 to xs:dziesiętny. Na podstawie semantyki dynamicznej, statyczna semantyka operacji + przekształca liczbę całkowitą w dziesiętną, a następnie zwraca liczbę dziesiętną. Wnioskowany typ statyczny to wtedy xs:dziesiętny.

W przypadku nietypowanych instancji XML istnieją specjalne typy wskazujące, że dane nie zostały wpisane. Informacje te są wykorzystywane podczas statycznego sprawdzania typów oraz do wykonywania niektórych niejawnych castów).

Dla danych typowanych typ wejściowy jest wywnioskowany z kolekcji schematów XML, która ogranicza instancję typu danych XML. Na przykład, jeśli schemat dopuszcza tylko elementy typu xs:liczba całkowita, wynik wyrażenia ścieżki z tym elementem będzie wynikiem zero lub więcej elementów typu xs:liczba całkowita. Obecnie wyraża się to za pomocą wyrażenia takiego, element(age,xs:integer)* gdzie gwiazdka (*) wskazuje moc uzyskania typu. W tym przykładzie wyrażenie może skutkować zerem lub więcej elementami nazwy "wiek" oraz typem xs:liczba całkowita. Inne kardynalności to dokładnie jeden i wyrażane są wyłącznie za pomocą nazwy typu, zero lub jeden, wyrażane za pomocą znaku zapytania (?), oraz 1 lub więcej i wyrażane za pomocą znaku plus (+).

Czasami wnioskowanie typu statycznego może wnioskować, że wyrażenie zawsze zwróci pustą sekwencję. Na przykład, jeśli wyrażenie ścieżki na typowanym typie danych XML szuka elementu <nazwy> wewnątrz elementu <klienta> (/customer/name), ale schemat nie pozwala na nazwę><wewnątrz <klienta>, statyczne wnioskowanie typu wywnioskuje, że wynik będzie pusty. Będzie to używane do wykrywania błędnych zapytań i zostanie zgłoszone jako błąd statyczny, chyba że wyrażenie to () lub data( () ).

Szczegółowe reguły wnioskowania zawarte są w formalnej semantyce specyfikacji XQuery. Microsoft zmodyfikował je tylko nieznacznie, aby pracować z typowanymi instancjami typów danych XML. Najważniejszą zmianą względem standardu jest to, że węzeł dokumentu niejawnego zna typ instancji typu danych XML. W rezultacie wyrażenie ścieżki o postaci /age zostanie precyzyjnie wpisane na podstawie tych informacji.

Korzystając z szablonów i uprawnień SQL Server Profiler, można zobaczyć statyczne typy zwracane w ramach kompilacji zapytań. Aby je zobaczyć, Twój ślad musi zawierać zdarzenie XQuery Static Type w kategorii zdarzeń TSQL.

Statyczne sprawdzanie typów

Statyczne sprawdzanie typów zapewnia, że wykonanie w czasie działania otrzyma tylko wartości odpowiedniego typu dla danej operacji. Ponieważ typy nie muszą być sprawdzane w czasie działania, potencjalne błędy mogą być wykrywane już na wczesnym etapie kompilacji. To pomaga poprawić wydajność. Jednak statyczne typowanie wymaga, aby autor zapytań był bardziej ostrożny przy formułowaniu zapytania.

Poniżej przedstawiono odpowiednie typy, które można użyć:

  • Typy wyraźnie dozwolone przez funkcję lub operację.

  • Podtyp o wyraźnie dozwolonym typie.

Podtypy są definiowane na podstawie reguł podtypowania stosujących wyprowadzanie przez ograniczenie lub rozszerzenie schematu XML. Na przykład typ S jest podtypem typu T, jeśli wszystkie wartości posiadające typ S są również instancjami typu T.

Dodatkowo, wszystkie wartości całkowite są również wartościami dziesiętnymi, opartymi na hierarchii typów schematu XML. Jednak nie wszystkie wartości dziesiętne są liczbami całkowitymi. Dlatego liczba całkowita jest podtypem dziesiętnym, ale nie odwrotnie. Na przykład operacja pozwala + na wartości tylko określonych typów, takich jak typy liczbowe xs:integer, xs:decimal, xs:float oraz xs:double. Jeśli wartości innych typów, takich jak xs:string, zostaną przekazane, operacja powoduje błąd typu. Nazywa się to mocnym typowaniem. Wartości innych typów, takie jak typ atomowy używany do oznaczania nietypowanego XML, mogą być niejawnie przekonwertowane na wartość typu, którą operacja akceptuje. Nazywa się to słabym typowaniem.

Jeśli jest wymagane po niejawnej konwersji, statyczne sprawdzanie typów gwarantuje, że do operacji przekazywane są tylko wartości dozwolonych typów o właściwej mocy. Dla "string" + 1 rozpoznaje, że statyczny typ "string" to xs:string. Ponieważ nie jest to dozwolony typ dla operacji + , pojawia się błąd typu.

W przypadku dodawania wyniku dowolnego wyrażenia E1 do dowolnego wyrażenia E2 (E1 + E2), statyczne wnioskowanie typu najpierw określa statyczne typy E1 i E2, a następnie sprawdza ich typy statyczne z dozwolonymi typami dla operacji. Na przykład, jeśli statyczny typ E1 może być albo xs:string , albo xs:integer, statyczny test typu powoduje błąd typu, mimo że niektóre wartości w czasie działania mogą być liczbami całkowitym. To samo byłoby w przypadku, gdyby statyczny typ E1 to xs:całkowita liczba*. Ponieważ operacja akceptuje + tylko jedną wartość całkowitą, a E1 może zwracać zero lub więcej niż 1, statyczna kontrola typu powoduje błąd.

Jak wspomniano wcześniej, wnioskowanie typów często wnioskuje o typie szerszym niż to, co użytkownik wie o typie przekazywanych danych. W takich przypadkach użytkownik musi przepisać zapytanie. Typowe przypadki obejmują:

  • Typ ten wywodzi się z bardziej ogólnego typu, takiego jak supertyp lub suma typów. Jeśli typ jest typem atomowym, powinieneś użyć wyrażenia odlewu lub funkcji konstruktora, aby wskazać rzeczywisty typ statyczny. Na przykład, jeśli wywnioskowany typ wyrażenia E1 to wybór między xs:string a xs:liczbą całkowitą, a dodawanie wymaga xs:integer, powinieneś zapisać xs:integer(E1) + E2 zamiast .E1+E2 To wyrażenie może zawiódć w czasie działania, jeśli napotkamy wartość ciągu znaków, której nie da się przerzucić do xs:integer. Jednak wyrażenie przejdzie teraz statyczny test typu. To wyrażenie jest odwzorowane na sekwencję pustą.

  • Typ ten sugeruje wyższą moc moc niż faktycznie zawarte w danych. Dzieje się to często, ponieważ typ danych xml może zawierać więcej niż jeden element najwyższego poziomu, a kolekcja schematów XML nie może tego ograniczać. Aby zmniejszyć typ statyczny i zagwarantować, że faktycznie jest przekazywana co najwyżej jedna wartość, należy użyć predykatu [1]pozycyjnego . Na przykład, aby dodać 1 do wartości atrybutu c tego elementu b pod elementem najwyższego poziomu, musisz .write (/a/b/@c)[1]+1 Dodatkowo, słowo kluczowe DOCUMENT może być używane razem z kolekcją schematów XML.

  • Niektóre operacje tracą informacje o typie podczas wnioskowania. Na przykład, jeśli typu węzła nie można określić, staje się on anyType. Nie jest to domyślnie przypisane żadnemu innemu typowi. Te konwersje występują najbardziej podczas nawigacji, korzystając z osi nadrzędnej. Powinieneś unikać używania takich operacji i przepisać zapytanie, jeśli wyrażenie spowoduje statyczny błąd typu.

Sprawdzanie typów związków

Typy związków wymagają ostrożnego obchodzenia się ze względu na sprawdzanie typów. Dwa z tych problemów przedstawiono na następujących przykładach.

Przykład: Funkcja nad typem sumy

Rozważmy definicję elementu dla <r> typu sumy:

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

W kontekście XQuery funkcja fn:avg (//r) "average" zwraca statyczny błąd, ponieważ kompilator XQuery nie może dodawać wartości różnych typów (xs:int, xs:float lub xs:double) dla <r> elementów argumentu fn:avg(). Aby to rozwiązać, przepisz wywołanie funkcji jako fn:avg(for $r in //r return $r cast as xs:double ?).

Przykład: Operator nad typem związkowym

Operacja dodawania ('+') wymaga precyzyjnych typów operandów. W rezultacie wyrażenie (//r)[1] + 1 zwraca statyczny błąd, który ma wcześniej opisaną definicję typu dla elementur<> . Jednym z rozwiązań jest przepisanie go na (//r)[1] cast as xs:int? +1, gdzie "?" oznacza 0 lub 1 wystąpień. SQL Server wymaga "cast as" z "?", ponieważ każde przesyłanie może spowodować pustą sekwencję w wyniku błędów w czasie działania.