use of org.teiid.query.processor.relational.RelationalPlan in project teiid by teiid.
the class PreparedPlan method setPlan.
/**
* Set the ProcessorPlan.
* @param context
*/
public void setPlan(ProcessorPlan planValue, CommandContext context) {
plan = planValue;
this.accessInfo.populate(context, false);
// TODO: expand this logic
if (planValue instanceof RelationalPlan) {
RelationalPlan rp = (RelationalPlan) planValue;
if (rp.getRootNode() instanceof AccessNode) {
this.accessInfo.setSensitiveToMetadataChanges(false);
}
}
}
use of org.teiid.query.processor.relational.RelationalPlan 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.processor.relational.RelationalPlan in project teiid by teiid.
the class RelationalPlanner method createUpdatePlan.
PlanNode createUpdatePlan(Command command) throws TeiidComponentException, TeiidProcessingException {
// Create top project node - define output columns for stored query / procedure
PlanNode projectNode = NodeFactory.getNewNode(NodeConstants.Types.PROJECT);
// Set output columns
List<Expression> cols = command.getProjectedSymbols();
projectNode.setProperty(NodeConstants.Info.PROJECT_COLS, cols);
// Define source of data for stored query / procedure
PlanNode sourceNode = NodeFactory.getNewNode(NodeConstants.Types.SOURCE);
sourceNode.setProperty(NodeConstants.Info.ATOMIC_REQUEST, command);
sourceNode.setProperty(NodeConstants.Info.VIRTUAL_COMMAND, command);
boolean usingTriggerAction = false;
if (command instanceof ProcedureContainer) {
ProcedureContainer container = (ProcedureContainer) command;
usingTriggerAction = addNestedProcedure(sourceNode, container, container.getGroup().getMetadataID());
}
GroupSymbol target = ((TargetedCommand) command).getGroup();
sourceNode.addGroup(target);
Object id = getTrackableGroup(target, metadata);
if (id != null) {
context.accessedPlanningObject(id);
}
attachLast(projectNode, sourceNode);
// for INTO query, attach source and project nodes
if (!usingTriggerAction && command instanceof Insert) {
Insert insert = (Insert) command;
if (insert.getQueryExpression() != null) {
PlanNode plan = generatePlan(insert.getQueryExpression());
attachLast(sourceNode, plan);
mergeTempMetadata(insert.getQueryExpression(), insert);
projectNode.setProperty(NodeConstants.Info.INTO_GROUP, insert.getGroup());
if (this.sourceHint != null) {
projectNode.setProperty(Info.SOURCE_HINT, this.sourceHint);
}
if (insert.getConstraint() != null) {
projectNode.setProperty(NodeConstants.Info.CONSTRAINT, insert.getConstraint());
}
if (insert.isUpsert()) {
projectNode.setProperty(NodeConstants.Info.UPSERT, true);
}
}
}
if (usingTriggerAction && FrameUtil.getNestedPlan(projectNode) instanceof RelationalPlan) {
sourceNode.removeFromParent();
return sourceNode;
}
return projectNode;
}
use of org.teiid.query.processor.relational.RelationalPlan in project teiid by teiid.
the class RelationalPlanner method assignWithClause.
private void assignWithClause(RelationalNode node, LinkedHashMap<String, WithQueryCommand> pushdownWith, boolean repeated) throws QueryPlannerException, TeiidComponentException {
List<SubqueryContainer<?>> subCommands = new ArrayList<SubqueryContainer<?>>();
if (node instanceof SubqueryAwareRelationalNode) {
for (LanguageObject lo : ((SubqueryAwareRelationalNode) node).getObjects()) {
ValueIteratorProviderCollectorVisitor.getValueIteratorProviders(lo, subCommands);
if (!subCommands.isEmpty()) {
for (SubqueryContainer<?> subquery : subCommands) {
if (subquery.getCommand().getProcessorPlan() instanceof RelationalPlan) {
assignWithClause(((RelationalPlan) subquery.getCommand().getProcessorPlan()).getRootNode(), pushdownWith, repeated | (subquery.getCommand().getCorrelatedReferences() != null && !subquery.getCommand().getCorrelatedReferences().asMap().isEmpty()));
}
}
subCommands.clear();
}
}
}
if (node instanceof PlanExecutionNode) {
// need to check for nested relational plans. these are created by things such as the semi-join optimization in rulemergevirtual
ProcessorPlan plan = ((PlanExecutionNode) node).getProcessorPlan();
if (plan instanceof RelationalPlan) {
// other types of plans will be contained under non-relational plans, which would be out of scope for the parent with
node = ((RelationalPlan) plan).getRootNode();
}
}
if (node instanceof AccessNode) {
AccessNode accessNode = (AccessNode) node;
Map<GroupSymbol, RelationalPlan> subplans = accessNode.getSubPlans();
if (subplans != null) {
for (RelationalPlan subplan : subplans.values()) {
assignWithClause(subplan.getRootNode(), pushdownWith, false);
}
}
Command command = accessNode.getCommand();
if (command instanceof Insert && ((Insert) command).getQueryExpression() != null) {
command = ((Insert) command).getQueryExpression();
}
if (command instanceof QueryCommand) {
if (this.withGroups == null) {
this.withGroups = new TreeSet<GroupSymbol>(nonCorrelatedComparator);
} else {
this.withGroups.clear();
}
GroupCollectorVisitor.getGroupsIgnoreInlineViewsAndEvaluatableSubqueries(command, this.withGroups);
List<WithQueryCommand> with = new ArrayList<WithQueryCommand>();
discoverWith(pushdownWith, command, with, new ArrayList<GroupSymbol>(this.withGroups));
if (!with.isEmpty()) {
List<WithQueryCommand> pushed = new ArrayList<WithQueryCommand>(with);
final Map<GroupSymbol, Integer> order = new HashMap<GroupSymbol, Integer>();
for (WithQueryCommand withQueryCommand : pushdownWith.values()) {
order.put(withQueryCommand.getGroupSymbol(), order.size());
}
Collections.sort(with, new Comparator<WithQueryCommand>() {
@Override
public int compare(WithQueryCommand o1, WithQueryCommand o2) {
return order.get(o1.getGroupSymbol()).compareTo(order.get(o2.getGroupSymbol()));
}
});
// pull up the with from the subqueries
for (int i = 0; i < with.size(); i++) {
WithQueryCommand wqc = with.get(i);
List<WithQueryCommand> with2 = wqc.getCommand().getWith();
if (with2 != null) {
with.addAll(i, with2);
i += with2.size();
wqc.getCommand().setWith(null);
}
}
QueryCommand query = (QueryCommand) command;
List<SubqueryContainer<?>> subqueries = ValueIteratorProviderCollectorVisitor.getValueIteratorProviders(query);
this.withGroups.clear();
for (WithQueryCommand wqc : with) {
withGroups.add(wqc.getGroupSymbol());
}
pullupWith(with, subqueries, withGroups);
if (query.getWith() != null) {
// we need to accumulate as a with clause could have been used at a lower scope
query.getWith().addAll(with);
} else {
query.setWith(with);
}
for (WithQueryCommand wqc : pushed) {
Object o = this.withPlanningState.pushdownState.get(wqc.getGroupSymbol().getName());
if (o == null) {
if (!repeated) {
if (accessNode.info != null) {
o = accessNode.info.id;
} else {
o = Boolean.FALSE;
}
} else {
o = Boolean.TRUE;
}
} else if (o instanceof Integer) {
// check for shared
if (accessNode.info == null || !o.equals(accessNode.info.id)) {
o = Boolean.TRUE;
}
} else {
o = Boolean.TRUE;
}
this.withPlanningState.pushdownState.put(wqc.getGroupSymbol().getName(), o);
}
// TODO: this should be based upon whether any of the need evaluated
accessNode.setShouldEvaluateExpressions(true);
}
}
}
// Recurse through children
RelationalNode[] children = node.getChildren();
for (int i = 0; i < node.getChildCount(); i++) {
assignWithClause(children[i], pushdownWith, repeated);
}
}
use of org.teiid.query.processor.relational.RelationalPlan in project teiid by teiid.
the class RuleCollapseSource method prepareSubquery.
public static void prepareSubquery(SubqueryContainer container) {
RelationalPlan subqueryPlan = (RelationalPlan) container.getCommand().getProcessorPlan();
AccessNode aNode = CriteriaCapabilityValidatorVisitor.getAccessNode(subqueryPlan);
QueryCommand command = CriteriaCapabilityValidatorVisitor.getQueryCommand(aNode);
if (command == null) {
return;
}
final SymbolMap map = container.getCommand().getCorrelatedReferences();
if (map != null) {
ExpressionMappingVisitor visitor = new RuleMergeCriteria.ReferenceReplacementVisitor(map);
DeepPostOrderNavigator.doVisit(command, visitor);
}
command.setProcessorPlan(container.getCommand().getProcessorPlan());
boolean removeLimit = false;
if (container instanceof ExistsCriteria) {
removeLimit = !((ExistsCriteria) container).shouldEvaluate();
} else if (container instanceof ScalarSubquery) {
removeLimit = !((ScalarSubquery) container).shouldEvaluate();
}
if (removeLimit && command.getLimit() != null && command.getLimit().isImplicit()) {
command.setLimit(null);
}
container.setCommand(command);
}
Aggregations