Markos Zaharioudakis has proposed merging lp:~zorba-coders/zorba/markos-scratch into lp:zorba.
Commit message: don't do unnecessary implicit iteration for jsoniq navigation Requested reviews: Markos Zaharioudakis (markos-za) For more details, see: https://code.launchpad.net/~zorba-coders/zorba/markos-scratch/+merge/179411 don't do unnecessary implicit iteration for jsoniq navigation -- https://code.launchpad.net/~zorba-coders/zorba/markos-scratch/+merge/179411 Your team Zorba Coders is subscribed to branch lp:zorba.
=== modified file 'modules/org/jsoniq/www/functions.xq' --- modules/org/jsoniq/www/functions.xq 2013-06-19 14:19:40 +0000 +++ modules/org/jsoniq/www/functions.xq 2013-08-09 10:32:03 +0000 @@ -197,18 +197,6 @@ (:~ - : Returns the value of a JSON Pair with a given name within a given JSON object. - : If no such pair exists in the object, returns the empty sequence. - : - : @param $o A JSON Object. - : @param $name The name of the pair whose value is to be retrieved - : @return the value of specified pair within the given object, or the empty sequence. - :) -(: obsolete - use $o($name) instead :) -declare function jn:value($o as item(), $name as item()?) as item()? external; - - -(:~ : Creates an object from the specified pairs of another given object. : Specifically, for each name in $names, if the object $o has a pair with : that name, then a copy of that pair is included in the new object. @@ -231,18 +219,6 @@ (:~ - : Returns the member of an Array at the specified position (starting from 1). - : If the position is out of bounds of the array, returns the empty sequence. - : - : @param $a A JSON Array. - : @param $p The position in the array. - : @return The member at the specified position, or empty sequence. - :) -(: obsolete - use $a($p) or $a[[$p]] instead :) -declare function jn:member($a as item(), $p as item()?) as item()? external; - - -(:~ : Returns the items belonging to the arrays found inside a given sequence : of items. The items are returned in an implementation-defined order. : === modified file 'src/compiler/rewriter/rules/flwor_rules.cpp' --- src/compiler/rewriter/rules/flwor_rules.cpp 2013-06-14 04:50:39 +0000 +++ src/compiler/rewriter/rules/flwor_rules.cpp 2013-08-09 10:32:03 +0000 @@ -462,7 +462,8 @@ // since one value is still returned, count variables are changed to 1 subst_vars(rCtx, static_cast<count_clause*>(clause)->get_var(), - rCtx.theEM->create_const_expr(sctx, udf, loc, numeric_consts<xs_integer>::one()), + rCtx.theEM->create_const_expr(sctx, udf, loc, + numeric_consts<xs_integer>::one()), 2); theFlwor->remove_clause(0); @@ -537,7 +538,21 @@ if (is_trivial_expr(varDomExpr)) { numRefs = 2; - return isSafeVar; + + if (isSafeVar) + { + return true; + } + else + { + expr* retExpr = theFlwor->get_return_expr(); + xqtref_t type = retExpr->get_return_type_with_empty_input(var); + + return TypeOps::is_equal(theFlwor->get_type_manager(), + *type, + *GENV_TYPESYSTEM.EMPTY_TYPE, + retExpr->get_loc()); + } } // If set to true, then it is unsafe to fold, but we may still be able to === modified file 'src/compiler/translator/translator.cpp' --- src/compiler/translator/translator.cpp 2013-08-02 18:29:44 +0000 +++ src/compiler/translator/translator.cpp 2013-08-09 10:32:03 +0000 @@ -10843,7 +10843,7 @@ args[1] = selectorExpr; expr* accessorExpr = - generate_fn_body(BUILTIN_FUNC(FN_JSONIQ_MEMBER_2), args, loc); + generate_fn_body(BUILTIN_FUNC(OP_ZORBA_ARRAY_MEMBER_2), args, loc); assert(accessorExpr->get_expr_kind() == fo_expr_kind); @@ -10889,7 +10889,7 @@ { fo_expr* pointExpr = CREATE(fo)(sourceExpr->get_sctx(), theUDF, sourceExpr->get_loc(), - BUILTIN_FUNC(FN_JSONIQ_MEMBER_2), + BUILTIN_FUNC(OP_ZORBA_ARRAY_MEMBER_2), arrayExpr, predExpr); @@ -11072,27 +11072,42 @@ assert(selectExpr && objectExpr); - flwor_expr* flworExpr = wrap_expr_in_flwor(objectExpr, false); - - for_clause* fc = static_cast<for_clause*>(flworExpr->get_clause(0)); - - expr* flworVarExpr = CREATE(wrapper)(theRootSctx, theUDF, loc, fc->get_var()); - - expr* accessorExpr; - - std::vector<expr*> args(2); - args[0] = flworVarExpr; - args[1] = selectExpr; - - accessorExpr = generate_fn_body(BUILTIN_FUNC(FN_JSONIQ_VALUE_2), args, loc); - - assert(accessorExpr->get_expr_kind() == fo_expr_kind); - - flworExpr->set_return_expr(accessorExpr); - - pop_scope(); - - push_nodestack(flworExpr); + xqtref_t domainType = objectExpr->get_return_type(); + + if (domainType->max_card() > 1) + { + flwor_expr* flworExpr = wrap_expr_in_flwor(objectExpr, false); + + for_clause* fc = static_cast<for_clause*>(flworExpr->get_clause(0)); + + expr* flworVarExpr = CREATE(wrapper)(theRootSctx, theUDF, loc, fc->get_var()); + + std::vector<expr*> args(2); + args[0] = flworVarExpr; + args[1] = selectExpr; + + expr* accessorExpr = + generate_fn_body(BUILTIN_FUNC(OP_ZORBA_OBJECT_VALUE_2), args, loc); + + assert(accessorExpr->get_expr_kind() == fo_expr_kind); + + flworExpr->set_return_expr(accessorExpr); + + pop_scope(); + + push_nodestack(flworExpr); + } + else + { + std::vector<expr*> args(2); + args[0] = objectExpr; + args[1] = selectExpr; + + expr* accessorExpr = + generate_fn_body(BUILTIN_FUNC(OP_ZORBA_OBJECT_VALUE_2), args, loc); + + push_nodestack(accessorExpr); + } } @@ -12191,14 +12206,14 @@ break; } - case FunctionConsts::FN_JSONIQ_VALUE_2: + case FunctionConsts::OP_ZORBA_OBJECT_VALUE_2: { arguments[1] = create_cast_expr(loc, arguments[1], theRTM.STRING_TYPE_ONE, true, true); break; } - case FunctionConsts::FN_JSONIQ_MEMBER_2: + case FunctionConsts::OP_ZORBA_ARRAY_MEMBER_2: { arguments[1] = create_cast_expr(loc, arguments[1], theRTM.INTEGER_TYPE_ONE, true, true); @@ -12501,11 +12516,11 @@ { if (TypeOps::is_subtype(tm, *srcType, *theRTM.JSON_ARRAY_TYPE_STAR)) { - func = BUILTIN_FUNC(FN_JSONIQ_MEMBER_2); + func = BUILTIN_FUNC(OP_ZORBA_ARRAY_MEMBER_2); } else if (TypeOps::is_subtype(tm, *srcType, *theRTM.JSON_OBJECT_TYPE_STAR)) { - func = BUILTIN_FUNC(FN_JSONIQ_VALUE_2); + func = BUILTIN_FUNC(OP_ZORBA_OBJECT_VALUE_2); } else { === modified file 'src/functions/func_jsoniq_functions_impl.cpp' --- src/functions/func_jsoniq_functions_impl.cpp 2013-06-08 05:33:57 +0000 +++ src/functions/func_jsoniq_functions_impl.cpp 2013-08-09 10:32:03 +0000 @@ -31,6 +31,41 @@ namespace zorba { +/******************************************************************************* + +********************************************************************************/ +xqtref_t op_zorba_json_item_accessor::getReturnType(const fo_expr* caller) const +{ + if (caller->get_arg(0)->get_return_type()->max_card() == 0) + return GENV_TYPESYSTEM.EMPTY_TYPE; + + return theSignature.returnType(); +} + + +/******************************************************************************* + +********************************************************************************/ +xqtref_t op_zorba_object_value::getReturnType(const fo_expr* caller) const +{ + if (caller->get_arg(0)->get_return_type()->max_card() == 0) + return GENV_TYPESYSTEM.EMPTY_TYPE; + + return theSignature.returnType(); +} + + +/******************************************************************************* + +********************************************************************************/ +xqtref_t op_zorba_array_member::getReturnType(const fo_expr* caller) const +{ + if (caller->get_arg(0)->get_return_type()->max_card() == 0) + return GENV_TYPESYSTEM.EMPTY_TYPE; + + return theSignature.returnType(); +} + /******************************************************************************* === modified file 'src/functions/pregenerated/func_jsoniq_functions.cpp' --- src/functions/pregenerated/func_jsoniq_functions.cpp 2013-06-08 05:33:57 +0000 +++ src/functions/pregenerated/func_jsoniq_functions.cpp 2013-08-09 10:32:03 +0000 @@ -83,7 +83,7 @@ return new SingleObjectNamesIterator(sctx, loc, argv[0]); } -PlanIter_t fn_jsoniq_value::codegen( +PlanIter_t op_zorba_object_value::codegen( CompilerCB*, static_context* sctx, const QueryLoc& loc, @@ -103,7 +103,7 @@ return new JSONObjectProjectIterator(sctx, loc, argv[0], argv[1]); } -PlanIter_t fn_jsoniq_member::codegen( +PlanIter_t op_zorba_array_member::codegen( CompilerCB*, static_context* sctx, const QueryLoc& loc, @@ -319,7 +319,7 @@ { DECL_WITH_KIND(sctx, op_zorba_json_item_accessor, (createQName("http://www.zorba-xquery.com/internal/zorba-ops","","json-item-accessor"), - GENV_TYPESYSTEM.ITEM_TYPE_ONE, + GENV_TYPESYSTEM.ITEM_TYPE_QUESTION, GENV_TYPESYSTEM.ITEM_TYPE_STAR), FunctionConsts::OP_ZORBA_JSON_ITEM_ACCESSOR_1); @@ -331,7 +331,7 @@ { DECL_WITH_KIND(sctx, op_zorba_json_item_accessor, (createQName("http://www.zorba-xquery.com/internal/zorba-ops","","json-item-accessor"), - GENV_TYPESYSTEM.ITEM_TYPE_ONE, + GENV_TYPESYSTEM.ITEM_TYPE_QUESTION, GENV_TYPESYSTEM.ITEM_TYPE_QUESTION, GENV_TYPESYSTEM.ITEM_TYPE_QUESTION), FunctionConsts::OP_ZORBA_JSON_ITEM_ACCESSOR_2); @@ -366,12 +366,12 @@ { - DECL_WITH_KIND(sctx, fn_jsoniq_value, - (createQName("http://jsoniq.org/functions","","value"), - GENV_TYPESYSTEM.ITEM_TYPE_ONE, + DECL_WITH_KIND(sctx, op_zorba_object_value, + (createQName("http://www.zorba-xquery.com/internal/zorba-ops","","object-value"), + GENV_TYPESYSTEM.ITEM_TYPE_QUESTION, GENV_TYPESYSTEM.ITEM_TYPE_QUESTION, GENV_TYPESYSTEM.ITEM_TYPE_QUESTION), - FunctionConsts::FN_JSONIQ_VALUE_2); + FunctionConsts::OP_ZORBA_OBJECT_VALUE_2); } @@ -392,12 +392,12 @@ { - DECL_WITH_KIND(sctx, fn_jsoniq_member, - (createQName("http://jsoniq.org/functions","","member"), - GENV_TYPESYSTEM.ITEM_TYPE_ONE, + DECL_WITH_KIND(sctx, op_zorba_array_member, + (createQName("http://www.zorba-xquery.com/internal/zorba-ops","","array-member"), + GENV_TYPESYSTEM.ITEM_TYPE_QUESTION, GENV_TYPESYSTEM.ITEM_TYPE_QUESTION, GENV_TYPESYSTEM.ITEM_TYPE_QUESTION), - FunctionConsts::FN_JSONIQ_MEMBER_2); + FunctionConsts::OP_ZORBA_ARRAY_MEMBER_2); } === modified file 'src/functions/pregenerated/func_jsoniq_functions.h' --- src/functions/pregenerated/func_jsoniq_functions.h 2013-06-08 05:33:57 +0000 +++ src/functions/pregenerated/func_jsoniq_functions.h 2013-08-09 10:32:03 +0000 @@ -125,6 +125,8 @@ } + xqtref_t getReturnType(const fo_expr* caller) const; + bool propagatesInputNodes(expr* fo, csize producer) const { return producer == 0; } bool mustCopyInputNodes(expr* fo, csize producer) const { return false; } @@ -173,17 +175,19 @@ }; -//fn-jsoniq:value -class fn_jsoniq_value : public function +//op-zorba:object-value +class op_zorba_object_value : public function { public: - fn_jsoniq_value(const signature& sig, FunctionConsts::FunctionKind kind) + op_zorba_object_value(const signature& sig, FunctionConsts::FunctionKind kind) : function(sig, kind) { } + xqtref_t getReturnType(const fo_expr* caller) const; + bool propagatesInputNodes(expr* fo, csize producer) const { return producer == 0; } bool mustCopyInputNodes(expr* fo, csize producer) const { return false; } @@ -211,17 +215,19 @@ }; -//fn-jsoniq:member -class fn_jsoniq_member : public function +//op-zorba:array-member +class op_zorba_array_member : public function { public: - fn_jsoniq_member(const signature& sig, FunctionConsts::FunctionKind kind) + op_zorba_array_member(const signature& sig, FunctionConsts::FunctionKind kind) : function(sig, kind) { } + xqtref_t getReturnType(const fo_expr* caller) const; + bool propagatesInputNodes(expr* fo, csize producer) const { return producer == 0; } bool mustCopyInputNodes(expr* fo, csize producer) const { return false; } === modified file 'src/functions/pregenerated/function_enum.h' --- src/functions/pregenerated/function_enum.h 2013-07-26 21:05:40 +0000 +++ src/functions/pregenerated/function_enum.h 2013-08-09 10:32:03 +0000 @@ -263,9 +263,9 @@ OP_ZORBA_JSON_ITEM_ACCESSOR_2, FN_JSONIQ_KEYS_1, OP_ZORBA_KEYS_1, - FN_JSONIQ_VALUE_2, + OP_ZORBA_OBJECT_VALUE_2, FN_JSONIQ_PROJECT_2, - FN_JSONIQ_MEMBER_2, + OP_ZORBA_ARRAY_MEMBER_2, FN_JSONIQ_MEMBERS_1, OP_ZORBA_MEMBERS_1, FN_JSONIQ_SIZE_1, === modified file 'src/runtime/json/jsoniq_functions_impl.cpp' --- src/runtime/json/jsoniq_functions_impl.cpp 2013-06-18 18:55:33 +0000 +++ src/runtime/json/jsoniq_functions_impl.cpp 2013-08-09 10:32:03 +0000 @@ -985,9 +985,9 @@ /******************************************************************************* - op_zorba:json-item-accessor($i as item(), $sel as item()) as item()? + op_zorba:json-item-accessor($i as item()?, $sel as item()?) as item()? - op_zorba:json-item-accessor($i as item()) as item()? + op_zorba:json-item-accessor($i as item()?) as item()* These two are zorba internal functions that are introduced by the translator when translating a dynamic function invocation (DFI) expr and we know statically @@ -1008,60 +1008,61 @@ JSONItemAccessorIteratorState* state; DEFAULT_STACK_INIT(JSONItemAccessorIteratorState, state, planState); - consumeNext(input, theChildren[0].getp(), planState); - - if (input->isArray()) - { - if (theChildren.size() == 2 && - consumeNext(selector, theChildren[1].getp(), planState)) - { - GenericCast::castToBuiltinAtomic(selector2, - selector, - store::XS_INTEGER, - NULL, - loc); - - result = input->getArrayValue(selector2->getIntegerValue()); - - STACK_PUSH(result != 0, state); - } - else - { - state->theIterator = input->getArrayValues(); - - state->theIterator->open(); - while (state->theIterator->next(result)) - { - STACK_PUSH(true, state); - } - state->theIterator->close(); - } - } - else if (input->isObject()) - { - if (theChildren.size() == 2 && - consumeNext(selector, theChildren[1].getp(), planState)) - { - GenericCast::castToBuiltinAtomic(selector2, - selector, - store::XS_STRING, - NULL, - loc); - - result = input->getObjectValue(selector2); - - STACK_PUSH(result != 0, state); - } - else - { - state->theIterator = input->getObjectKeys(); - - state->theIterator->open(); - while (state->theIterator->next(result)) - { - STACK_PUSH(true, state); - } - state->theIterator->close(); + if (consumeNext(input, theChildren[0].getp(), planState)) + { + if (input->isArray()) + { + if (theChildren.size() == 2 && + consumeNext(selector, theChildren[1].getp(), planState)) + { + GenericCast::castToBuiltinAtomic(selector2, + selector, + store::XS_INTEGER, + NULL, + loc); + + result = input->getArrayValue(selector2->getIntegerValue()); + + STACK_PUSH(result != 0, state); + } + else + { + state->theIterator = input->getArrayValues(); + + state->theIterator->open(); + while (state->theIterator->next(result)) + { + STACK_PUSH(true, state); + } + state->theIterator->close(); + } + } + else if (input->isObject()) + { + if (theChildren.size() == 2 && + consumeNext(selector, theChildren[1].getp(), planState)) + { + GenericCast::castToBuiltinAtomic(selector2, + selector, + store::XS_STRING, + NULL, + loc); + + result = input->getObjectValue(selector2); + + STACK_PUSH(result != 0, state); + } + else + { + state->theIterator = input->getObjectKeys(); + + state->theIterator->open(); + while (state->theIterator->next(result)) + { + STACK_PUSH(true, state); + } + state->theIterator->close(); + } } } @@ -1190,15 +1191,16 @@ PlanIteratorState* state; DEFAULT_STACK_INIT(PlanIteratorState, state, planState); - consumeNext(input, theChild0.getp(), planState); - - if (input->isObject()) + if (consumeNext(input, theChild0.getp(), planState)) { - if (consumeNext(name, theChild1.getp(), planState)) + if (input->isObject()) { - result = input->getObjectValue(name); - + if (consumeNext(name, theChild1.getp(), planState)) + { + result = input->getObjectValue(name); + STACK_PUSH(result != NULL, state); + } } } @@ -1308,15 +1310,16 @@ PlanIteratorState* state; DEFAULT_STACK_INIT(PlanIteratorState, state, planState); - consumeNext(input, theChild0.getp(), planState); - - if (input->isArray()) + if (consumeNext(input, theChild0.getp(), planState)) { - if (consumeNext(position, theChild1.getp(), planState)) + if (input->isArray()) { - result = input->getArrayValue(position->getIntegerValue()); - - STACK_PUSH(result != 0, state); + if (consumeNext(position, theChild1.getp(), planState)) + { + result = input->getArrayValue(position->getIntegerValue()); + + STACK_PUSH(result != 0, state); + } } } === modified file 'src/runtime/spec/json/jsoniq_functions.xml' --- src/runtime/spec/json/jsoniq_functions.xml 2013-06-18 18:55:33 +0000 +++ src/runtime/spec/json/jsoniq_functions.xml 2013-08-09 10:32:03 +0000 @@ -240,17 +240,18 @@ <zorba:function isDeterministic="true"> <zorba:signature localname="json-item-accessor" prefix="op-zorba"> - <zorba:param>item()</zorba:param> + <zorba:param>item()?</zorba:param> <zorba:output>item()*</zorba:output> </zorba:signature> <zorba:signature localname="json-item-accessor" prefix="op-zorba"> - <zorba:param>item()</zorba:param> + <zorba:param>item()?</zorba:param> <zorba:param>item()?</zorba:param> <zorba:output>item()?</zorba:output> </zorba:signature> <zorba:methods> + <zorba:getReturnType/> <zorba:propagatesInputNodes producer="0"/> <zorba:mustCopyInputNodes value="false"/> </zorba:methods> @@ -338,13 +339,14 @@ <zorba:function isDeterministic="true"> - <zorba:signature localname="value" prefix="fn-jsoniq"> - <zorba:param>item()</zorba:param> + <zorba:signature localname="object-value" prefix="op-zorba"> + <zorba:param>item()?</zorba:param> <zorba:param>item()?</zorba:param> <zorba:output>item()?</zorba:output> </zorba:signature> <zorba:methods> + <zorba:getReturnType/> <zorba:propagatesInputNodes producer="0"/> <zorba:mustCopyInputNodes value="false"/> </zorba:methods> @@ -386,13 +388,14 @@ <zorba:function isDeterministic="true"> - <zorba:signature localname="member" prefix="fn-jsoniq"> - <zorba:param>item()</zorba:param> + <zorba:signature localname="array-member" prefix="op-zorba"> + <zorba:param>item()?</zorba:param> <zorba:param>item()?</zorba:param> <zorba:output>item()?</zorba:output> </zorba:signature> <zorba:methods> + <zorba:getReturnType/> <zorba:propagatesInputNodes producer="0"/> <zorba:mustCopyInputNodes value="false"/> </zorba:methods> === added directory 'test/rbkt/ExpCompilerResults/IterPlan/zorba/jsoniq' === added file 'test/rbkt/ExpCompilerResults/IterPlan/zorba/jsoniq/member_01.iter' --- test/rbkt/ExpCompilerResults/IterPlan/zorba/jsoniq/member_01.iter 1970-01-01 00:00:00 +0000 +++ test/rbkt/ExpCompilerResults/IterPlan/zorba/jsoniq/member_01.iter 2013-08-09 10:32:03 +0000 @@ -0,0 +1,31 @@ +Iterator tree for main query: +<flwor::FLWORIterator> + <LetVariable name="j" materialize="true"> + <TreatIterator quant="?"> + <JSONParseIterator> + <SingletonIterator value="xs:string([ "foo", "bar" ])"/> + </JSONParseIterator> + </TreatIterator> + </LetVariable> + <ReturnClause> + <FnConcatIterator> + <FnEmptyIterator> + <JSONItemAccessorIterator> + <LetVarIterator varname="j"/> + <SingletonIterator value="xs:integer(0)"/> + </JSONItemAccessorIterator> + </FnEmptyIterator> + <JSONItemAccessorIterator> + <LetVarIterator varname="j"/> + <SingletonIterator value="xs:integer(1)"/> + </JSONItemAccessorIterator> + <FnEmptyIterator> + <JSONItemAccessorIterator> + <LetVarIterator varname="j"/> + <SingletonIterator value="xs:integer(3)"/> + </JSONItemAccessorIterator> + </FnEmptyIterator> + </FnConcatIterator> + </ReturnClause> +</flwor::FLWORIterator> + === modified file 'test/rbkt/Queries/zorba/jsoniq/member_01.xq' --- test/rbkt/Queries/zorba/jsoniq/member_01.xq 2013-02-07 17:24:36 +0000 +++ test/rbkt/Queries/zorba/jsoniq/member_01.xq 2013-08-09 10:32:03 +0000 @@ -1,4 +1,4 @@ import module namespace j = "http://jsoniq.org/functions"; -let $j := j:parse-json('[ "foo", "bar" ]') -return (empty(j:member($j, 0)), j:member($j, 1), empty(j:member($j, 3))) +let $j as item()? := j:parse-json('[ "foo", "bar" ]') +return (empty($j(0)), $j(1), empty($j(3))) === modified file 'test/rbkt/Queries/zorba/jsoniq/pair_01.xq' --- test/rbkt/Queries/zorba/jsoniq/pair_01.xq 2013-02-07 17:24:36 +0000 +++ test/rbkt/Queries/zorba/jsoniq/pair_01.xq 2013-08-09 10:32:03 +0000 @@ -1,5 +1,5 @@ import module namespace j = "http://jsoniq.org/functions"; -let $j := j:parse-json('{ "foo": "bar" }') -return (empty(j:value($j, "bar")), j:value($j, "foo")) +let $j as object()? := j:parse-json('{ "foo": "bar" }') +return (empty($j("bar")), $j("foo"))
-- 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