/* *************************************************************************************** * 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.lookup; import com.espertech.esper.client.EventBean; import com.espertech.esper.client.EventType; import com.espertech.esper.core.context.util.AgentInstanceContext; import com.espertech.esper.epl.core.EngineImportService; import com.espertech.esper.epl.expression.core.ExprEvaluator; import com.espertech.esper.epl.expression.core.ExprValidationException; import com.espertech.esper.epl.join.plan.CoercionDesc; import com.espertech.esper.epl.join.table.EventTable; import com.espertech.esper.epl.join.table.EventTableAndNamePair; import com.espertech.esper.epl.join.table.EventTableUtil; import com.espertech.esper.epl.join.util.*; import com.espertech.esper.util.CollectionUtil; import com.espertech.esper.util.JavaClassHelper; import org.slf4j.Logger; import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class SubordinateQueryPlannerUtil { private EventBean[] events; public static void queryPlanLogOnExpr(boolean queryPlanLogging, Logger queryPlanLog, SubordinateWMatchExprQueryPlanResult strategy, Annotation[] annotations, EngineImportService engineImportService) { QueryPlanIndexHook hook = QueryPlanIndexHookUtil.getHook(annotations, engineImportService); if (queryPlanLogging && (queryPlanLog.isInfoEnabled() || hook != null)) { String prefix = "On-Expr "; queryPlanLog.info(prefix + "strategy " + strategy.getFactory().toQueryPlan()); if (strategy.getIndexDescs() == null) { queryPlanLog.info(prefix + "full table scan"); } else { for (int i = 0; i < strategy.getIndexDescs().length; i++) { String indexName = strategy.getIndexDescs()[i].getIndexName(); String indexText = indexName != null ? "index " + indexName + " " : "(implicit) (" + i + ")"; queryPlanLog.info(prefix + indexText); } } if (hook != null) { IndexNameAndDescPair[] pairs = getPairs(strategy.getIndexDescs()); SubordTableLookupStrategyFactory inner = strategy.getFactory().getOptionalInnerStrategy(); hook.infraOnExpr(new QueryPlanIndexDescOnExpr(pairs, strategy.getFactory().getClass().getSimpleName(), inner == null ? null : inner.getClass().getSimpleName())); } } } public static void queryPlanLogOnSubq(boolean queryPlanLogging, Logger queryPlanLog, SubordinateQueryPlanDesc plan, int subqueryNum, Annotation[] annotations, EngineImportService engineImportService) { QueryPlanIndexHook hook = QueryPlanIndexHookUtil.getHook(annotations, engineImportService); if (queryPlanLogging && (queryPlanLog.isInfoEnabled() || hook != null)) { String prefix = "Subquery " + subqueryNum + " "; String strategy = (plan == null || plan.getLookupStrategyFactory() == null) ? "table scan" : plan.getLookupStrategyFactory().toQueryPlan(); queryPlanLog.info(prefix + "strategy " + strategy); if (plan != null) { if (plan.getIndexDescs() != null) { for (int i = 0; i < plan.getIndexDescs().length; i++) { String indexName = plan.getIndexDescs()[i].getIndexName(); String indexText = indexName != null ? "index " + indexName + " " : "(implicit) "; queryPlanLog.info(prefix + "shared index"); queryPlanLog.info(prefix + indexText); } } } if (hook != null) { IndexNameAndDescPair[] pairs = plan == null ? new IndexNameAndDescPair[0] : getPairs(plan.getIndexDescs()); String factory = plan == null ? null : plan.getLookupStrategyFactory().getClass().getSimpleName(); hook.subquery(new QueryPlanIndexDescSubquery(pairs, subqueryNum, factory)); } } } private static IndexNameAndDescPair[] getPairs(SubordinateQueryIndexDesc[] indexDescs) { if (indexDescs == null) { return null; } IndexNameAndDescPair[] pairs = new IndexNameAndDescPair[indexDescs.length]; for (int i = 0; i < indexDescs.length; i++) { SubordinateQueryIndexDesc index = indexDescs[i]; pairs[i] = new IndexNameAndDescPair(index.getIndexName(), index.getIndexMultiKey().toQueryPlan()); } return pairs; } public static SubordinateQueryPlannerIndexPropListPair toListOfHashedAndBtreeProps(String[] hashIndexPropsProvided, Class[] hashIndexCoercionType, String[] rangeIndexPropsProvided, Class[] rangeIndexCoercionType) { List<IndexedPropDesc> hashedProps = new ArrayList<IndexedPropDesc>(); List<IndexedPropDesc> btreeProps = new ArrayList<IndexedPropDesc>(); for (int i = 0; i < hashIndexPropsProvided.length; i++) { hashedProps.add(new IndexedPropDesc(hashIndexPropsProvided[i], hashIndexCoercionType[i])); } for (int i = 0; i < rangeIndexPropsProvided.length; i++) { btreeProps.add(new IndexedPropDesc(rangeIndexPropsProvided[i], rangeIndexCoercionType[i])); } return new SubordinateQueryPlannerIndexPropListPair(hashedProps, btreeProps); } /** * Given an index with a defined set of hash(equals) and range(btree) props and uniqueness flag, * and given a list of indexable properties and accessors for both hash and range, * return the ordered keys and coercion information. * * @param indexMultiKey index definition * @param hashIndexPropsProvided hash indexable properties * @param hashJoinedProps keys for hash indexable properties * @param rangeIndexPropsProvided btree indexable properties * @param rangeJoinedProps keys for btree indexable properties * @return ordered set of key information */ public static IndexKeyInfo compileIndexKeyInfo(IndexMultiKey indexMultiKey, String[] hashIndexPropsProvided, SubordPropHashKey[] hashJoinedProps, String[] rangeIndexPropsProvided, SubordPropRangeKey[] rangeJoinedProps) { // map the order of indexed columns (key) to the key information available IndexedPropDesc[] indexedKeyProps = indexMultiKey.getHashIndexedProps(); boolean isCoerceHash = false; SubordPropHashKey[] hashesDesc = new SubordPropHashKey[indexedKeyProps.length]; Class[] hashPropCoercionTypes = new Class[indexedKeyProps.length]; for (int i = 0; i < indexedKeyProps.length; i++) { String indexField = indexedKeyProps[i].getIndexPropName(); int index = CollectionUtil.findItem(hashIndexPropsProvided, indexField); if (index == -1) { throw new IllegalStateException("Could not find index property for lookup '" + indexedKeyProps[i]); } hashesDesc[i] = hashJoinedProps[index]; hashPropCoercionTypes[i] = indexedKeyProps[i].getCoercionType(); ExprEvaluator evaluatorHashkey = hashesDesc[i].getHashKey().getKeyExpr().getExprEvaluator(); if (evaluatorHashkey != null && JavaClassHelper.getBoxedType(indexedKeyProps[i].getCoercionType()) != JavaClassHelper.getBoxedType(evaluatorHashkey.getType())) { // we allow null evaluator isCoerceHash = true; } } // map the order of range columns (range) to the range information available indexedKeyProps = indexMultiKey.getRangeIndexedProps(); SubordPropRangeKey[] rangesDesc = new SubordPropRangeKey[indexedKeyProps.length]; Class[] rangePropCoercionTypes = new Class[indexedKeyProps.length]; boolean isCoerceRange = false; for (int i = 0; i < indexedKeyProps.length; i++) { String indexField = indexedKeyProps[i].getIndexPropName(); int index = CollectionUtil.findItem(rangeIndexPropsProvided, indexField); if (index == -1) { throw new IllegalStateException("Could not find range property for lookup '" + indexedKeyProps[i]); } rangesDesc[i] = rangeJoinedProps[index]; rangePropCoercionTypes[i] = rangeJoinedProps[index].getCoercionType(); if (JavaClassHelper.getBoxedType(indexedKeyProps[i].getCoercionType()) != JavaClassHelper.getBoxedType(rangePropCoercionTypes[i])) { isCoerceRange = true; } } return new IndexKeyInfo(Arrays.asList(hashesDesc), new CoercionDesc(isCoerceHash, hashPropCoercionTypes), Arrays.asList(rangesDesc), new CoercionDesc(isCoerceRange, rangePropCoercionTypes)); } private static IndexNameAndDescPair[] getTableClassNamePairs(EventTableAndNamePair[] pairs) { if (pairs == null) { return new IndexNameAndDescPair[0]; } IndexNameAndDescPair[] names = new IndexNameAndDescPair[pairs.length]; for (int i = 0; i < pairs.length; i++) { names[i] = new IndexNameAndDescPair(pairs[i].getIndexName(), pairs[i].getEventTable().getProviderClass().getSimpleName()); } return names; } public static EventTable[] realizeTables(SubordinateQueryIndexDesc[] indexDescriptors, EventType eventType, EventTableIndexRepository indexRepository, Iterable<EventBean> contents, AgentInstanceContext agentInstanceContext, boolean isRecoveringResilient) { EventTable[] tables = new EventTable[indexDescriptors.length]; for (int i = 0; i < tables.length; i++) { SubordinateQueryIndexDesc desc = indexDescriptors[i]; EventTable table = indexRepository.getIndexByDesc(desc.getIndexMultiKey()); if (table == null) { table = EventTableUtil.buildIndex(agentInstanceContext, 0, desc.getQueryPlanIndexItem(), eventType, true, desc.getIndexMultiKey().isUnique(), desc.getIndexName(), null, false); // fill table since its new if (!isRecoveringResilient) { EventBean[] events = new EventBean[1]; for (EventBean prefilledEvent : contents) { events[0] = prefilledEvent; table.add(events, agentInstanceContext); } } indexRepository.addIndex(desc.getIndexMultiKey(), new EventTableIndexRepositoryEntry(null, table)); } tables[i] = table; } return tables; } public static void addIndexMetaAndRef(SubordinateQueryIndexDesc[] indexDescs, EventTableIndexMetadata repo, String statementName) throws ExprValidationException { for (SubordinateQueryIndexDesc desc : indexDescs) { if (desc.getIndexName() != null) { repo.addIndexReference(desc.getIndexName(), statementName); } else { repo.addIndexNonExplicit(desc.getIndexMultiKey(), statementName, desc.getQueryPlanIndexItem()); repo.addIndexReference(desc.getIndexMultiKey(), statementName); } } } }