use of org.teiid.core.TeiidComponentException in project teiid by teiid.
the class RulePushAggregates method execute.
/**
* @see org.teiid.query.optimizer.relational.OptimizerRule#execute(org.teiid.query.optimizer.relational.plantree.PlanNode,
* org.teiid.query.metadata.QueryMetadataInterface, org.teiid.query.optimizer.capabilities.CapabilitiesFinder,
* org.teiid.query.optimizer.relational.RuleStack, AnalysisRecord, CommandContext)
* @since 4.2
*/
public PlanNode execute(PlanNode plan, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, RuleStack rules, AnalysisRecord analysisRecord, CommandContext ctx) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
this.context = ctx;
groupingNodes = NodeEditor.findAllNodes(plan, NodeConstants.Types.GROUP, NodeConstants.Types.ACCESS);
outer: for (int i = 0; i < groupingNodes.size(); i++) {
PlanNode groupNode = groupingNodes.get(i);
if (groupNode.hasBooleanProperty(Info.ROLLUP)) {
continue;
}
PlanNode child = groupNode.getFirstChild();
List<Expression> groupingExpressions = (List<Expression>) groupNode.getProperty(NodeConstants.Info.GROUP_COLS);
if (groupingExpressions == null) {
groupingExpressions = Collections.emptyList();
}
try {
if (child.getType() == NodeConstants.Types.SOURCE) {
PlanNode setOp = child.getFirstChild();
pushGroupNodeOverUnion(metadata, capFinder, groupNode, child, groupingExpressions, setOp, analysisRecord);
continue;
} else if (child.getType() != NodeConstants.Types.JOIN) {
PlanNode access = NodeEditor.findNodePreOrder(child, NodeConstants.Types.ACCESS, NodeConstants.Types.SOURCE | NodeConstants.Types.JOIN | NodeConstants.Types.SET_OP);
if (access != null) {
PlanNode parent = access.getParent();
while (parent != groupNode) {
if (parent.getType() != NodeConstants.Types.SELECT) {
continue outer;
}
parent = parent.getParent();
}
Set<AggregateSymbol> aggregates = collectAggregates(groupNode);
// hybrid of the join/union/decompose pushing logic
if (access.hasBooleanProperty(Info.IS_MULTI_SOURCE)) {
if (!RuleRaiseAccess.isPartitioned(metadata, groupingExpressions, groupNode)) {
for (AggregateSymbol agg : aggregates) {
if (!agg.canStage()) {
continue outer;
}
}
boolean shouldPushdown = canPushGroupByToUnionChild(metadata, capFinder, groupingExpressions, aggregates, access, analysisRecord, groupNode);
if (!shouldPushdown) {
continue;
}
Set<Expression> stagedGroupingSymbols = new LinkedHashSet<Expression>();
stagedGroupingSymbols.addAll(groupingExpressions);
aggregates = stageAggregates(groupNode, metadata, stagedGroupingSymbols, aggregates, false);
if (aggregates.isEmpty() && stagedGroupingSymbols.isEmpty()) {
continue;
}
addGroupBy(child, new ArrayList<Expression>(stagedGroupingSymbols), aggregates, metadata, groupNode.getParent(), capFinder, false, stagedGroupingSymbols.isEmpty() && containsNullDependent(aggregates));
} else if (groupNode.getFirstChild() == access && RuleRaiseAccess.canRaiseOverGroupBy(groupNode, child, aggregates, metadata, capFinder, analysisRecord, false) && canFilterEmpty(metadata, capFinder, child, groupingExpressions)) {
if (groupingExpressions.isEmpty()) {
addEmptyFilter(aggregates, groupNode, metadata, capFinder, RuleRaiseAccess.getModelIDFromAccess(child, metadata));
}
access.getGroups().clear();
access.getGroups().addAll(groupNode.getGroups());
RuleRaiseAccess.performRaise(null, access, access.getParent());
if (groupingExpressions.isEmpty() && RuleRaiseAccess.canRaiseOverSelect(access, metadata, capFinder, access.getParent(), null)) {
RuleRaiseAccess.performRaise(null, access, access.getParent());
}
}
}
// TODO: consider pushing aggregate in general
}
continue;
}
} catch (QueryResolverException e) {
throw new TeiidComponentException(QueryPlugin.Event.TEIID30264, e);
}
Set<AggregateSymbol> aggregates = collectAggregates(groupNode);
pushGroupNode(groupNode, groupingExpressions, aggregates, metadata, capFinder, context);
}
return plan;
}
use of org.teiid.core.TeiidComponentException in project teiid by teiid.
the class PlanToProcessConverter method convertNode.
protected RelationalNode convertNode(PlanNode node) throws TeiidComponentException, TeiidProcessingException {
RelationalNode processNode = null;
switch(node.getType()) {
case NodeConstants.Types.PROJECT:
GroupSymbol intoGroup = (GroupSymbol) node.getProperty(NodeConstants.Info.INTO_GROUP);
if (intoGroup != null) {
try {
Insert insert = (Insert) node.getFirstChild().getProperty(Info.VIRTUAL_COMMAND);
List<ElementSymbol> allIntoElements = insert.getVariables();
Object groupID = intoGroup.getMetadataID();
Object modelID = metadata.getModelID(groupID);
String modelName = metadata.getFullName(modelID);
if (metadata.isVirtualGroup(groupID) && !metadata.isTemporaryTable(groupID)) {
InsertPlanExecutionNode ipen = new InsertPlanExecutionNode(getID(), metadata);
ProcessorPlan plan = (ProcessorPlan) node.getFirstChild().getProperty(Info.PROCESSOR_PLAN);
Assertion.isNotNull(plan);
ipen.setProcessorPlan(plan);
ipen.setReferences(insert.getValues());
processNode = ipen;
} else {
ProjectIntoNode pinode = new ProjectIntoNode(getID());
pinode.setIntoGroup(intoGroup);
pinode.setIntoElements(allIntoElements);
pinode.setModelName(modelName);
pinode.setConstraint((Criteria) node.getProperty(Info.CONSTRAINT));
pinode.setSourceHint((SourceHint) node.getProperty(Info.SOURCE_HINT));
if (node.hasBooleanProperty(Info.UPSERT)) {
pinode.setUpsert(true);
}
processNode = pinode;
SourceCapabilities caps = capFinder.findCapabilities(modelName);
if (caps.supportsCapability(Capability.INSERT_WITH_ITERATOR)) {
pinode.setMode(org.teiid.query.processor.relational.ProjectIntoNode.Mode.ITERATOR);
} else if (caps.supportsCapability(Capability.BATCHED_UPDATES)) {
pinode.setMode(org.teiid.query.processor.relational.ProjectIntoNode.Mode.BATCH);
} else {
pinode.setMode(org.teiid.query.processor.relational.ProjectIntoNode.Mode.SINGLE);
}
pinode.setTransactionSupport((TransactionSupport) caps.getSourceProperty(Capability.TRANSACTION_SUPPORT));
}
} catch (QueryMetadataException e) {
throw new TeiidComponentException(QueryPlugin.Event.TEIID30247, e);
}
} else {
List<Expression> symbols = (List) node.getProperty(NodeConstants.Info.PROJECT_COLS);
ProjectNode pnode = new ProjectNode(getID());
pnode.setSelectSymbols(symbols);
processNode = pnode;
if (node.hasBooleanProperty(Info.HAS_WINDOW_FUNCTIONS)) {
WindowFunctionProjectNode wfpn = new WindowFunctionProjectNode(getID());
// with partial projection the window function may already be pushed, we'll check for that here
ArrayList<Expression> filtered = new ArrayList<Expression>();
List<Expression> childSymbols = (List) node.getFirstChild().getProperty(NodeConstants.Info.OUTPUT_COLS);
for (Expression ex : symbols) {
ex = SymbolMap.getExpression(ex);
if (childSymbols.contains(ex)) {
continue;
}
filtered.add(ex);
}
Set<WindowFunction> windowFunctions = RuleAssignOutputElements.getWindowFunctions(filtered);
if (!windowFunctions.isEmpty()) {
// TODO: check for selecting all window functions
List<Expression> outputElements = new ArrayList<Expression>(windowFunctions);
// collect the other projected expressions
for (Expression singleElementSymbol : (List<Expression>) node.getFirstChild().getProperty(Info.OUTPUT_COLS)) {
outputElements.add(singleElementSymbol);
}
wfpn.setElements(outputElements);
wfpn.init();
pnode.addChild(wfpn);
for (WindowFunction wf : windowFunctions) {
validateAggregateFunctionEvaluation(wf.getFunction());
}
}
}
}
break;
case NodeConstants.Types.JOIN:
JoinType jtype = (JoinType) node.getProperty(NodeConstants.Info.JOIN_TYPE);
JoinStrategyType stype = (JoinStrategyType) node.getProperty(NodeConstants.Info.JOIN_STRATEGY);
JoinNode jnode = new JoinNode(getID());
jnode.setJoinType(jtype);
jnode.setLeftDistinct(node.hasBooleanProperty(NodeConstants.Info.IS_LEFT_DISTINCT));
jnode.setRightDistinct(node.hasBooleanProperty(NodeConstants.Info.IS_RIGHT_DISTINCT));
List joinCrits = (List) node.getProperty(NodeConstants.Info.JOIN_CRITERIA);
String depValueSource = (String) node.getProperty(NodeConstants.Info.DEPENDENT_VALUE_SOURCE);
SortOption leftSort = (SortOption) node.getProperty(NodeConstants.Info.SORT_LEFT);
if (stype == JoinStrategyType.MERGE || stype == JoinStrategyType.ENHANCED_SORT) {
MergeJoinStrategy mjStrategy = null;
if (stype.equals(JoinStrategyType.ENHANCED_SORT)) {
EnhancedSortMergeJoinStrategy esmjStrategy = new EnhancedSortMergeJoinStrategy(leftSort, (SortOption) node.getProperty(NodeConstants.Info.SORT_RIGHT));
esmjStrategy.setSemiDep(node.hasBooleanProperty(Info.IS_SEMI_DEP));
mjStrategy = esmjStrategy;
} else {
mjStrategy = new MergeJoinStrategy(leftSort, (SortOption) node.getProperty(NodeConstants.Info.SORT_RIGHT), false);
}
jnode.setJoinStrategy(mjStrategy);
List leftExpressions = (List) node.getProperty(NodeConstants.Info.LEFT_EXPRESSIONS);
List rightExpressions = (List) node.getProperty(NodeConstants.Info.RIGHT_EXPRESSIONS);
jnode.setJoinExpressions(leftExpressions, rightExpressions);
joinCrits = (List) node.getProperty(NodeConstants.Info.NON_EQUI_JOIN_CRITERIA);
} else if (stype == JoinStrategyType.NESTED_TABLE) {
NestedTableJoinStrategy ntjStrategy = new NestedTableJoinStrategy();
jnode.setJoinStrategy(ntjStrategy);
SymbolMap references = (SymbolMap) node.getProperty(Info.RIGHT_NESTED_REFERENCES);
ntjStrategy.setRightMap(references);
} else {
NestedLoopJoinStrategy nljStrategy = new NestedLoopJoinStrategy();
jnode.setJoinStrategy(nljStrategy);
}
Criteria joinCrit = Criteria.combineCriteria(joinCrits);
jnode.setJoinCriteria(joinCrit);
processNode = jnode;
jnode.setDependentValueSource(depValueSource);
break;
case NodeConstants.Types.ACCESS:
ProcessorPlan plan = (ProcessorPlan) node.getProperty(NodeConstants.Info.PROCESSOR_PLAN);
if (plan != null) {
PlanExecutionNode peNode = null;
Criteria crit = (Criteria) node.getProperty(NodeConstants.Info.PROCEDURE_CRITERIA);
if (crit != null) {
List references = (List) node.getProperty(NodeConstants.Info.PROCEDURE_INPUTS);
List defaults = (List) node.getProperty(NodeConstants.Info.PROCEDURE_DEFAULTS);
peNode = new DependentProcedureExecutionNode(getID(), crit, references, defaults);
} else {
peNode = new PlanExecutionNode(getID());
}
peNode.setProcessorPlan(plan);
processNode = peNode;
} else {
AccessNode aNode = null;
Command command = (Command) node.getProperty(NodeConstants.Info.ATOMIC_REQUEST);
Object modelID = node.getProperty(NodeConstants.Info.MODEL_ID);
if (modelID != null) {
String fullName = metadata.getFullName(modelID);
if (!capFinder.isValid(fullName)) {
// TODO: we ideally want to handle the partial resutls case here differently
// by adding a null node / and a source warning
// for now it's just as easy to say that the user needs to take steps to
// return static capabilities
SourceCapabilities caps = capFinder.findCapabilities(fullName);
Exception cause = null;
if (caps != null) {
cause = (Exception) caps.getSourceProperty(Capability.INVALID_EXCEPTION);
}
throw new QueryPlannerException(QueryPlugin.Event.TEIID30498, cause, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30498, fullName));
}
}
EvaluatableVisitor ev = null;
if (node.hasBooleanProperty(NodeConstants.Info.IS_DEPENDENT_SET)) {
if (command instanceof StoredProcedure) {
List references = (List) node.getProperty(NodeConstants.Info.PROCEDURE_INPUTS);
List defaults = (List) node.getProperty(NodeConstants.Info.PROCEDURE_DEFAULTS);
Criteria crit = (Criteria) node.getProperty(NodeConstants.Info.PROCEDURE_CRITERIA);
DependentProcedureAccessNode depAccessNode = new DependentProcedureAccessNode(getID(), crit, references, defaults);
processNode = depAccessNode;
aNode = depAccessNode;
} else {
// create dependent access node
DependentAccessNode depAccessNode = new DependentAccessNode(getID());
if (modelID != null) {
depAccessNode.setPushdown(CapabilitiesUtil.supports(Capability.DEPENDENT_JOIN, modelID, metadata, capFinder));
depAccessNode.setMaxSetSize(CapabilitiesUtil.getMaxInCriteriaSize(modelID, metadata, capFinder));
depAccessNode.setMaxPredicates(CapabilitiesUtil.getMaxDependentPredicates(modelID, metadata, capFinder));
depAccessNode.setUseBindings(CapabilitiesUtil.supports(Capability.DEPENDENT_JOIN_BINDINGS, modelID, metadata, capFinder));
// TODO: allow the translator to drive this property
// simplistic check of whether this query is complex to re-execute
Query query = (Query) command;
if (query.getGroupBy() != null || query.getFrom().getClauses().size() > 1 || !(query.getFrom().getClauses().get(0) instanceof UnaryFromClause) || query.getWith() != null) {
depAccessNode.setComplexQuery(true);
} else {
// check to see if there in an index on at least one of the dependent sets
Set<GroupSymbol> groups = new HashSet<GroupSymbol>(query.getFrom().getGroups());
boolean found = false;
for (Criteria crit : Criteria.separateCriteriaByAnd(query.getCriteria())) {
if (crit instanceof DependentSetCriteria) {
DependentSetCriteria dsc = (DependentSetCriteria) crit;
if (NewCalculateCostUtil.getKeyUsed(ElementCollectorVisitor.getElements(dsc.getExpression(), true), groups, metadata, null) != null) {
found = true;
break;
}
}
}
if (!found) {
depAccessNode.setComplexQuery(true);
}
}
}
processNode = depAccessNode;
aNode = depAccessNode;
}
aNode.setShouldEvaluateExpressions(true);
} else {
// create access node
aNode = new AccessNode(getID());
processNode = aNode;
}
// -- special handling for system tables. currently they cannot perform projection
try {
if (command instanceof Query) {
processNode = correctProjectionInternalTables(node, aNode);
}
} catch (QueryMetadataException err) {
throw new TeiidComponentException(QueryPlugin.Event.TEIID30248, err);
}
setRoutingName(aNode, node, command);
boolean shouldEval = false;
if (command instanceof Insert) {
Insert insert = (Insert) command;
if (insert.getQueryExpression() != null) {
insert.setQueryExpression((QueryCommand) aliasCommand(aNode, insert.getQueryExpression(), modelID));
} else {
for (int i = 0; i < insert.getValues().size(); i++) {
Expression ex = (Expression) insert.getValues().get(i);
if (!CriteriaCapabilityValidatorVisitor.canPushLanguageObject(ex, modelID, metadata, capFinder, analysisRecord)) {
// replace with an expression symbol to let the rewriter know that it should be replaced
insert.getValues().set(i, new ExpressionSymbol("x", ex));
shouldEval = true;
}
}
}
} else if (command instanceof QueryCommand) {
command = aliasCommand(aNode, command, modelID);
}
ev = EvaluatableVisitor.needsEvaluationVisitor(modelID, metadata, capFinder);
if (!shouldEval && modelID != null) {
// do a capabilities sensitive check for needs eval
String modelName = metadata.getFullName(modelID);
SourceCapabilities caps = capFinder.findCapabilities(modelName);
final CriteriaCapabilityValidatorVisitor capVisitor = new CriteriaCapabilityValidatorVisitor(modelID, metadata, capFinder, caps);
capVisitor.setCheckEvaluation(false);
DeepPreOrderNavigator nav = new DeepPreOrderNavigator(ev) {
protected void visitNode(org.teiid.query.sql.LanguageObject obj) {
if (capVisitor.isValid() && obj instanceof Expression) {
obj.acceptVisitor(capVisitor);
}
super.visitNode(obj);
}
};
command.acceptVisitor(nav);
if (!capVisitor.isValid()) {
// there's a non-supported construct pushed, we should eval
ev.evaluationNotPossible(EvaluationLevel.PROCESSING);
}
} else {
DeepPreOrderNavigator.doVisit(command, ev);
}
aNode.setShouldEvaluateExpressions(ev.requiresEvaluation(EvaluationLevel.PROCESSING) || shouldEval);
aNode.setCommand(command);
if (modelID != null) {
String fullName = metadata.getFullName(modelID);
SourceCapabilities caps = capFinder.findCapabilities(fullName);
aNode.setTransactionSupport((TransactionSupport) caps.getSourceProperty(Capability.TRANSACTION_SUPPORT));
}
Map<GroupSymbol, PlanNode> subPlans = (Map<GroupSymbol, PlanNode>) node.getProperty(Info.SUB_PLANS);
// it makes more sense to allow the multisource affect to be elevated above just access nodes
if (aNode.getModelId() != null && metadata.isMultiSource(aNode.getModelId())) {
VDBMetaData vdb = context.getVdb();
// forces a rewrite
aNode.setShouldEvaluateExpressions(true);
aNode.setElements((List) node.getProperty(NodeConstants.Info.OUTPUT_COLS));
if (node.hasBooleanProperty(Info.IS_MULTI_SOURCE)) {
Expression ex = rewriteMultiSourceCommand(aNode.getCommand());
aNode.setConnectorBindingExpression(ex);
aNode.setMultiSource(true);
} else {
String sourceName = (String) node.getProperty(Info.SOURCE_NAME);
aNode.setConnectorBindingExpression(new Constant(sourceName));
}
} else if (subPlans == null) {
if (!aNode.isShouldEvaluate()) {
aNode.minimizeProject(command);
}
// check if valid to share this with other nodes
if (ev != null && ev.getDeterminismLevel().compareTo(Determinism.INSTRUCTION_DETERMINISTIC) >= 0 && command.areResultsCachable()) {
checkForSharedSourceCommand(aNode, node);
}
}
if (subPlans != null) {
QueryCommand qc = (QueryCommand) command;
if (qc.getWith() == null) {
qc.setWith(new ArrayList<WithQueryCommand>(subPlans.size()));
}
Map<GroupSymbol, RelationalPlan> plans = new LinkedHashMap<GroupSymbol, RelationalPlan>();
for (Map.Entry<GroupSymbol, PlanNode> entry : subPlans.entrySet()) {
RelationalPlan subPlan = convert(entry.getValue());
List<ElementSymbol> elems = ResolverUtil.resolveElementsInGroup(entry.getKey(), metadata);
subPlan.setOutputElements(elems);
plans.put(entry.getKey(), subPlan);
WithQueryCommand withQueryCommand = new WithQueryCommand(entry.getKey(), elems, null);
qc.getWith().add(withQueryCommand);
}
aNode.setSubPlans(plans);
}
}
break;
case NodeConstants.Types.SELECT:
Criteria crit = (Criteria) node.getProperty(NodeConstants.Info.SELECT_CRITERIA);
if (!node.hasCollectionProperty(Info.OUTPUT_COLS)) {
// the late optimization to create a dependent join from a subquery introduces
// criteria that have no output elements set
// TODO that should be cleaner, but the logic currently expects to be run after join implementation
// and rerunning assign output elements seems excessive
node.setProperty(Info.OUTPUT_COLS, node.getFirstChild().getProperty(Info.OUTPUT_COLS));
}
SelectNode selnode = new SelectNode(getID());
selnode.setCriteria(crit);
// in case the parent was a source
selnode.setProjectedExpressions((List<Expression>) node.getProperty(NodeConstants.Info.PROJECT_COLS));
processNode = selnode;
break;
case NodeConstants.Types.SORT:
case NodeConstants.Types.DUP_REMOVE:
if (node.getType() == NodeConstants.Types.DUP_REMOVE) {
processNode = new DupRemoveNode(getID());
} else {
SortNode sortNode = new SortNode(getID());
OrderBy orderBy = (OrderBy) node.getProperty(NodeConstants.Info.SORT_ORDER);
if (orderBy != null) {
sortNode.setSortElements(orderBy.getOrderByItems());
}
if (node.hasBooleanProperty(NodeConstants.Info.IS_DUP_REMOVAL)) {
sortNode.setMode(Mode.DUP_REMOVE_SORT);
}
processNode = sortNode;
}
break;
case NodeConstants.Types.GROUP:
GroupingNode gnode = new GroupingNode(getID());
gnode.setRollup(node.hasBooleanProperty(Info.ROLLUP));
SymbolMap groupingMap = (SymbolMap) node.getProperty(NodeConstants.Info.SYMBOL_MAP);
gnode.setOutputMapping(groupingMap);
gnode.setRemoveDuplicates(node.hasBooleanProperty(NodeConstants.Info.IS_DUP_REMOVAL));
List<Expression> gCols = (List) node.getProperty(NodeConstants.Info.GROUP_COLS);
OrderBy orderBy = (OrderBy) node.getProperty(Info.SORT_ORDER);
if (orderBy == null) {
if (gCols != null) {
LinkedHashSet<Expression> exprs = new LinkedHashSet<Expression>();
for (Expression ex : gCols) {
exprs.add(SymbolMap.getExpression(ex));
}
orderBy = new OrderBy(RuleChooseJoinStrategy.createExpressionSymbols(new ArrayList<Expression>(exprs)));
}
} else {
HashSet<Expression> seen = new HashSet<Expression>();
for (int i = 0; i < gCols.size(); i++) {
if (i < orderBy.getOrderByItems().size()) {
OrderByItem orderByItem = orderBy.getOrderByItems().get(i);
Expression ex = SymbolMap.getExpression(orderByItem.getSymbol());
if (!seen.add(ex)) {
continue;
}
if (ex instanceof ElementSymbol) {
ex = groupingMap.getMappedExpression((ElementSymbol) ex);
// $NON-NLS-1$
orderByItem.setSymbol(new ExpressionSymbol("expr", ex));
}
} else {
// $NON-NLS-1$
orderBy.addVariable(new ExpressionSymbol("expr", gCols.get(i)), OrderBy.ASC);
}
}
}
if (orderBy != null) {
gnode.setOrderBy(orderBy.getOrderByItems());
}
for (Expression ex : groupingMap != null ? groupingMap.getValues() : (List<Expression>) node.getFirstChild().getProperty(NodeConstants.Info.PROJECT_COLS)) {
if (ex instanceof AggregateSymbol) {
validateAggregateFunctionEvaluation((AggregateSymbol) ex);
}
}
processNode = gnode;
break;
case NodeConstants.Types.SOURCE:
Object source = node.getProperty(NodeConstants.Info.TABLE_FUNCTION);
if (source instanceof XMLTable) {
XMLTable xt = (XMLTable) source;
XMLTableNode xtn = new XMLTableNode(getID());
// we handle the projection filtering once here rather than repeating the
// path analysis on a per plan basis
updateGroupName(node, xt);
Map<Expression, Integer> elementMap = RelationalNode.createLookupMap(xt.getProjectedSymbols());
List cols = (List) node.getProperty(NodeConstants.Info.OUTPUT_COLS);
int[] projectionIndexes = RelationalNode.getProjectionIndexes(elementMap, cols);
ArrayList<XMLColumn> filteredColumns = new ArrayList<XMLColumn>(projectionIndexes.length);
for (int col : projectionIndexes) {
filteredColumns.add(xt.getColumns().get(col));
}
xt.getXQueryExpression().useDocumentProjection(filteredColumns, analysisRecord);
xtn.setProjectedColumns(filteredColumns);
xtn.setTable(xt);
processNode = xtn;
break;
}
if (source instanceof ObjectTable) {
ObjectTable ot = (ObjectTable) source;
ObjectTableNode otn = new ObjectTableNode(getID());
// we handle the projection filtering once here rather than repeating the
// path analysis on a per plan basis
updateGroupName(node, ot);
Map<Expression, Integer> elementMap = RelationalNode.createLookupMap(ot.getProjectedSymbols());
List<Expression> cols = (List<Expression>) node.getProperty(NodeConstants.Info.OUTPUT_COLS);
int[] projectionIndexes = RelationalNode.getProjectionIndexes(elementMap, cols);
ArrayList<ObjectColumn> filteredColumns = new ArrayList<ObjectColumn>(projectionIndexes.length);
for (int col : projectionIndexes) {
filteredColumns.add(ot.getColumns().get(col));
}
otn.setProjectedColumns(filteredColumns);
otn.setTable(ot);
processNode = otn;
break;
}
if (source instanceof TextTable) {
TextTableNode ttn = new TextTableNode(getID());
TextTable tt = (TextTable) source;
updateGroupName(node, tt);
ttn.setTable(tt);
processNode = ttn;
break;
}
if (source instanceof ArrayTable) {
ArrayTableNode atn = new ArrayTableNode(getID());
ArrayTable at = (ArrayTable) source;
updateGroupName(node, at);
atn.setTable(at);
processNode = atn;
break;
}
SymbolMap symbolMap = (SymbolMap) node.getProperty(NodeConstants.Info.SYMBOL_MAP);
if (symbolMap != null) {
PlanNode child = node.getLastChild();
if (child.getType() == NodeConstants.Types.PROJECT || child.getType() == NodeConstants.Types.SELECT) {
// update the project cols based upon the original output
child.setProperty(NodeConstants.Info.PROJECT_COLS, child.getProperty(NodeConstants.Info.OUTPUT_COLS));
}
if (child.getType() != NodeConstants.Types.SET_OP || child.getProperty(Info.SET_OPERATION) == Operation.UNION) {
child.setProperty(NodeConstants.Info.OUTPUT_COLS, node.getProperty(NodeConstants.Info.OUTPUT_COLS));
} else {
// else we cannot directly update the child properties as the child will get converted to a join
// create a projection instead for initialization purposes, but won't impact performance
ProjectNode pNode = new ProjectNode(getID());
pNode.setSelectSymbols((List<? extends Expression>) child.getProperty(NodeConstants.Info.OUTPUT_COLS));
return prepareToAdd(node, pNode);
}
}
return null;
case NodeConstants.Types.SET_OP:
Operation setOp = (Operation) node.getProperty(NodeConstants.Info.SET_OPERATION);
boolean useAll = ((Boolean) node.getProperty(NodeConstants.Info.USE_ALL)).booleanValue();
if (setOp == Operation.UNION) {
RelationalNode unionAllNode = new UnionAllNode(getID());
if (useAll) {
processNode = unionAllNode;
} else {
boolean onlyDupRemoval = node.hasBooleanProperty(NodeConstants.Info.IS_DUP_REMOVAL);
if (onlyDupRemoval) {
processNode = new DupRemoveNode(getID());
} else {
SortNode sNode = new SortNode(getID());
sNode.setMode(Mode.DUP_REMOVE_SORT);
processNode = sNode;
}
unionAllNode.setElements((List) node.getProperty(NodeConstants.Info.OUTPUT_COLS));
processNode.addChild(unionAllNode);
}
} else {
JoinNode joinAsSet = new JoinNode(getID());
joinAsSet.setJoinStrategy(new MergeJoinStrategy(SortOption.SORT_DISTINCT, SortOption.SORT_DISTINCT, true));
// If we push these sorts, we will have to enforce null order, since nulls are equal here
List leftExpressions = (List) node.getFirstChild().getProperty(NodeConstants.Info.OUTPUT_COLS);
List rightExpressions = (List) node.getLastChild().getProperty(NodeConstants.Info.OUTPUT_COLS);
joinAsSet.setJoinType(setOp == Operation.EXCEPT ? JoinType.JOIN_ANTI_SEMI : JoinType.JOIN_SEMI);
joinAsSet.setJoinExpressions(leftExpressions, rightExpressions);
processNode = joinAsSet;
}
break;
case NodeConstants.Types.TUPLE_LIMIT:
Expression rowLimit = (Expression) node.getProperty(NodeConstants.Info.MAX_TUPLE_LIMIT);
Expression offset = (Expression) node.getProperty(NodeConstants.Info.OFFSET_TUPLE_COUNT);
LimitNode ln = new LimitNode(getID(), rowLimit, offset);
ln.setImplicit(node.hasBooleanProperty(Info.IS_IMPLICIT_LIMIT));
processNode = ln;
break;
case NodeConstants.Types.NULL:
processNode = new NullNode(getID());
break;
default:
throw new QueryPlannerException(QueryPlugin.Event.TEIID30250, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30250, NodeConstants.getNodeTypeString(node.getType())));
}
if (processNode != null) {
processNode = prepareToAdd(node, processNode);
}
return processNode;
}
use of org.teiid.core.TeiidComponentException in project teiid by teiid.
the class RuleCollapseSource method execute.
public PlanNode execute(PlanNode plan, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, RuleStack rules, AnalysisRecord analysisRecord, CommandContext context) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
for (PlanNode accessNode : NodeEditor.findAllNodes(plan, NodeConstants.Types.ACCESS)) {
// Get nested non-relational plan if there is one
ProcessorPlan nonRelationalPlan = FrameUtil.getNestedPlan(accessNode);
Command command = FrameUtil.getNonQueryCommand(accessNode);
if (nonRelationalPlan != null) {
accessNode.setProperty(NodeConstants.Info.PROCESSOR_PLAN, nonRelationalPlan);
} else if (RuleRaiseAccess.getModelIDFromAccess(accessNode, metadata) == null) {
// with query or processor plan already set
} else if (command == null) {
PlanNode commandRoot = accessNode;
GroupSymbol intoGroup = (GroupSymbol) accessNode.getFirstChild().getProperty(NodeConstants.Info.INTO_GROUP);
Set<Object> toCheck = (Set<Object>) commandRoot.getProperty(NodeConstants.Info.CHECK_MAT_VIEW);
if (intoGroup != null) {
commandRoot = NodeEditor.findNodePreOrder(accessNode, NodeConstants.Types.SOURCE).getFirstChild();
} else {
plan = removeUnnecessaryInlineView(plan, commandRoot);
}
QueryCommand queryCommand = createQuery(context, capFinder, accessNode, commandRoot);
if (toCheck != null) {
modifyToCheckMatViewStatus(metadata, queryCommand, toCheck);
}
Object modelId = RuleRaiseAccess.getModelIDFromAccess(accessNode, metadata);
if (queryCommand instanceof Query && CapabilitiesUtil.supports(Capability.PARTIAL_FILTERS, modelId, metadata, capFinder)) {
// this logic relies on the capability restrictions made in capabilities converter
Query query = (Query) queryCommand;
if (query.getCriteria() != null) {
List<Criteria> toFilter = new ArrayList<Criteria>();
HashSet<ElementSymbol> select = new LinkedHashSet(query.getSelect().getProjectedSymbols());
outer: for (Criteria crit : Criteria.separateCriteriaByAnd(query.getCriteria())) {
for (ElementSymbol es : ElementCollectorVisitor.getElements(crit, true)) {
if (Boolean.valueOf(metadata.getExtensionProperty(es.getMetadataID(), PARTIAL_PROPERTY, false)) && select.contains(es)) {
toFilter.add((Criteria) crit.clone());
continue outer;
}
}
}
if (!toFilter.isEmpty()) {
PlanNode postFilter = RelationalPlanner.createSelectNode(CompoundCriteria.combineCriteria(toFilter), false);
ElementCollectorVisitor.getElements(toFilter, select);
postFilter.setProperty(Info.OUTPUT_COLS, new ArrayList<Expression>(query.getSelect().getProjectedSymbols()));
if (accessNode.getParent() != null) {
accessNode.addAsParent(postFilter);
} else {
plan = postFilter;
postFilter.addFirstChild(accessNode);
}
if (select.size() != query.getSelect().getProjectedSymbols().size()) {
// correct projection
query.getSelect().setSymbols(select);
accessNode.setProperty(Info.OUTPUT_COLS, new ArrayList<Expression>(select));
}
}
}
}
// find all pushdown functions in evaluatable locations and mark them to be evaluated by the source
LanguageVisitor lv = new LanguageVisitor() {
@Override
public void visit(Function f) {
FunctionDescriptor fd = f.getFunctionDescriptor();
if (f.isEval()) {
try {
if (modelId != null && fd.getPushdown() == PushDown.MUST_PUSHDOWN && fd.getMethod() != null && CapabilitiesUtil.isSameConnector(modelId, fd.getMethod().getParent(), metadata, capFinder)) {
f.setEval(false);
} else if (fd.getDeterministic() == Determinism.NONDETERMINISTIC && CapabilitiesUtil.supportsScalarFunction(modelId, f, metadata, capFinder)) {
f.setEval(false);
}
} catch (QueryMetadataException e) {
throw new TeiidRuntimeException(e);
} catch (TeiidComponentException e) {
throw new TeiidRuntimeException(e);
}
}
}
@Override
public void visit(SubqueryFromClause obj) {
PreOrPostOrderNavigator.doVisit(obj.getCommand(), this, true);
}
@Override
public void visit(WithQueryCommand obj) {
PreOrPostOrderNavigator.doVisit(obj.getCommand(), this, true);
}
};
PreOrPostOrderNavigator.doVisit(queryCommand, lv, true);
plan = addDistinct(metadata, capFinder, accessNode, plan, queryCommand, capFinder);
command = queryCommand;
queryCommand.setSourceHint((SourceHint) accessNode.getProperty(Info.SOURCE_HINT));
queryCommand.getProjectedQuery().setSourceHint((SourceHint) accessNode.getProperty(Info.SOURCE_HINT));
if (intoGroup != null) {
Insert insertCommand = (Insert) commandRoot.getParent().getProperty(NodeConstants.Info.VIRTUAL_COMMAND);
if (insertCommand == null) {
// TODO: this is probably no longer needed as we rewrite select into
insertCommand = new Insert(intoGroup, ResolverUtil.resolveElementsInGroup(intoGroup, metadata), null);
}
insertCommand.setQueryExpression(queryCommand);
command = insertCommand;
}
}
if (command != null) {
accessNode.setProperty(NodeConstants.Info.ATOMIC_REQUEST, command);
}
accessNode.removeAllChildren();
}
return plan;
}
use of org.teiid.core.TeiidComponentException in project teiid by teiid.
the class RuleCollapseSource method processOrderBy.
private void processOrderBy(PlanNode node, QueryCommand query, Object modelID, CommandContext context, CapabilitiesFinder capFinder) throws QueryMetadataException, TeiidComponentException {
boolean userOrdering = NodeEditor.findParent(node, NodeConstants.Types.JOIN | NodeConstants.Types.SOURCE) == null;
OrderBy orderBy = (OrderBy) node.getProperty(NodeConstants.Info.SORT_ORDER);
query.setOrderBy(orderBy);
if (query instanceof Query) {
List<Expression> cols = query.getProjectedSymbols();
List<Expression> exprs = new ArrayList<Expression>(cols.size());
for (Expression expr : cols) {
exprs.add(SymbolMap.getExpression(expr));
}
for (OrderByItem item : orderBy.getOrderByItems()) {
item.setExpressionPosition(exprs.indexOf(SymbolMap.getExpression(item.getSymbol())));
}
try {
QueryRewriter.rewriteOrderBy(query, orderBy, query.getProjectedSymbols(), context, context.getMetadata());
} catch (TeiidProcessingException e) {
throw new TeiidComponentException(e);
}
}
boolean supportsNullOrdering = CapabilitiesUtil.supports(Capability.QUERY_ORDERBY_NULL_ORDERING, modelID, context.getMetadata(), capFinder);
NullOrder defaultNullOrder = CapabilitiesUtil.getDefaultNullOrder(modelID, context.getMetadata(), capFinder);
for (OrderByItem item : orderBy.getOrderByItems()) {
if (item.getNullOrdering() != null) {
if (!supportsNullOrdering) {
item.setNullOrdering(null);
}
} else if (userOrdering && supportsNullOrdering && defaultNullOrder != context.getOptions().getDefaultNullOrder() && context.getOptions().isPushdownDefaultNullOrder()) {
// try to match the expected default
if (item.isAscending()) {
if (context.getOptions().getDefaultNullOrder() == NullOrder.FIRST || context.getOptions().getDefaultNullOrder() == NullOrder.LOW) {
if (defaultNullOrder != NullOrder.FIRST && defaultNullOrder != NullOrder.LOW) {
item.setNullOrdering(NullOrdering.FIRST);
}
} else {
if (defaultNullOrder != NullOrder.LAST && defaultNullOrder != NullOrder.HIGH) {
item.setNullOrdering(NullOrdering.LAST);
}
}
} else {
if (context.getOptions().getDefaultNullOrder() == NullOrder.LAST || context.getOptions().getDefaultNullOrder() == NullOrder.LOW) {
if (defaultNullOrder != NullOrder.LAST && defaultNullOrder != NullOrder.LOW) {
item.setNullOrdering(NullOrdering.LAST);
}
} else {
if (defaultNullOrder != NullOrder.FIRST && defaultNullOrder != NullOrder.HIGH) {
item.setNullOrdering(NullOrdering.FIRST);
}
}
}
}
}
}
use of org.teiid.core.TeiidComponentException in project teiid by teiid.
the class CriteriaCapabilityValidatorVisitor method canPushLanguageObject.
public static boolean canPushLanguageObject(LanguageObject obj, Object modelID, final QueryMetadataInterface metadata, CapabilitiesFinder capFinder, AnalysisRecord analysisRecord, boolean isJoin, boolean isSelectClause, final boolean multiValuedReferences) throws QueryMetadataException, TeiidComponentException {
if (obj == null) {
return true;
}
if (modelID == null || metadata.isVirtualModel(modelID)) {
// Couldn't determine model ID, so give up
return false;
}
String modelName = metadata.getFullName(modelID);
SourceCapabilities caps = capFinder.findCapabilities(modelName);
if (caps == null) {
// this doesn't seem right, but tests were expecting it...
return true;
}
CriteriaCapabilityValidatorVisitor visitor = new CriteriaCapabilityValidatorVisitor(modelID, metadata, capFinder, caps);
visitor.setCheckEvaluation(!multiValuedReferences);
visitor.analysisRecord = analysisRecord;
visitor.isJoin = isJoin;
visitor.isSelectClause = isSelectClause;
// we use an array to represent multiple comparision attributes,
// but we don't want that to inhibit pushdown as we'll account for that later
// in criteria processing
final EvaluatableVisitor ev = new EvaluatableVisitor(modelID, metadata, capFinder);
PreOrPostOrderNavigator nav = new PreOrPostOrderNavigator(visitor, PreOrPostOrderNavigator.POST_ORDER, false) {
@Override
public void visit(DependentSetCriteria obj1) {
if (obj1.hasMultipleAttributes()) {
Array array = (Array) obj1.getExpression();
visitNodes(array.getExpressions());
super.postVisitVisitor(obj1);
} else {
super.visit(obj1);
}
}
@Override
protected void visitNode(LanguageObject obj) {
if (obj == null) {
return;
}
Determinism d = ev.getDeterminismLevel();
boolean pushDown = ev.requiresEvaluation(EvaluationLevel.PUSH_DOWN);
// decend with clean state, then restore
ev.reset();
super.visitNode(obj);
ev.setDeterminismLevel(d);
if (pushDown) {
ev.evaluationNotPossible(EvaluationLevel.PUSH_DOWN);
}
}
@Override
protected void visitVisitor(LanguageObject obj) {
if (obj == null) {
return;
}
if (!ev.requiresEvaluation(EvaluationLevel.PUSH_DOWN) && ev.getDeterminismLevel() != Determinism.NONDETERMINISTIC) {
if (obj instanceof ElementSymbol) {
ElementSymbol es = (ElementSymbol) obj;
if (es.getMetadataID() != null) {
try {
if (metadata.isMultiSourceElement(es.getMetadataID())) {
// no need to visit
return;
}
} catch (QueryMetadataException e) {
} catch (TeiidComponentException e) {
}
}
}
obj.acceptVisitor(ev);
if (!multiValuedReferences && obj instanceof Expression) {
if (obj instanceof Function) {
if (!(obj instanceof AggregateSymbol)) {
Function f = (Function) obj;
if (f.getFunctionDescriptor().getPushdown() != PushDown.MUST_PUSHDOWN && f.getFunctionDescriptor().getDeterministic() != Determinism.NONDETERMINISTIC) {
// don't need to consider
return;
}
}
} else if (obj instanceof Criteria && !(obj instanceof SubqueryContainer) && !(obj instanceof DependentSetCriteria)) {
// don't need to consider
return;
}
}
}
super.visitVisitor(obj);
}
};
obj.acceptVisitor(nav);
if (visitor.getException() != null) {
throw visitor.getException();
}
return visitor.isValid();
}
Aggregations