/* * JBoss, Home of Professional Open Source. * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. Some portions may be licensed * to Red Hat, Inc. under one or more contributor license agreements. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA. */ package org.teiid.query.util; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; import java.lang.ref.WeakReference; import java.sql.Clob; import java.sql.SQLException; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.util.AbstractMap.SimpleEntry; import java.util.*; import java.util.Map.Entry; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import java.util.regex.Pattern; import javax.security.auth.Subject; import org.teiid.CommandListener; import org.teiid.adminapi.DataPolicy; import org.teiid.adminapi.impl.SessionMetadata; import org.teiid.adminapi.impl.VDBMetaData; import org.teiid.api.exception.query.QueryProcessingException; import org.teiid.common.buffer.BufferManager; import org.teiid.common.buffer.TupleSource; import org.teiid.core.TeiidComponentException; import org.teiid.core.TeiidException; import org.teiid.core.types.ClobImpl; import org.teiid.core.types.InputStreamFactory; import org.teiid.core.util.ArgCheck; import org.teiid.core.util.ExecutorUtils; import org.teiid.core.util.LRUCache; import org.teiid.dqp.internal.process.AuthorizationValidator; import org.teiid.dqp.internal.process.DQPWorkContext; import org.teiid.dqp.internal.process.PreparedPlan; import org.teiid.dqp.internal.process.RequestWorkItem; import org.teiid.dqp.internal.process.SessionAwareCache; import org.teiid.dqp.internal.process.SessionAwareCache.CacheID; import org.teiid.dqp.internal.process.TupleSourceCache; import org.teiid.dqp.message.RequestID; import org.teiid.dqp.service.TransactionContext; import org.teiid.dqp.service.TransactionService; import org.teiid.jdbc.ConnectionImpl; import org.teiid.jdbc.LocalProfile; import org.teiid.jdbc.TeiidConnection; import org.teiid.jdbc.TeiidSQLException; import org.teiid.logging.LogConstants; import org.teiid.logging.LogManager; import org.teiid.logging.MessageLevel; import org.teiid.metadata.AbstractMetadataRecord; import org.teiid.metadata.FunctionMethod.Determinism; import org.teiid.net.ServerConnection; import org.teiid.query.QueryPlugin; import org.teiid.query.metadata.QueryMetadataInterface; import org.teiid.query.metadata.TempMetadataAdapter; import org.teiid.query.parser.ParseInfo; import org.teiid.query.processor.QueryProcessor; import org.teiid.query.sql.symbol.ElementSymbol; import org.teiid.query.sql.symbol.Expression; import org.teiid.query.sql.util.VariableContext; import org.teiid.query.tempdata.GlobalTableStore; import org.teiid.query.tempdata.GlobalTableStoreImpl; import org.teiid.query.tempdata.TempTableStore; import org.teiid.translator.ReusableExecution; /** * Defines the context that a command is processing in. For example, this defines * who is processing the command and why. Also, this class (or subclasses) provide * a means to pass context-specific information between users of the query processor * framework. */ public class CommandContext implements Cloneable, org.teiid.CommandContext { private static ThreadLocal<LinkedList<CommandContext>> threadLocalContext = new ThreadLocal<LinkedList<CommandContext>>() { @Override protected LinkedList<CommandContext> initialValue() { return new LinkedList<CommandContext>(); } }; private static class VDBState { private String vdbName = ""; //$NON-NLS-1$ private String vdbVersion = ""; //$NON-NLS-1$ private QueryMetadataInterface metadata; private GlobalTableStore globalTables; private SessionMetadata session; private ClassLoader classLoader; private DQPWorkContext dqpWorkContext; } private static class LookupKey implements Comparable<LookupKey> { String matTableName; Comparable keyValue; public LookupKey(String matTableName, Object keyValue) { this.matTableName = matTableName; this.keyValue = (Comparable) keyValue; } @Override public int compareTo(LookupKey arg0) { int comp = matTableName.compareTo(arg0.matTableName); if (comp != 0) { return comp; } return keyValue.compareTo(arg0.keyValue); } } private static class GlobalState implements Cloneable { private WeakReference<RequestWorkItem> processorID; /** Identify a group of related commands, which typically get cleaned up together */ private String connectionID; private int processorBatchSize = BufferManager.DEFAULT_PROCESSOR_BATCH_SIZE; private String userName; private Serializable commandPayload; /** Indicate whether statistics should be collected for relational node processing*/ private boolean collectNodeStatistics; private Random random = null; private TimeZone timezone = TimeZone.getDefault(); private QueryProcessor.ProcessorFactory queryProcessorFactory; private Set<String> groups; private Map<String, String> aliasMapping; private long timeSliceEnd = Long.MAX_VALUE; private long timeoutEnd = Long.MAX_VALUE; private boolean validateXML; private BufferManager bufferManager; private SessionAwareCache<PreparedPlan> planCache; private boolean resultSetCacheEnabled = true; private int userRequestSourceConcurrency; private Subject subject; private HashSet<Object> dataObjects; private RequestID requestId; private TransactionContext transactionContext; private TransactionService transactionService; private Executor executor = ExecutorUtils.getDirectExecutor(); Map<Object, List<ReusableExecution<?>>> reusableExecutions; Set<CommandListener> commandListeners = null; private LRUCache<String, DecimalFormat> decimalFormatCache; private LRUCache<String, SimpleDateFormat> dateFormatCache; private LRUCache<Entry<String,Integer>, Pattern> patternCache; private AtomicLong reuseCount = null; private List<Exception> warnings = null; private Options options = null; private boolean returnAutoGeneratedKeys; private GeneratedKeysImpl generatedKeys; private long reservedBuffers; private AuthorizationValidator authorizationValidator; private Map<LookupKey, TupleSource> lookups; private TempTableStore sessionTempTableStore; private Set<InputStreamFactory> created = Collections.newSetFromMap(new WeakHashMap<InputStreamFactory, Boolean>()); private LRUCache<AbstractMetadataRecord, Boolean> accessible; private Throwable batchUpdateException; } private GlobalState globalState = new GlobalState(); private VariableContext variableContext = new VariableContext(); private TempTableStore tempTableStore; private LinkedList<String> recursionStack; private boolean nonBlocking; private HashSet<Object> planningObjects; private HashSet<Object> dataObjects = this.globalState.dataObjects; private TupleSourceCache tupleSourceCache; private VDBState vdbState = new VDBState(); private Determinism[] determinismLevel = new Determinism[] {Determinism.DETERMINISTIC}; private AtomicBoolean cancelled = new AtomicBoolean(); private AtomicBoolean parentCancelled; /** * Construct a new context. */ public CommandContext(String connectionID, String userName, Serializable commandPayload, String vdbName, Object vdbVersion, boolean collectNodeStatistics) { setConnectionID(connectionID); setUserName(userName); setCommandPayload(commandPayload); setVdbName(vdbName); setVdbVersion(vdbVersion.toString()); setCollectNodeStatistics(collectNodeStatistics); } /** * Construct a new context. */ public CommandContext(Object processorID, String connectionID, String userName, String vdbName, Object vdbVersion) { this(connectionID, userName, null, vdbName, vdbVersion, false); } public CommandContext() { } private CommandContext(GlobalState state) { this.globalState = state; this.dataObjects = this.globalState.dataObjects; } public Determinism getDeterminismLevel() { return determinismLevel[0]; } public Determinism resetDeterminismLevel(boolean detach) { Determinism result = determinismLevel[0]; if (detach) { determinismLevel = new Determinism[1]; } determinismLevel[0] = Determinism.DETERMINISTIC; return result; } public Determinism resetDeterminismLevel() { return resetDeterminismLevel(false); } public void setDeterminismLevel(Determinism level) { if (determinismLevel[0] == null || level.compareTo(determinismLevel[0]) < 0) { determinismLevel[0] = level; } } /** * @return */ public RequestWorkItem getWorkItem() { if (globalState.processorID == null) { return null; } return globalState.processorID.get(); } /** * @param object */ public void setWorkItem(RequestWorkItem object) { ArgCheck.isNotNull(object); globalState.processorID = new WeakReference<RequestWorkItem>(object); } public CommandContext clone() { CommandContext clone = new CommandContext(this.globalState); clone.variableContext = this.variableContext; clone.tempTableStore = this.tempTableStore; if (this.recursionStack != null) { clone.recursionStack = new LinkedList<String>(this.recursionStack); } clone.setNonBlocking(this.nonBlocking); clone.tupleSourceCache = this.tupleSourceCache; clone.vdbState = this.vdbState; clone.determinismLevel = this.determinismLevel; if (this.parentCancelled != null) { clone.parentCancelled = this.parentCancelled; } else { clone.parentCancelled = this.cancelled; } return clone; } public void setNewVDBState(DQPWorkContext newWorkContext) { this.vdbState = new VDBState(); VDBMetaData vdb = newWorkContext.getVDB(); GlobalTableStore actualGlobalStore = vdb.getAttachment(GlobalTableStore.class); this.vdbState.globalTables = actualGlobalStore; this.vdbState.session = newWorkContext.getSession(); this.vdbState.classLoader = vdb.getAttachment(ClassLoader.class); this.vdbState.vdbName = vdb.getName(); this.vdbState.vdbVersion = vdb.getVersion(); this.vdbState.dqpWorkContext = newWorkContext; TempMetadataAdapter metadata = new TempMetadataAdapter(vdb.getAttachment(QueryMetadataInterface.class), globalState.sessionTempTableStore.getMetadataStore()); metadata.setSession(true); this.vdbState.metadata = metadata; } public String toString() { return "CommandContext: " + globalState.processorID; //$NON-NLS-1$ } public String getConnectionId() { return globalState.connectionID; } public String getConnectionID() { return globalState.connectionID; } public String getUserName() { return globalState.userName; } public String getVdbName() { return vdbState.vdbName; } public String getVdbVersion() { return vdbState.vdbVersion; } /** * Sets the connectionID. * @param connectionID The connectionID to set */ public void setConnectionID(String connectionID) { this.globalState.connectionID = connectionID; } /** * Sets the userName. * @param userName The userName to set */ public void setUserName(String userName) { this.globalState.userName = userName; } /** * Sets the vdbName. * @param vdbName The vdbName to set */ public void setVdbName(String vdbName) { this.vdbState.vdbName = vdbName; } /** * Sets the vdbVersion. * @param vdbVersion The vdbVersion to set */ public void setVdbVersion(Object vdbVersion) { this.vdbState.vdbVersion = vdbVersion.toString(); } public Serializable getCommandPayload() { return this.globalState.commandPayload; } public void setCommandPayload(Serializable commandPayload) { this.globalState.commandPayload = commandPayload; } /** * @param collectNodeStatistics The collectNodeStatistics to set. * @since 4.2 */ public void setCollectNodeStatistics(boolean collectNodeStatistics) { this.globalState.collectNodeStatistics = collectNodeStatistics; } public boolean getCollectNodeStatistics() { return this.globalState.collectNodeStatistics; } @Override public int getProcessorBatchSize() { return this.globalState.processorBatchSize; } public int getProcessorBatchSize(List<Expression> schema) { return this.globalState.bufferManager.getProcessorBatchSize(schema); } public void setProcessorBatchSize(int processorBatchSize) { this.globalState.processorBatchSize = processorBatchSize; } public double getNextRand() { if (globalState.random == null) { globalState.random = new Random(); } return globalState.random.nextDouble(); } public double getNextRand(long seed) { if (globalState.random == null) { globalState.random = new Random(); } globalState.random.setSeed(seed); return globalState.random.nextDouble(); } void setRandom(Random random) { this.globalState.random = random; } public void pushCall(String value) throws QueryProcessingException { if (recursionStack == null) { recursionStack = new LinkedList<String>(); } else if (recursionStack.contains(value)) { throw new QueryProcessingException(QueryPlugin.Event.TEIID30347, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30347, value)); } recursionStack.push(value); } public int getCallStackDepth() { if (this.recursionStack == null) { return 0; } return this.recursionStack.size(); } public void popCall() { if (recursionStack != null) { recursionStack.pop(); } } /** * @param securityFunctionEvaluator The securityFunctionEvaluator to set. */ public void setAuthoriziationValidator(AuthorizationValidator authorizationValidator) { this.globalState.authorizationValidator = authorizationValidator; } public TempTableStore getTempTableStore() { return tempTableStore; } public void setTempTableStore(TempTableStore tempTableStore) { this.tempTableStore = tempTableStore; if (globalState.sessionTempTableStore == null) { globalState.sessionTempTableStore = tempTableStore; } } public TempTableStore getSessionTempTableStore() { return globalState.sessionTempTableStore; } public void setSessionTempTableStore(TempTableStore tempTableStore) { this.globalState.sessionTempTableStore = tempTableStore; } public TimeZone getServerTimeZone() { return globalState.timezone; } public QueryProcessor.ProcessorFactory getQueryProcessorFactory() { return this.globalState.queryProcessorFactory; } public void setQueryProcessorFactory(QueryProcessor.ProcessorFactory queryProcessorFactory) { this.globalState.queryProcessorFactory = queryProcessorFactory; } public VariableContext getVariableContext() { return variableContext; } public void setVariableContext(VariableContext variableContext) { this.variableContext = variableContext; } public void pushVariableContext(VariableContext toPush) { toPush.setParentContext(this.variableContext); this.variableContext = toPush; } public Object getFromContext(Expression expression) throws TeiidComponentException { if (variableContext == null || !(expression instanceof ElementSymbol)) { throw new TeiidComponentException(QueryPlugin.Event.TEIID30328, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30328, expression, QueryPlugin.Util.getString("Evaluator.no_value"))); //$NON-NLS-1$ } Object value = variableContext.getValue((ElementSymbol)expression); if (value == null && !variableContext.containsVariable((ElementSymbol)expression)) { throw new TeiidComponentException(QueryPlugin.Event.TEIID30328, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30328, expression, QueryPlugin.Util.getString("Evaluator.no_value"))); //$NON-NLS-1$ } return value; } public Set<String> getGroups() { if (globalState.groups == null) { globalState.groups = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER); } return globalState.groups; } public Map<String, String> getAliasMapping() { if (globalState.aliasMapping == null) { globalState.aliasMapping = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER); } return globalState.aliasMapping; } public long getTimeSliceEnd() { return globalState.timeSliceEnd; } public long getTimeoutEnd() { return globalState.timeoutEnd; } public void setTimeSliceEnd(long timeSliceEnd) { globalState.timeSliceEnd = timeSliceEnd; } public void setTimeoutEnd(long timeoutEnd) { globalState.timeoutEnd = timeoutEnd; } public void setMetadata(QueryMetadataInterface metadata) { vdbState.metadata = metadata; } public QueryMetadataInterface getMetadata() { return vdbState.metadata; } public void setValidateXML(boolean validateXML) { globalState.validateXML = validateXML; } public boolean validateXML() { return globalState.validateXML; } public BufferManager getBufferManager() { return globalState.bufferManager; } public void setBufferManager(BufferManager bm) { globalState.bufferManager = bm; } public GlobalTableStore getGlobalTableStore() { return vdbState.globalTables; } public void setGlobalTableStore(GlobalTableStore tempTableStore) { vdbState.globalTables = tempTableStore; } public boolean isNonBlocking() { return nonBlocking; } public void setNonBlocking(boolean nonBlocking) { this.nonBlocking = nonBlocking; } public void setPreparedPlanCache(SessionAwareCache<PreparedPlan> cache) { this.globalState.planCache = cache; } public PreparedPlan getPlan(String key) { if (this.globalState.planCache == null) { return null; } CacheID id = new CacheID(new ParseInfo(), key, getVdbName(), getVdbVersion(), getConnectionId(), getUserName()); PreparedPlan pp = this.globalState.planCache.get(id); if (pp != null) { if (id.getSessionId() != null) { setDeterminismLevel(Determinism.USER_DETERMINISTIC); } else if (id.getUserName() != null) { setDeterminismLevel(Determinism.SESSION_DETERMINISTIC); } return pp; } return null; } public void putPlan(String key, PreparedPlan plan, Determinism determinismLevel) { if (this.globalState.planCache == null) { return; } CacheID id = new CacheID(new ParseInfo(), key, getVdbName(), getVdbVersion(), getConnectionId(), getUserName()); this.globalState.planCache.put(id, determinismLevel, plan, null); } public boolean isResultSetCacheEnabled() { return globalState.resultSetCacheEnabled; } public void setResultSetCacheEnabled(boolean resultSetCacheEnabled) { this.globalState.resultSetCacheEnabled = resultSetCacheEnabled; } public int getUserRequestSourceConcurrency() { return this.globalState.userRequestSourceConcurrency; } public void setUserRequestSourceConcurrency(int userRequestSourceConcurrency) { this.globalState.userRequestSourceConcurrency = userRequestSourceConcurrency; } @Override public Subject getSubject() { return this.globalState.subject; } public void setSubject(Subject subject) { this.globalState.subject = subject; } public void accessedPlanningObject(Object id) { if (this.planningObjects == null) { this.planningObjects = new HashSet<Object>(); } this.planningObjects.add(id); } public Set<Object> getPlanningObjects() { if (this.planningObjects == null) { return Collections.emptySet(); } return planningObjects; } public void accessedDataObject(Object id) { if (this.dataObjects != null) { this.dataObjects.add(id); } } public Set<Object> getDataObjects() { return dataObjects; } public void setDataObjects(HashSet<Object> dataObjectsAccessed) { this.dataObjects = dataObjectsAccessed; } @Override public SessionMetadata getSession() { return this.vdbState.session; } public void setSession(SessionMetadata session) { this.vdbState.session = session; } @Override public String getRequestId() { return this.globalState.requestId != null ? this.globalState.requestId.toString() : null; } public void setRequestId(RequestID requestId) { this.globalState.requestId = requestId; } public void setDQPWorkContext(DQPWorkContext workContext) { this.vdbState.dqpWorkContext = workContext; } @Override public Map<String, DataPolicy> getAllowedDataPolicies() { if (this.vdbState.dqpWorkContext == null) { return null; } return this.vdbState.dqpWorkContext.getAllowedDataPolicies(); } @Override public VDBMetaData getVdb() { if (this.vdbState.dqpWorkContext == null) { return null; } return this.vdbState.dqpWorkContext.getVDB(); } public DQPWorkContext getDQPWorkContext() { return this.vdbState.dqpWorkContext; } public TransactionContext getTransactionContext() { return globalState.transactionContext; } public void setTransactionContext(TransactionContext transactionContext) { globalState.transactionContext = transactionContext; } public TransactionService getTransactionServer() { return globalState.transactionService; } public void setTransactionService(TransactionService transactionService) { globalState.transactionService = transactionService; } public Executor getExecutor() { return this.globalState.executor; } public void setExecutor(Executor e) { this.globalState.executor = e; } public ReusableExecution<?> getReusableExecution(Object key) { synchronized (this.globalState) { if (this.globalState.reusableExecutions == null) { return null; } List<ReusableExecution<?>> reusableExecutions = this.globalState.reusableExecutions.get(key); if (reusableExecutions != null && !reusableExecutions.isEmpty()) { return reusableExecutions.remove(0); } return null; } } public void putReusableExecution(Object key, ReusableExecution<?> execution) { synchronized (this.globalState) { if (this.globalState.reusableExecutions == null) { this.globalState.reusableExecutions = new HashMap<Object, List<ReusableExecution<?>>>(); } List<ReusableExecution<?>> reusableExecutions = this.globalState.reusableExecutions.get(key); if (reusableExecutions == null) { reusableExecutions = new LinkedList<ReusableExecution<?>>(); this.globalState.reusableExecutions.put(key, reusableExecutions); } reusableExecutions.add(execution); } } public void close() { synchronized (this.globalState) { if (this.globalState.reservedBuffers > 0) { long toRelease = this.globalState.reservedBuffers; this.globalState.reservedBuffers = 0; this.globalState.bufferManager.releaseOrphanedBuffers(toRelease); } if (this.globalState.reusableExecutions != null) { for (List<ReusableExecution<?>> reusableExecutions : this.globalState.reusableExecutions.values()) { for (ReusableExecution<?> reusableExecution : reusableExecutions) { try { reusableExecution.dispose(); } catch (Exception e) { LogManager.logWarning(LogConstants.CTX_DQP, e, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30030)); } } } this.globalState.reusableExecutions.clear(); } if (this.globalState.commandListeners != null) { for (CommandListener listener : this.globalState.commandListeners) { try { listener.commandClosed(this); } catch (Exception e) { LogManager.logWarning(LogConstants.CTX_DQP, e, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30031)); } } this.globalState.commandListeners.clear(); } if (this.globalState.lookups != null) { for (TupleSource ts : this.globalState.lookups.values()) { ts.closeSource(); } this.globalState.lookups = null; } if (this.globalState.created != null) { for (InputStreamFactory isf : this.globalState.created) { try { isf.free(); } catch (IOException e) { } } this.globalState.created.clear(); } } } @Override public void addListener(CommandListener listener) { if (listener != null) { synchronized (this.globalState) { if (this.globalState.commandListeners == null) { this.globalState.commandListeners = Collections.newSetFromMap(new IdentityHashMap<CommandListener, Boolean>()); } this.globalState.commandListeners.add(listener); } } } @Override public void removeListener(CommandListener listener) { if (listener != null) { synchronized (this.globalState) { if (this.globalState.commandListeners != null) { this.globalState.commandListeners.remove(listener); } } } } public static DecimalFormat getDecimalFormat(CommandContext context, String format) { DecimalFormat result = null; if (context != null) { if (context.globalState.decimalFormatCache == null) { context.globalState.decimalFormatCache = new LRUCache<String, DecimalFormat>(32); } else { result = context.globalState.decimalFormatCache.get(format); } } if (result == null) { result = new DecimalFormat(format); //TODO: could be locale sensitive result.setParseBigDecimal(true); if (context != null) { context.globalState.decimalFormatCache.put(format, result); } } return result; } public static SimpleDateFormat getDateFormat(CommandContext context, String format) { SimpleDateFormat result = null; if (context != null) { if (context.globalState.dateFormatCache == null) { context.globalState.dateFormatCache = new LRUCache<String, SimpleDateFormat>(32); } else { result = context.globalState.dateFormatCache.get(format); } } if (result == null) { result = new SimpleDateFormat(format); //TODO: could be locale sensitive if (context != null) { context.globalState.dateFormatCache.put(format, result); } } return result; } /** * Compile a regular expression into a {@link java.util.regex.Pattern} and cache it in * the {@link CommandContext} for future use. * * @param context * @param regex Regular expression. * @param flags Bitmask flags like {@link java.util.regex.Pattern#CASE_INSENSITIVE}. * @return Compiled regex. */ public static Pattern getPattern(CommandContext context, String regex, int flags) { Pattern result = null; if (context != null) { if (context.globalState.patternCache == null) { context.globalState.patternCache = new LRUCache<Entry<String,Integer>,Pattern>(32); } else { result = context.globalState.patternCache.get(new SimpleEntry(result, flags)); } } if (result == null) { result = Pattern.compile(regex, flags); if (context != null) { context.globalState.patternCache.put(new SimpleEntry(result, flags), result); } } return result; } public void incrementReuseCount() { globalState.reuseCount.getAndIncrement(); } @Override public long getReuseCount() { if (globalState.reuseCount == null) { return 0; } return globalState.reuseCount.get(); } @Override public boolean isContinuous() { return globalState.reuseCount != null; } public void setContinuous() { this.globalState.reuseCount = new AtomicLong(); } @Override public ClassLoader getVDBClassLoader() { return this.vdbState.classLoader; } public void setVDBClassLoader(ClassLoader classLoader) { this.vdbState.classLoader = classLoader; } /** * Get all warnings found while processing this plan. These warnings may * be detected throughout the plan lifetime, which means new ones may arrive * at any time. This method returns all current warnings and clears * the current warnings list. The warnings are in order they were detected. * @return Current list of warnings, never null */ public List<Exception> getAndClearWarnings() { if (globalState.warnings == null) { return null; } synchronized (this.globalState) { List<Exception> copied = globalState.warnings; globalState.warnings = null; return copied; } } public void addWarning(Exception warning) { if (warning == null) { return; } synchronized (this.globalState) { if (globalState.warnings == null) { globalState.warnings = new ArrayList<Exception>(1); } globalState.warnings.add(warning); } if (!this.getOptions().isSanitizeMessages() || LogManager.isMessageToBeRecorded(LogConstants.CTX_DQP, MessageLevel.DETAIL)) { LogManager.logInfo(LogConstants.CTX_DQP, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID31105, warning.getMessage())); } } public TupleSourceCache getTupleSourceCache() { return tupleSourceCache; } public void setTupleSourceCache(TupleSourceCache tupleSourceCache) { this.tupleSourceCache = tupleSourceCache; } public Options getOptions() { if (this.globalState.options == null) { this.globalState.options = new Options(); } return this.globalState.options; } public void setOptions(Options options) { this.globalState.options = options; } @Override public boolean isReturnAutoGeneratedKeys() { return this.globalState.returnAutoGeneratedKeys; } public void setReturnAutoGeneratedKeys(boolean b) { this.globalState.returnAutoGeneratedKeys = b; } @Override public GeneratedKeysImpl returnGeneratedKeys(String[] columnNames, Class<?>[] columnDataTypes) { synchronized (this.globalState) { this.globalState.generatedKeys = new GeneratedKeysImpl(columnNames, columnDataTypes); return this.globalState.generatedKeys; } } public GeneratedKeysImpl getGeneratedKeys() { synchronized (this.globalState) { return this.globalState.generatedKeys; } } public static CommandContext getThreadLocalContext() { return threadLocalContext.get().peek(); } public static void pushThreadLocalContext(CommandContext context) { threadLocalContext.get().push(context); } public static void popThreadLocalContext() { threadLocalContext.get().poll(); } public long addAndGetReservedBuffers(int i) { return globalState.reservedBuffers += i; } @Override public Object setSessionVariable(String key, Object value) { return this.vdbState.session.getSessionVariables().put(key, value); } @Override public Object getSessionVariable(String key) { return this.vdbState.session.getSessionVariables().get(key); } public AuthorizationValidator getAuthorizationValidator() { return this.globalState.authorizationValidator; } public TupleSource getCodeLookup(String matTableName, Object keyValue) { if (this.globalState.lookups != null) { return this.globalState.lookups.remove(new LookupKey(matTableName, keyValue)); } return null; } public void putCodeLookup(String matTableName, Object keyValue, TupleSource ts) { if (this.globalState.lookups == null) { this.globalState.lookups = new TreeMap<LookupKey, TupleSource>(); } this.globalState.lookups.put(new LookupKey(matTableName, keyValue), ts); } public GlobalTableStoreImpl getSessionScopedStore(boolean create) { GlobalTableStoreImpl impl = getSession().getAttachment(GlobalTableStoreImpl.class); if (!create) { return impl; } impl = getSession().getAttachment(GlobalTableStoreImpl.class); if (impl == null) { impl = new GlobalTableStoreImpl(getBufferManager(), null, getMetadata()); getSession().addAttchment(GlobalTableStoreImpl.class, impl); } return impl; } public static GlobalTableStoreImpl removeSessionScopedStore(SessionMetadata session) { return session.removeAttachment(GlobalTableStoreImpl.class); } @Override public TeiidConnection getConnection() throws TeiidSQLException { LocalProfile ep = getDQPWorkContext().getConnectionProfile(); //TODO: this is problematic as the client properties are not conveyed Properties info = new Properties(); info.put(LocalProfile.DQP_WORK_CONTEXT, getDQPWorkContext()); String url = "jdbc:teiid:" + getVdbName() + "." + getVdbVersion(); //$NON-NLS-1$ //$NON-NLS-2$ ServerConnection sc; try { sc = ep.createServerConnection(info); } catch (TeiidException e) { throw TeiidSQLException.create(e); } return new ConnectionImpl(sc, info, url) { @Override public void close() throws SQLException { //just ignore } @Override public void rollback() throws SQLException { //just ignore } @Override public void setAutoCommit(boolean autoCommit) throws SQLException { //TODO: detect if attempted set conflicts with current txn state throw new TeiidSQLException(); } @Override public void commit() throws SQLException { throw new TeiidSQLException(); } @Override public void changeUser(String userName, String newPassword) throws SQLException { throw new TeiidSQLException(); } @Override protected synchronized long nextRequestID() { //need to choose ids that won't conflict with the user connection return -(long)(Math.random()*Long.MAX_VALUE); } }; } /** * Used by the system table logic * @return */ public Clob getSpatialRefSys() { return new ClobImpl(new InputStreamFactory() { @Override public InputStream getInputStream() throws IOException { return getClass().getClassLoader().getResourceAsStream("org/teiid/metadata/spatial_ref_sys.csv"); //$NON-NLS-1$ } }, -1); } public void addCreatedLob(InputStreamFactory isf) { if (this.globalState.created != null) { this.globalState.created.add(isf); } } public void disableAutoCleanLobs() { this.globalState.created = null; } public void requestCancelled() { this.cancelled.set(true); } /** * Check if this context or the parent has been cancelled. * If the parent has been, then we'll propagate. * @return */ public boolean isCancelled() { if (this.cancelled.get()) { return true; } if (this.parentCancelled != null && this.parentCancelled.get()) { return true; } return false; } public void clearGeneratedKeys() { synchronized (this.globalState) { this.globalState.generatedKeys = null; } } public Boolean isAccessible(AbstractMetadataRecord record) { if (this.globalState.accessible == null) { return null; } return this.globalState.accessible.get(record); } public void setAccessible(AbstractMetadataRecord record, Boolean result) { if (this.globalState.accessible == null) { this.globalState.accessible = new LRUCache<>(1000); } this.globalState.accessible.put(record, result); } public Throwable getBatchUpdateException() { return this.globalState.batchUpdateException; } public void setBatchUpdateException(Throwable t) { this.globalState.batchUpdateException = t; } }