use of org.teiid.query.sql.util.VariableContext in project teiid by teiid.
the class BatchedUpdatePlanner method optimize.
/**
* Optimizes batched updates by batching all contiguous commands that relate to the same physical model.
* For example, for the following batch of commands:
* <br/>
* <ol>
* <li>1. INSERT INTO physicalModel.myPhysical ...</li>
* <li>2. UPDATE physicalModel.myPhysical ... </li>
* <li>3. DELETE FROM virtualmodel.myVirtual ... </li>
* <li>4. UPDATE virtualmodel.myVirtual ... </li>
* <li>5. UPDATE physicalModel.myOtherPhysical ...</li>
* <li>6. INSERT INTO physicalModel.myOtherPhysical ... <li>
* <li>7. DELETE FROM physicalModel.myOtherPhysical ...</li>
* <li>8. INSERT INTO physicalModel.myPhysical ... </li>
* <li>9. INSERT INTO physicalModel.myPhysical ... </li>
* <li>10. INSERT INTO physicalModel.myPhysical ... </li>
* <li>11. INSERT INTO physicalModel.myPhysical ... </li>
* <li>12. INSERT INTO physicalModel.myPhysical ... </li>
* </ol>
* <br/> this implementation will batch as follows: (1,2), (5, 6, 7), (8 thru 12).
* The remaining commands/plans will be executed individually.
* @see org.teiid.query.optimizer.CommandPlanner#optimize(Command, org.teiid.core.id.IDGenerator, org.teiid.query.metadata.QueryMetadataInterface, org.teiid.query.optimizer.capabilities.CapabilitiesFinder, org.teiid.query.analysis.AnalysisRecord, CommandContext)
* @since 4.2
*/
public ProcessorPlan optimize(Command command, IDGenerator idGenerator, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, AnalysisRecord analysisRecord, CommandContext context) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
BatchedUpdateCommand batchedUpdateCommand = (BatchedUpdateCommand) command;
List<ProcessorPlan> childPlans = new ArrayList<ProcessorPlan>(batchedUpdateCommand.getUpdateCommands().size());
List<Command> updateCommands = batchedUpdateCommand.getUpdateCommands();
int numCommands = updateCommands.size();
List<VariableContext> allContexts = batchedUpdateCommand.getVariableContexts();
List<VariableContext> planContexts = null;
if (allContexts != null) {
planContexts = new ArrayList<VariableContext>(allContexts.size());
}
for (int commandIndex = 0; commandIndex < numCommands; commandIndex++) {
// Potentially the first command of a batch
Command updateCommand = updateCommands.get(commandIndex);
boolean commandWasBatched = false;
// If this command can be placed in a batch
if (isEligibleForBatching(updateCommand, metadata)) {
// Get the model ID. Subsequent and contiguous commands that update a group in this model are candidates for this batch
Object batchModelID = metadata.getModelID(getUpdatedGroup(updateCommand).getMetadataID());
String modelName = metadata.getFullName(batchModelID);
SourceCapabilities caps = capFinder.findCapabilities(modelName);
// Only attempt batching if the source supports batching
if (caps.supportsCapability(Capability.BATCHED_UPDATES)) {
// Start a new batch
List<Command> batch = new ArrayList<Command>();
List<VariableContext> contexts = new ArrayList<VariableContext>();
List<Boolean> shouldEvaluate = new ArrayList<Boolean>();
// This is the first command in a potential batch, so add it to the batch
batch.add(updateCommand);
if (allContexts != null) {
contexts.add(allContexts.get(commandIndex));
shouldEvaluate.add(Boolean.TRUE);
} else {
shouldEvaluate.add(EvaluatableVisitor.needsProcessingEvaluation(updateCommand));
}
// immediately and contiguously after this one
batchLoop: for (int batchIndex = commandIndex + 1; batchIndex < numCommands; batchIndex++) {
Command batchingCandidate = updateCommands.get(batchIndex);
// If this command updates the same model, and is eligible for batching, add it to the batch
if (canBeAddedToBatch(batchingCandidate, batchModelID, metadata, capFinder)) {
batch.add(batchingCandidate);
if (allContexts != null) {
contexts.add(allContexts.get(batchIndex));
shouldEvaluate.add(Boolean.TRUE);
} else {
shouldEvaluate.add(EvaluatableVisitor.needsProcessingEvaluation(batchingCandidate));
}
} else {
// Otherwise, stop batching at this point. The next command may well be the start of a new batch
break batchLoop;
}
}
// If two or more contiguous commands made on the same model were found, then batch them
if (batch.size() > 1) {
ProjectNode projectNode = new ProjectNode(idGenerator.nextInt());
// Create a BatchedUpdateNode that creates a batched request for the connector
BatchedUpdateNode batchNode = new BatchedUpdateNode(idGenerator.nextInt(), batch, contexts, shouldEvaluate, modelName);
List symbols = batchedUpdateCommand.getProjectedSymbols();
projectNode.setSelectSymbols(symbols);
projectNode.setElements(symbols);
batchNode.setElements(symbols);
projectNode.addChild(batchNode);
// Add a new RelationalPlan that represents the plan for this batch.
childPlans.add(new RelationalPlan(projectNode));
if (planContexts != null) {
planContexts.add(new VariableContext());
}
// Skip those commands that were added to this batch
commandIndex += batch.size() - 1;
commandWasBatched = true;
}
}
}
if (!commandWasBatched) {
// If the command wasn't batched, just add the plan for this command to the list of plans
Command cmd = batchedUpdateCommand.getUpdateCommands().get(commandIndex);
ProcessorPlan plan = cmd.getProcessorPlan();
if (plan == null) {
plan = QueryOptimizer.optimizePlan(cmd, metadata, idGenerator, capFinder, analysisRecord, context);
}
childPlans.add(plan);
if (allContexts != null) {
planContexts.add(allContexts.get(commandIndex));
}
}
}
return new BatchedUpdatePlan(childPlans, batchedUpdateCommand.getUpdateCommands().size(), planContexts, batchedUpdateCommand.isSingleResult());
}
use of org.teiid.query.sql.util.VariableContext in project teiid by teiid.
the class ExecDynamicSqlInstruction method process.
/**
* <p>
* Processing this instruction executes the ProcessorPlan for the command on
* the CommandStatement of the update procedure language. Executing this
* plan does not effect the values of any of the variables defined as part
* of the update procedure and hence the results of the ProcessPlan
* execution need not be stored for further processing. The results are
* removed from the buffer manager immediately after execution. The program
* counter is incremented after execution of the plan.
* </p>
*
* @throws BlockedException
* if this processing the plan throws a currentVarContext
*/
public void process(ProcedurePlan procEnv) throws BlockedException, TeiidComponentException, TeiidProcessingException {
VariableContext localContext = procEnv.getCurrentVariableContext();
String query = null;
try {
Clob value = (Clob) procEnv.evaluateExpression(dynamicCommand.getSql());
if (value == null) {
throw new QueryProcessingException(QueryPlugin.Util.getString(// $NON-NLS-1$
"ExecDynamicSqlInstruction.0"));
}
if (value.length() > MAX_SQL_LENGTH) {
throw new QueryProcessingException(QueryPlugin.Util.gs(QueryPlugin.Event.TEIID31204, MAX_SQL_LENGTH));
}
query = value.getSubString(1, MAX_SQL_LENGTH);
LogManager.logTrace(org.teiid.logging.LogConstants.CTX_DQP, // $NON-NLS-1$
new Object[] { "Executing dynamic sql ", query });
Command command = QueryParser.getQueryParser().parseCommand(query);
// special handling for dynamic anon blocks
if (command instanceof CreateProcedureCommand) {
if (dynamicCommand.getIntoGroup() != null || returnable) {
// and the creation of an inline view
throw new QueryProcessingException(QueryPlugin.Event.TEIID31250, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID31250));
}
((CreateProcedureCommand) command).setResultSetColumns(Collections.EMPTY_LIST);
}
command.setExternalGroupContexts(dynamicCommand.getExternalGroupContexts());
command.setTemporaryMetadata(dynamicCommand.getTemporaryMetadata().clone());
updateContextWithUsingValues(procEnv, localContext);
TempMetadataStore metadataStore = command.getTemporaryMetadata();
if (dynamicCommand.getUsing() != null && !dynamicCommand.getUsing().isEmpty()) {
metadataStore.addTempGroup(Reserved.USING, new LinkedList<ElementSymbol>(dynamicCommand.getUsing().getClauseMap().keySet()));
GroupSymbol using = new GroupSymbol(Reserved.USING);
using.setMetadataID(metadataStore.getTempGroupID(Reserved.USING));
command.addExternalGroupToContext(using);
metadataStore.addTempGroup(ProcedureReservedWords.DVARS, new LinkedList<ElementSymbol>(dynamicCommand.getUsing().getClauseMap().keySet()));
using = new GroupSymbol(ProcedureReservedWords.DVARS);
using.setMetadataID(metadataStore.getTempGroupID(ProcedureReservedWords.DVARS));
command.addExternalGroupToContext(using);
}
QueryResolver.resolveCommand(command, metadata.getDesignTimeMetadata());
validateDynamicCommand(procEnv, command, value.toString());
// create a new set of variables including vars
Map<ElementSymbol, Expression> nameValueMap = createVariableValuesMap(localContext);
ValidationVisitor visitor = new ValidationVisitor();
Request.validateWithVisitor(visitor, metadata, command);
boolean insertInto = false;
boolean updateCommand = false;
if (!command.returnsResultSet() && !(command instanceof StoredProcedure)) {
if (dynamicCommand.isAsClauseSet()) {
if (dynamicCommand.getProjectedSymbols().size() != 1 || ((Expression) dynamicCommand.getProjectedSymbols().get(0)).getType() != DataTypeManager.DefaultDataClasses.INTEGER) {
throw new QueryProcessingException(QueryPlugin.Event.TEIID31157, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID31157));
}
}
updateCommand = true;
} else if (dynamicCommand.getAsColumns() != null && !dynamicCommand.getAsColumns().isEmpty()) {
// $NON-NLS-1$
command = QueryRewriter.createInlineViewQuery(new GroupSymbol("X"), command, metadata, dynamicCommand.getAsColumns());
if (dynamicCommand.getIntoGroup() != null) {
Insert insert = new Insert(dynamicCommand.getIntoGroup(), dynamicCommand.getAsColumns(), Collections.emptyList());
insert.setQueryExpression((Query) command);
command = insert;
insertInto = true;
}
}
// if this is an update procedure, it could reassign variables
command = QueryRewriter.rewrite(command, metadata, procEnv.getContext(), command instanceof CreateProcedureCommand ? Collections.EMPTY_MAP : nameValueMap);
ProcessorPlan commandPlan = QueryOptimizer.optimizePlan(command, metadata, idGenerator, capFinder, AnalysisRecord.createNonRecordingRecord(), procEnv.getContext());
if (command instanceof CreateProcedureCommand && commandPlan instanceof ProcedurePlan) {
((ProcedurePlan) commandPlan).setValidateAccess(procEnv.isValidateAccess());
}
CreateCursorResultSetInstruction inst = new CreateCursorResultSetInstruction(null, commandPlan, (insertInto || updateCommand) ? Mode.UPDATE : returnable ? Mode.HOLD : Mode.NOHOLD) {
@Override
public void process(ProcedurePlan procEnv) throws BlockedException, TeiidComponentException, TeiidProcessingException {
boolean done = true;
try {
super.process(procEnv);
} catch (BlockedException e) {
done = false;
throw e;
} finally {
if (done) {
procEnv.getContext().popCall();
}
}
}
};
dynamicProgram = new Program(false);
dynamicProgram.addInstruction(inst);
if (dynamicCommand.getIntoGroup() != null) {
String groupName = dynamicCommand.getIntoGroup().getName();
if (!procEnv.getTempTableStore().hasTempTable(groupName, true)) {
// create the temp table in the parent scope
Create create = new Create();
create.setTable(new GroupSymbol(groupName));
for (ElementSymbol es : (List<ElementSymbol>) dynamicCommand.getAsColumns()) {
Column c = new Column();
c.setName(es.getShortName());
c.setRuntimeType(DataTypeManager.getDataTypeName(es.getType()));
create.getColumns().add(c);
}
procEnv.getDataManager().registerRequest(procEnv.getContext(), create, TempMetadataAdapter.TEMP_MODEL.getName(), new RegisterRequestParameter());
}
// backwards compatibility to support into with a rowcount
if (updateCommand) {
Insert insert = new Insert();
insert.setGroup(new GroupSymbol(groupName));
for (ElementSymbol es : (List<ElementSymbol>) dynamicCommand.getAsColumns()) {
ElementSymbol col = new ElementSymbol(es.getShortName(), insert.getGroup());
col.setType(es.getType());
insert.addVariable(col);
}
insert.addValue(new Constant(procEnv.getCurrentVariableContext().getValue(ProcedurePlan.ROWCOUNT)));
QueryResolver.resolveCommand(insert, metadata.getDesignTimeMetadata());
TupleSource ts = procEnv.getDataManager().registerRequest(procEnv.getContext(), insert, TempMetadataAdapter.TEMP_MODEL.getName(), new RegisterRequestParameter());
ts.nextTuple();
ts.closeSource();
}
}
// Add group to recursion stack
if (parentProcCommand.getUpdateType() != Command.TYPE_UNKNOWN) {
// $NON-NLS-1$
procEnv.getContext().pushCall(Command.getCommandToken(parentProcCommand.getUpdateType()) + " " + parentProcCommand.getVirtualGroup());
} else {
if (parentProcCommand.getVirtualGroup() != null) {
procEnv.getContext().pushCall(parentProcCommand.getVirtualGroup().toString());
}
}
procEnv.push(dynamicProgram);
} catch (SQLException e) {
Object[] params = { dynamicCommand, dynamicCommand.getSql(), e.getMessage() };
throw new QueryProcessingException(QueryPlugin.Event.TEIID30168, e, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30168, params));
} catch (TeiidProcessingException e) {
Object[] params = { dynamicCommand, query == null ? dynamicCommand.getSql() : query, e.getMessage() };
throw new QueryProcessingException(QueryPlugin.Event.TEIID30168, e, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30168, params));
}
}
use of org.teiid.query.sql.util.VariableContext in project teiid by teiid.
the class LoopInstruction method process.
public void process(ProcedurePlan procEnv) throws TeiidComponentException {
List<?> currentRow = procEnv.getCurrentRow(rsName);
VariableContext varContext = procEnv.getCurrentVariableContext();
// set results to the variable context(the cursor.element is treated as variable)
if (this.elements == null) {
List schema = procEnv.getSchema(rsName);
elements = new ArrayList<ElementSymbol>(schema.size());
for (int i = 0; i < schema.size(); i++) {
Expression element = (Expression) schema.get(i);
ElementSymbol e = new ElementSymbol(rsName + Symbol.SEPARATOR + Symbol.getShortName(element));
e.setType(element.getType());
elements.add(e);
}
}
for (int i = 0; i < elements.size(); i++) {
varContext.setValue(elements.get(i), currentRow.get(i));
}
}
use of org.teiid.query.sql.util.VariableContext in project teiid by teiid.
the class ProcedurePlan method processProcedure.
/**
* <p>Process the procedure, using the stack of Programs supplied by the
* ProcessorEnvironment. With each pass through the loop, the
* current Program is gotten off the top of the stack, and the
* current instruction is gotten from that program; each call
* to an instruction's process method may alter the Program
* Stack and/or the current instruction pointer of a Program,
* so it's important that this method's loop refer to the
* call stack of the ProcessorEnvironment each time, and not
* cache things in local variables. If the current Program's
* current instruction is null, then it's time to pop that
* Program off the stack.</p>
*
* @return List a single tuple containing one Integer: the update
* count resulting from the procedure execution.
*/
private TupleSource processProcedure() throws TeiidComponentException, TeiidProcessingException, BlockedException {
// execute plan
ProgramInstruction inst = null;
while (!this.programs.empty()) {
Program program = peek();
inst = program.getCurrentInstruction();
if (inst == null) {
// $NON-NLS-1$
LogManager.logTrace(org.teiid.logging.LogConstants.CTX_DQP, "Finished program", program);
// look ahead to see if we need to process in place
VariableContext vc = this.cursorStates.getParentContext();
CursorState last = (CursorState) this.cursorStates.getValue(null);
if (last != null) {
if (last.resultsBuffer == null && (last.usesLocalTemp || !txnTupleSources.isEmpty())) {
last.resultsBuffer = bufferMgr.createTupleBuffer(last.processor.getOutputElements(), getContext().getConnectionId(), TupleSourceType.PROCESSOR);
last.returning = true;
}
if (last.returning) {
while (last.ts.hasNext()) {
List<?> tuple = last.ts.nextTuple();
last.resultsBuffer.addTuple(tuple);
}
last.resultsBuffer.close();
last.ts = last.resultsBuffer.createIndexedTupleSource(true);
last.returning = false;
}
}
this.pop(true);
continue;
}
try {
getContext().setCurrentTimestamp(System.currentTimeMillis());
if (inst instanceof RepeatedInstruction) {
// $NON-NLS-1$
LogManager.logTrace(org.teiid.logging.LogConstants.CTX_DQP, "Executing repeated instruction", inst);
RepeatedInstruction loop = (RepeatedInstruction) inst;
if (loop.testCondition(this)) {
// $NON-NLS-1$
LogManager.logTrace(org.teiid.logging.LogConstants.CTX_DQP, "Passed condition, executing program " + loop.getNestedProgram());
inst.process(this);
this.push(loop.getNestedProgram());
continue;
}
// $NON-NLS-1$
LogManager.logTrace(org.teiid.logging.LogConstants.CTX_DQP, "Exiting repeated instruction", inst);
loop.postInstruction(this);
} else {
// $NON-NLS-1$
LogManager.logTrace(org.teiid.logging.LogConstants.CTX_DQP, "Executing instruction", inst);
inst.process(this);
this.evaluator.close();
}
} catch (TeiidComponentException e) {
throw e;
} catch (Exception e) {
// processing or teiidsqlexception
boolean atomic = program.isAtomic();
while (program.getExceptionGroup() == null) {
this.pop(false);
if (this.programs.empty()) {
// reached the top without a handler, so throw
if (e instanceof TeiidProcessingException) {
throw (TeiidProcessingException) e;
}
throw new ProcedureErrorInstructionException(QueryPlugin.Event.TEIID30167, e);
}
program = peek();
atomic |= program.isAtomic();
}
try {
// allow the current program to go out of scope
this.pop(false);
if (atomic) {
TransactionContext tc = this.getContext().getTransactionContext();
if (tc != null && tc.getTransactionType() != Scope.NONE) {
// a non-completing atomic block under a higher level transaction
// this will not work correctly until we support
// checkpoints/subtransactions
tc.getTransaction().setRollbackOnly();
getContext().addWarning(TeiidSQLException.create(e, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID31266)));
}
}
} catch (IllegalStateException | SystemException | TeiidComponentException e1) {
// $NON-NLS-1$
LogManager.logDetail(LogConstants.CTX_DQP, "Caught exception while rolling back transaction", e1);
} catch (Throwable e1) {
LogManager.logWarning(LogConstants.CTX_DQP, e1);
}
if (e instanceof RuntimeException) {
LogManager.logWarning(LogConstants.CTX_DQP, e);
} else {
// $NON-NLS-1$
LogManager.logDetail(LogConstants.CTX_DQP, "Caught exception in exception hanlding block", e);
}
if (program.getExceptionProgram() == null) {
continue;
}
Program exceptionProgram = program.getExceptionProgram();
this.push(exceptionProgram);
TeiidSQLException tse = TeiidSQLException.create(e);
GroupSymbol gs = new GroupSymbol(program.getExceptionGroup());
this.currentVarContext.setValue(exceptionSymbol(gs, 0), tse.getSQLState());
this.currentVarContext.setValue(exceptionSymbol(gs, 1), tse.getErrorCode());
this.currentVarContext.setValue(exceptionSymbol(gs, 2), tse.getTeiidCode());
this.currentVarContext.setValue(exceptionSymbol(gs, 3), tse);
this.currentVarContext.setValue(exceptionSymbol(gs, 4), tse.getCause());
continue;
}
program.incrementProgramCounter();
}
CursorState last = (CursorState) this.cursorStates.getValue(null);
if (last == null) {
return CollectionTupleSource.createNullTupleSource();
}
return last.ts;
}
use of org.teiid.query.sql.util.VariableContext in project teiid by teiid.
the class ProcedurePlan method pop.
/**
* @param success
* @throws TeiidComponentException
* @throws XATransactionException
*/
public void pop(boolean success) throws TeiidComponentException {
this.evaluator.close();
Program program = this.programs.pop();
VariableContext vc = this.currentVarContext;
VariableContext cs = this.cursorStates;
try {
this.currentVarContext = this.currentVarContext.getParentContext();
this.cursorStates = this.cursorStates.getParentContext();
TempTableStore tempTableStore = program.getTempTableStore();
this.getContext().setTempTableStore(tempTableStore.getParentTempTableStore());
tempTableStore.removeTempTables();
if (program.startedTxn()) {
TransactionService ts = this.getContext().getTransactionServer();
TransactionContext tc = this.blockContext;
this.blockContext = null;
try {
ts.resume(tc);
for (WeakReference<DataTierTupleSource> ref : txnTupleSources) {
DataTierTupleSource dtts = ref.get();
if (dtts != null) {
dtts.fullyCloseSource();
}
}
this.txnTupleSources.clear();
if (success) {
ts.commit(tc);
} else {
ts.rollback(tc);
}
} catch (XATransactionException e) {
throw new TeiidComponentException(QueryPlugin.Event.TEIID30165, e);
}
}
} finally {
removeAllCursors(cs);
}
}
Aggregations