XQuery и статическая типизация

Применимо к:SQL Server

XQuery в SQL Server — это статически типизированный язык. Это означает, что при компиляции запросов, если выражение возвращает значение, тип или количество элементов которого неприемлемы для указанной функции или оператора, будет выдана ошибка преобразования типов. В дополнение к этому статическая проверка типов может также обнаружить несоответствие типа выражения пути в типизированном документе XML. Компилятор XQuery сначала применяет фазу нормализации, во время которой добавляются неявные операции (например атомизация), а затем производит статический вывод и статическую проверку типов.

Статический вывод типов

Во время операции вывода статического типа определяется тип возвращаемого значения выражения. Для этого берутся статические типы входных параметров и статическая семантика операции и выводится статический тип результата. Например статический тип выражения «1 + 2.3» определяется следующим образом.

  • Статический тип 1 — xs:integer , а статический тип 2.3 — xs:decimal. На основе динамической семантики статическая семантика + операции преобразует целое число в десятичное, а затем возвращает десятичное значение. Затем вычисленный статический тип будет xs:decimal.

Для нетипизированных экземпляров XML имеются специальные типы, обозначающие, что данные нетипизированы. Эти сведения используются при статической проверке типов и для неявного приведения некоторых типов.

Для типизированных данных входной тип выводится из коллекции XML-схем, ограничивающей экземпляр типа данных XML. Например, если схема разрешает только элементы типа xs:integer, результаты выражения пути с помощью этого элемента будут равны нулю или нескольким элементам типа xs:integer. В настоящее время это выражение выражается с помощью выражения, например element(age,xs:integer)* , где звездочка (*) указывает кратность результирующего типа. В этом примере выражение может привести к нулю или нескольким элементам имени "age" и типу xs:integer. Другие кратности являются ровно одним и выражаются с помощью имени типа в одиночку, ноль или один и выражены с помощью вопросительного знака (?), а также 1 или более и выражены с помощью знака плюса (+).

Иногда вывод статического типа может определить, что выражение всегда возвращает пустую последовательность. Например, если выражение пути в типизированном xml-типе данных ищет <элемент name внутри клиентского> элемента (/customer/name), но схема не разрешает <имя>> внутри <<клиента>, вывод статического типа приведет к тому, что результат будет пустым. Это будет использоваться для обнаружения неправильных запросов и будет сообщаться как статическое сообщение об ошибке, если выражение не было () или data() ().

Подробное описание правил вывода содержится в формальной семантике спецификации XQuery. Корпорация Майкрософт только незначительно изменила их для работы с типизированными экземплярами типа данных XML. Наиболее важное отличие от стандарта заключается в том, что неявный узел документа знает тип данных экземпляра XML. Поэтому выражение пути в форме «/age» на основе этих сведений будет точно типизировано.

С помощью шаблонов и разрешений профилировщика SQL Server можно увидеть статические типы, возвращаемые в рамках компиляции запросов. Чтобы просмотреть их, трассировка должна включать событие XQuery Static Type в категории событий TSQL.

Статическая проверка типов

Статическая проверка типов гарантирует, что на стадии выполнения операции будут переданы только те значения, которые имеют соответствующие типы данных. Поскольку эти типы на стадии выполнения не надо проверять, потенциальные ошибки могут быть обнаружены на ранней стадии компиляции, что позволяет повысить производительность. Однако статическая типизация требует точности формулировок при написании запроса.

Ниже приведены все применимые типы:

  • типы, явно допустимые для функции или операции;

  • подтипы явно допустимых типов.

Подтипы определяются на основе правил создания подтипов XML-схемы при наследовании по ограничению или по расширению. Например, тип S является подтипом типа T, если все значения, которые имеет тип S, являются также экземплярами типа T.

