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:
- An arithmetic or comparison operator can work only on certain data types. Static typing ensures that the operand has the correct type. To ensure that
$j + 1
can execute, the type of$j
must be known statically. DataDirect XQuery raises a type error if this type information is not known statically. The solution is to declare the type of the operand.- In a path expression, the left part of a step must be a node. For example, in the query
$x/*
, static typing ensures that$x
is a node. DataDirect XQuery raises a type error if this type information is not known statically. The solution is to declare the type of the variable as an element or a document node.- An order by clause needs to know the type to be used for comparing values. Static typing raises an error if this type information is not known statically. The solution is to use a constructor function, a cast expression, or treat as to indicate the correct type.
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:
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
.The solution is to declare
$x
to be an element.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.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: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:
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.
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.
You also can use treat as to tell XQuery which type to expect:
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:
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:
In most cases, you would sort based on the numeric value of shares, which is easily done using a constructor function:
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 $hStatic Typing Extensions
For static typing analysis, DataDirect XQuery follows the rules of the XQuery Formal Semantics with the following exceptions:
- DataDirect XQuery does not raise static errors for quantifiers that do not match.
- DataDirect XQuery provides more precise typing rules for parent and fn:root.
- The static type of a parameter is determined by the argument expression, not the parameter declaration. The following function executes without raising a static error although types for the function parameters are not declared:
declare function local:add($left, $right)
{
$left + $right
};
local:add(1, 1)
- The static type of a function return is determined by the function expression, not the declared type. The following example executes without raising a static error although the function return type is not declared:
declare function local:one()
{
1
};
local:one() + 1
- Static typing for constructors use knowledge of the resulting structure as specified by the constructor expression. For example, the expression
<a>1</a> + 1
succeeds because DataDirect XQuery knows statically that the value of the a element is an integer. Similarly,<a><b/></a>/c
fails with error XPST0005 because DataDirect XQuery knows statically that the constructed <a/> element does not have a <c/> element as a child.- The XPST0005 error can be disabled by specifying the detect-XPST0005 option declaration.