XQuery e digitação estática
Aplica-se a:SQL Server
XQuery no SQL Server é uma linguagem tipada estaticamente. Ou seja, ele gera erros de tipo durante a compilação da consulta quando uma expressão retorna um valor que tem um tipo ou cardinalidade que não é aceito por uma função ou operador específico. Além disso, a verificação de tipo estático também pode detetar se uma expressão de caminho em um documento XML digitado foi digitada incorretamente. O compilador XQuery primeiro aplica a fase de normalização que adiciona as operações implícitas, como atomização, e, em seguida, executa a inferência de tipo estático e a verificação de tipo estático.
Inferência de tipo estático
A inferência de tipo estático determina o tipo de retorno de uma expressão. Ele determina isso tomando os tipos estáticos dos parâmetros de entrada e a semântica estática da operação e inferindo o tipo estático do resultado. Por exemplo, o tipo estático da expressão 1 + 2.3 é determinado da seguinte maneira:
- O tipo estático de 1 é xs:inteiro e o tipo estático de 2.3 é xs:decimal. Com base na semântica dinâmica, a semântica estática da operação + converte o inteiro em decimal e, em seguida, retorna um decimal. O tipo estático inferido seria então xs:decimal.
Para instâncias XML não tipadas, há tipos especiais para indicar que os dados não foram digitados. Essas informações são usadas durante a verificação de tipo estático e para executar certos moldes implícitos).
Para dados digitados, o tipo de entrada é inferido da coleção de esquema XML que restringe a instância do tipo de dados XML. Por exemplo, se o esquema permitir apenas elementos do tipo xs:integer, os resultados de uma expressão de caminho usando esse elemento serão zero ou mais elementos do tipo xs:integer. Isso é atualmente expresso usando uma expressão como element(age,xs:integer)*
onde o asterisco (*) indica a cardinalidade do tipo resultante. Neste exemplo, a expressão pode resultar em zero ou mais elementos do nome "age" e digitar xs:integer. Outras cardinalidades são exatamente uma e são expressas usando apenas o nome do tipo, zero ou um e expressas usando um ponto de interrogação (?), e 1 ou mais e expressas usando um sinal de mais (+).
Às vezes, a inferência de tipo estático pode inferir que uma expressão sempre retornará a sequência vazia. Por exemplo, se uma expressão de caminho em um tipo de dados XML digitado procurar um <nome> elemento dentro de um elemento> cliente <(/customer/name), mas o esquema não permitir que um nome <> dentro de um>cliente <, a inferência de tipo estático inferirá que o resultado estará vazio. Isso será usado para detetar consultas incorretas e será relatado como um erro estático, a menos que a expressão fosse () ou data( () ).
As regras de inferência detalhadas são fornecidas na semântica formal da especificação XQuery. A Microsoft modificou-os apenas ligeiramente para trabalhar com instâncias de tipo de dados XML tipadas. A alteração mais importante do padrão é que o nó implícito do documento sabe sobre o tipo da instância do tipo de dados XML. Como resultado, uma expressão de caminho da forma/idade será digitada com precisão com base nessa informação.
Usando Modelos e Permissões do SQL Server Profiler, você pode ver os tipos estáticos retornados como parte das compilações de consulta. Para vê-los, seu rastreamento deve incluir o evento XQuery Static Type na categoria de evento TSQL.
Verificação de tipo estático
A verificação de tipo estático garante que a execução em tempo de execução receba apenas valores que sejam o tipo apropriado para a operação. Como os tipos não precisam ser verificados em tempo de execução, possíveis erros podem ser detetados no início da compilação. Isso ajuda a melhorar o desempenho. No entanto, a digitação estática requer que o gravador de consultas seja mais cuidadoso ao formular uma consulta.
A seguir estão os tipos apropriados que podem ser usados:
Tipos explicitamente permitidos por uma função ou operação.
Um subtipo de um tipo explicitamente permitido.
Os subtipos são definidos com base nas regras de subtipagem para usar derivação por restrição ou extensão do esquema XML. Por exemplo, um tipo S é um subtipo do tipo T, se todos os valores que têm o tipo S também são instâncias do tipo T.
Além disso, todos os valores inteiros também são valores decimais, com base na hierarquia de tipo de esquema XML. No entanto, nem todos os valores decimais são inteiros. Portanto, um inteiro é um subtipo de decimal, mas não vice-versa. Por exemplo, a operação + só permite valores de determinados tipos, como os tipos numéricos xs:inteiro, xs:decimal, xs:floate xs:double. Se valores de outros tipos, como xs:string, forem passados, a operação gerará um erro de tipo. Isso é conhecido como digitação forte. Valores de outros tipos, como o tipo atômico usado para indicar XML não tipado, podem ser implicitamente convertidos em um valor de um tipo que a operação aceita. Isso é conhecido como digitação fraca.
Se for necessário após uma conversão implícita, a verificação de tipo estático garante que apenas os valores dos tipos permitidos com a cardinalidade correta sejam passados para uma operação. Para "string" + 1, ele reconhece que o tipo estático de "string" é xs:string. Como este não é um tipo permitido para a operação +, um erro de tipo é gerado.
No caso de adicionar o resultado de uma expressão arbitrária E1 a uma expressão arbitrária E2 (E1 + E2), a inferência de tipo estático primeiro determina os tipos estáticos de E1 e E2 e, em seguida, verifica seus tipos estáticos com os tipos permitidos para a operação. Por exemplo, se o tipo estático de E1 pode ser um xs:string ou um xs:integer, a verificação de tipo estático gera um erro de tipo, mesmo que alguns valores em tempo de execução possam ser inteiros. O mesmo seria o caso se o tipo estático de E1 fosse xs:inteiro*. Como a operação + só aceita exatamente um valor inteiro e E1 pode retornar zero ou mais de 1, a verificação de tipo estático gera um erro.
Como mencionado anteriormente, a inferência de tipo frequentemente infere um tipo que é mais amplo do que o que o usuário sabe sobre o tipo de dados que está sendo passado. Nesses casos, o usuário tem que reescrever a consulta. Alguns casos típicos incluem o seguinte:
O tipo infere um tipo mais geral, como um supertipo ou uma união de tipos. Se o tipo for um tipo atômico, você deve usar a expressão de elenco ou a função de construtor para indicar o tipo estático real. Por exemplo, se o tipo inferido da expressão E1 for uma escolha entre xs:string ou xs:integer e a adição exigir xs:integer, você deverá escrever
xs:integer(E1) + E2
em vez deE1+E2
. Esta expressão pode falhar em tempo de execução se for encontrado um valor de cadeia de caracteres que não pode ser convertido para xs:integer. No entanto, a expressão passará agora pela verificação de tipo estático. Esta expressão é mapeada para a sequência vazia.O tipo infere uma cardinalidade maior do que o que os dados realmente contêm. Isso ocorre com freqüência, porque o tipo de dados xml pode conter mais de um elemento de nível superior e uma coleção de esquema XML não pode restringir isso. A fim de reduzir o tipo estático e garantir que há realmente no máximo um valor sendo passado, você deve usar o predicado posicional
[1]
. Por exemplo, para adicionar 1 ao valor do atributoc
do elementob
sob o elemento de nível superior a, você devewrite (/a/b/@c)[1]+1
. Além disso, a palavra-chave DOCUMENT pode ser usada em conjunto com uma coleção de esquema XML.Algumas operações perdem informações de tipo durante a inferência. Por exemplo, se o tipo de um nó não puder ser determinado, ele se tornará anyType. Isto não é implicitamente lançado para qualquer outro tipo. Essas conversões ocorrem principalmente durante a navegação usando o eixo pai. Você deve evitar usar essas operações e reescrever a consulta, se a expressão criará um erro de tipo estático.
Verificação de tipo de tipos de união
Os tipos de união exigem um manuseamento cuidadoso devido à verificação do tipo. Dois dos problemas são ilustrados nos exemplos que se seguem.
Exemplo: Função sobre Tipo de União
Considere uma definição de elemento para <r
> de um tipo de união:
<xs:element name="r">
<xs:simpleType>
<xs:union memberTypes="xs:int xs:float xs:double"/>
</xs:simpleType>
</xs:element>
Dentro do contexto XQuery, a função "média" fn:avg (//r)
retorna um erro estático, porque o compilador XQuery não pode adicionar valores de tipos diferentes (xs:int, xs:float ou xs:double) para os elementos <r
> no argumento de fn:avg(). Para resolver isso, reescreva a invocação da função como fn:avg(for $r in //r return $r cast as xs:double ?)
.
Exemplo: Operador sobre o tipo de União
A operação de adição ('+') requer tipos precisos de operandos. Como resultado, a expressão (//r)[1] + 1
retorna um erro estático que tem a definição de tipo descrita anteriormente para o elemento <r
>. Uma solução é reescrevê-lo como (//r)[1] cast as xs:int? +1
, onde o "?" indica 0 ou 1 ocorrências. O SQL Server requer "cast as" com "?", porque qualquer cast pode causar a sequência vazia como resultado de erros em tempo de execução.