Juan Zacarias has proposed merging lp:~zorba-coders/zorba/bug11369_xqxq_bind_cast_variable into lp:zorba.
Commit message: Added Implementation and test for xqxq module functions xqxq:variable-type and xqxq:bind-cast-variable. Also added function getVariable to the Dynamic Context Implementation and API. Requested reviews: Juan Zacarias (juan457) For more details, see: https://code.launchpad.net/~zorba-coders/zorba/bug11369_xqxq_bind_cast_variable/+merge/158480 Added Implementation and test for xqxq module functions xqxq:variable-type and xqxq:bind-cast-variable. Also added function getVariable to the Dynamic Context Implementation and API. -- https://code.launchpad.net/~zorba-coders/zorba/bug11369_xqxq_bind_cast_variable/+merge/158480 Your team Zorba Coders is subscribed to branch lp:zorba.
=== modified file 'include/zorba/dynamic_context.h' --- include/zorba/dynamic_context.h 2013-03-13 16:17:38 +0000 +++ include/zorba/dynamic_context.h 2013-04-11 20:40:28 +0000 @@ -348,6 +348,21 @@ virtual bool isBoundContextItem() const = 0; + /** \brief Returns the type of an external variable. + * + * The named external variable may be located in the main query or in any + * modules imported directly or indirectly by the query. + * + * @param aNamespace the namespace URI of the variable's expanded QName + * @param aLocalname the local name of the variable's expanded QName + * @param outType a String representing the type of + * the external variable. + * @return true if the variable has been retrieved successfully, false otherwise. + * @throw ZorbaException if an error occured. + */ + virtual bool + getVariableType(const String& aNamespace, const String& aLocalname, String& outType) = 0; + protected: /** \brief Destructor */ === modified file 'modules/xqxq/xqxq.xq' --- modules/xqxq/xqxq.xq 2013-04-09 14:22:41 +0000 +++ modules/xqxq/xqxq.xq 2013-04-11 20:40:28 +0000 @@ -23,7 +23,9 @@ : @author Juan Zacarias : @project Zorba/Programming Languages/XQuery :) -module namespace xqxq = 'http://www.zorba-xquery.com/modules/xqxq'; +module namespace xqxq = 'http://www.zorba-xquery.com/modules/xqxq'; +import module namespace parse-xml = "http://www.zorba-xquery.com/modules/xml"; +import schema namespace opt = "http://www.zorba-xquery.com/modules/xml-options"; declare namespace an = "http://www.zorba-xquery.com/annotations"; declare namespace ver = "http://www.zorba-xquery.com/options/versioning"; @@ -285,6 +287,66 @@ declare %an:sequential function xqxq:bind-variable($query-key as xs:anyURI, $var as xs:QName, $value as item()*) as empty-sequence() external ; +(:~ + : This function uses a string value to bind the value of an external variable + : by trying to cast the string to the corresponding type defined in the query. + : Currently the types supported for automatic casting are: xs:string*, xs:integer*, + : xs:int*, xs:long*, xs:short*, xs:decimal*, xs:double*, xs:float*, xs:date*, + : xs:time*, xs:dateTime*, object()*, array()*, document-node()* and element()*. + : If the variable doesn't have a defined type xs:string is assumed. + : + : NOTE: if the user wants to set the variable using an item() the use of + : xqxq:bind-variable is suggested. + : + : @param $query-key the identifier for a compiled query + : @param $name the name of the external variable to bind + : @param $value the sequence of strings to which the external variable $name + : should be casted and set + : + : @return the function has side effects and returns the empty + : sequence. + : + : @error xqxq:NoQueryMatch if no query with the given identifier + : was prepared. + : @error xqxq:UndeclaredVariable if the given variable is not declared + : in the query. + :) +declare %an:sequential function xqxq:bind-cast-variable($query-key as xs:anyURI, $var-name as + xs:QName, $value as xs:string*) as empty-sequence() +{ + variable $type := xqxq:variable-type($query-key, $var-name); + variable $unquanttype := fn:replace($type, "[*+?]$", ""); + let $casted-value := + if (fn:contains($unquanttype, "object")) then + for $val in $value return jn:parse-json($val) + else if (fn:contains($unquanttype, "array")) then + for $val in $value return jn:parse-json($val) + else if (fn:contains($unquanttype, "document-node")) then + for $val in $value return fn:parse-xml($val) + else if (fn:contains($unquanttype, "element")) then + for $val in $value return parse-xml:parse($val, + <opt:options> + <opt:parse-external-parsed-entity/> + </opt:options>) + else + if ($unquanttype eq "xs:anyType") + then $value + else xqxq:caster($unquanttype, $value) + return xqxq:bind-variable($query-key, $var-name, $casted-value) +}; + +declare %private %an:sequential function xqxq:caster($unquanttype as xs:string, + $value as xs:string*) as item()* +{ + variable $caster := xqxq:prepare-main-module( + fn:concat("declare variable $val as xs:string* external; ", + "for $v in $val return $v cast as ", + $unquanttype)); + xqxq:bind-variable($caster, xs:QName("val"), $value); + variable $casted := xqxq:evaluate($caster); + xqxq:delete-query($caster); + $casted +}; (:~ : Evaluates the given prepared query and returns the result @@ -387,6 +449,24 @@ xs:QName) as item()* external; (:~ + : This function returns the type of a variable that is bound in the + : given query. + : + : @param $query-key the identifier of a compiled query. + : @param $var-name the name of the variable whose value should be returned. + : + : @return the type of the given variable. + : + : @error xqxq:NoQueryMatch if no query with the given identifier + : was prepared. + : @error xqxq:UndeclaredVariable if the given variable is not declared + : in the query. + : @error xqxq:UnboundVariable if the given variable doesn't have a value. + :) +declare function xqxq:variable-type($query-key as xs:anyURI, $var-name as + xs:QName) as xs:string external; + +(:~ : Returns the compiled query identified by the given query-key : as binary data. : === modified file 'modules/xqxq/xqxq.xq.src/xqxq.cpp' --- modules/xqxq/xqxq.xq.src/xqxq.cpp 2013-03-25 19:01:32 +0000 +++ modules/xqxq/xqxq.xq.src/xqxq.cpp 2013-04-11 20:40:28 +0000 @@ -85,6 +85,10 @@ { lFunc = new VariableValueFunction(this); } + else if (localName == "variable-type") + { + lFunc = new VariableTypeFunction(this); + } else if (localName == "query-plan") { lFunc = new QueryPlanFunction(this); @@ -975,6 +979,47 @@ /******************************************************************************* ********************************************************************************/ +zorba::ItemSequence_t VariableTypeFunction::evaluate( + const Arguments_t& aArgs, + const zorba::StaticContext* aSctx, + const zorba::DynamicContext* aDctx) const +{ + String lQueryID = XQXQFunction::getOneStringArgument(aArgs,0); + + QueryMap* lQueryMap; + if (!(lQueryMap= dynamic_cast<QueryMap*>(aDctx->getExternalFunctionParameter("xqxqQueryMap")))) + { + throwError("NoQueryMatch", "String identifying query does not exists."); + } + + XQuery_t lQuery = getQuery(aDctx, lQueryID); + + Item lVarQName = XQXQFunction::getItemArgument(aArgs, 1); + + zorba::DynamicContext* lCtx = lQuery->getDynamicContext(); + zorba::String lNS = lVarQName.getNamespace(), lLocal = lVarQName.getLocalName(); + zorba::String lType; + try + { + if(!lCtx->getVariableType(lNS, lLocal, lType)) + { + std::ostringstream lMsg; + lMsg << lLocal << ": variable not bound"; + XQXQFunction::throwError("UndeclaredVariable", lMsg.str()); + } + } + catch (ZorbaException& ze) + { + if (ze.diagnostic() == zerr::ZAPI0011_VARIABLE_NOT_DECLARED) + XQXQFunction::throwError("UndeclaredVariable", ze.what()); + throw; // should not happen + } + return ItemSequence_t(new SingletonItemSequence(XQXQModule::getItemFactory()->createString(lType))); +} + +/******************************************************************************* + +********************************************************************************/ zorba::ItemSequence_t QueryPlanFunction::evaluate( const Arguments_t& aArgs, const zorba::StaticContext* aSctx, === modified file 'modules/xqxq/xqxq.xq.src/xqxq.h' --- modules/xqxq/xqxq.xq.src/xqxq.h 2013-03-22 00:09:14 +0000 +++ modules/xqxq/xqxq.xq.src/xqxq.h 2013-04-11 20:40:28 +0000 @@ -529,38 +529,61 @@ const zorba::DynamicContext*) const; }; - class VariableValueFunction : public XQXQFunction{ - protected: - class ValueItemSequence : public ItemSequence - { - protected: - Iterator_t theIterator; - - public: - ValueItemSequence(Iterator_t& aIter) - : theIterator(aIter) - { - } - - virtual ~ValueItemSequence(){} - - Iterator_t - getIterator() { return theIterator; } - - }; - public: - VariableValueFunction(const XQXQModule* aModule) : XQXQFunction(aModule) {} - - virtual ~VariableValueFunction() {} - - virtual zorba::String - getLocalName() const {return "variable-value"; } - - virtual zorba::ItemSequence_t - evaluate(const Arguments_t&, - const zorba::StaticContext*, - const zorba::DynamicContext*) const; - }; + +/******************************************************************************* + +********************************************************************************/ +class VariableValueFunction : public XQXQFunction{ + protected: + class ValueItemSequence : public ItemSequence + { + protected: + Iterator_t theIterator; + + public: + ValueItemSequence(Iterator_t& aIter) + : theIterator(aIter) + { + } + + virtual ~ValueItemSequence(){} + + Iterator_t + getIterator() { return theIterator; } + + }; + public: + VariableValueFunction(const XQXQModule* aModule) : XQXQFunction(aModule) {} + + virtual ~VariableValueFunction() {} + + virtual zorba::String + getLocalName() const {return "variable-value"; } + + virtual zorba::ItemSequence_t + evaluate(const Arguments_t&, + const zorba::StaticContext*, + const zorba::DynamicContext*) const; +}; + +/******************************************************************************* + +********************************************************************************/ +class VariableTypeFunction : public XQXQFunction +{ +public: + VariableTypeFunction(const XQXQModule* aModule) : XQXQFunction(aModule) {} + + virtual ~VariableTypeFunction() {} + + virtual zorba::String + getLocalName() const {return "variable-type"; } + + virtual zorba::ItemSequence_t + evaluate(const Arguments_t&, + const zorba::StaticContext*, + const zorba::DynamicContext*) const; +}; /******************************************************************************* @@ -643,6 +666,7 @@ getURLResolver(size_t i) const { return theUrlResolvers.size() < i? NULL : theUrlResolvers[i]; } }; }; + }/*xqxq namespace*/}/*zorba namespace*/ === modified file 'src/api/dynamiccontextimpl.cpp' --- src/api/dynamiccontextimpl.cpp 2013-03-13 16:17:38 +0000 +++ src/api/dynamiccontextimpl.cpp 2013-04-11 20:40:28 +0000 @@ -184,6 +184,50 @@ return var; } +/****************************************************************************//** + +********************************************************************************/ +bool DynamicContextImpl::getVariableType( + const String& inNamespace, + const String& inLocalname, + String& outType) +{ + ZORBA_DCTX_TRY + { + checkNoIterators(); + + const zstring& nameSpace = Unmarshaller::getInternalString(inNamespace); + const zstring& localName = Unmarshaller::getInternalString(inLocalname); + + VarInfo* var = NULL; + + try + { + var = get_var_info(nameSpace, localName); + + const XQType* varType = var->getType(); + + if (!varType) + outType = "xs:anyType"; + else + outType = varType->toSchemaString(); + } + catch (ZorbaException const& e) + { + // Normally, we should be throwing an exception if the variable has not + // been declared inside the xquery program, but this cases many failures + // with the w3c XQTS. + if (e.diagnostic() == err::XPST0008) + { + return false; + } + throw; + } + return true; + } + ZORBA_DCTX_CATCH + return false; +} /****************************************************************************//** === modified file 'src/api/dynamiccontextimpl.h' --- src/api/dynamiccontextimpl.h 2013-03-13 16:17:38 +0000 +++ src/api/dynamiccontextimpl.h 2013-04-11 20:40:28 +0000 @@ -83,6 +83,9 @@ public: + virtual bool + getVariableType(const String& inNamespace, const String& inLocalname, String& outType); + virtual bool getVariable( const String& inNamespace, === added file 'test/rbkt/ExpQueryResults/zorba/xqxq/bind-cast-variable.xml.res' --- test/rbkt/ExpQueryResults/zorba/xqxq/bind-cast-variable.xml.res 1970-01-01 00:00:00 +0000 +++ test/rbkt/ExpQueryResults/zorba/xqxq/bind-cast-variable.xml.res 2013-04-11 20:40:28 +0000 @@ -0,0 +1,1 @@ +2 3 \ No newline at end of file === added file 'test/rbkt/ExpQueryResults/zorba/xqxq/bind-cast-variable2.xml.res' --- test/rbkt/ExpQueryResults/zorba/xqxq/bind-cast-variable2.xml.res 1970-01-01 00:00:00 +0000 +++ test/rbkt/ExpQueryResults/zorba/xqxq/bind-cast-variable2.xml.res 2013-04-11 20:40:28 +0000 @@ -0,0 +1,1 @@ +2 \ No newline at end of file === added file 'test/rbkt/ExpQueryResults/zorba/xqxq/bind-cast-variable3.xml.res' --- test/rbkt/ExpQueryResults/zorba/xqxq/bind-cast-variable3.xml.res 1970-01-01 00:00:00 +0000 +++ test/rbkt/ExpQueryResults/zorba/xqxq/bind-cast-variable3.xml.res 2013-04-11 20:40:28 +0000 @@ -0,0 +1,1 @@ +success \ No newline at end of file === added file 'test/rbkt/ExpQueryResults/zorba/xqxq/variable-type.xml.res' --- test/rbkt/ExpQueryResults/zorba/xqxq/variable-type.xml.res 1970-01-01 00:00:00 +0000 +++ test/rbkt/ExpQueryResults/zorba/xqxq/variable-type.xml.res 2013-04-11 20:40:28 +0000 @@ -0,0 +1,1 @@ +xs:integer xs:string xs:dateTime object() element(*, xs:anyType?) \ No newline at end of file === added file 'test/rbkt/Queries/zorba/xqxq/bind-cast-variable.xq' --- test/rbkt/Queries/zorba/xqxq/bind-cast-variable.xq 1970-01-01 00:00:00 +0000 +++ test/rbkt/Queries/zorba/xqxq/bind-cast-variable.xq 2013-04-11 20:40:28 +0000 @@ -0,0 +1,4 @@ +import module namespace xqxq = 'http://www.zorba-xquery.com/modules/xqxq'; +variable $queryID := xqxq:prepare-main-module('declare variable $ext as xs:integer* external; for $i in $ext return $i+1'); +xqxq:bind-cast-variable( $queryID, xs:QName("ext"), ('1', '2')); +xqxq:evaluate($queryID) \ No newline at end of file === added file 'test/rbkt/Queries/zorba/xqxq/bind-cast-variable2.xq' --- test/rbkt/Queries/zorba/xqxq/bind-cast-variable2.xq 1970-01-01 00:00:00 +0000 +++ test/rbkt/Queries/zorba/xqxq/bind-cast-variable2.xq 2013-04-11 20:40:28 +0000 @@ -0,0 +1,4 @@ +import module namespace xqxq = 'http://www.zorba-xquery.com/modules/xqxq'; +variable $queryID := xqxq:prepare-main-module('declare variable $ext as object() external; $ext("value")+1'); +xqxq:bind-cast-variable( $queryID, xs:QName("ext"), '{ "value" : 1}'); +xqxq:evaluate($queryID) \ No newline at end of file === added file 'test/rbkt/Queries/zorba/xqxq/bind-cast-variable3.xq' --- test/rbkt/Queries/zorba/xqxq/bind-cast-variable3.xq 1970-01-01 00:00:00 +0000 +++ test/rbkt/Queries/zorba/xqxq/bind-cast-variable3.xq 2013-04-11 20:40:28 +0000 @@ -0,0 +1,4 @@ +import module namespace xqxq = 'http://www.zorba-xquery.com/modules/xqxq'; +variable $queryID := xqxq:prepare-main-module('declare variable $ext as element() external; $ext//b[@id = 131]/text()'); +xqxq:bind-cast-variable( $queryID, xs:QName("ext"), '<a><b id="131">success</b><b id="2">foo</b></a>'); +xqxq:evaluate($queryID) \ No newline at end of file === added file 'test/rbkt/Queries/zorba/xqxq/bind-cast-variable4.spec' --- test/rbkt/Queries/zorba/xqxq/bind-cast-variable4.spec 1970-01-01 00:00:00 +0000 +++ test/rbkt/Queries/zorba/xqxq/bind-cast-variable4.spec 2013-04-11 20:40:28 +0000 @@ -0,0 +1,1 @@ +Error: http://www.zorba-xquery.com/modules/xqxq:UndeclaredVariable \ No newline at end of file === added file 'test/rbkt/Queries/zorba/xqxq/bind-cast-variable4.xq' --- test/rbkt/Queries/zorba/xqxq/bind-cast-variable4.xq 1970-01-01 00:00:00 +0000 +++ test/rbkt/Queries/zorba/xqxq/bind-cast-variable4.xq 2013-04-11 20:40:28 +0000 @@ -0,0 +1,4 @@ +import module namespace xqxq = 'http://www.zorba-xquery.com/modules/xqxq'; +variable $queryID := xqxq:prepare-main-module('declare variable $ext external; $ext'); +xqxq:bind-cast-variable( $queryID, xs:QName("ext2"), '2'); +xqxq:evaluate($queryID) \ No newline at end of file === added file 'test/rbkt/Queries/zorba/xqxq/variable-type.xq' --- test/rbkt/Queries/zorba/xqxq/variable-type.xq 1970-01-01 00:00:00 +0000 +++ test/rbkt/Queries/zorba/xqxq/variable-type.xq 2013-04-11 20:40:28 +0000 @@ -0,0 +1,13 @@ +import module namespace xqxq = 'http://www.zorba-xquery.com/modules/xqxq'; + +variable $queryID := xqxq:prepare-main-module('declare variable $ext as xs:integer external; $ext'); +variable $queryID2 := xqxq:prepare-main-module('declare variable $ext as xs:string external; $ext'); +variable $queryID3 := xqxq:prepare-main-module('declare variable $ext as xs:dateTime external; $ext'); +variable $queryID4 := xqxq:prepare-main-module('declare variable $ext as object() external; $ext'); +variable $queryID5 := xqxq:prepare-main-module('declare variable $ext as element() external; $ext'); + +xqxq:variable-type($queryID, xs:QName('ext')), +xqxq:variable-type($queryID2, xs:QName('ext')), +xqxq:variable-type($queryID3, xs:QName('ext')), +xqxq:variable-type($queryID4, xs:QName('ext')), +xqxq:variable-type($queryID5, xs:QName('ext')) \ No newline at end of file === added file 'test/rbkt/Queries/zorba/xqxq/variable-type2.spec' --- test/rbkt/Queries/zorba/xqxq/variable-type2.spec 1970-01-01 00:00:00 +0000 +++ test/rbkt/Queries/zorba/xqxq/variable-type2.spec 2013-04-11 20:40:28 +0000 @@ -0,0 +1,1 @@ +Error: http://www.zorba-xquery.com/modules/xqxq:UndeclaredVariable \ No newline at end of file === added file 'test/rbkt/Queries/zorba/xqxq/variable-type2.xq' --- test/rbkt/Queries/zorba/xqxq/variable-type2.xq 1970-01-01 00:00:00 +0000 +++ test/rbkt/Queries/zorba/xqxq/variable-type2.xq 2013-04-11 20:40:28 +0000 @@ -0,0 +1,5 @@ +import module namespace xqxq = 'http://www.zorba-xquery.com/modules/xqxq'; + +variable $queryID := xqxq:prepare-main-module('declare variable $ext as xs:integer external; $ext'); + +xqxq:variable-type($queryID, xs:QName('ext2')) \ No newline at end of file
-- Mailing list: https://launchpad.net/~zorba-coders Post to : zorba-coders@lists.launchpad.net Unsubscribe : https://launchpad.net/~zorba-coders More help : https://help.launchpad.net/ListHelp