/************************************************************************************** * Copyright (C) 2008 EsperTech, Inc. All rights reserved. * * http://esper.codehaus.org * * 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.epl.expression.ExprIdentNode; import com.espertech.esper.epl.expression.ExprNode; import java.io.StringWriter; import java.util.*; /** * Property lists stored as a value for each stream-to-stream relationship, for use by {@link QueryGraph}. */ public class QueryGraphValue { private Map<String, QueryGraphValueEntry> entries; /** * Ctor. */ public QueryGraphValue() { entries = new LinkedHashMap<String, QueryGraphValueEntry>(); } public Map<String, QueryGraphValueEntry> getEntries() { return entries; } /** * Add key and index property. * @param keyProperty - key property * @param indexProperty - index property * @return true if added and either property did not exist, false if either already existed */ public boolean addStrictCompare(String keyProperty, ExprIdentNode keyPropNode, String indexProperty, ExprIdentNode indexPropNode) { QueryGraphValueEntry value = entries.get(indexProperty); if (value instanceof QueryGraphValueEntryHashKeyedExpr) { // if this index property exists and is compared to a constant, ignore the index prop QueryGraphValueEntryHashKeyedExpr expr = (QueryGraphValueEntryHashKeyedExpr) value; if (expr.isConstant()) { return false; } } if (value instanceof QueryGraphValueEntryHashKeyedProp) { return false; // second comparison, ignore } entries.put(indexProperty, new QueryGraphValueEntryHashKeyedProp(keyPropNode, keyProperty)); return true; } public void addRange(QueryGraphRangeEnum rangeType, ExprNode propertyStart, ExprNode propertyEnd, String propertyValue) { if (!rangeType.isRange()) { throw new IllegalArgumentException("Expected range type, received " + rangeType); } // duplicate can be removed right away if (entries.containsKey(propertyValue)) { return; } entries.put(propertyValue, new QueryGraphValueEntryRangeIn(rangeType, propertyStart, propertyEnd, true)); } public void addRelOp(ExprNode propertyKey, QueryGraphRangeEnum op, String propertyValue, boolean isBetweenOrIn) { // Note: Read as follows: // System.out.println("If I have an index on '" + propertyValue + "' I'm evaluating " + propertyKey + " and finding all values of " + propertyValue + " " + op + " then " + propertyKey); // Check if there is an opportunity to convert this to a range or remove an earlier specification QueryGraphValueEntry existing = entries.get(propertyValue); if (existing == null) { entries.put(propertyValue, new QueryGraphValueEntryRangeRelOp(op, propertyKey, isBetweenOrIn)); return; } if (!(existing instanceof QueryGraphValueEntryRangeRelOp)) { return; // another comparison exists already, don't add range } QueryGraphValueEntryRangeRelOp relOp = (QueryGraphValueEntryRangeRelOp) existing; QueryGraphRangeConsolidateDesc opsDesc = QueryGraphRangeUtil.getCanConsolidate(op, relOp.getType()); if (opsDesc != null) { ExprNode start = !opsDesc.isReverse() ? relOp.getExpression() : propertyKey; ExprNode end = !opsDesc.isReverse() ? propertyKey : relOp.getExpression(); entries.remove(propertyValue); addRange(opsDesc.getType(), start, end, propertyValue); } } public void addUnkeyedExpr(String indexedProp, ExprNode exprNodeNoIdent) { entries.put(indexedProp, new QueryGraphValueEntryHashKeyedExpr(exprNodeNoIdent, false)); } public void addKeyedExpr(String indexedProp, ExprNode exprNodeNoIdent) { entries.put(indexedProp, new QueryGraphValueEntryHashKeyedExpr(exprNodeNoIdent, true)); } public QueryGraphValuePairHashKeyIndex getHashKeyProps() { List<QueryGraphValueEntryHashKeyed> keys = new ArrayList<QueryGraphValueEntryHashKeyed>(); Deque<String> indexed = new ArrayDeque<String>(); for (Map.Entry<String, QueryGraphValueEntry> entry : entries.entrySet()) { if (entry.getValue() instanceof QueryGraphValueEntryHashKeyed) { QueryGraphValueEntryHashKeyed keyprop = (QueryGraphValueEntryHashKeyed) entry.getValue(); keys.add(keyprop); indexed.add(entry.getKey()); } } String[] strictKeys = new String[indexed.size()]; int count = 0; for (Map.Entry<String, QueryGraphValueEntry> entry : entries.entrySet()) { if (entry.getValue() instanceof QueryGraphValueEntryHashKeyed) { if (entry.getValue() instanceof QueryGraphValueEntryHashKeyedProp) { QueryGraphValueEntryHashKeyedProp keyprop = (QueryGraphValueEntryHashKeyedProp) entry.getValue(); strictKeys[count] = keyprop.getKeyProperty(); } count++; } } return new QueryGraphValuePairHashKeyIndex(indexed.toArray(new String[indexed.size()]), keys, strictKeys); } public QueryGraphValuePairRangeIndex getRangeProps() { Deque<String> indexed = new ArrayDeque<String>(); List<QueryGraphValueEntryRange> keys = new ArrayList<QueryGraphValueEntryRange>(); for (Map.Entry<String, QueryGraphValueEntry> entry : entries.entrySet()) { if (entry.getValue() instanceof QueryGraphValueEntryRange) { QueryGraphValueEntryRange keyprop = (QueryGraphValueEntryRange) entry.getValue(); keys.add(keyprop); indexed.add(entry.getKey()); } } return new QueryGraphValuePairRangeIndex(indexed.toArray(new String[indexed.size()]), keys); } public String toString() { StringWriter writer = new StringWriter(); writer.append("QueryGraphValue "); String delimiter = ""; for (Map.Entry<String, QueryGraphValueEntry> entry : entries.entrySet()) { writer.append(delimiter); writer.append(entry.getKey() + ": " + entry.getValue()); delimiter = ", "; } return writer.toString(); } }