Кроме того, в соответствии с иерархией типов XML-схемы, все целочисленные значения являются также и десятичными. Но при этом не все десятичные значения являются целочисленными. Иными словами, целочисленное является подтипом десятичного, но не наоборот. Например, + операция разрешает только значения определенных типов, например числовые типы xs:integer, xs:decimal, xs:float и xs:double. Если передаются значения других типов, например xs:string, операция вызывает ошибку типа. Это называется строгой типизацией. Значения других типов, например атомарного типа, применяемого для обозначения нетипизированного XML, могут быть неявно преобразованы в значение типа, поддерживаемого для данной операции. Это называется слабой типизацией.

Если требуется неявное преобразование, статическая проверка типов гарантирует, что операции будут переданы только значения допустимых типов с верным количеством элементов. Для "string" + 1 он распознает, что статический тип "string" имеет значение xs:string. Так как это недопустимый тип для + операции, возникает ошибка типа.

При сложении результатов произвольного выражения E1 и произвольного выражения E2 (E1 + E2) статический вывод типов сначала определяет статические типы E1 и E2, а затем сверяет их с типами, допустимыми для данной операции. Например, если статический тип E1 может быть xs:string или xs:integer, проверка статического типа вызывает ошибку типа, даже если некоторые значения во время выполнения могут быть целыми числами. То же самое было бы, если статический тип E1 был xs:integer*. + Так как операция принимает только одно целочисленное значение, и E1 может возвращать ноль или более 1, проверка статического типа вызывает ошибку.

Как говорилось ранее, вывод типов часто определяет тип более свободно, чем известно о передаваемом типе данных пользователю. В таких случаях пользователь должен переписать запрос. Некоторые наиболее распространенные причины этого:

  • Тип выводит более общий тип: супертип или объединение типов. Если тип является атомарным, для обозначения действительного статического типа необходимо применить выражение явного приведения или функцию конструктора. Например, если выводимый тип выражения E1 является выбором между xs:string или xs:integer и добавлением требуется xs:integer, то вместо него E1+E2следует писатьxs:integer(E1) + E2. Это выражение может завершиться ошибкой во время выполнения, если обнаружено строковое значение, которое не может быть приведение к xs:integer. но зато теперь выражение будет проходить статическую проверку типов. Такое выражение сопоставляется с пустой последовательностью.

  • Тип выводит количество элементов большее, чем в действительности содержат данные. Это часто происходит, так как тип данных XML может содержать несколько элементов верхнего уровня, а коллекция схем XML не может ограничить это. Чтобы ограничить статический тип и гарантировать, что передается не более одного значения, следует применять позиционный предикат [1]. Например, чтобы добавить 1 к значению атрибута c элемента b под элементом верхнего уровня, необходимо выполнить write (/a/b/@c)[1]+1. Также ключевое слово DOCUMENT может использоваться с коллекцией XML-схем.

  • Некоторые операции приводят к потере типа данных во время вывода. Например, если не удается определить тип узла, он становится любым типом. Это не неявное приведение типа к любому другому типу. Эти преобразования наиболее заметно появляются во время перемещения с помощью родительской оси. Если выражение приводит к ошибке статической типизации, избегайте таких операций и перепишите запрос.

Контроль типов объединенных типов

Работать с объединенными типами нужно особенно внимательно из-за проверки типов. Следующие примеры поясняют две из возможных проблем.

Пример: функция над типом объединения

Рассмотрим определение элемента для <r> типа объединения:

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

В контексте XQuery функция fn:avg (//r) "average" возвращает статическую ошибку, так как компилятор XQuery не может добавлять значения различных типов (xs:int, xs:float или xs:double) для <>rэлементов в аргументе fn:avg(). Чтобы решить эту проблему, перепишите вызов функции как fn:avg(for $r in //r return $r cast as xs:double ?).

Пример: оператор по типу union

Оператор сложения ('+') требует использования точных типов операндов. В результате выражение (//r)[1] + 1 возвращает статическую ошибку, которая содержит ранее описанное определение типа для элементаr<>. Единственное решение — переписать его как (//r)[1] cast as xs:int? +1, где «?» обозначает появление 0 или 1. ДЛЯ SQL Server требуется "приведение как" с "?", так как любой приведение может вызвать пустую последовательность в результате ошибок во время выполнения.

См. также

Справочник по языку XQuery (SQL Server)