/*
* 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.dqp.internal.datamgr;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.activation.DataSource;
import javax.resource.ResourceException;
import javax.xml.stream.XMLStreamException;
import javax.xml.transform.Source;
import javax.xml.transform.stax.StAXSource;
import javax.xml.transform.stream.StreamSource;
import org.teiid.GeometryInputSource;
import org.teiid.adminapi.impl.VDBMetaData;
import org.teiid.client.ResizingArrayList;
import org.teiid.client.util.ExceptionUtil;
import org.teiid.common.buffer.BufferManager;
import org.teiid.common.buffer.FileStore;
import org.teiid.common.buffer.FileStoreInputStreamFactory;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.TeiidException;
import org.teiid.core.TeiidProcessingException;
import org.teiid.core.types.BlobImpl;
import org.teiid.core.types.BlobType;
import org.teiid.core.types.DataTypeManager;
import org.teiid.core.types.InputStreamFactory;
import org.teiid.core.types.SQLXMLImpl;
import org.teiid.core.types.StandardXMLTranslator;
import org.teiid.core.types.Streamable;
import org.teiid.core.types.TransformationException;
import org.teiid.core.types.XMLType;
import org.teiid.core.util.Assertion;
import org.teiid.core.util.ReaderInputStream;
import org.teiid.dqp.internal.process.SaveOnReadInputStream;
import org.teiid.dqp.message.AtomicRequestID;
import org.teiid.dqp.message.AtomicRequestMessage;
import org.teiid.dqp.message.AtomicResultsMessage;
import org.teiid.language.BatchedCommand;
import org.teiid.language.BatchedUpdates;
import org.teiid.language.Call;
import org.teiid.logging.CommandLogMessage.Event;
import org.teiid.logging.LogConstants;
import org.teiid.logging.LogManager;
import org.teiid.logging.MessageLevel;
import org.teiid.query.QueryPlugin;
import org.teiid.query.function.GeometryUtils;
import org.teiid.query.function.source.XMLSystemFunctions;
import org.teiid.query.metadata.QueryMetadataInterface;
import org.teiid.query.metadata.TempMetadataAdapter;
import org.teiid.query.metadata.TempMetadataStore;
import org.teiid.query.optimizer.capabilities.SourceCapabilities;
import org.teiid.query.optimizer.capabilities.SourceCapabilities.Capability;
import org.teiid.query.processor.CollectionTupleSource;
import org.teiid.query.sql.lang.Command;
import org.teiid.query.sql.lang.QueryCommand;
import org.teiid.query.sql.lang.SourceHint;
import org.teiid.query.sql.lang.SourceHint.SpecificHint;
import org.teiid.query.sql.lang.StoredProcedure;
import org.teiid.query.sql.symbol.Expression;
import org.teiid.query.util.CommandContext;
import org.teiid.resource.spi.WrappedConnection;
import org.teiid.translator.*;
import org.teiid.translator.ExecutionFactory.TransactionSupport;
import org.teiid.util.XMLInputStream;
public class ConnectorWorkItem implements ConnectorWork {
/* Permanent state members */
private AtomicRequestID id;
private ConnectorManager manager;
private AtomicRequestMessage requestMsg;
private ExecutionFactory<Object, Object> connector;
private RuntimeMetadataImpl queryMetadata;
/* Created on new request */
private Object connection;
private Object connectionFactory;
private ExecutionContextImpl securityContext;
private volatile ResultSetExecution execution;
private ProcedureBatchHandler procedureBatchHandler;
private int expectedColumns;
/* End state information */
private volatile boolean lastBatch;
private long rowCount;
private AtomicBoolean isCancelled = new AtomicBoolean();
private org.teiid.language.Command translatedCommand;
private DataNotAvailableException dnae;
private FileStore lobStore;
private byte[] lobBuffer;
private boolean[] convertToRuntimeType;
private boolean[] convertToDesiredRuntimeType;
private boolean[] isLob;
private Class<?>[] schema;
private boolean explicitClose;
private boolean copyLobs;
private boolean areLobsUsableAfterClose;
private TeiidException conversionError;
private ThreadCpuTimer timer = new ThreadCpuTimer();
private boolean unmodifiableList;
ConnectorWorkItem(AtomicRequestMessage message, ConnectorManager manager) throws TeiidComponentException {
this.id = message.getAtomicRequestID();
this.requestMsg = message;
this.manager = manager;
AtomicRequestID requestID = this.requestMsg.getAtomicRequestID();
this.securityContext = new ExecutionContextImpl(message.getCommandContext(),
requestMsg.getConnectorName(),
Integer.toString(requestID.getNodeID()),
Integer.toString(requestID.getExecutionId()),
this);
SourceHint hint = message.getCommand().getSourceHint();
if (hint != null) {
this.securityContext.setGeneralHints(hint.getGeneralHints());
SpecificHint specificHint = hint.getSpecificHint(message.getConnectorName());
if (specificHint != null) {
this.securityContext.setHints(specificHint.getHints());
}
}
this.securityContext.setBatchSize(this.requestMsg.getFetchSize());
this.securityContext.setSession(requestMsg.getWorkContext().getSession());
this.connector = manager.getExecutionFactory();
VDBMetaData vdb = requestMsg.getWorkContext().getVDB();
QueryMetadataInterface qmi = vdb.getAttachment(QueryMetadataInterface.class);
qmi = new TempMetadataAdapter(qmi, new TempMetadataStore());
this.queryMetadata = new RuntimeMetadataImpl(qmi);
this.securityContext.setRuntimeMetadata(this.queryMetadata);
this.securityContext.setTransactional(requestMsg.isTransactional());
LanguageBridgeFactory factory = new LanguageBridgeFactory(this.queryMetadata);
try {
SourceCapabilities capabilities = manager.getCapabilities();
//set other properties once the capabilities have been obtained
factory.setSupportsConcat2(capabilities.supportsFunction(SourceSystemFunctions.CONCAT2));
factory.setSupportFromUnixtime(capabilities.supportsFunction(SourceSystemFunctions.FROM_UNIXTIME));
//read directly from the connector
factory.setConvertIn(!this.connector.supportsInCriteria());
factory.setMaxInPredicateSize((Integer) capabilities.getSourceProperty(Capability.MAX_IN_CRITERIA_SIZE));
factory.setCommandContext(requestMsg.getCommandContext());
factory.setExcludeWithName((String) capabilities.getSourceProperty(Capability.EXCLUDE_COMMON_TABLE_EXPRESSION_NAME));
} catch (TranslatorException e) {
throw new TeiidComponentException(e);
}
translatedCommand = factory.translate(message.getCommand());
List<Expression> symbols = this.requestMsg.getCommand().getProjectedSymbols();
this.schema = new Class[symbols.size()];
this.convertToDesiredRuntimeType = new boolean[symbols.size()];
this.convertToRuntimeType = new boolean[symbols.size()];
this.isLob = new boolean[symbols.size()];
for (int i = 0; i < symbols.size(); i++) {
Expression symbol = symbols.get(i);
this.schema[i] = symbol.getType();
this.convertToDesiredRuntimeType[i] = true;
this.convertToRuntimeType[i] = true;
this.isLob[i] = DataTypeManager.isLOB(this.schema[i]);
}
this.areLobsUsableAfterClose = this.connector.areLobsUsableAfterClose();
this.copyLobs = this.connector.isCopyLobs();
}
@Override
public AtomicRequestID getId() {
return id;
}
@Override
public void cancel(boolean abnormal) {
if (lastBatch) {
return;
}
try {
if (this.isCancelled.compareAndSet(false, true)) {
LogManager.logDetail(LogConstants.CTX_CONNECTOR, new Object[] {this.id, "Processing CANCEL request"}); //$NON-NLS-1$
Execution ex = this.execution;
if(ex != null) {
if (abnormal) {
this.manager.logSRCCommand(this.requestMsg, this.securityContext, Event.CANCEL, -1l, null);
}
ex.cancel();
LogManager.logDetail(LogConstants.CTX_CONNECTOR, QueryPlugin.Util.getString("DQPCore.The_atomic_request_has_been_cancelled", this.id)); //$NON-NLS-1$
}
}
} catch (TranslatorException e) {
LogManager.logWarning(LogConstants.CTX_CONNECTOR, e, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30024, this.id));
}
}
public synchronized AtomicResultsMessage more() throws TranslatorException {
if (this.execution == null) {
return null; //already closed
}
if (this.dnae != null) {
//clear the exception if it has been set
DataNotAvailableException e = this.dnae;
this.dnae = null;
throw e;
}
if (this.conversionError != null) {
throw handleError(this.conversionError);
}
LogManager.logDetail(LogConstants.CTX_CONNECTOR, new Object[] {this.id, "Processing MORE request"}); //$NON-NLS-1$
try {
timer.start();
return handleBatch();
} catch (Throwable t) {
throw handleError(t);
} finally {
timer.stop();
}
}
public synchronized void close() {
lobBuffer = null;
if (lobStore != null) {
lobStore.remove();
lobStore = null;
}
if (!manager.removeState(this.id)) {
return; //already closed
}
LogManager.logDetail(LogConstants.CTX_CONNECTOR, new Object[] {this.id, "Processing Close :", this.requestMsg.getCommand()}); //$NON-NLS-1$
try {
timer.start();
if (execution != null) {
execution.close();
LogManager.logDetail(LogConstants.CTX_CONNECTOR, new Object[] {this.id, "Closed execution"}); //$NON-NLS-1$
if (execution instanceof ReusableExecution<?>) {
this.requestMsg.getCommandContext().putReusableExecution(this.manager.getId(), (ReusableExecution<?>) execution);
}
execution = null;
}
} catch (Throwable e) {
LogManager.logError(LogConstants.CTX_CONNECTOR, e, e.getMessage());
} finally {
if (this.connection != null) {
try {
this.connector.closeConnection(connection, connectionFactory);
} catch (Throwable e) {
LogManager.logError(LogConstants.CTX_CONNECTOR, e, e.getMessage());
}
LogManager.logDetail(LogConstants.CTX_CONNECTOR, new Object[] {this.id, "Closed connection"}); //$NON-NLS-1$
}
Long time = timer.stop();
manager.logSRCCommand(this.requestMsg, this.securityContext, Event.END, this.rowCount, time);
}
}
private TranslatorException handleError(Throwable t) {
if (t instanceof DataNotAvailableException) {
throw (DataNotAvailableException)t;
}
if (t instanceof RuntimeException && t.getCause() != null) {
t = t.getCause();
}
String msg = QueryPlugin.Util.getString("ConnectorWorker.process_failed", this.id); //$NON-NLS-1$
if (isCancelled.get()) {
LogManager.logDetail(LogConstants.CTX_CONNECTOR, msg);
} else {
manager.logSRCCommand(this.requestMsg, this.securityContext, Event.ERROR, null, null);
Throwable toLog = t;
if (this.requestMsg.getCommandContext().getOptions().isSanitizeMessages() && !LogManager.isMessageToBeRecorded(LogConstants.CTX_CONNECTOR, MessageLevel.DETAIL)) {
toLog = ExceptionUtil.sanitize(toLog, true);
}
if (toLog instanceof TranslatorException || toLog instanceof TeiidProcessingException) {
LogManager.logWarning(LogConstants.CTX_CONNECTOR, toLog, msg);
} else {
LogManager.logError(LogConstants.CTX_CONNECTOR, toLog, msg);
}
}
if (t instanceof TranslatorException) {
return (TranslatorException)t;
}
return new TranslatorException(t);
}
public synchronized void execute() throws TranslatorException {
if(isCancelled()) {
throw new TranslatorException(QueryPlugin.Event.TEIID30476, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30476));
}
timer.start();
try {
if (this.execution == null) {
if (this.connection == null) {
LogManager.logDetail(LogConstants.CTX_CONNECTOR, new Object[] {this.requestMsg.getAtomicRequestID(), "Processing NEW request:", this.requestMsg.getCommand()}); //$NON-NLS-1$
try {
this.connectionFactory = this.manager.getConnectionFactory();
} catch (TranslatorException e) {
if (this.connector.isSourceRequired()) {
throw e;
}
}
if (this.connectionFactory != null) {
this.connection = this.connector.getConnection(this.connectionFactory, securityContext);
}
if (this.connection == null && this.connector.isSourceRequired()) {
throw new TranslatorException(QueryPlugin.Event.TEIID31108, QueryPlugin.Util.getString("datasource_not_found", this.manager.getConnectionName())); //$NON-NLS-1$);
}
}
Object unwrapped = null;
if (connection instanceof WrappedConnection) {
try {
unwrapped = ((WrappedConnection)connection).unwrap();
} catch (ResourceException e) {
throw new TranslatorException(QueryPlugin.Event.TEIID30477, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30477, this.manager.getConnectionName()));
}
}
// Translate the command
Command command = this.requestMsg.getCommand();
this.expectedColumns = command.getProjectedSymbols().size();
if (command instanceof StoredProcedure) {
this.expectedColumns = ((StoredProcedure)command).getResultSetColumns().size();
}
Execution exec = this.requestMsg.getCommandContext().getReusableExecution(this.manager.getId());
if (exec != null) {
((ReusableExecution)exec).reset(translatedCommand, this.securityContext, connection);
} else {
exec = connector.createExecution(translatedCommand, this.securityContext, queryMetadata, (unwrapped == null) ? this.connection:unwrapped);
}
setExecution(command, translatedCommand, exec);
LogManager.logDetail(LogConstants.CTX_CONNECTOR, new Object[] {this.requestMsg.getAtomicRequestID(), "Obtained execution"}); //$NON-NLS-1$
//Log the Source Command (Must be after obtaining the execution context)
manager.logSRCCommand(this.requestMsg, this.securityContext, Event.NEW, null, null);
}
// Execute query
this.execution.execute();
LogManager.logDetail(LogConstants.CTX_CONNECTOR, new Object[] {this.id, "Executed command"}); //$NON-NLS-1$
} catch (Throwable t) {
throw handleError(t);
} finally {
timer.stop();
}
}
private void setExecution(Command command,
org.teiid.language.Command translatedCommand, final Execution exec) {
if (translatedCommand instanceof Call) {
this.execution = Assertion.isInstanceOf(exec, ProcedureExecution.class, "Call Executions are expected to be ProcedureExecutions"); //$NON-NLS-1$
StoredProcedure proc = (StoredProcedure)command;
if (proc.returnParameters()) {
this.procedureBatchHandler = new ProcedureBatchHandler((Call)translatedCommand, (ProcedureExecution)exec);
}
} else if (command instanceof QueryCommand){
this.execution = Assertion.isInstanceOf(exec, ResultSetExecution.class, "QueryExpression Executions are expected to be ResultSetExecutions"); //$NON-NLS-1$
} else {
final boolean singleUpdateCount = connector.returnsSingleUpdateCount()
&& (translatedCommand instanceof BatchedUpdates || (translatedCommand instanceof BatchedCommand && ((BatchedCommand)translatedCommand).getParameterValues() != null));
Assertion.isInstanceOf(exec, UpdateExecution.class, "Update Executions are expected to be UpdateExecutions"); //$NON-NLS-1$
this.execution = new ResultSetExecution() {
private int[] results;
private int index;
@Override
public void cancel() throws TranslatorException {
exec.cancel();
}
@Override
public void close() {
exec.close();
}
@Override
public void execute() throws TranslatorException {
exec.execute();
}
@Override
public List<?> next() throws TranslatorException,
DataNotAvailableException {
if (results == null) {
results = ((UpdateExecution)exec).getUpdateCounts();
}
if (singleUpdateCount) {
if (index++ < results[0]) {
return CollectionTupleSource.UPDATE_ROW;
}
return null;
}
if (index < results.length) {
return Arrays.asList(results[index++]);
}
return null;
}
};
}
}
protected AtomicResultsMessage handleBatch() throws TranslatorException {
Assertion.assertTrue(!this.lastBatch);
LogManager.logDetail(LogConstants.CTX_CONNECTOR, new Object[] {this.id, "Getting results from connector"}); //$NON-NLS-1$
int batchSize = 0;
List<List<?>> rows = new ResizingArrayList<List<?>>(batchSize/4);
try {
while (batchSize < this.requestMsg.getFetchSize()) {
List<?> row = this.execution.next();
if (row == null) {
this.lastBatch = true;
break;
}
if (row.size() != this.expectedColumns) {
throw new AssertionError("Inproper results returned. Expected " + this.expectedColumns + " columns, but was " + row.size()); //$NON-NLS-1$ //$NON-NLS-2$
}
try {
try {
if (unmodifiableList) {
row = new ArrayList<Object>(row);
}
row = correctTypes(row);
} catch (UnsupportedOperationException | ArrayStoreException e) {
//it's generally expected that the returned list from
//the translator should be modifiable, but we should be lax
if (unmodifiableList) {
throw e;
}
unmodifiableList = true;
row = new ArrayList<Object>(row);
row = correctTypes(row);
}
} catch (TeiidException e) {
conversionError = e;
break;
}
if (this.procedureBatchHandler != null) {
row = this.procedureBatchHandler.padRow(row);
}
this.rowCount += 1;
batchSize++;
rows.add(row);
// Check for max result rows exceeded
if(this.requestMsg.getMaxResultRows() > -1 && this.rowCount >= this.requestMsg.getMaxResultRows()){
if (this.rowCount == this.requestMsg.getMaxResultRows() && !this.requestMsg.isExceptionOnMaxRows()) {
LogManager.logDetail(LogConstants.CTX_CONNECTOR, new Object[] {this.id, "Exceeded max, returning", this.requestMsg.getMaxResultRows()}); //$NON-NLS-1$
this.lastBatch = true;
break;
} else if (this.rowCount > this.requestMsg.getMaxResultRows() && this.requestMsg.isExceptionOnMaxRows()) {
String msg = QueryPlugin.Util.getString("ConnectorWorker.MaxResultRowsExceed", this.requestMsg.getMaxResultRows()); //$NON-NLS-1$
throw new TranslatorException(QueryPlugin.Event.TEIID30478, msg);
}
}
}
} catch (DataNotAvailableException e) {
if (rows.size() == 0) {
throw e;
}
if (e.getWaitUntil() != null) {
//we have an await until that we need to enforce
this.dnae = e;
}
//else we can just ignore the delay
}
if (lastBatch) {
if (this.procedureBatchHandler != null) {
List<?> row = this.procedureBatchHandler.getParameterRow();
if (row != null) {
try {
row = correctTypes(row);
rows.add(row);
this.rowCount += 1;
} catch (TeiidException e) {
lastBatch = false;
conversionError = e;
}
}
}
LogManager.logDetail(LogConstants.CTX_CONNECTOR, new Object[] {this.id, "Obtained last batch, total row count:", rowCount}); //$NON-NLS-1$\
} else {
LogManager.logDetail(LogConstants.CTX_CONNECTOR, new Object[] {this.id, "Obtained results from connector, current row count:", rowCount}); //$NON-NLS-1$
}
int currentRowCount = rows.size();
if ( !lastBatch && currentRowCount == 0 ) {
// Defect 13366 - Should send all batches, even if they're zero size.
// Log warning if received a zero-size non-last batch from the connector.
LogManager.logWarning(LogConstants.CTX_CONNECTOR, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30004, requestMsg.getConnectorName()));
}
AtomicResultsMessage response = createResultsMessage(rows.toArray(new List[currentRowCount]));
// if we need to keep the execution alive, then we can not support implicit close.
response.setSupportsImplicitClose(!this.securityContext.keepExecutionAlive() && !explicitClose);
response.setWarnings(this.securityContext.getWarnings());
if (this.securityContext.getCacheDirective() != null) {
response.setScope(this.securityContext.getCacheDirective().getScope());
}
if (this.securityContext.getScope() != null &&
(response.getScope() == null || response.getScope().compareTo(this.securityContext.getScope()) > 0)) {
response.setScope(this.securityContext.getScope());
}
if ( lastBatch ) {
response.setFinalRow(rowCount);
}
return response;
}
public static AtomicResultsMessage createResultsMessage(List<?>[] batch) {
return new AtomicResultsMessage(batch);
}
boolean isCancelled() {
return this.isCancelled.get();
}
@Override
public String toString() {
return this.id.toString();
}
@Override
public boolean isDataAvailable() {
return this.securityContext.isDataAvailable();
}
@Override
public CacheDirective getCacheDirective() throws TranslatorException {
CacheDirective cd = connector.getCacheDirective(this.translatedCommand, this.securityContext, this.queryMetadata);
this.securityContext.setCacheDirective(cd);
return cd;
}
@Override
public boolean isForkable() {
return this.connector.isForkable()
&& (!this.requestMsg.isTransactional() || this.connector.getTransactionSupport() != TransactionSupport.XA);
}
@Override
public boolean isThreadBound() {
return this.connector.isThreadBound();
}
private List<?> correctTypes(List row) throws TeiidException {
//TODO: add a proper intermediate schema
for (int i = 0; i < row.size(); i++) {
try {
Object value = row.get(i);
if (value == null) {
continue;
}
if (convertToRuntimeType[i]) {
Object result = convertToRuntimeType(requestMsg.getBufferManager(), value, this.schema[i], this.requestMsg.getCommandContext());
if (value == result && !DataTypeManager.DefaultDataClasses.OBJECT.equals(this.schema[i])) {
convertToRuntimeType[i] = false;
} else {
if (!explicitClose && isLob[i] && !copyLobs && !areLobsUsableAfterClose && DataTypeManager.isLOB(result.getClass())
&& DataTypeManager.isLOB(DataTypeManager.convertToRuntimeType(value, false).getClass())) {
explicitClose = true;
}
row.set(i, result);
value = result;
}
}
if (convertToDesiredRuntimeType[i]) {
if (value != null) {
Object result = DataTypeManager.transformValue(value, value.getClass(), this.schema[i]);
if (isLob[i] && copyLobs) {
if (lobStore == null) {
lobStore = requestMsg.getBufferManager().createFileStore("lobs"); //$NON-NLS-1$
lobBuffer = new byte[1 << 14];
}
requestMsg.getBufferManager().persistLob((Streamable<?>) result, lobStore, lobBuffer);
} else if (value == result) {
convertToDesiredRuntimeType[i] = false;
continue;
}
row.set(i, result);
}
} else if (DataTypeManager.isValueCacheEnabled()) {
row.set(i, DataTypeManager.getCanonicalValue(value));
}
} catch (TeiidComponentException e) {
throw new TeiidComponentException(QueryPlugin.Event.TEIID31176, e, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID31176, this.requestMsg.getCommand().getProjectedSymbols().get(i), DataTypeManager.getDataTypeName(this.schema[i])));
} catch (TransformationException e) {
throw new TeiidException(QueryPlugin.Event.TEIID31176, e, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID31176, this.requestMsg.getCommand().getProjectedSymbols().get(i), DataTypeManager.getDataTypeName(this.schema[i])));
}
}
return row;
}
static Object convertToRuntimeType(BufferManager bm, Object value, Class<?> desiredType, CommandContext context) throws TransformationException {
if (desiredType != DataTypeManager.DefaultDataClasses.XML || !(value instanceof Source)) {
if (value instanceof InputStreamFactory) {
return new BlobType(new BlobImpl((InputStreamFactory)value));
}
if (value instanceof DataSource) {
FileStore fs = bm.createFileStore("bytes"); //$NON-NLS-1$
//TODO: guess at the encoding from the content type
FileStoreInputStreamFactory fsisf = new FileStoreInputStreamFactory(fs, Streamable.ENCODING);
try {
SaveOnReadInputStream is = new SaveOnReadInputStream(((DataSource)value).getInputStream(), fsisf);
if (context != null) {
context.addCreatedLob(fsisf);
}
return new BlobType(new BlobImpl(is.getInputStreamFactory()));
} catch (IOException e) {
throw new TransformationException(QueryPlugin.Event.TEIID30500, e, e.getMessage());
}
}
if (value instanceof GeometryInputSource) {
GeometryInputSource gis = (GeometryInputSource)value;
try {
InputStream is = gis.getEwkb();
if (is != null) {
return GeometryUtils.geometryFromEwkb(is, gis.getSrid());
}
} catch (Exception e) {
throw new TransformationException(e);
}
try {
Reader r = gis.getGml();
if (r != null) {
return GeometryUtils.geometryFromGml(r, gis.getSrid());
}
} catch (Exception e) {
throw new TransformationException(e);
}
}
}
if (value instanceof Source) {
if (!(value instanceof InputStreamFactory)) {
if (value instanceof StreamSource) {
StreamSource ss = (StreamSource)value;
InputStream is = ss.getInputStream();
Reader r = ss.getReader();
if (is == null && r != null) {
is = new ReaderInputStream(r, Streamable.CHARSET);
}
final FileStore fs = bm.createFileStore("xml"); //$NON-NLS-1$
final FileStoreInputStreamFactory fsisf = new FileStoreInputStreamFactory(fs, Streamable.ENCODING);
value = new SaveOnReadInputStream(is, fsisf).getInputStreamFactory();
if (context != null) {
context.addCreatedLob(fsisf);
}
} else if (value instanceof StAXSource) {
//TODO: do this lazily. if the first access to get the STaXSource, then
//it's more efficient to let the processing happen against STaX
StAXSource ss = (StAXSource)value;
try {
final FileStore fs = bm.createFileStore("xml"); //$NON-NLS-1$
final FileStoreInputStreamFactory fsisf = new FileStoreInputStreamFactory(fs, Streamable.ENCODING);
value = new SaveOnReadInputStream(new XMLInputStream(ss, XMLSystemFunctions.getOutputFactory(true)), fsisf).getInputStreamFactory();
if (context != null) {
context.addCreatedLob(fsisf);
}
} catch (XMLStreamException e) {
throw new TransformationException(e);
}
} else {
//maybe dom or some other source we want to get out of memory
StandardXMLTranslator sxt = new StandardXMLTranslator((Source)value);
SQLXMLImpl sqlxml;
try {
sqlxml = XMLSystemFunctions.saveToBufferManager(bm, sxt, context);
} catch (TeiidComponentException e) {
throw new TransformationException(e);
} catch (TeiidProcessingException e) {
throw new TransformationException(e);
}
return new XMLType(sqlxml);
}
}
return new XMLType(new SQLXMLImpl((InputStreamFactory)value));
}
return DataTypeManager.convertToRuntimeType(value, desiredType != DataTypeManager.DefaultDataClasses.OBJECT);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof ConnectorWork))
return false;
ConnectorWork other = (ConnectorWork) obj;
if (id == null) {
if (other.getId() != null)
return false;
} else if (!id.equals(other.getId()))
return false;
return true;
}
public void logCommand(Object... command) {
this.manager.logSRCCommand(this.requestMsg, securityContext, Event.SOURCE, null, null, command);
}
}