use of org.apache.ignite.internal.processors.query.h2.sql.GridSqlOperation in project ignite by apache.
the class GridSubqueryJoinOptimizer method pullOutSubQryFromSelectExpr.
/**
* Pulls out subquery from select expression.
*
* @param select Parent query where to find and pull out subqueries.
*/
private static void pullOutSubQryFromSelectExpr(GridSqlSelect select) {
for (int i = 0; i < select.allColumns(); i++) {
boolean wasPulledOut = false;
GridSqlAst col = select.columns(false).get(i);
if (col instanceof GridSqlSubquery)
wasPulledOut = pullOutSubQryFromSelectExpr(select, null, i);
else if (col instanceof GridSqlOperation && ((GridSqlOperation) col).operationType() == EXISTS)
// We actially can't rewrite select query under exists operator. So we skip it.
continue;
else {
ASTNodeFinder finder = new ASTNodeFinder(col, ELEMENT_WITH_SUBQUERY);
ASTNodeFinder.Result res;
while ((res = finder.findNext()) != null) wasPulledOut |= pullOutSubQryFromSelectExpr(select, res.getEl(), res.getIdx());
}
if (// we have to analyze just pulled out element as well
wasPulledOut)
i--;
}
}
use of org.apache.ignite.internal.processors.query.h2.sql.GridSqlOperation in project ignite by apache.
the class GridSubqueryJoinOptimizer method pullOutSubQryFromInClause.
/**
* Pull out sub-select from IN clause to the parent select level.
* <p>
* Example:
* <pre>
* Before:
* SELECT name
* FROM emp e
* WHERE e.dep_id IN (SELECT d.id FROM dep d WHERE d.name = 'dep1')
* AND sal > 2000
*
* After:
* SELECT name
* FROM emp e
* JOIN dep d
* WHERE sal > 2000 AND d.id = e.dep_id and d.name = 'dep1
* </pre>
*
* @param parent Parent select.
* @param targetEl Target sql element. Can be {@code null}.
* @param childInd Column index.
*/
private static boolean pullOutSubQryFromInClause(GridSqlSelect parent, @Nullable GridSqlAst targetEl, int childInd) {
// extract sub-query
GridSqlSubquery subQry = targetEl != null ? targetEl.child(childInd).child(1) : parent.where().child(1);
if (!isSimpleSelect(subQry.subquery()))
return false;
GridSqlSelect subS = subQry.subquery();
GridSqlAst leftExpr = targetEl != null ? targetEl.child(childInd).child(0) : parent.where().child(0);
// 4) c1 + c2/const IN (SELECT in_col FROM ...)
if (subS.visibleColumns() != 1)
return false;
List<GridSqlElement> conditions = new ArrayList<>();
if (leftExpr instanceof GridSqlArray) {
GridSqlAst col = subS.columns(true).get(0);
if (!(col instanceof GridSqlArray) || leftExpr.size() != col.size())
return false;
for (int i = 0; i < col.size(); i++) {
GridSqlElement el = leftExpr.child(i);
conditions.add(new GridSqlOperation(EQUAL, el, col.child(i)));
}
} else if (targetEl instanceof GridSqlFunction)
return false;
else
conditions.add(new GridSqlOperation(EQUAL, leftExpr, subS.columns(true).get(0)));
// save old condition and IN expression to restore them
// in case of unsuccessfull pull out
GridSqlElement oldCond = (GridSqlElement) subS.where();
if (oldCond != null)
conditions.add(oldCond);
GridSqlElement oldInExpr = targetEl != null ? targetEl.child(childInd) : (GridSqlElement) parent.where();
// update sub-query condition and convert IN clause to EXISTS
subS.where(buildConditionBush(conditions));
GridSqlOperation existsExpr = new GridSqlOperation(EXISTS, subQry);
if (targetEl != null)
targetEl.child(childInd, existsExpr);
else
parent.where(existsExpr);
boolean res = pullOutSubQryFromExistsClause(parent, targetEl, childInd);
if (!res) {
// restore original query in case of failure
if (targetEl != null)
targetEl.child(childInd, oldInExpr);
else
parent.where(oldInExpr);
subS.where(oldCond);
}
return res;
}
use of org.apache.ignite.internal.processors.query.h2.sql.GridSqlOperation in project ignite by apache.
the class DmlAstUtils method isEqualityCondition.
/**
* @param op Operation.
* @param key true - check for key equality condition,
* otherwise check for value equality condition
* @return Whether this condition is of form {@code colName} = ?
*/
private static boolean isEqualityCondition(GridSqlOperation op, boolean key) {
if (op.operationType() != GridSqlOperationType.EQUAL)
return false;
GridSqlElement left = op.child(0);
GridSqlElement right = op.child(1);
if (!(left instanceof GridSqlColumn))
return false;
GridSqlColumn column = (GridSqlColumn) left;
if (!(column.column().getTable() instanceof GridH2Table))
return false;
GridH2RowDescriptor desc = ((GridH2Table) column.column().getTable()).rowDescriptor();
return (key ? desc.isKeyColumn(column.column().getColumnId()) : desc.isValueColumn(column.column().getColumnId())) && (right instanceof GridSqlConst || right instanceof GridSqlParameter);
}
use of org.apache.ignite.internal.processors.query.h2.sql.GridSqlOperation in project ignite by apache.
the class GridSubqueryJoinOptimizer method subQueryCanBePulledOut.
/**
* Whether sub-query can be pulled out or not.
*
* @param subQry Sub-query.
* @return {@code true} if sub-query cound be pulled out, {@code false} otherwise.
*/
private static boolean subQueryCanBePulledOut(GridSqlSubquery subQry) {
GridSqlQuery subQ = subQry.subquery();
if (!isSimpleSelect(subQ))
return false;
assert subQ instanceof GridSqlSelect;
GridSqlSelect subS = (GridSqlSelect) subQ;
if (subS.where() == null)
return false;
Predicate<GridSqlAst> andOrEqPre = ELEMENT_IS_AND_OPERATION.or(ELEMENT_IS_EQ);
if (!andOrEqPre.test(subS.where()))
return false;
ASTNodeFinder opEqFinder = new ASTNodeFinder(subS.where(), (parent, child) -> ELEMENT_IS_EQ.test(parent), andOrEqPre);
List<GridSqlColumn> sqlCols = new ArrayList<>();
ASTNodeFinder.Result res;
while ((res = opEqFinder.findNext()) != null) {
GridSqlOperation op = (GridSqlOperation) res.getEl();
assert op.size() == 2;
GridSqlColumn[] colArr = new GridSqlColumn[2];
for (int i = 0; i < 2; i++) {
if (op.child(i) instanceof GridSqlColumn)
colArr[i] = op.child(i);
else if (op.child(i) instanceof GridSqlOperation && ((GridSqlOperation) op.child(i)).operationType() == NEGATE && op.child() instanceof GridSqlColumn)
colArr[i] = op.child(i).child();
}
if (colArr[0] == null || colArr[1] == null || // whether the column refers to exactly the same table
colArr[0].expressionInFrom() != colArr[1].expressionInFrom()) {
if (colArr[0] != null && colArr[0].expressionInFrom() == subS.from())
sqlCols.add(colArr[0]);
if (colArr[1] != null && colArr[1].expressionInFrom() == subS.from())
sqlCols.add(colArr[1]);
}
}
GridSqlAst subTbl = GridSqlAlias.unwrap(subS.from());
return subTbl instanceof GridSqlTable && isUniqueIndexExists(sqlCols, (GridSqlTable) subTbl);
}
use of org.apache.ignite.internal.processors.query.h2.sql.GridSqlOperation in project ignite by apache.
the class GridSubqueryJoinOptimizer method buildConditionBush.
/**
* Creates tree from provided elements which will be connected with an AND operator.
*
* @param ops Ops.
* @return Root of the resulting tree.
*/
private static GridSqlElement buildConditionBush(List<GridSqlElement> ops) {
assert !F.isEmpty(ops);
if (ops.size() == 1)
return ops.get(0);
int m = (ops.size() + 1) / 2;
GridSqlElement left = buildConditionBush(ops.subList(0, m));
GridSqlElement right = buildConditionBush(ops.subList(m, ops.size()));
return new GridSqlOperation(AND, left, right);
}
Aggregations