use of org.teiid.query.sql.lang.OrderBy in project teiid by teiid.
the class RuleImplementJoinStrategy method createSortNode.
private static PlanNode createSortNode(List<Expression> orderSymbols, Collection<Expression> outputElements) {
PlanNode sortNode = NodeFactory.getNewNode(NodeConstants.Types.SORT);
OrderBy order = new OrderBy(orderSymbols);
sortNode.setProperty(NodeConstants.Info.SORT_ORDER, order);
sortNode.setProperty(NodeConstants.Info.OUTPUT_COLS, new ArrayList<Expression>(outputElements));
return sortNode;
}
use of org.teiid.query.sql.lang.OrderBy in project teiid by teiid.
the class RulePushLimit method pushOrderByAndLimit.
private void pushOrderByAndLimit(PlanNode limitNode, List<PlanNode> limitNodes, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, CommandContext context, PlanNode child, Expression parentLimit, Expression parentOffset, PlanNode branch) throws QueryMetadataException, TeiidComponentException {
// push both the limit and order by
OrderBy parentOrderBy = (OrderBy) child.getProperty(NodeConstants.Info.SORT_ORDER);
PlanNode newSort = NodeFactory.getNewNode(NodeConstants.Types.SORT);
OrderBy newOrderBy = parentOrderBy.clone();
newSort.setProperty(Info.SORT_ORDER, newOrderBy);
newSort.addGroups(child.getGroups());
newSort.setProperty(NodeConstants.Info.OUTPUT_COLS, branch.getProperty(NodeConstants.Info.OUTPUT_COLS));
branch.addAsParent(newSort);
addBranchLimit(limitNode, limitNodes, metadata, parentLimit, parentOffset, newSort);
if (limitNode.hasBooleanProperty(Info.IS_PUSHED)) {
// remove the intermediate ordering/limit
NodeEditor.removeChildNode(limitNode, limitNode.getFirstChild());
NodeEditor.removeChildNode(limitNode.getParent(), limitNode);
}
}
use of org.teiid.query.sql.lang.OrderBy in project teiid by teiid.
the class RulePushLimit method canPushLimit.
private boolean canPushLimit(PlanNode[] rootNode, PlanNode limitNode, List<PlanNode> limitNodes, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, AnalysisRecord record, CommandContext context) throws QueryMetadataException, TeiidComponentException, QueryPlannerException {
PlanNode child = limitNode.getFirstChild();
if (child == null || child.getChildCount() == 0) {
return false;
}
Expression parentLimit = (Expression) limitNode.getProperty(NodeConstants.Info.MAX_TUPLE_LIMIT);
Expression parentOffset = (Expression) limitNode.getProperty(NodeConstants.Info.OFFSET_TUPLE_COUNT);
switch(child.getType()) {
case NodeConstants.Types.TUPLE_LIMIT:
{
// combine the limits
Expression childLimit = (Expression) child.getProperty(NodeConstants.Info.MAX_TUPLE_LIMIT);
Expression childOffset = (Expression) child.getProperty(NodeConstants.Info.OFFSET_TUPLE_COUNT);
combineLimits(limitNode, metadata, parentLimit, parentOffset, childLimit, childOffset);
if (child.hasBooleanProperty(Info.IS_NON_STRICT)) {
limitNode.setProperty(Info.IS_NON_STRICT, true);
}
NodeEditor.removeChildNode(limitNode, child);
limitNodes.remove(child);
return canPushLimit(rootNode, limitNode, limitNodes, metadata, capFinder, record, context);
}
case NodeConstants.Types.SET_OP:
{
if (!canPushToBranches(limitNode, child)) {
return false;
}
// distribute the limit
List<PlanNode> grandChildren = new LinkedList<PlanNode>(child.getChildren());
for (PlanNode grandChild : grandChildren) {
addBranchLimit(limitNode, limitNodes, metadata, parentLimit, parentOffset, grandChild);
}
return false;
}
case NodeConstants.Types.JOIN:
if (parentLimit == null) {
return false;
}
JoinType joinType = (JoinType) child.getProperty(Info.JOIN_TYPE);
boolean pushLeft = false;
boolean pushRight = false;
if (joinType == JoinType.JOIN_CROSS) {
pushLeft = true;
pushRight = true;
} else if (joinType == JoinType.JOIN_LEFT_OUTER || joinType == JoinType.JOIN_FULL_OUTER) {
// we're allowed to do this based upon two conditions
// 1 - we're not going to further change the join type/structure
// 2 - outer results will be produced using the left product first
pushLeft = true;
}
if (pushLeft && !FrameUtil.findJoinSourceNode(child.getLastChild()).hasProperty(NodeConstants.Info.CORRELATED_REFERENCES)) {
PlanNode newLimit = newLimit(limitNode);
newLimit.setProperty(NodeConstants.Info.MAX_TUPLE_LIMIT, op(SourceSystemFunctions.ADD_OP, parentLimit, parentOffset, metadata.getFunctionLibrary()));
child.getFirstChild().addAsParent(newLimit);
newLimit.setProperty(NodeConstants.Info.OUTPUT_COLS, newLimit.getFirstChild().getProperty(NodeConstants.Info.OUTPUT_COLS));
limitNodes.add(newLimit);
}
if (pushRight) {
PlanNode newLimit = newLimit(limitNode);
newLimit.setProperty(NodeConstants.Info.MAX_TUPLE_LIMIT, op(SourceSystemFunctions.ADD_OP, parentLimit, parentOffset, metadata.getFunctionLibrary()));
child.getLastChild().addAsParent(newLimit);
newLimit.setProperty(NodeConstants.Info.OUTPUT_COLS, newLimit.getFirstChild().getProperty(NodeConstants.Info.OUTPUT_COLS));
limitNodes.add(newLimit);
}
return false;
case NodeConstants.Types.ACCESS:
{
raiseAccessOverLimit(rootNode[0], child, metadata, capFinder, limitNode, record);
return false;
}
case NodeConstants.Types.PROJECT:
{
return child.getProperty(NodeConstants.Info.INTO_GROUP) == null && !child.hasProperty(Info.HAS_WINDOW_FUNCTIONS);
}
case NodeConstants.Types.SOURCE:
{
return canPushThroughView(child);
}
case NodeConstants.Types.SELECT:
case NodeConstants.Types.DUP_REMOVE:
return limitNode.hasBooleanProperty(Info.IS_NON_STRICT);
case NodeConstants.Types.SORT:
switch(child.getFirstChild().getType()) {
case NodeConstants.Types.SOURCE:
{
if (canPushThroughView(child.getFirstChild())) {
PlanNode sourceNode = child.getFirstChild();
NodeEditor.removeChildNode(limitNode, child);
NodeEditor.removeChildNode(limitNode.getParent(), limitNode);
limitNode.setProperty(NodeConstants.Info.OUTPUT_COLS, sourceNode.getFirstChild().getProperty(NodeConstants.Info.OUTPUT_COLS));
child.setProperty(NodeConstants.Info.OUTPUT_COLS, sourceNode.getFirstChild().getProperty(NodeConstants.Info.OUTPUT_COLS));
// project the order through the source - which needs to preserve the aliasing
HashMap<ElementSymbol, Expression> symbolMap = new HashMap<ElementSymbol, Expression>();
List<ElementSymbol> virtual = ((SymbolMap) sourceNode.getProperty(NodeConstants.Info.SYMBOL_MAP)).getKeys();
List<Expression> projected = (List<Expression>) NodeEditor.findNodePreOrder(sourceNode, NodeConstants.Types.PROJECT).getProperty(Info.PROJECT_COLS);
for (int i = 0; i < virtual.size(); i++) {
symbolMap.put(virtual.get(i), projected.get(i));
}
// map the expression directly to avoid issues with naming logic in the general node conversion
OrderBy orderBy = (OrderBy) child.getProperty(Info.SORT_ORDER);
for (OrderByItem item : orderBy.getOrderByItems()) {
Expression ex = symbolMap.get(item.getSymbol());
if (ex != null) {
item.setSymbol(ex);
item.setExpressionPosition(projected.indexOf(ex));
}
}
FrameUtil.convertNode(child, sourceNode.getGroups().iterator().next(), null, symbolMap, metadata, false);
sourceNode.getFirstChild().addAsParent(child);
child.addAsParent(limitNode);
// push again
limitNodes.add(limitNode);
return false;
}
}
case NodeConstants.Types.SET_OP:
{
PlanNode setOp = child.getFirstChild();
if (!canPushToBranches(limitNode, setOp)) {
return false;
}
OrderBy parentOrderBy = (OrderBy) child.getProperty(NodeConstants.Info.SORT_ORDER);
distributeLimit(limitNode, setOp, parentOrderBy, metadata, limitNodes, parentLimit, parentOffset, capFinder, context);
break;
}
case NodeConstants.Types.JOIN:
{
if (parentLimit == null) {
return false;
}
PlanNode join = child.getFirstChild();
JoinType jt = (JoinType) join.getProperty(NodeConstants.Info.JOIN_TYPE);
if (!jt.isOuter()) {
return false;
}
if ((jt == JoinType.JOIN_FULL_OUTER || jt == JoinType.JOIN_LEFT_OUTER) && join.getFirstChild().getGroups().containsAll(child.getGroups()) && !FrameUtil.findJoinSourceNode(join.getLastChild()).hasProperty(NodeConstants.Info.CORRELATED_REFERENCES)) {
pushOrderByAndLimit(limitNode, limitNodes, metadata, capFinder, context, child, parentLimit, parentOffset, join.getFirstChild());
} else if (jt == JoinType.JOIN_FULL_OUTER && join.getLastChild().getGroups().containsAll(child.getGroups())) {
pushOrderByAndLimit(limitNode, limitNodes, metadata, capFinder, context, child, parentLimit, parentOffset, join.getLastChild());
}
break;
}
case NodeConstants.Types.PROJECT:
{
rootNode[0] = RulePlanSorts.checkForProjectOptimization(child, rootNode[0], metadata, capFinder, record, context);
if (child.getFirstChild().getType() != NodeConstants.Types.PROJECT && NodeEditor.findParent(child, NodeConstants.Types.ACCESS) == null) {
return canPushLimit(rootNode, limitNode, limitNodes, metadata, capFinder, record, context);
}
break;
}
case NodeConstants.Types.ACCESS:
{
if (RuleRaiseAccess.canRaiseOverSort(child.getFirstChild(), metadata, capFinder, child, null, false, context)) {
NodeEditor.removeChildNode(limitNode, child);
limitNode.getFirstChild().getFirstChild().addAsParent(child);
// try to keep pushing
limitNodes.add(limitNode);
return false;
}
}
}
return false;
default:
{
return false;
}
}
}
use of org.teiid.query.sql.lang.OrderBy in project teiid by teiid.
the class FrameUtil method convertNode.
// If newGroup == null, this will be performing a straight symbol swap - that is,
// an oldGroup is undergoing a name change and that is the only difference in the
// symbols. In that case, some additional work can be done because we can assume
// that an oldElement isn't being replaced by an expression using elements from
// multiple new groups.
static void convertNode(PlanNode node, GroupSymbol oldGroup, Set<GroupSymbol> newGroups, Map symbolMap, QueryMetadataInterface metadata, boolean rewrite) throws QueryPlannerException {
if (node.getType() == NodeConstants.Types.GROUP) {
correctSymbolMap(symbolMap, node);
}
// Convert expressions from correlated subquery references;
List<SymbolMap> refMaps = node.getAllReferences();
LinkedList<Expression> correlatedExpression = new LinkedList<Expression>();
for (SymbolMap refs : refMaps) {
for (Map.Entry<ElementSymbol, Expression> ref : refs.asUpdatableMap().entrySet()) {
Expression expr = ref.getValue();
Expression convertedExpr = convertExpression(expr, symbolMap);
ref.setValue(convertedExpr);
correlatedExpression.add(convertedExpr);
}
}
// Update groups for current node
Set<GroupSymbol> groups = node.getGroups();
boolean hasOld = groups.remove(oldGroup);
int type = node.getType();
boolean singleMapping = newGroups != null && newGroups.size() == 1;
if (singleMapping) {
if (!hasOld) {
return;
}
groups.addAll(newGroups);
} else if ((type & (NodeConstants.Types.ACCESS | NodeConstants.Types.JOIN | NodeConstants.Types.SOURCE)) == type) {
if (newGroups != null) {
groups.addAll(newGroups);
}
} else {
groups.clear();
}
groups.addAll(GroupsUsedByElementsVisitor.getGroups(correlatedExpression));
if (type == NodeConstants.Types.SELECT) {
Criteria crit = (Criteria) node.getProperty(NodeConstants.Info.SELECT_CRITERIA);
crit = convertCriteria(crit, symbolMap, metadata, rewrite);
node.setProperty(NodeConstants.Info.SELECT_CRITERIA, crit);
if (!singleMapping) {
GroupsUsedByElementsVisitor.getGroups(crit, groups);
}
} else if (type == NodeConstants.Types.PROJECT) {
List<Expression> projectedSymbols = (List<Expression>) node.getProperty(NodeConstants.Info.PROJECT_COLS);
Select select = new Select(projectedSymbols);
ExpressionMappingVisitor.mapExpressions(select, symbolMap);
if (rewrite) {
for (LanguageObject expr : select.getSymbols()) {
rewriteSingleElementSymbol(metadata, (Expression) expr);
}
}
node.setProperty(NodeConstants.Info.PROJECT_COLS, select.getSymbols());
if (!singleMapping) {
GroupsUsedByElementsVisitor.getGroups(select, groups);
}
} else if (type == NodeConstants.Types.JOIN) {
// Convert join criteria property
List<Criteria> joinCrits = (List<Criteria>) node.getProperty(NodeConstants.Info.JOIN_CRITERIA);
if (joinCrits != null && !joinCrits.isEmpty()) {
Criteria crit = new CompoundCriteria(joinCrits);
crit = convertCriteria(crit, symbolMap, metadata, rewrite);
if (crit instanceof CompoundCriteria && ((CompoundCriteria) crit).getOperator() == CompoundCriteria.AND) {
node.setProperty(NodeConstants.Info.JOIN_CRITERIA, ((CompoundCriteria) crit).getCriteria());
} else {
joinCrits = new ArrayList<Criteria>();
joinCrits.add(crit);
node.setProperty(NodeConstants.Info.JOIN_CRITERIA, joinCrits);
}
}
convertAccessPatterns(symbolMap, node);
} else if (type == NodeConstants.Types.SORT) {
OrderBy orderBy = (OrderBy) node.getProperty(NodeConstants.Info.SORT_ORDER);
ExpressionMappingVisitor.mapExpressions(orderBy, symbolMap);
if (rewrite) {
for (OrderByItem item : orderBy.getOrderByItems()) {
rewriteSingleElementSymbol(metadata, item.getSymbol());
}
}
if (!singleMapping) {
GroupsUsedByElementsVisitor.getGroups(orderBy, groups);
}
} else if (type == NodeConstants.Types.GROUP) {
List<Expression> groupCols = (List<Expression>) node.getProperty(NodeConstants.Info.GROUP_COLS);
if (groupCols != null) {
GroupBy groupBy = new GroupBy(groupCols);
ExpressionMappingVisitor.mapExpressions(groupBy, symbolMap);
node.setProperty(NodeConstants.Info.GROUP_COLS, groupBy.getSymbols());
if (!singleMapping) {
GroupsUsedByElementsVisitor.getGroups(groupBy, groups);
}
}
if (!singleMapping) {
// add back the anon group
SymbolMap property = (SymbolMap) node.getProperty(Info.SYMBOL_MAP);
if (!property.asMap().isEmpty()) {
groups.add(property.asMap().keySet().iterator().next().getGroupSymbol());
}
}
} else if (type == NodeConstants.Types.SOURCE || type == NodeConstants.Types.ACCESS) {
convertAccessPatterns(symbolMap, node);
}
}
use of org.teiid.query.sql.lang.OrderBy in project teiid by teiid.
the class RuleAssignOutputElements method determineSourceOutput.
/**
* A special case to consider is when the virtual group is defined by a
* UNION (no ALL) or a SELECT DISTINCT. In this case, the dup removal means
* that all columns need to be used to determine duplicates. So, filtering the
* columns at all will alter the number of rows flowing through the frame.
* So, in this case filtering should not occur. In fact the output columns
* that were set on root above are filtered, but we actually want all the
* virtual elements - so just reset it and proceed as before
* @throws TeiidComponentException
* @throws QueryMetadataException
* @throws QueryPlannerException
*/
static List<? extends Expression> determineSourceOutput(PlanNode root, List<Expression> outputElements, QueryMetadataInterface metadata, CapabilitiesFinder capFinder) throws QueryMetadataException, TeiidComponentException, QueryPlannerException {
PlanNode virtualRoot = root.getLastChild();
if (hasDupRemoval(virtualRoot)) {
// Reset the outputColumns for this source node to be all columns for the virtual group
SymbolMap symbolMap = (SymbolMap) root.getProperty(NodeConstants.Info.SYMBOL_MAP);
if (!symbolMap.asMap().keySet().containsAll(outputElements)) {
outputElements.removeAll(symbolMap.asMap().keySet());
throw new QueryPlannerException(QueryPlugin.Event.TEIID30259, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30259, outputElements));
}
return symbolMap.getKeys();
}
PlanNode limit = NodeEditor.findNodePreOrder(root, NodeConstants.Types.TUPLE_LIMIT, NodeConstants.Types.PROJECT);
if (limit == null) {
return outputElements;
}
// reset the output elements to be the output columns + what's required by the sort
PlanNode sort = NodeEditor.findNodePreOrder(limit, NodeConstants.Types.SORT, NodeConstants.Types.PROJECT);
if (sort == null) {
return outputElements;
}
PlanNode access = NodeEditor.findParent(sort, NodeConstants.Types.ACCESS);
if (sort.hasBooleanProperty(NodeConstants.Info.UNRELATED_SORT) || (access != null && capFinder != null && CapabilitiesUtil.supports(Capability.QUERY_ORDERBY_UNRELATED, RuleRaiseAccess.getModelIDFromAccess(access, metadata), metadata, capFinder))) {
return outputElements;
}
OrderBy sortOrder = (OrderBy) sort.getProperty(NodeConstants.Info.SORT_ORDER);
List<Expression> topCols = FrameUtil.findTopCols(sort);
SymbolMap symbolMap = (SymbolMap) root.getProperty(NodeConstants.Info.SYMBOL_MAP);
List<ElementSymbol> symbolOrder = symbolMap.getKeys();
for (OrderByItem item : sortOrder.getOrderByItems()) {
final Expression expr = item.getSymbol();
int index = topCols.indexOf(expr);
if (index < 0) {
continue;
}
ElementSymbol symbol = symbolOrder.get(index);
if (!outputElements.contains(symbol)) {
outputElements.add(symbol);
}
}
return outputElements;
}
Aggregations