use of org.teiid.query.sql.lang.BatchedUpdateCommand in project teiid by teiid.
the class TestInsertProcessing method helpInsertIntoWithSubquery2.
public void helpInsertIntoWithSubquery2(boolean doBatching, boolean doBulkInsert) {
FakeCapabilitiesFinder capFinder = new FakeCapabilitiesFinder();
BasicSourceCapabilities caps = TestOptimizer.getTypicalCapabilities();
caps.setCapabilitySupport(Capability.BATCHED_UPDATES, doBatching);
caps.setCapabilitySupport(Capability.BULK_UPDATE, doBulkInsert);
caps.setCapabilitySupport(Capability.INSERT_WITH_ITERATOR, doBulkInsert);
caps.setCapabilitySupport(Capability.QUERY_FROM_GROUP_ALIAS, false);
// $NON-NLS-1$
capFinder.addCapabilities("pm1", caps);
QueryMetadataInterface metadata = RealMetadataFactory.example1Cached();
HardcodedDataManager dataManager = new HardcodedDataManager();
// $NON-NLS-1$
dataManager.addData(// $NON-NLS-1$
"SELECT pm1.g1.e1, pm1.g1.e2, pm1.g1.e3, pm1.g1.e4 FROM pm1.g1", new List[] { // $NON-NLS-1$
Arrays.asList(new Object[] { "1", new Integer(1), Boolean.FALSE, new Double(1) }), // $NON-NLS-1$
Arrays.asList(new Object[] { "2", new Integer(2), Boolean.TRUE, new Double(2) }) });
if (doBulkInsert) {
// $NON-NLS-1$
dataManager.addData(// $NON-NLS-1$
"INSERT INTO pm1.g2 (e1, e2, e3, e4) VALUES (...)", new List[] { Arrays.asList(1), Arrays.asList(1), Arrays.asList(1), Arrays.asList(1) });
} else if (doBatching) {
// $NON-NLS-1$
dataManager.addData(// $NON-NLS-1$
"BatchedUpdate{I,I}", new List[] { Arrays.asList(1), Arrays.asList(1) });
} else {
// $NON-NLS-1$
dataManager.addData(// $NON-NLS-1$
"INSERT INTO pm1.g2 (e1, e2, e3, e4) VALUES ('1', 1, FALSE, 1.0)", new List[] { Arrays.asList(new Object[] { new Integer(1) }) });
// $NON-NLS-1$
dataManager.addData(// $NON-NLS-1$
"INSERT INTO pm1.g2 (e1, e2, e3, e4) VALUES ('2', 2, TRUE, 2.0)", new List[] { Arrays.asList(new Object[] { new Integer(1) }) });
}
// $NON-NLS-1$
String sql = "INSERT INTO pm1.g2 SELECT pm1.g1.e1, pm1.g1.e2, pm1.g1.e3, pm1.g1.e4 from pm1.g1 UNION ALL SELECT pm1.g1.e1, pm1.g1.e2, pm1.g1.e3, pm1.g1.e4 from pm1.g1";
// String sql = "SELECT pm1.g1.e1, pm1.g1.e2, pm1.g1.e3, pm1.g1.e4 INTO pm1.g2 from pm1.g1"; //$NON-NLS-1$
Command command = helpParse(sql);
ProcessorPlan plan = helpGetPlan(command, metadata, capFinder);
List<?>[] expected = new List[] { Arrays.asList(new Object[] { new Integer(4) }) };
helpProcess(plan, dataManager, expected);
// check the command hist to ensure it contains the expected commands
if (!doBulkInsert && doBatching) {
BatchedUpdateCommand bu = (BatchedUpdateCommand) dataManager.getCommandHistory().get(2);
assertEquals(2, bu.getUpdateCommands().size());
// $NON-NLS-1$
assertEquals("INSERT INTO pm1.g2 (e1, e2, e3, e4) VALUES ('1', 1, FALSE, 1.0)", bu.getUpdateCommands().get(0).toString());
// $NON-NLS-1$
assertEquals("INSERT INTO pm1.g2 (e1, e2, e3, e4) VALUES ('2', 2, TRUE, 2.0)", bu.getUpdateCommands().get(1).toString());
}
}
use of org.teiid.query.sql.lang.BatchedUpdateCommand in project teiid by teiid.
the class HardcodedDataManager method registerRequest.
/**
* @see org.teiid.query.processor.ProcessorDataManager#registerRequest(CommandContext, org.teiid.query.sql.lang.Command, java.lang.String, RegisterRequestParameter)
* @since 4.2
*/
public TupleSource registerRequest(CommandContext context, Command command, String modelName, RegisterRequestParameter parameterObject) throws TeiidComponentException {
if (modelName != null && validModels != null && !validModels.contains(modelName)) {
// $NON-NLS-1$//$NON-NLS-2$
throw new TeiidComponentException("Detected query against invalid model: " + modelName + ": " + command);
}
this.commandHistory.add(command);
List<Expression> projectedSymbols = command.getProjectedSymbols();
String commandString = null;
if (lbf == null) {
if (command instanceof BatchedUpdateCommand && fullBatchedUpdate) {
commandString = ((BatchedUpdateCommand) command).getStringForm(true);
} else {
commandString = command.toString();
}
} else {
org.teiid.language.Command cmd = lbf.translate(command);
this.pushdownCommands.add(cmd);
commandString = cmd.toString();
}
List<?>[] rows = getData(commandString);
if (rows == null) {
if (mustRegisterCommands) {
// $NON-NLS-1$
throw new TeiidComponentException("Unknown command: " + commandString);
}
// Create one row of nulls
rows = new List[1];
rows[0] = new ArrayList();
for (int i = 0; i < projectedSymbols.size(); i++) {
rows[0].add(null);
}
}
FakeTupleSource source = new FakeTupleSource(projectedSymbols, rows);
if (blockOnce) {
source.setBlockOnce();
}
return source;
}
use of org.teiid.query.sql.lang.BatchedUpdateCommand in project teiid by teiid.
the class DataTierTupleSource method nextTuple.
public List<?> nextTuple() throws TeiidComponentException, TeiidProcessingException {
if (waitUntil > 0 && waitUntil > System.currentTimeMillis()) {
if (!this.cwi.isDataAvailable()) {
// $NON-NLS-1$
throw BlockedException.block(aqr.getAtomicRequestID(), "Blocking until", waitUntil);
}
this.waitUntil = 0;
}
while (true) {
if (arm == null) {
if (isDone()) {
// TODO: could throw an illegal state exception
return null;
}
boolean partial = false;
AtomicResultsMessage results = null;
boolean noResults = false;
try {
if (futureResult != null || !aqr.isSerial()) {
results = asynchGet();
} else {
results = getResults();
}
// check for update events
if (index == 0 && this.dtm.detectChangeEvents()) {
Command command = aqr.getCommand();
int commandIndex = 0;
if (RelationalNodeUtil.isUpdate(command)) {
long ts = System.currentTimeMillis();
checkForUpdates(results, command, dtm.getEventDistributor(), commandIndex, ts);
} else if (command instanceof BatchedUpdateCommand) {
long ts = System.currentTimeMillis();
BatchedUpdateCommand bac = (BatchedUpdateCommand) command;
for (Command uc : bac.getUpdateCommands()) {
checkForUpdates(results, uc, dtm.getEventDistributor(), commandIndex++, ts);
}
}
}
} catch (TranslatorException e) {
errored = true;
results = exceptionOccurred(e);
partial = true;
} catch (BlockedException e) {
noResults = true;
throw e;
} catch (DataNotAvailableException e) {
noResults = true;
handleDataNotAvailable(e);
continue;
} finally {
if (!noResults && results == null) {
errored = true;
}
}
receiveResults(results, partial);
}
if (index < arm.getResults().length) {
if (limit-- == 0) {
this.done = true;
arm = null;
return null;
}
return this.arm.getResults()[index++];
}
arm = null;
if (isDone()) {
return null;
}
}
}
use of org.teiid.query.sql.lang.BatchedUpdateCommand in project teiid by teiid.
the class PreparedStatementRequest method handlePreparedBatchUpdate.
/**
* There are two cases
* if
* The source supports preparedBatchUpdate -> just let the command and values pass to the source
* else
* create a batchedupdatecommand that represents the batch operation
* @param command
* @throws QueryMetadataException
* @throws TeiidComponentException
* @throws QueryResolverException
* @throws QueryPlannerException
* @throws QueryValidatorException
*/
private void handlePreparedBatchUpdate() throws QueryMetadataException, TeiidComponentException, QueryResolverException, QueryPlannerException, QueryValidatorException {
List<List<?>> paramValues = (List<List<?>>) requestMsg.getParameterValues();
if (paramValues.isEmpty()) {
throw new QueryValidatorException(QueryPlugin.Event.TEIID30555, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30555));
}
boolean supportPreparedBatchUpdate = false;
Command command = null;
if (this.processPlan instanceof RelationalPlan) {
RelationalPlan rPlan = (RelationalPlan) this.processPlan;
if (rPlan.getRootNode() instanceof AccessNode) {
AccessNode aNode = (AccessNode) rPlan.getRootNode();
String modelName = aNode.getModelName();
command = aNode.getCommand();
SourceCapabilities caps = capabilitiesFinder.findCapabilities(modelName);
supportPreparedBatchUpdate = caps.supportsCapability(SourceCapabilities.Capability.BULK_UPDATE);
if (supportPreparedBatchUpdate && // only allow the plan if the multi-valued references result in expressions that can be pushed
!CriteriaCapabilityValidatorVisitor.canPushLanguageObject(command, metadata.getModelID(modelName), metadata, capabilitiesFinder, analysisRecord, false, false, true)) {
supportPreparedBatchUpdate = false;
}
}
}
List<Command> commands = new LinkedList<Command>();
List<VariableContext> contexts = new LinkedList<VariableContext>();
List<List<Object>> multiValues = new ArrayList<List<Object>>(this.prepPlan.getReferences().size());
for (List<?> values : paramValues) {
PreparedStatementRequest.resolveParameterValues(this.prepPlan.getReferences(), values, this.context, this.metadata);
contexts.add(this.context.getVariableContext());
if (supportPreparedBatchUpdate) {
if (multiValues.isEmpty()) {
for (int i = 0; i < values.size(); i++) {
multiValues.add(new ArrayList<Object>(paramValues.size()));
}
}
for (int i = 0; i < values.size(); i++) {
List<Object> multiValue = multiValues.get(i);
Object value = this.context.getVariableContext().getGlobalValue(this.prepPlan.getReferences().get(i).getContextSymbol());
multiValue.add(value);
}
} else {
// just accumulate copies of the command/plan - clones are not necessary
if (command == null) {
command = this.prepPlan.getCommand();
}
command.setProcessorPlan(this.processPlan);
commands.add(command);
}
}
if (paramValues.size() > 1) {
this.context.setVariableContext(new VariableContext());
}
if (paramValues.size() == 1) {
// just use the existing plan, and global reference evaluation
return;
}
if (supportPreparedBatchUpdate) {
for (int i = 0; i < this.prepPlan.getReferences().size(); i++) {
Constant c = new Constant(null, this.prepPlan.getReferences().get(i).getType());
c.setMultiValued(multiValues.get(i));
this.context.getVariableContext().setGlobalValue(this.prepPlan.getReferences().get(i).getContextSymbol(), c);
}
return;
}
BatchedUpdateCommand buc = new BatchedUpdateCommand(commands);
buc.setVariableContexts(contexts);
BatchedUpdatePlanner planner = new BatchedUpdatePlanner();
this.processPlan = planner.optimize(buc, idGenerator, metadata, capabilitiesFinder, analysisRecord, context);
}
use of org.teiid.query.sql.lang.BatchedUpdateCommand 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());
}
Aggregations