| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more contributor license |
| * agreements. See the NOTICE file distributed with this work for additional information regarding |
| * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the License. You may obtain a |
| * copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software distributed under the License |
| * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
| * or implied. See the License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| package org.apache.geode.cache.query.internal; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Stack; |
| |
| import org.apache.geode.cache.query.Query; |
| import org.apache.geode.internal.cache.InternalCache; |
| import org.apache.geode.pdx.internal.PdxString; |
| |
| /** |
| * This ExecutionContext will be used ONLY for querying because this is a bit heavt-weight context |
| * whose life is longer in JVM than {@link ExecutionContext} which will be used ONLY for index |
| * updates. |
| * |
| * @since GemFire 7.0 |
| */ |
| public class QueryExecutionContext extends ExecutionContext { |
| |
| private int nextFieldNum = 0; |
| |
| private final Query query; |
| |
| private final boolean cqQueryContext; |
| |
| private List bucketList; |
| |
| private boolean indexUsed = false; |
| |
| /** |
| * stack used to determine which execCache to currently be using |
| */ |
| private final Stack execCacheStack = new Stack(); |
| |
| /** |
| * a map that stores general purpose maps for caching data that is valid for one query execution |
| * only |
| */ |
| private final Map execCaches = new HashMap(); |
| |
| /** |
| * This map stores PdxString corresponding to the bind argument |
| */ |
| private Map<Integer, PdxString> bindArgumentToPdxStringMap; |
| |
| /** |
| * List of query index names that the user has hinted on using |
| */ |
| private ArrayList hints = null; |
| |
| public QueryExecutionContext(Object[] bindArguments, InternalCache cache) { |
| super(bindArguments, cache); |
| this.query = null; |
| this.cqQueryContext = false; |
| } |
| |
| public QueryExecutionContext(Object[] bindArguments, InternalCache cache, |
| boolean cqQueryContext) { |
| super(bindArguments, cache); |
| this.query = null; |
| this.cqQueryContext = cqQueryContext; |
| } |
| |
| public QueryExecutionContext(Object[] bindArguments, InternalCache cache, Query query) { |
| super(bindArguments, cache); |
| this.query = query; |
| this.cqQueryContext = ((DefaultQuery) query).isCqQuery(); |
| } |
| |
| @Override |
| void cachePut(Object key, Object value) { |
| if (key.equals(CompiledValue.QUERY_INDEX_HINTS)) { |
| setHints((ArrayList) value); |
| return; |
| } |
| // execCache can be empty in cases where we are doing adds to indexes |
| // in that case, we use a default execCache |
| int scopeId = -1; |
| if (!execCacheStack.isEmpty()) { |
| scopeId = (Integer) execCacheStack.peek(); |
| } |
| Map execCache = (Map) execCaches.get(scopeId); |
| if (execCache == null) { |
| execCache = new HashMap(); |
| execCaches.put(scopeId, execCache); |
| } |
| execCache.put(key, value); |
| } |
| |
| @Override |
| public Object cacheGet(Object key) { |
| return cacheGet(key, null); |
| } |
| |
| @Override |
| public Object cacheGet(Object key, Object defaultValue) { |
| // execCache can be empty in cases where we are doing adds to indexes |
| // in that case, we use a default execCache |
| int scopeId = -1; |
| if (!execCacheStack.isEmpty()) { |
| scopeId = (Integer) execCacheStack.peek(); |
| } |
| Map execCache = (Map) execCaches.get(scopeId); |
| if (execCache == null) { |
| return defaultValue; |
| } |
| if (execCache.containsKey(key)) { |
| return execCache.get(key); |
| } |
| return defaultValue; |
| } |
| |
| @Override |
| public void pushExecCache(int scopeNum) { |
| execCacheStack.push(scopeNum); |
| } |
| |
| @Override |
| public void popExecCache() { |
| execCacheStack.pop(); |
| } |
| |
| /** |
| * Added to reset the state from the last execution. This is added for CQs only. |
| */ |
| @Override |
| public void reset() { |
| super.reset(); |
| this.execCacheStack.clear(); |
| } |
| |
| @Override |
| int nextFieldNum() { |
| return this.nextFieldNum++; |
| } |
| |
| @Override |
| public boolean isCqQueryContext() { |
| return this.cqQueryContext; |
| } |
| |
| @Override |
| public Query getQuery() { |
| return query; |
| } |
| |
| @Override |
| public void setBucketList(List list) { |
| this.bucketList = list; |
| } |
| |
| @Override |
| public List getBucketList() { |
| return this.bucketList; |
| } |
| |
| /** |
| * creates new PdxString from String and caches it |
| */ |
| @Override |
| public PdxString getSavedPdxString(int index) { |
| if (bindArgumentToPdxStringMap == null) { |
| bindArgumentToPdxStringMap = new HashMap<>(); |
| } |
| |
| PdxString pdxString = bindArgumentToPdxStringMap.get(index - 1); |
| if (pdxString == null) { |
| pdxString = new PdxString((String) bindArguments[index - 1]); |
| bindArgumentToPdxStringMap.put(index - 1, pdxString); |
| } |
| return pdxString; |
| } |
| |
| public boolean isIndexUsed() { |
| return indexUsed; |
| } |
| |
| void setIndexUsed(boolean indexUsed) { |
| this.indexUsed = indexUsed; |
| } |
| |
| private void setHints(ArrayList<String> hints) { |
| this.hints = new ArrayList<>(); |
| this.hints.addAll(hints); |
| } |
| |
| /** |
| * @param indexName of index to check if in the hinted list |
| * @return true if the index name was hinted by the user |
| */ |
| public boolean isHinted(String indexName) { |
| return hints != null && hints.contains(indexName); |
| } |
| |
| /** |
| * Hint size is used for filter ordering. Smaller values have preference |
| */ |
| public int getHintSize(String indexName) { |
| return -(hints.size() - hints.indexOf(indexName)); |
| } |
| |
| boolean hasHints() { |
| return hints != null; |
| } |
| |
| boolean hasMultiHints() { |
| return hints != null && hints.size() > 1; |
| } |
| } |