Resolving Static Type Errors


DataDirect XQuery implements the Static Typing feature of XQuery, which is pessimistic. This means that DataDirect XQuery raises errors if an expression cannot be guaranteed to be typesafe.

Static typing provides the following advantages:

The disadvantage of static typing is that you must rewrite queries if they do not provide specific type information for certain expressions. For example, you may need to specify the type of an external variable.

Typically, static type errors occur because more specific type information is needed during static analysis, which occurs before any data is encountered. Errors typically are resolved by adding the missing type declaration or making the declaration more specific. For example:

For all these errors, as well as for other static errors that can occur, a static type error message is raised. The solution is to specify more accurate type information, either by specifying the type of a variable or by using constructor functions, casting, treat as, or typeswitch. Now, let’s look at some common cases where this occurs in queries.

Types for External Variables

Static type errors often are encountered in expressions that use external variables, if they do not have a specific type declared. Consider the following example:

declare variable $i external; 
declare variable $j external; 
$i + $j 
Error: [DataDirect][XQuery][err:XP0004]Error at line 3, 
column 7. Static type error. Types 'item()*' and 'item()*' 
are invalid argument types for binary operator '+'. 

If you see this type of static type error for an expression that uses an external variable, make sure the type of the variable is declared:

declare variable $i as xs:integer external; 
declare variable $j as xs:decimal external; 
$i + $j 

Suppose $x is bound to the value <x><a/><b/><c/></x>. The following query raises a static error, because the query does not provide the type of $x.

declare variable $x external; 
$x/* 

The solution is to declare $x to be an element.

declare variable $x as element() external; 
$x/* 

In DataDirect XQuery, XML bound to an external variable is always untyped. It is often convenient to declare it to be untyped in the external variable declaration, which makes it easier to use in queries. For example, consider the following query.

declare variable $y as element() external; 
$y/b + 1 
Static type error. Types 'element(b, xs:untyped)*' and 
'xs:integer' are invalid argument types for binary operator 
'+'. 

Static typing cannot look at the actual value to which $y will be bound, so it raises an error for the query, because the query does not state that $y is an element with untyped content. The solution is to explicitly declare that $y is bound to an XML element, and also to state that this element is untyped.

declare variable $y as element(*, xs:untyped) external; 
$y/b + 1 

Now, the query executes as expected. Suppose $y is bound to an XML document containing the same element used in the preceding query. If the external variable is bound to an untyped XML document, rather than an element, you can declare it like this:

declare variable $y as document-node(element(*, 
  xs:anyType)) external; 

Types for Initial Context Items

Just as with external variables, static type errors often are encountered in expressions that use the initial context item if they do not have a specific type declared. Unlike external variables, the type of the initial context item is not specified as part of the XQuery, but through the XQJ API, using the XQStaticContext object associated with an XQuery expression.

For example, if you want to bind the external variable $y to an untyped XML document, you would do this:

declare variable $y as document-node(element(*, 
  xs:anyType)) external; 

If you need to do the same for the initial context item, you would define the type of the initial context item and bind it to a document using XQJ:

XQStaticContext context = xqConnection.getStaticContext(); 
cntxt.setContextItemStaticType(xqConnection.createDocumentElementType
  (xqConnection.createElementType(null, XQItemType.XQBASETYPE_UNTYPED))); 
xqExpression = xqConnection.createExpression(cntxt); 
xqExpression.bindDocument(XQConstants.CONTEXT_ITEM, new 
FileInputStream("myXMLDocument.xml")); 
... 

Union Types

Sometimes an expression can return more than one type of data, but the query writer knows it will be of a given type. Static typing may need to know the types that are expected. Consider the following expression.

(1, 'a')[1] + 2 

The static typing rules of XQuery do not examine the value of the subscript, so they do not know whether the left operand is an integer or a string. Therefore, DataDirect XQuery raises the following error.

Error: [DataDirect][XQuery][err:XP0004]Error at line 1, 
column 15. Static type error. Types 
'(xs:integer?,xs:string?)' and 'xs:integer' are invalid 
argument types for binary operator '+'. 

When you know that an expression returns the correct type, often the simplest approach is to use a constructor function or a cast expression to guarantee the correct type.

xs:integer((1, 'a')[1]) + 2 

You also can use treat as to tell XQuery which type to expect:

((1, 'a')[1] treat as xs:integer) + 2 

In DataDirect XQuery, using treat as is generally slower because it is compensated.

Types for Sorting

When sorting data, XQuery must be able to compare all the values it encounters. Because static typing cannot examine the values in an expression, it uses the static type information from the query to guarantee that no runtime type errors will be generated because values of incomparable types are being compared. For example, if the query sorts the holdings table and the shares column is a decimal value, the following query is sorted by comparing decimals:

for $h in collection("holdings")//holdings 
order by $h/shares 
return $h 

Static analysis also applies to XML documents, but all XML documents are untyped, because DataDirect XQuery does not support schema validation. Therefore, the following query is statically valid, but the shares are sorted as strings, not using their decimal values:

for $h in doc("holdings.xml")//holdings 
order by $h/shares 
return $h 

In most cases, you would sort based on the numeric value of shares, which is easily done using a constructor function:

for $h in doc("holdings.xml")//holdings 
order by xs:decimal($h/shares) 
return $h 

Static analysis does not allow sorting unless all types used for sorting are comparable. For example, if you wanted to return the holdings in both the holdings database table and an XML file named holdings.xml, you would have a mixture of types that cannot be compared:

for $h in doc("holdings.xml")//holdings 
collection("holdings")//holdings 
order by $h/shares 
return $h 
Error: [DataDirect][XQuery][err:XP0004]Error at line 30, 
column 11. Static type error. Order spec contains invalid 
comparison of types 'xs:string' and 'DECIMAL_19_4'. 

The solution is to use a constructor function to ensure that all values are compared as decimals:

for $h in doc("holdings.xml")//holdings 
collection("holdings")//holdings 
order by xs:decimal($h/shares) 
return $h 

Static Typing Extensions

For static typing analysis, DataDirect XQuery follows the rules of the XQuery Formal Semantics with the following exceptions: