use of org.teiid.query.sql.lang.OrderByItem in project teiid by teiid.
the class AccessNode method minimizeProject.
public void minimizeProject(Command atomicCommand) {
if (!(atomicCommand instanceof Query)) {
return;
}
Query query = (Query) atomicCommand;
Select select = query.getSelect();
List<Expression> symbols = select.getSymbols();
if (symbols.size() == 1) {
return;
}
boolean shouldProject = false;
LinkedHashMap<Expression, Integer> uniqueSymbols = new LinkedHashMap<Expression, Integer>();
projection = new Object[symbols.size()];
this.originalSelect = new ArrayList<Expression>(query.getSelect().getSymbols());
int i = 0;
int j = 0;
for (Iterator<Expression> iter = symbols.iterator(); iter.hasNext(); ) {
Expression ss = iter.next();
Expression ex = SymbolMap.getExpression(ss);
if (ex instanceof Constant) {
projection[i] = ex;
if (iter.hasNext() || j != 0) {
iter.remove();
shouldProject = true;
} else {
projection[i] = j++;
}
} else {
Integer index = uniqueSymbols.get(ex);
if (index == null) {
uniqueSymbols.put(ex, j);
index = j++;
} else {
iter.remove();
shouldProject = true;
}
projection[i] = index;
}
i++;
}
if (!shouldProject) {
this.projection = NO_PROJECTION;
} else if (query.getOrderBy() != null) {
for (OrderByItem item : query.getOrderBy().getOrderByItems()) {
Integer index = uniqueSymbols.get(SymbolMap.getExpression(item.getSymbol()));
if (index != null) {
item.setExpressionPosition(index);
item.setSymbol(select.getSymbols().get(index));
}
}
}
}
use of org.teiid.query.sql.lang.OrderByItem in project teiid by teiid.
the class GroupingNode method initAccumulator.
static AggregateFunction initAccumulator(AggregateSymbol aggSymbol, RelationalNode node, LinkedHashMap<Expression, Integer> expressionIndexes) {
int[] argIndexes = new int[aggSymbol.getArgs().length];
AggregateFunction result = null;
Expression[] args = aggSymbol.getArgs();
Class<?>[] inputTypes = new Class[args.length];
for (int j = 0; j < args.length; j++) {
inputTypes[j] = args[j].getType();
argIndexes[j] = getIndex(args[j], expressionIndexes);
}
Type function = aggSymbol.getAggregateFunction();
switch(function) {
case RANK:
case DENSE_RANK:
result = new RankingFunction(function);
break;
// same as count(*)
case ROW_NUMBER:
case COUNT:
result = new Count();
break;
case SUM:
result = new Sum();
break;
case AVG:
result = new Avg();
break;
case MIN:
result = new Min();
break;
case MAX:
result = new Max();
break;
case XMLAGG:
result = new XMLAgg();
break;
case ARRAY_AGG:
result = new ArrayAgg();
break;
case JSONARRAY_AGG:
result = new JSONArrayAgg();
break;
case TEXTAGG:
result = new TextAgg((TextLine) args[0]);
break;
case STRING_AGG:
result = new StringAgg(aggSymbol.getType() == DataTypeManager.DefaultDataClasses.BLOB);
break;
case FIRST_VALUE:
result = new FirstLastValue(aggSymbol.getType(), true);
break;
case LAST_VALUE:
result = new FirstLastValue(aggSymbol.getType(), false);
break;
case LEAD:
case LAG:
result = new LeadLagValue();
break;
case USER_DEFINED:
try {
result = new UserDefined(aggSymbol.getFunctionDescriptor());
} catch (FunctionExecutionException e) {
throw new TeiidRuntimeException(e);
}
break;
default:
result = new StatsFunction(function);
}
if (aggSymbol.getOrderBy() != null) {
int numOrderByItems = aggSymbol.getOrderBy().getOrderByItems().size();
List<OrderByItem> orderByItems = new ArrayList<OrderByItem>(numOrderByItems);
List<ElementSymbol> schema = createSortSchema(result, inputTypes);
argIndexes = Arrays.copyOf(argIndexes, argIndexes.length + numOrderByItems);
for (ListIterator<OrderByItem> iterator = aggSymbol.getOrderBy().getOrderByItems().listIterator(); iterator.hasNext(); ) {
OrderByItem item = iterator.next();
argIndexes[args.length + iterator.previousIndex()] = getIndex(item.getSymbol(), expressionIndexes);
ElementSymbol element = new ElementSymbol(String.valueOf(iterator.previousIndex()));
element.setType(item.getSymbol().getType());
schema.add(element);
OrderByItem newItem = item.clone();
newItem.setSymbol(element);
orderByItems.add(newItem);
}
SortingFilter filter = new SortingFilter(result, node.getBufferManager(), node.getConnectionID(), aggSymbol.isDistinct());
filter.setElements(schema);
filter.setSortItems(orderByItems);
result = filter;
} else if (aggSymbol.isDistinct()) {
SortingFilter filter = new SortingFilter(result, node.getBufferManager(), node.getConnectionID(), true);
List<ElementSymbol> elements = createSortSchema(result, inputTypes);
filter.setElements(elements);
result = filter;
}
result.setArgIndexes(argIndexes);
if (aggSymbol.getCondition() != null) {
result.setConditionIndex(getIndex(aggSymbol.getCondition(), expressionIndexes));
}
result.initialize(aggSymbol.getType(), inputTypes);
return result;
}
use of org.teiid.query.sql.lang.OrderByItem in project teiid by teiid.
the class GroupingNode method initialize.
@Override
public void initialize(CommandContext context, BufferManager bufferManager, ProcessorDataManager dataMgr) {
super.initialize(context, bufferManager, dataMgr);
if (this.functions != null) {
return;
}
// Incoming elements and lookup map for evaluating expressions
List<? extends Expression> sourceElements = this.getChildren()[0].getElements();
this.elementMap = createLookupMap(sourceElements);
this.collectedExpressions = new LinkedHashMap<Expression, Integer>();
// List should contain all grouping columns / expressions as we need those for sorting
if (this.orderBy != null) {
for (OrderByItem item : this.orderBy) {
Expression ex = SymbolMap.getExpression(item.getSymbol());
getIndex(ex, this.collectedExpressions);
}
if (removeDuplicates) {
for (Expression ses : sourceElements) {
getIndex(ses, collectedExpressions);
}
distinctCols = collectedExpressions.size();
}
}
// Construct aggregate function state accumulators
functions = new AggregateFunction[getElements().size()][];
for (int i = 0; i < getElements().size(); i++) {
Expression symbol = getElements().get(i);
if (this.outputMapping != null) {
symbol = outputMapping.getMappedExpression((ElementSymbol) symbol);
}
Class<?> outputType = symbol.getType();
if (symbol instanceof AggregateSymbol) {
AggregateSymbol aggSymbol = (AggregateSymbol) symbol;
functions[i] = new AggregateFunction[rollup ? orderBy.size() + 1 : 1];
for (int j = 0; j < functions[i].length; j++) {
functions[i][j] = initAccumulator(aggSymbol, this, this.collectedExpressions);
}
} else {
AggregateFunction af = new ConstantFunction();
af.setArgIndexes(new int[] { this.collectedExpressions.get(symbol) });
af.initialize(outputType, new Class<?>[] { symbol.getType() });
functions[i] = new AggregateFunction[] { af };
}
}
}
use of org.teiid.query.sql.lang.OrderByItem in project teiid by teiid.
the class BaseIndexInfo method useIndexForOrderBy.
/**
* Return a non-null direction if the index can be used, otherwise null.
* @param orderBy
* @return
*/
private Boolean useIndexForOrderBy(OrderBy orderBy) {
Boolean direction = null;
int size = orderBy.getOrderByItems().size();
if (size > table.getPkLength()) {
return null;
}
for (int i = 0; i < size; i++) {
OrderByItem item = orderBy.getOrderByItems().get(i);
if (!Boolean.TRUE.equals(table.matchesPkColumn(i, item.getSymbol())) || !table.supportsOrdering(i, item.getSymbol())) {
return null;
}
if (item.getNullOrdering() != null && ((item.isAscending() && item.getNullOrdering() == NullOrdering.LAST) || (!item.isAscending() && item.getNullOrdering() == NullOrdering.FIRST))) {
// assumes nulls low
return null;
}
if (item.isAscending()) {
if (direction == null) {
direction = OrderBy.ASC;
} else if (direction != OrderBy.ASC) {
return null;
}
} else if (direction == null) {
direction = OrderBy.DESC;
} else if (direction != OrderBy.DESC) {
return null;
}
}
return direction;
}
use of org.teiid.query.sql.lang.OrderByItem in project teiid by teiid.
the class RuleMergeVirtual method doMerge.
static PlanNode doMerge(PlanNode frame, PlanNode root, boolean beforeDecomposeJoin, QueryMetadataInterface metadata, CapabilitiesFinder capFinder) throws QueryPlannerException, QueryMetadataException, TeiidComponentException {
if (frame.hasBooleanProperty(Info.NO_UNNEST)) {
return root;
}
GroupSymbol virtualGroup = frame.getGroups().iterator().next();
// check to see if frame represents a proc relational query.
if (virtualGroup.isProcedure()) {
return root;
}
List<PlanNode> sources = NodeEditor.findAllNodes(frame.getFirstChild(), NodeConstants.Types.SOURCE, NodeConstants.Types.SOURCE);
SymbolMap references = (SymbolMap) frame.getProperty(NodeConstants.Info.CORRELATED_REFERENCES);
if (references != null) {
if (!sources.isEmpty()) {
// correlated nested table commands should not be merged
return root;
}
// this is ok only if all of the references go above the correlating join
// currently this check is simplistic - just look at the parent join more nested scenarios won't work
PlanNode parentJoin = NodeEditor.findParent(frame, NodeConstants.Types.JOIN, NodeConstants.Types.SOURCE | NodeConstants.Types.GROUP);
if (parentJoin != null && !parentJoin.getGroups().containsAll(GroupsUsedByElementsVisitor.getGroups(references.getValues()))) {
return root;
}
}
PlanNode parentProject = NodeEditor.findParent(frame, NodeConstants.Types.PROJECT);
// Check whether the upper frame is a SELECT INTO
if (parentProject.getProperty(NodeConstants.Info.INTO_GROUP) != null) {
return root;
}
if (!FrameUtil.canConvertAccessPatterns(frame)) {
return root;
}
PlanNode projectNode = frame.getFirstChild();
// Check if lower frame has only a stored procedure execution - this cannot be merged to parent frame
if (FrameUtil.isProcedure(projectNode)) {
return root;
}
SymbolMap symbolMap = (SymbolMap) frame.getProperty(NodeConstants.Info.SYMBOL_MAP);
PlanNode sortNode = NodeEditor.findParent(parentProject, NodeConstants.Types.SORT, NodeConstants.Types.SOURCE);
if (sortNode != null && sortNode.hasBooleanProperty(NodeConstants.Info.UNRELATED_SORT)) {
OrderBy sortOrder = (OrderBy) sortNode.getProperty(NodeConstants.Info.SORT_ORDER);
boolean unrelated = false;
for (OrderByItem item : sortOrder.getOrderByItems()) {
if (!item.isUnrelated()) {
continue;
}
Collection<ElementSymbol> elements = ElementCollectorVisitor.getElements(item.getSymbol(), true);
for (ElementSymbol elementSymbol : elements) {
if (virtualGroup.equals(elementSymbol.getGroupSymbol())) {
unrelated = true;
}
}
}
// the lower frame cannot contain DUP_REMOVE, GROUP, UNION if unrelated
if (unrelated && NodeEditor.findNodePreOrder(frame, NodeConstants.Types.DUP_REMOVE, NodeConstants.Types.PROJECT) != null || NodeEditor.findNodePreOrder(frame, NodeConstants.Types.SET_OP, NodeConstants.Types.SOURCE) != null || NodeEditor.findNodePreOrder(frame, NodeConstants.Types.GROUP, NodeConstants.Types.SOURCE) != null) {
return root;
}
}
PlanNode parentJoin = NodeEditor.findParent(frame, NodeConstants.Types.JOIN, NodeConstants.Types.SOURCE | NodeConstants.Types.GROUP);
// 3. if the frame has no sources
if (projectNode.getType() != NodeConstants.Types.PROJECT || NodeEditor.findNodePreOrder(frame.getFirstChild(), NodeConstants.Types.GROUP, NodeConstants.Types.SOURCE | NodeConstants.Types.JOIN) != null || sources.isEmpty()) {
PlanNode parentSource = NodeEditor.findParent(parentProject, NodeConstants.Types.SOURCE);
if (beforeDecomposeJoin && parentSource != null && parentSource.hasProperty(Info.PARTITION_INFO) && !NodeEditor.findAllNodes(frame.getFirstChild(), NodeConstants.Types.SET_OP, NodeConstants.Types.SOURCE).isEmpty()) {
// don't bother to merge until after
return root;
}
root = checkForSimpleProjection(frame, root, parentProject, metadata, capFinder);
if (frame.getParent() == null || !sources.isEmpty() || projectNode.getType() != NodeConstants.Types.PROJECT || parentJoin == null) {
// only consider no sources when the frame is simple and there is a parent join
return root;
}
if (sources.isEmpty() && parentJoin != null) {
JoinType jt = (JoinType) parentJoin.getProperty(Info.JOIN_TYPE);
if (jt.isOuter()) {
// cannot remove if the no source side is an outer side, or if it can change the meaning of the plan
return root;
}
PlanNode joinToTest = parentJoin;
while (joinToTest != null) {
if (FrameUtil.findJoinSourceNode(joinToTest.getFirstChild()).getGroups().contains(virtualGroup)) {
// scan all sources under the other side as there could be a join structure
for (PlanNode node : NodeEditor.findAllNodes(joinToTest.getLastChild(), NodeConstants.Types.SOURCE, NodeConstants.Types.SOURCE)) {
SymbolMap map = (SymbolMap) node.getProperty(NodeConstants.Info.CORRELATED_REFERENCES);
if (map != null && GroupsUsedByElementsVisitor.getGroups(map.getValues()).contains(virtualGroup)) {
// TODO: we don't have the logic yet to then replace the correlated references
return root;
}
}
}
joinToTest = NodeEditor.findParent(joinToTest, NodeConstants.Types.JOIN, NodeConstants.Types.SOURCE | NodeConstants.Types.GROUP);
}
}
}
if (!checkJoinCriteria(frame.getFirstChild(), virtualGroup, parentJoin)) {
return root;
}
// we don't have to check for null dependent with no source without criteria since there must be a row
if (!checkProjectedSymbols(projectNode, virtualGroup, parentJoin, metadata, sources, !sources.isEmpty() || frame.getParent() != parentJoin, parentProject)) {
// TODO: propagate constants if just inhibited by subquery/non-deterministic expressions
return root;
}
// Otherwise merge should work
// Convert parent frame before merge
Set<GroupSymbol> groups = Collections.emptySet();
if (!sources.isEmpty()) {
groups = FrameUtil.findJoinSourceNode(projectNode).getGroups();
} else if (references != null) {
// convert from correlated form to regular references
RuleMergeCriteria.ReferenceReplacementVisitor rrv = new RuleMergeCriteria.ReferenceReplacementVisitor(references);
for (Map.Entry<ElementSymbol, Expression> entry : symbolMap.asUpdatableMap().entrySet()) {
if (entry.getValue() instanceof Reference) {
Expression ex = rrv.replaceExpression(entry.getValue());
entry.setValue(ex);
} else {
PreOrPostOrderNavigator.doVisit(entry.getValue(), rrv, PreOrPostOrderNavigator.PRE_ORDER);
}
}
}
FrameUtil.convertFrame(frame, virtualGroup, groups, symbolMap.asMap(), metadata);
PlanNode parentBottom = frame.getParent();
prepareFrame(frame);
if (sources.isEmpty() && parentJoin != null) {
// special handling for no sources
PlanNode parent = frame;
List<PlanNode> criteriaNodes = new ArrayList<PlanNode>();
while (parent.getParent() != parentJoin) {
parent = parent.getParent();
if (!parent.hasBooleanProperty(Info.IS_PHANTOM)) {
criteriaNodes.add(parent);
}
}
PlanNode parentNode = parentJoin.getParent();
parentJoin.removeChild(parent);
PlanNode other = parentJoin.getFirstChild();
NodeEditor.removeChildNode(parentNode, parentJoin);
JoinType jt = (JoinType) parentJoin.getProperty(Info.JOIN_TYPE);
if (!jt.isOuter()) {
// if we are not an outer join then the join/parent criteria is effectively
// applied to the other side
List<Criteria> joinCriteria = (List<Criteria>) parentJoin.getProperty(Info.JOIN_CRITERIA);
if (joinCriteria != null) {
for (Criteria crit : joinCriteria) {
PlanNode critNode = RelationalPlanner.createSelectNode(crit, false);
criteriaNodes.add(critNode);
}
}
if (!criteriaNodes.isEmpty()) {
for (PlanNode selectNode : criteriaNodes) {
selectNode.removeAllChildren();
selectNode.removeFromParent();
other.addAsParent(selectNode);
}
}
}
} else {
// Remove top 2 nodes (SOURCE, PROJECT) of virtual group - they're no longer needed
NodeEditor.removeChildNode(parentBottom, frame);
NodeEditor.removeChildNode(parentBottom, projectNode);
}
return root;
}
Aggregations