/* *************************************************************************************** * 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.join.plan; import com.espertech.esper.collection.Pair; import com.espertech.esper.util.UuidGenerator; import java.util.*; /** * Specifies an index to build as part of an overall query plan. */ public class QueryPlanIndex { private Map<TableLookupIndexReqKey, QueryPlanIndexItem> items; public QueryPlanIndex(Map<TableLookupIndexReqKey, QueryPlanIndexItem> items) { if (items == null) { throw new IllegalArgumentException("Null value not allowed for items"); } this.items = items; } public Map<TableLookupIndexReqKey, QueryPlanIndexItem> getItems() { return items; } public static QueryPlanIndex makeIndex(QueryPlanIndexItem... items) { Map<TableLookupIndexReqKey, QueryPlanIndexItem> result = new LinkedHashMap<TableLookupIndexReqKey, QueryPlanIndexItem>(); for (QueryPlanIndexItem item : items) { result.put(new TableLookupIndexReqKey(UuidGenerator.generate()), item); } return new QueryPlanIndex(result); } public static QueryPlanIndex makeIndex(List<QueryPlanIndexItem> indexesSet) { Map<TableLookupIndexReqKey, QueryPlanIndexItem> items = new LinkedHashMap<TableLookupIndexReqKey, QueryPlanIndexItem>(); for (QueryPlanIndexItem item : indexesSet) { items.put(new TableLookupIndexReqKey(UuidGenerator.generate()), item); } return new QueryPlanIndex(items); } /** * Find a matching index for the property names supplied. * * @param indexProps - property names to search for * @param rangeProps - range props * @return -1 if not found, or offset within indexes if found */ protected Pair<TableLookupIndexReqKey, int[]> getIndexNum(String[] indexProps, String[] rangeProps) { // find an exact match first QueryPlanIndexItem proposed = new QueryPlanIndexItem(indexProps, null, rangeProps, null, false, null); for (Map.Entry<TableLookupIndexReqKey, QueryPlanIndexItem> entry : items.entrySet()) { if (entry.getValue().equalsCompareSortedProps(proposed)) { return new Pair<TableLookupIndexReqKey, int[]>(entry.getKey(), null); } } // find partial match second, i.e. for unique indexes where the where-clause is overspecific for (Map.Entry<TableLookupIndexReqKey, QueryPlanIndexItem> entry : items.entrySet()) { if (entry.getValue().getRangeProps() == null || entry.getValue().getRangeProps().length == 0) { int[] indexes = QueryPlanIndexUniqueHelper.checkSufficientGetAssignment(entry.getValue().getIndexProps(), indexProps); if (indexes != null && indexes.length != 0) { return new Pair<TableLookupIndexReqKey, int[]>(entry.getKey(), indexes); } } } return null; } protected TableLookupIndexReqKey getFirstIndexNum() { return items.keySet().iterator().next(); } /** * Add an index specification element. * * @param indexProperties - list of property names to index * @param coercionTypes - list of coercion types if required, or null if no coercion required * @return number indicating position of index that was added */ public String addIndex(String[] indexProperties, Class[] coercionTypes) { String uuid = UuidGenerator.generate(); items.put(new TableLookupIndexReqKey(uuid), new QueryPlanIndexItem(indexProperties, coercionTypes, null, null, false, null)); return uuid; } /** * For testing - Returns property names of all indexes. * * @return property names array */ public String[][] getIndexProps() { String[][] arr = new String[items.size()][]; int count = 0; for (Map.Entry<TableLookupIndexReqKey, QueryPlanIndexItem> entry : items.entrySet()) { arr[count] = entry.getValue().getIndexProps(); count++; } return arr; } /** * Returns a list of coercion types for a given index. * * @param indexProperties is the index field names * @return coercion types, or null if no coercion is required */ public Class[] getCoercionTypes(String[] indexProperties) { for (Map.Entry<TableLookupIndexReqKey, QueryPlanIndexItem> entry : items.entrySet()) { if (Arrays.deepEquals(entry.getValue().getIndexProps(), indexProperties)) { return entry.getValue().getOptIndexCoercionTypes(); } } throw new IllegalArgumentException("Index properties not found"); } /** * Sets the coercion types for a given index. * * @param indexProperties is the index property names * @param coercionTypes is the coercion types */ public void setCoercionTypes(String[] indexProperties, Class[] coercionTypes) { boolean found = false; for (Map.Entry<TableLookupIndexReqKey, QueryPlanIndexItem> entry : items.entrySet()) { if (Arrays.deepEquals(entry.getValue().getIndexProps(), indexProperties)) { entry.getValue().setOptIndexCoercionTypes(coercionTypes); found = true; } } if (!found) { throw new IllegalArgumentException("Index properties not found"); } } public String toString() { if (items.isEmpty()) { return " (none)"; } StringBuilder buf = new StringBuilder(); String delimiter = ""; for (Map.Entry<TableLookupIndexReqKey, QueryPlanIndexItem> entry : items.entrySet()) { buf.append(delimiter); String info = entry.getValue() == null ? "" : " : " + entry.getValue(); buf.append(" index " + entry.getKey() + info); delimiter = "\n"; } return buf.toString(); } /** * Print index specifications in readable format. * * @param indexSpecs - define indexes * @return readable format of index info */ @SuppressWarnings({"StringConcatenationInsideStringBufferAppend"}) public static String print(QueryPlanIndex[] indexSpecs) { StringBuilder buffer = new StringBuilder(); buffer.append("QueryPlanIndex[]\n"); String delimiter = ""; for (int i = 0; i < indexSpecs.length; i++) { buffer.append(delimiter); buffer.append(" index spec stream " + i + " : \n" + (indexSpecs[i] == null ? " null" : indexSpecs[i])); delimiter = "\n"; } return buffer.toString() + "\n"; } public static QueryPlanIndex makeIndexTableAccess(TableLookupIndexReqKey indexName) { Map<TableLookupIndexReqKey, QueryPlanIndexItem> indexMap = new HashMap<TableLookupIndexReqKey, QueryPlanIndexItem>(); indexMap.put(indexName, null); return new QueryPlanIndex(indexMap); } }