use of org.teiid.query.sql.symbol.ExpressionSymbol in project teiid by teiid.
the class TempMetadataStore method createElementSymbol.
private TempMetadataID createElementSymbol(String tempName, Expression symbol, boolean isTempTable) {
// Create new element name
String elementName = tempName + Symbol.SEPARATOR + Symbol.getShortName(symbol);
Object metadataID = null;
if (symbol instanceof AliasSymbol) {
AliasSymbol as = (AliasSymbol) symbol;
symbol = as.getSymbol();
}
// the following allows for original metadata ids to be determined for proc inputs
if (symbol instanceof ExpressionSymbol) {
Expression expr = ((ExpressionSymbol) symbol).getExpression();
if (expr instanceof Reference) {
expr = ((Reference) expr).getExpression();
}
if (expr instanceof ElementSymbol) {
symbol = expr;
}
}
if (symbol instanceof ElementSymbol) {
metadataID = ((ElementSymbol) symbol).getMetadataID();
}
while (metadataID != null && metadataID instanceof TempMetadataID) {
metadataID = ((TempMetadataID) metadataID).getOriginalMetadataID();
}
TempMetadataID elementID = new TempMetadataID(elementName, symbol.getType(), metadataID);
elementID.setTempTable(isTempTable);
return elementID;
}
use of org.teiid.query.sql.symbol.ExpressionSymbol in project teiid by teiid.
the class RuleMergeVirtual method checkForSimpleProjection.
/**
* Removes source layers that only do a simple projection of the elements below.
* @param capFinder
* @throws TeiidComponentException
* @throws QueryMetadataException
* @throws QueryPlannerException
*/
private static PlanNode checkForSimpleProjection(PlanNode frame, PlanNode root, PlanNode parentProject, QueryMetadataInterface metadata, CapabilitiesFinder capFinder) throws QueryMetadataException, TeiidComponentException, QueryPlannerException {
// check that the parent only performs projection
PlanNode nodeToCheck = parentProject.getFirstChild();
while (nodeToCheck != frame) {
if (nodeToCheck.getType() != NodeConstants.Types.SELECT || !nodeToCheck.hasBooleanProperty(NodeConstants.Info.IS_PHANTOM)) {
return root;
}
nodeToCheck = nodeToCheck.getFirstChild();
}
if (frame.getFirstChild().getType() == NodeConstants.Types.TUPLE_LIMIT && NodeEditor.findParent(parentProject, NodeConstants.Types.SORT | NodeConstants.Types.DUP_REMOVE, NodeConstants.Types.SOURCE | NodeConstants.Types.SET_OP) != null) {
return root;
}
List<? extends Expression> requiredElements = RuleAssignOutputElements.determineSourceOutput(frame, new ArrayList<Expression>(), metadata, null);
List<Expression> selectSymbols = (List<Expression>) parentProject.getProperty(NodeConstants.Info.PROJECT_COLS);
// check that it only performs simple projection and that all required symbols are projected
// ensuring there are no duplicates prevents problems with subqueries
LinkedHashSet<Expression> symbols = new LinkedHashSet<Expression>();
for (Expression symbol : selectSymbols) {
Expression expr = SymbolMap.getExpression(symbol);
if (expr instanceof Constant) {
if (!symbols.add(new ExpressionSymbol("const" + symbols.size(), expr))) {
// $NON-NLS-1$
return root;
}
continue;
}
if (!(expr instanceof ElementSymbol)) {
return root;
}
requiredElements.remove(expr);
if (!symbols.add(expr)) {
return root;
}
}
if (!requiredElements.isEmpty()) {
return root;
}
PlanNode sort = NodeEditor.findParent(parentProject, NodeConstants.Types.SORT, NodeConstants.Types.SOURCE);
if (sort != null && sort.hasBooleanProperty(Info.UNRELATED_SORT)) {
return root;
}
// re-order the lower projects
RuleAssignOutputElements.filterVirtualElements(frame, new ArrayList<Expression>(symbols), metadata);
// remove phantom select nodes
nodeToCheck = parentProject.getFirstChild();
while (nodeToCheck != frame) {
PlanNode current = nodeToCheck;
nodeToCheck = nodeToCheck.getFirstChild();
NodeEditor.removeChildNode(current.getParent(), current);
}
if (NodeEditor.findParent(parentProject, NodeConstants.Types.DUP_REMOVE, NodeConstants.Types.SOURCE) != null) {
PlanNode lowerDup = NodeEditor.findNodePreOrder(frame.getFirstChild(), NodeConstants.Types.DUP_REMOVE, NodeConstants.Types.PROJECT);
if (lowerDup != null) {
NodeEditor.removeChildNode(lowerDup.getParent(), lowerDup);
}
PlanNode setOp = NodeEditor.findNodePreOrder(frame.getFirstChild(), NodeConstants.Types.SET_OP, NodeConstants.Types.SOURCE);
if (setOp != null) {
setOp.setProperty(NodeConstants.Info.USE_ALL, Boolean.FALSE);
distributeDupRemove(metadata, capFinder, setOp);
if (parentProject.getParent().getParent() != null) {
NodeEditor.removeChildNode(parentProject.getParent().getParent(), parentProject.getParent());
} else {
parentProject.removeFromParent();
root = parentProject;
}
}
}
correctOrderBy(frame, sort, selectSymbols, parentProject);
PlanNode parentSource = NodeEditor.findParent(frame, NodeConstants.Types.SOURCE);
if (parentSource != null && NodeEditor.findNodePreOrder(parentSource, NodeConstants.Types.PROJECT) == parentProject) {
FrameUtil.correctSymbolMap(((SymbolMap) frame.getProperty(NodeConstants.Info.SYMBOL_MAP)).asMap(), parentSource);
}
prepareFrame(frame);
// remove the parent project and the source node
NodeEditor.removeChildNode(parentProject, frame);
if (parentProject.getParent() == null) {
root = parentProject.getFirstChild();
parentProject.removeChild(root);
return root;
}
NodeEditor.removeChildNode(parentProject.getParent(), parentProject);
return root;
}
use of org.teiid.query.sql.symbol.ExpressionSymbol in project teiid by teiid.
the class RulePlanSorts method checkForProjectOptimization.
static PlanNode checkForProjectOptimization(PlanNode node, PlanNode root, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, AnalysisRecord record, CommandContext context) throws QueryMetadataException, TeiidComponentException, QueryPlannerException {
PlanNode projectNode = node.getFirstChild();
PlanNode parent = node.getParent();
boolean raiseAccess = false;
// special check for unrelated order by compensation
if (projectNode.getType() == NodeConstants.Types.ACCESS && RuleRaiseAccess.canRaiseOverSort(projectNode, metadata, capFinder, node, record, true, context)) {
projectNode = NodeEditor.findNodePreOrder(projectNode, NodeConstants.Types.PROJECT, NodeConstants.Types.SOURCE | NodeConstants.Types.SET_OP);
if (projectNode == null) {
// no interviening project
return root;
}
raiseAccess = true;
} else if (projectNode.getType() == NodeConstants.Types.PROJECT && projectNode.getFirstChild() != null) {
raiseAccess = projectNode.getFirstChild().getType() == NodeConstants.Types.ACCESS && RuleRaiseAccess.canRaiseOverSort(projectNode.getFirstChild(), metadata, capFinder, node, record, false, context);
// if we can't raise the access node and this doesn't have a limit, there's no point in optimizing
if (!raiseAccess && (parent == null || parent.getType() != NodeConstants.Types.TUPLE_LIMIT)) {
return root;
}
} else {
return root;
}
List<Expression> childOutputCols = (List<Expression>) projectNode.getFirstChild().getProperty(Info.OUTPUT_COLS);
OrderBy orderBy = (OrderBy) node.getProperty(Info.SORT_ORDER);
List<Expression> orderByKeys = orderBy.getSortKeys();
LinkedHashSet<Expression> toProject = new LinkedHashSet();
for (Expression ss : orderByKeys) {
Expression original = ss;
if (ss instanceof AliasSymbol) {
ss = ((AliasSymbol) ss).getSymbol();
}
if (ss instanceof ExpressionSymbol) {
if (!raiseAccess) {
// TODO: insert a new project node to handle this case
return root;
}
}
if (!childOutputCols.contains(ss)) {
if (!raiseAccess) {
return root;
}
toProject.add(original);
}
}
PlanNode toRepair = projectNode.getParent();
if (!toProject.isEmpty()) {
PlanNode intermediateProject = NodeFactory.getNewNode(NodeConstants.Types.PROJECT);
toProject.addAll(childOutputCols);
List<Expression> projectCols = new ArrayList<Expression>(toProject);
childOutputCols = projectCols;
intermediateProject.setProperty(NodeConstants.Info.PROJECT_COLS, projectCols);
intermediateProject.setProperty(NodeConstants.Info.OUTPUT_COLS, new ArrayList<Expression>(projectCols));
toRepair.getFirstChild().addAsParent(intermediateProject);
}
NodeEditor.removeChildNode(projectNode.getParent(), projectNode);
if (parent != null && parent.getType() == NodeConstants.Types.TUPLE_LIMIT && parent.getParent() != null) {
parent.addAsParent(projectNode);
} else {
if (parent == null) {
root = projectNode;
}
if (parent != null && parent.getType() == NodeConstants.Types.TUPLE_LIMIT) {
if (root == parent) {
root = projectNode;
}
projectNode.addFirstChild(parent);
} else {
projectNode.addFirstChild(node);
}
}
List<Expression> orderByOutputSymbols = (List<Expression>) node.getProperty(Info.OUTPUT_COLS);
boolean unrelated = false;
if (node.hasBooleanProperty(Info.UNRELATED_SORT)) {
node.setProperty(Info.UNRELATED_SORT, false);
unrelated = true;
}
for (OrderByItem item : orderBy.getOrderByItems()) {
if (unrelated || !toProject.isEmpty()) {
// update sort order
int index = childOutputCols.indexOf(item.getSymbol());
item.setExpressionPosition(index);
}
if (toProject.isEmpty()) {
// strip alias as project was raised
if (item.getSymbol() instanceof AliasSymbol) {
item.setSymbol(((AliasSymbol) item.getSymbol()).getSymbol());
}
}
}
while (toRepair != node) {
toRepair.setProperty(Info.OUTPUT_COLS, childOutputCols);
toRepair = toRepair.getParent();
}
projectNode.setProperty(Info.OUTPUT_COLS, orderByOutputSymbols);
projectNode.setProperty(Info.PROJECT_COLS, orderByOutputSymbols);
node.setProperty(Info.OUTPUT_COLS, childOutputCols);
if (parent != null) {
parent.setProperty(Info.OUTPUT_COLS, childOutputCols);
}
if (raiseAccess) {
PlanNode accessNode = NodeEditor.findNodePreOrder(node, NodeConstants.Types.ACCESS);
// instead of just calling ruleraiseaccess, we're more selective
// we do not want to raise the access node over a project that is handling an unrelated sort
PlanNode newRoot = RuleRaiseAccess.raiseAccessNode(root, accessNode, metadata, capFinder, true, record, context);
if (newRoot != null) {
accessNode.setProperty(NodeConstants.Info.OUTPUT_COLS, childOutputCols);
root = newRoot;
if (!toProject.isEmpty()) {
newRoot = RuleRaiseAccess.raiseAccessNode(root, accessNode, metadata, capFinder, true, record, context);
}
if (newRoot != null) {
root = newRoot;
if (accessNode.getParent().getType() == NodeConstants.Types.TUPLE_LIMIT) {
newRoot = RulePushLimit.raiseAccessOverLimit(root, accessNode, metadata, capFinder, accessNode.getParent(), record);
}
if (newRoot != null) {
root = newRoot;
}
}
}
}
return root;
}
use of org.teiid.query.sql.symbol.ExpressionSymbol 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.query.sql.symbol.ExpressionSymbol in project teiid by teiid.
the class TempTable method createTupleSource.
public TupleSource createTupleSource(final List<? extends Expression> projectedCols, final Criteria condition, OrderBy orderBy) throws TeiidComponentException, TeiidProcessingException {
// special handling for count(*)
boolean agg = false;
for (Expression singleElementSymbol : projectedCols) {
if (singleElementSymbol instanceof ExpressionSymbol && ((ExpressionSymbol) singleElementSymbol).getExpression() instanceof AggregateSymbol) {
agg = true;
break;
}
}
if (agg) {
if (condition == null) {
long count = this.getRowCount();
return new CollectionTupleSource(Arrays.asList(Collections.nCopies(projectedCols.size(), (int) Math.min(Integer.MAX_VALUE, count))).iterator());
}
orderBy = null;
}
IndexInfo primary = new IndexInfo(this, projectedCols, condition, orderBy, true);
IndexInfo ii = primary;
if ((indexTables != null || (!this.updatable && allowImplicitIndexing && condition != null && this.getRowCount() > 2 * this.getTree().getPageSize(true))) && (condition != null || orderBy != null) && ii.valueSet.size() != 1) {
// $NON-NLS-1$ //$NON-NLS-2$
LogManager.logDetail(LogConstants.CTX_DQP, "Considering indexes on table", this, "for query", projectedCols, condition, orderBy);
long rowCost = this.tree.getRowCount();
long bestCost = estimateCost(orderBy, ii, rowCost);
if (this.indexTables != null) {
for (TempTable table : this.indexTables.values()) {
IndexInfo secondary = new IndexInfo(table, projectedCols, condition, orderBy, false);
long cost = estimateCost(orderBy, secondary, rowCost);
if (cost < bestCost) {
ii = secondary;
bestCost = cost;
}
}
}
if (ii == primary && allowImplicitIndexing) {
// TODO: detect if it should be covering
if (createImplicitIndexIfNeeded(condition)) {
IndexInfo secondary = new IndexInfo(this.indexTables.values().iterator().next(), projectedCols, condition, orderBy, false);
// $NON-NLS-1$
LogManager.logDetail(LogConstants.CTX_DQP, "Created an implicit index ", secondary.table);
long cost = estimateCost(orderBy, secondary, rowCost);
if (cost < bestCost) {
ii = secondary;
bestCost = cost;
} else {
// $NON-NLS-1$ //$NON-NLS-2$
LogManager.logDetail(LogConstants.CTX_DQP, "Did not utilize the implicit index");
}
}
}
// $NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
LogManager.logDetail(LogConstants.CTX_DQP, "Choose index", ii.table, "covering:", ii.coveredCriteria, "ordering:", ii.ordering);
if (ii.covering) {
return ii.table.createTupleSource(projectedCols, condition, orderBy, ii, agg);
}
List<ElementSymbol> pkColumns = this.columns.subList(0, this.tree.getKeyLength());
if (ii.ordering != null) {
// use order and join
primary.valueTs = ii.table.createTupleSource(pkColumns, ii.coveredCriteria, orderBy, ii, agg);
primary.ordering = null;
return createTupleSource(projectedCols, ii.nonCoveredCriteria, null, primary, agg);
}
// order by pk to localize lookup costs, then join
OrderBy pkOrderBy = new OrderBy();
for (ElementSymbol elementSymbol : pkColumns) {
pkOrderBy.addVariable(elementSymbol);
}
primary.valueTs = ii.table.createTupleSource(pkColumns, ii.coveredCriteria, pkOrderBy, ii, agg);
return createTupleSource(projectedCols, ii.nonCoveredCriteria, orderBy, primary, agg);
}
return createTupleSource(projectedCols, condition, orderBy, ii, agg);
}
Aggregations