/* *************************************************************************************** * Copyright (C) 2006 EsperTech, Inc. All rights reserved. * * http://www.espertech.com/esper * * http://www.espertech.com * * ---------------------------------------------------------------------------------- * * The software in this package is published under the terms of the GPL license * * a copy of which has been included with this distribution in the license.txt file. * *************************************************************************************** */ package com.espertech.esper.epl.index.quadtree; import com.espertech.esper.collection.Pair; import com.espertech.esper.epl.core.EngineImportApplicationDotMethod; import com.espertech.esper.epl.core.EngineImportException; import com.espertech.esper.epl.declexpr.ExprDeclaredNode; import com.espertech.esper.epl.expression.core.*; import com.espertech.esper.epl.expression.dot.ExprDotNode; import com.espertech.esper.epl.expression.visitor.ExprNodeIdentifierAndStreamRefVisitor; import com.espertech.esper.epl.index.service.AdvancedIndexFactoryProvider; import com.espertech.esper.epl.index.service.FilterExprAnalyzerAffectorIndexProvision; import com.espertech.esper.epl.join.plan.FilterExprAnalyzerAffector; import com.espertech.esper.epl.lookup.AdvancedIndexConfigContextPartition; import com.espertech.esper.filter.FilterSpecCompilerAdvIndexDesc; import com.espertech.esper.util.CollectionUtil; import java.util.*; public abstract class EngineImportApplicationDotMethodBase implements EngineImportApplicationDotMethod { protected final static String LHS_VALIDATION_NAME = "left-hand-side"; protected final static String RHS_VALIDATION_NAME = "right-hand-side"; private final String lhsName; private final ExprNode[] lhs; private final String dotMethodName; private final String rhsName; private final ExprNode[] rhs; private final ExprNode[] indexNamedParameter; private String optionalIndexName; private AdvancedIndexConfigContextPartition optionalIndexConfig; private ExprEvaluator evaluator; protected abstract ExprEvaluator validateAll(String lhsName, ExprNode[] lhs, String rhsName, ExprNode[] rhs, ExprValidationContext validationContext) throws ExprValidationException; protected abstract String indexTypeName(); protected abstract String operationName(); public EngineImportApplicationDotMethodBase(String lhsName, ExprNode[] lhs, String dotMethodName, String rhsName, ExprNode[] rhs, ExprNode[] indexNamedParameter) { this.lhsName = lhsName; this.lhs = lhs; this.dotMethodName = dotMethodName; this.rhsName = rhsName; this.rhs = rhs; this.indexNamedParameter = indexNamedParameter; } public String getLhsName() { return lhsName; } public ExprNode[] getLhs() { return lhs; } public String getDotMethodName() { return dotMethodName; } public String getRhsName() { return rhsName; } public ExprNode[] getRhs() { return rhs; } public ExprNode validate(ExprValidationContext validationContext) throws ExprValidationException { ExprNodeUtility.getValidatedSubtree(ExprNodeOrigin.DOTNODEPARAMETER, lhs, validationContext); ExprNodeUtility.getValidatedSubtree(ExprNodeOrigin.DOTNODEPARAMETER, rhs, validationContext); evaluator = validateAll(lhsName, lhs, rhsName, rhs, validationContext); if (indexNamedParameter != null) { validateIndexNamedParameter(validationContext); } return null; } public ExprEvaluator getExprEvaluator() { return evaluator; } public FilterExprAnalyzerAffector getFilterExprAnalyzerAffector() { ExprNodeIdentifierAndStreamRefVisitor visitor = new ExprNodeIdentifierAndStreamRefVisitor(false); for (ExprNode lhsNode : lhs) { lhsNode.accept(visitor); } Set<Integer> indexedPropertyStreams = new HashSet<>(); for (ExprNodePropOrStreamDesc ref : visitor.getRefs()) { indexedPropertyStreams.add(ref.getStreamNum()); } if (indexedPropertyStreams.size() == 0 || indexedPropertyStreams.size() > 1) { return null; // there are no properties from any streams that could be used for building an index, or the properties come from different disjoint streams } int streamNumIndex = indexedPropertyStreams.iterator().next(); List<Pair<ExprNode, int[]>> keyExpressions = new ArrayList<>(); Set<Integer> dependencies = new HashSet<>(); for (ExprNode node : rhs) { visitor.reset(); dependencies.clear(); node.accept(visitor); for (ExprNodePropOrStreamDesc ref : visitor.getRefs()) { dependencies.add(ref.getStreamNum()); } if (dependencies.contains(streamNumIndex)) { return null; } Pair<ExprNode, int[]> pair = new Pair<>(node, CollectionUtil.intArray(dependencies)); keyExpressions.add(pair); } return new FilterExprAnalyzerAffectorIndexProvision(operationName(), lhs, keyExpressions, streamNumIndex); } public FilterSpecCompilerAdvIndexDesc getFilterSpecCompilerAdvIndexDesc() { if (indexNamedParameter == null) { return null; } return new FilterSpecCompilerAdvIndexDesc(lhs, rhs, optionalIndexConfig, indexTypeName(), optionalIndexName); } private void validateIndexNamedParameter(ExprValidationContext validationContext) throws ExprValidationException { if (indexNamedParameter.length != 1 || !(indexNamedParameter[0] instanceof ExprDeclaredNode)) { throw getIndexNameMessage("requires an expression name"); } ExprDeclaredNode node = (ExprDeclaredNode) indexNamedParameter[0]; if (!(node.getBody() instanceof ExprDotNode)) { throw getIndexNameMessage("requires an index expression"); } ExprDotNode dotNode = (ExprDotNode) node.getBody(); if (dotNode.getChainSpec().size() > 1) { throw getIndexNameMessage("invalid chained index expression"); } List<ExprNode> params = dotNode.getChainSpec().get(0).getParameters(); String indexTypeName = dotNode.getChainSpec().get(0).getName(); optionalIndexName = node.getPrototype().getName(); AdvancedIndexFactoryProvider provider; try { provider = validationContext.getEngineImportService().resolveAdvancedIndexProvider(indexTypeName); } catch (EngineImportException e) { throw new ExprValidationException(e.getMessage(), e); } if (!indexTypeName.toLowerCase(Locale.ENGLISH).equals(indexTypeName())) { throw new ExprValidationException("Invalid index type '" + indexTypeName + "', expected '" + indexTypeName() + "'"); } optionalIndexConfig = provider.validateConfigureFilterIndex(optionalIndexName, indexTypeName, ExprNodeUtility.toArray(params), validationContext); } private ExprValidationException getIndexNameMessage(String message) { return new ExprValidationException("Named parameter '" + ExprDotNode.FILTERINDEX_NAMED_PARAMETER + "' " + message); } }