logical::LogicalPtr apply(const logical::LogicalPtr &input) override { expressions::UnorderedAttributeSet inner_attributes; std::vector<expressions::AttributeReferencePtr> probe_join_attributes; std::vector<expressions::AttributeReferencePtr> build_join_attributes; std::vector<expressions::PredicatePtr> non_hash_join_predicates; const logical::LogicalPtr output = applyInternal(input, &inner_attributes, &probe_join_attributes, &build_join_attributes, &non_hash_join_predicates); probe_join_attributes_->insert(probe_join_attributes_->end(), probe_join_attributes.begin(), probe_join_attributes.end()); build_join_attributes_->insert(build_join_attributes_->end(), build_join_attributes.begin(), build_join_attributes.end()); correlated_non_hash_join_predicates_->insert(correlated_non_hash_join_predicates_->end(), non_hash_join_predicates.begin(), non_hash_join_predicates.end()); return output; }
void TextureMapperAnimation::apply(Client& client) { if (!isActive()) return; double totalRunningTime = computeTotalRunningTime(); double normalizedValue = normalizedAnimationValue(totalRunningTime, m_animation->duration(), m_animation->direction(), m_animation->iterationCount()); if (m_animation->iterationCount() != Animation::IterationCountInfinite && totalRunningTime >= m_animation->duration() * m_animation->iterationCount()) { m_state = AnimationState::Stopped; m_pauseTime = 0; if (m_animation->fillsForwards()) normalizedValue = normalizedAnimationValueForFillsForwards(m_animation->iterationCount(), m_animation->direction()); } if (!normalizedValue) { applyInternal(client, m_keyframes.at(0), m_keyframes.at(1), 0); return; } if (normalizedValue == 1.0) { applyInternal(client, m_keyframes.at(m_keyframes.size() - 2), m_keyframes.at(m_keyframes.size() - 1), 1); return; } if (m_keyframes.size() == 2) { const TimingFunction* timingFunction = timingFunctionForAnimationValue(m_keyframes.at(0), m_animation.get()); normalizedValue = applyTimingFunction(timingFunction, normalizedValue, m_animation->duration()); applyInternal(client, m_keyframes.at(0), m_keyframes.at(1), normalizedValue); return; } for (size_t i = 0; i < m_keyframes.size() - 1; ++i) { const AnimationValue& from = m_keyframes.at(i); const AnimationValue& to = m_keyframes.at(i + 1); if (from.keyTime() > normalizedValue || to.keyTime() < normalizedValue) continue; normalizedValue = (normalizedValue - from.keyTime()) / (to.keyTime() - from.keyTime()); const TimingFunction* timingFunction = timingFunctionForAnimationValue(from, m_animation.get()); normalizedValue = applyTimingFunction(timingFunction, normalizedValue, m_animation->duration()); applyInternal(client, from, to, normalizedValue); break; } }
void GraphicsLayerAnimation::apply(Client* client) { if (!isActive()) return; double totalRunningTime = m_state == PausedState ? m_pauseTime : WTF::currentTime() - m_startTime; double normalizedValue = normalizedAnimationValue(totalRunningTime, m_animation->duration(), m_animation->direction(), m_animation->iterationCount()); if (m_animation->iterationCount() != Animation::IterationCountInfinite && totalRunningTime >= m_animation->duration() * m_animation->iterationCount()) { setState(StoppedState); if (m_animation->fillsForwards()) normalizedValue = normalizedAnimationValueForFillsForwards(m_animation->iterationCount(), m_animation->direction()); } if (!normalizedValue) { applyInternal(client, m_keyframes.at(0), m_keyframes.at(1), 0); return; } if (normalizedValue == 1.0) { applyInternal(client, m_keyframes.at(m_keyframes.size() - 2), m_keyframes.at(m_keyframes.size() - 1), 1); return; } if (m_keyframes.size() == 2) { const TimingFunction* timingFunction = timingFunctionForAnimationValue(m_keyframes.at(0), m_animation.get()); normalizedValue = applyTimingFunction(timingFunction, normalizedValue, m_animation->duration()); applyInternal(client, m_keyframes.at(0), m_keyframes.at(1), normalizedValue); return; } for (size_t i = 0; i < m_keyframes.size() - 1; ++i) { const AnimationValue* from = m_keyframes.at(i); const AnimationValue* to = m_keyframes.at(i + 1); if (from->keyTime() > normalizedValue || to->keyTime() < normalizedValue) continue; normalizedValue = (normalizedValue - from->keyTime()) / (to->keyTime() - from->keyTime()); const TimingFunction* timingFunction = timingFunctionForAnimationValue(from, m_animation.get()); normalizedValue = applyTimingFunction(timingFunction, normalizedValue, m_animation->duration()); applyInternal(client, from, to, normalizedValue); break; } }
P::PhysicalPtr ReduceGroupByAttributes::apply(const P::PhysicalPtr &input) { DCHECK(input->getPhysicalType() == P::PhysicalType::kTopLevelPlan); cost_model_.reset(new cost::StarSchemaSimpleCostModel( std::static_pointer_cast<const P::TopLevelPlan>(input)->shared_subplans())); P::PhysicalPtr output = applyInternal(input); if (output != input) { output = PruneColumns().apply(output); } return output; }
P::PhysicalPtr ReduceGroupByAttributes::applyInternal(const P::PhysicalPtr &input) { std::vector<P::PhysicalPtr> new_children; for (const P::PhysicalPtr &child : input->children()) { new_children.push_back(applyInternal(child)); } if (new_children != input->children()) { return applyToNode(input->copyWithNewChildren(new_children)); } else { return applyToNode(input); } }
/******************************************************************************* If "node" is inside a UDF body, then "udfCaller" is the fo expr that invokes that UDF. ********************************************************************************/ void MarkNodeCopyProps::applyInternal(expr* node, bool deferred) { static_context* sctx = node->get_sctx(); switch (node->get_expr_kind()) { case const_expr_kind: case var_expr_kind: case argument_placeholder_expr_kind: { return; } case doc_expr_kind: case elem_expr_kind: case attr_expr_kind: case namespace_expr_kind: case text_expr_kind: case pi_expr_kind: { // If a doc or element constructor needs to copy (and the ns mode is preserve // and inherit), should it be considered unsafe? The answer is no, because if // copy is needed, then any other construction done during the "current" one // will need to copy as well, so the input trees to the current constructor // will be standalone. This is enforced by the findNodeSources() method, // which drills down inside constructors and will collect as sources any // nested c onstructors as well. break; } case json_direct_object_expr_kind: { // For now, assume that nodes to appear as pair values must be copied first. // TODO improve this json_direct_object_expr* e = static_cast<json_direct_object_expr *>(node); if (sctx->preserve_ns() && sctx->inherit_ns()) { csize numPairs = e->num_pairs(); for (csize i = 0; i < numPairs; ++i) { std::vector<expr*> sources; theSourceFinder->findNodeSources(e->get_value_expr(i), sources); markSources(sources); } } break; } case json_object_expr_kind: { // The input to this expr is a sequence of other objects, which if they // contain any nodes, those nodes are in standalone trees. So, copying // these nodes when the objects are copied is ok. break; } case json_array_expr_kind: { // For now, assume that nodes to appear as members must be copied first. // TODO improve this json_array_expr* e = static_cast<json_array_expr *>(node); if (sctx->preserve_ns() && sctx->inherit_ns() && e->get_expr()) { std::vector<expr*> sources; theSourceFinder->findNodeSources(e->get_expr(), sources); markSources(sources); } break; } case relpath_expr_kind: { relpath_expr* e = static_cast<relpath_expr *>(node); std::vector<expr*>::const_iterator ite = e->begin(); std::vector<expr*>::const_iterator end = e->end(); for (++ite; ite != end; ++ite) { axis_step_expr* axisExpr = static_cast<axis_step_expr*>((*ite)); axis_kind_t axisKind = axisExpr->getAxis(); if (axisKind != axis_kind_child && axisKind != axis_kind_descendant && axisKind != axis_kind_descendant_or_self && axisKind != axis_kind_self && axisKind != axis_kind_attribute) { std::vector<expr*> sources; theSourceFinder->findNodeSources((*e)[0], sources); markSources(sources); break; } else { match_expr* matchExpr = axisExpr->getTest(); if (matchExpr->getTypeName() != NULL && sctx->construction_mode() == StaticContextConsts::cons_strip) { std::vector<expr*> sources; theSourceFinder->findNodeSources((*e)[0], sources); markSources(sources); break; } } } applyInternal((*e)[0], deferred); return; } case fo_expr_kind: { fo_expr* e = static_cast<fo_expr *>(node); function* f = e->get_func(); if (f->isUdf() && static_cast<user_function*>(f)->getBody() != NULL) { user_function* udf = static_cast<user_function*>(f); user_function* callerUdf = e->get_udf(); bool recursive = (callerUdf ? callerUdf->isMutuallyRecursiveWith(udf) : false); if (recursive && !deferred) { callerUdf->addRecursiveCall(e); } else { UdfSet::iterator ite = theProcessedUDFs.find(udf); if (ite == theProcessedUDFs.end()) { theProcessedUDFs.insert(udf); applyInternal(udf->getBody(), deferred); if (udf->isRecursive()) { std::vector<fo_expr*>::const_iterator ite = udf->getRecursiveCalls().begin(); std::vector<fo_expr*>::const_iterator end = udf->getRecursiveCalls().end(); for (; ite != end; ++ite) { applyInternal(*ite, true); } } } // if an arg var of this udf has been marked as a source before, it // means that that var is consumed in some unsafe operation, so we // now have to find the sources of the arg expr and mark them. csize numArgs = e->num_args(); for (csize i = 0; i < numArgs; ++i) { var_expr* argVar = udf->getArgVar(i); if (theSourceFinder->theVarSourcesMap.find(argVar) != theSourceFinder->theVarSourcesMap.end()) { std::vector<expr*> sources; theSourceFinder->findNodeSources(e->get_arg(i), sources); markSources(sources); } } } } // f->isUdf() else { csize numArgs = e->num_args(); for (csize i = 0; i < numArgs; ++i) { if (f->mustCopyInputNodes(e, i)) { std::vector<expr*> sources; theSourceFinder->findNodeSources(e->get_arg(i), sources); markSources(sources); } } FunctionConsts::FunctionKind fkind = f->getKind(); switch (fkind) { case FunctionConsts::FN_DATA_1: case FunctionConsts::FN_NILLED_1: { if (sctx->construction_mode() == StaticContextConsts::cons_strip) { findSourcesForNodeExtractors(e->get_arg(0)); } break; } case FunctionConsts::FN_BASE_URI_1: case FunctionConsts::FN_ROOT_1: // TODO: node-before, node-after { findSourcesForNodeExtractors(e->get_arg(0)); break; } default: break; } } break; } case flwor_expr_kind: case if_expr_kind: case trycatch_expr_kind: case promote_expr_kind: case name_cast_expr_kind: case order_expr_kind: case wrapper_expr_kind: case function_trace_expr_kind: case extension_expr_kind: { break; } case castable_expr_kind: case cast_expr_kind: case instanceof_expr_kind: case treat_expr_kind: { if (sctx->construction_mode() == StaticContextConsts::cons_strip) { cast_or_castable_base_expr* e = static_cast<cast_or_castable_base_expr*>(node); findSourcesForNodeExtractors(e->get_input()); } break; } case validate_expr_kind: { validate_expr* e = static_cast<validate_expr *>(node); std::vector<expr*> sources; theSourceFinder->findNodeSources(e->get_input(), sources); markSources(sources); break; } case delete_expr_kind: case rename_expr_kind: case insert_expr_kind: case replace_expr_kind: { update_expr_base* e = static_cast<update_expr_base*>(node); expr_kind_t kind = e->get_expr_kind(); // The target node cannot be a shared node because the update would be seen // by multiple trees. For updates that delete nodes (delete and replace), the // whole tree must be standalone because we have to sum up the reference // counts of all the nodes in the delete subtree and that won't work if the // deleted subtree contains shared nodes. if (kind == replace_expr_kind || kind == delete_expr_kind) { std::vector<expr*> sources; theSourceFinder->findNodeSources(e->getTargetExpr(), sources); markSources(sources); } else { findSourcesForNodeExtractors(node); } // TODO: apply no-copy rule to insert and replace updates if (e->getSourceExpr() != NULL && (kind == insert_expr_kind || (kind == replace_expr_kind && static_cast<replace_expr*>(e)->getType() == store::UpdateConsts::NODE)) && sctx->inherit_ns() && sctx->preserve_ns()) { std::vector<expr*> sources; theSourceFinder->findNodeSources(e->getSourceExpr(), sources); markSources(sources); } break; } case transform_expr_kind: { transform_expr* e = static_cast<transform_expr *>(node); if (sctx->preserve_ns() && sctx->inherit_ns()) { std::vector<copy_clause*>::const_iterator ite = e->begin(); std::vector<copy_clause*>::const_iterator end = e->end(); for (; ite != end; ++ite) { std::vector<expr*> sources; theSourceFinder->findNodeSources((*ite)->getExpr(), sources); markSources(sources); } } break; } case var_decl_expr_kind: case var_set_expr_kind: case apply_expr_kind: case while_expr_kind: case flowctl_expr_kind: case exit_expr_kind: case exit_catcher_expr_kind: case block_expr_kind: { break; } case eval_expr_kind: { eval_expr* e = static_cast<eval_expr*>(node); // Conservatively assume that, when executed, the eval query will apply // a "node-id-sensitive" operation on each of the in-scope variables, so // these variables must be bound to statndalone trees. csize numEvalVars = e->num_vars(); for (csize i = 0; i < numEvalVars; ++i) { expr* arg = e->get_arg_expr(i); std::vector<expr*> sources; theSourceFinder->findNodeSources(arg, sources); markSources(sources); } break; } case debugger_expr_kind: { break; } #ifndef ZORBA_NO_FULL_TEXT case ft_expr_kind: { // This expr prefrorms whole-tree tokenization. So, its input nodes // must not be shared nodes. What if the input nodes are not shared? // if ft_expr safe in that case ???? ftcontains_expr* e = static_cast<ftcontains_expr*>(node); std::vector<expr*> sources; theSourceFinder->findNodeSources(e->get_range(), sources); markSources(sources); break; } #endif case dynamic_function_invocation_expr_kind: { // Conservatively assume that the function item that is going to be executed // requires stand-alone trees as inputs, so find and mark the sources in the // arguments. TODO: look for function_item_expr in the subtree to check if // this assumption is really true. dynamic_function_invocation_expr* e = static_cast<dynamic_function_invocation_expr*>(node); const std::vector<expr*>& args = e->get_args(); FOR_EACH(std::vector<expr*>, ite, args) { std::vector<expr*> sources; theSourceFinder->findNodeSources((*ite), sources); markSources(sources); } break; } case function_item_expr_kind: { function_item_expr* e = static_cast<function_item_expr*>(node); user_function* udf = static_cast<user_function*>(e->get_function()); applyInternal(udf->getBody(), deferred); return; } case axis_step_expr_kind: case match_expr_kind: default: ZORBA_ASSERT(false); }
expr* MarkNodeCopyProps::apply( RewriterContext& rCtx, expr* node, bool& modified) { modified = false; theSourceFinder = new SourceFinder; try { if (rCtx.theForSerializationOnly) { // Serialization may or may not be a "safe" op. static_context* sctx = node->get_sctx(); if (sctx->preserve_ns()) { if (sctx->inherit_ns()) { // In this case, the result of the query should not contain any shared // node N, because if N was reached via a referencing tree, then // serializing N will miss the namespace bindings that N would have // inherited from the referencing tree if N had been copied into that // tree. (On the other hand it is ok if the query result contains nodes // which are not shared but have shared descendants). To handle this, // we call markInUnsafeContext() so that any exprs that (a) extract nodes // out of input nodes and (b) may propagate the extracted nodes to the // query result will be considered as unsafe and thus require that // their input trees are standalone. findSourcesForNodeExtractors(node); } } else { // In this case serialization is always unsafe. std::vector<expr*> sources; theSourceFinder->findNodeSources(rCtx.theRoot, sources); markSources(sources); } } else { // We have to assume that the result of the "node" expr will be used in an // unsafe op, so it must consist of standalone trees. std::vector<expr*> sources; theSourceFinder->findNodeSources(rCtx.theRoot, sources); markSources(sources); } applyInternal(node, false); } catch (...) { delete theSourceFinder; theSourceFinder = NULL; throw; } delete theSourceFinder; theSourceFinder = NULL; return NULL; }
expressions::ExpressionPtr apply(const expressions::ExpressionPtr &node) override { return applyInternal(true /* allow_exists_or_in */, node); }