use of org.apache.ignite.internal.processors.query.h2.sql.GridSqlAlias in project ignite by apache.
the class GridSubqueryJoinOptimizer method remapColumns.
/**
* Remap all columns that satisfy the predicate such they be referred to the given table.
*
* @param parent Tree where to search columns.
* @param subSelect Tree where to search column aliases.
* @param colPred Collection predicate.
* @param tbl Table.
*/
private static void remapColumns(GridSqlAst parent, GridSqlAst subSelect, Predicate<GridSqlColumn> colPred, GridSqlAlias tbl) {
ASTNodeFinder colFinder = new ASTNodeFinder(parent, (p, c) -> c instanceof GridSqlColumn && colPred.test((GridSqlColumn) c));
ASTNodeFinder.Result res;
while ((res = colFinder.findNext()) != null) {
GridSqlColumn oldCol = res.getEl().child(res.getIdx());
BiPredicate<GridSqlAst, GridSqlAst> constPred = (p, c) -> c != null && c.getSQL().equals(oldCol.columnName());
BiPredicate<GridSqlAst, GridSqlAst> aliasPred = (p, c) -> c instanceof GridSqlAlias && ((GridSqlAlias) c).alias().equals(oldCol.columnName());
ASTNodeFinder.Result aliasOrPred = findNode(subSelect, constPred.or(aliasPred));
if (aliasOrPred != null)
res.getEl().child(res.getIdx(), GridSqlAlias.unwrap(aliasOrPred.getEl().child(aliasOrPred.getIdx())));
else {
res.getEl().child(res.getIdx(), new GridSqlColumn(oldCol.column(), tbl, oldCol.schema(), tbl.alias(), oldCol.columnName()));
}
}
}
use of org.apache.ignite.internal.processors.query.h2.sql.GridSqlAlias in project ignite by apache.
the class GridSubqueryJoinOptimizer method pullOutSubQryFromTableList.
/**
* Pull out sub-select from table list.
* <p>
* Example:
* <pre>
* Before:
* SELECT d.name
* FROM emp e,
* (select * from dep) d
* WHERE e.dep_id = d.id
* AND e.sal > 2000
*
* After:
* SELECT d.name
* FROM emp e
* JOIN dep d
* WHERE sal > 2000 AND d.id = e.dep_id
* </pre>
*
* @param parent Parent select.
* @param target Target sql element. Can be {@code null}.
* @param childInd Column index.
*/
private static boolean pullOutSubQryFromTableList(GridSqlSelect parent, @Nullable GridSqlAst target, int childInd) {
if (target != null && !ELEMENT_IS_JOIN.test(target))
return false;
GridSqlAlias wrappedSubQry = target != null ? target.child(childInd) : (GridSqlAlias) parent.from();
GridSqlSubquery subQry = GridSqlAlias.unwrap(wrappedSubQry);
if (!isSimpleSelect(subQry.subquery()))
return false;
GridSqlSelect subSel = subQry.subquery();
if (!(subSel.from() instanceof GridSqlAlias) && !(subSel.from() instanceof GridSqlTable))
// we can't deal with joins and others right now
return false;
GridSqlAlias subTbl = new GridSqlAlias(wrappedSubQry.alias(), GridSqlAlias.unwrap(subSel.from()));
if (target == null)
// it's true only when the subquery is only table in the table list
// so we can safely replace entire FROM expression of the parent
parent.from(subTbl);
else
target.child(childInd, subTbl);
GridSqlAst where = subSel.where();
if (where != null) {
if (target != null) {
GridSqlJoin join = (GridSqlJoin) target;
join.child(GridSqlJoin.ON_CHILD, new GridSqlOperation(AND, join.on(), where));
} else
parent.where(parent.where() == null ? where : new GridSqlOperation(AND, parent.where(), where));
}
remapColumns(parent, subSel, // reference equality used intentionally here
col -> wrappedSubQry == col.expressionInFrom(), subTbl);
return true;
}
use of org.apache.ignite.internal.processors.query.h2.sql.GridSqlAlias in project ignite by apache.
the class GridSqlQueryParser method parseSelect.
/**
* @param select Select.
*/
private GridSqlSelect parseSelect(Select select) {
GridSqlSelect res = (GridSqlSelect) h2ObjToGridObj.get(select);
if (res != null)
return res;
res = new GridSqlSelect();
h2ObjToGridObj.put(select, res);
res.distinct(select.isDistinct());
Expression where = CONDITION.get(select);
res.where(parseExpression(where, true));
ArrayList<TableFilter> tableFilters = new ArrayList<>();
TableFilter filter = select.getTopTableFilter();
boolean isForUpdate = SELECT_IS_FOR_UPDATE.get(select);
do {
assert0(filter != null, select);
assert0(filter.getNestedJoin() == null, select);
// Can use optimized join order only if we are not inside of an expression.
if (parsingSubQryExpression == 0 && optimizedTableFilterOrder != null) {
String tblAlias = filter.getTableAlias();
int idx = optimizedTableFilterOrder.get(tblAlias);
setElementAt(tableFilters, idx, filter);
} else
tableFilters.add(filter);
filter = filter.getJoin();
} while (filter != null);
// Build FROM clause from correctly ordered table filters.
GridSqlElement from = null;
for (int i = 0; i < tableFilters.size(); i++) {
TableFilter f = tableFilters.get(i);
GridSqlElement gridFilter = parseTableFilter(f);
from = from == null ? gridFilter : new GridSqlJoin(from, gridFilter, f.isJoinOuter(), parseExpression(f.getJoinCondition(), true));
}
res.from(from);
if (isForUpdate) {
if (!(from instanceof GridSqlTable || (from instanceof GridSqlAlias && from.size() == 1 && from.child() instanceof GridSqlTable))) {
throw new IgniteSQLException("SELECT FOR UPDATE with joins is not supported.", IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
}
GridSqlTable gridTbl = from instanceof GridSqlTable ? (GridSqlTable) from : ((GridSqlAlias) from).child();
GridH2Table tbl = gridTbl.dataTable();
if (tbl == null) {
throw new IgniteSQLException("SELECT FOR UPDATE query must involve Ignite table.", IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
}
if (select.getLimit() != null || select.getOffset() != null) {
throw new IgniteSQLException("LIMIT/OFFSET clauses are not supported for SELECT FOR UPDATE.", IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
}
if (SELECT_IS_GROUP_QUERY.get(select)) {
throw new IgniteSQLException("SELECT FOR UPDATE with aggregates and/or GROUP BY is not supported.", IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
}
if (select.isDistinct())
throw new IgniteSQLException("DISTINCT clause is not supported for SELECT FOR UPDATE.", IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
if (SplitterUtils.hasSubQueries(res))
throw new IgniteSQLException("Sub queries are not supported for SELECT FOR UPDATE.", IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
}
ArrayList<Expression> expressions = select.getExpressions();
for (int i = 0; i < expressions.size(); i++) res.addColumn(parseExpression(expressions.get(i), true), i < select.getColumnCount());
int[] grpIdx = GROUP_INDEXES.get(select);
if (grpIdx != null)
res.groupColumns(grpIdx);
int havingIdx = HAVING_INDEX.get(select);
if (havingIdx >= 0)
res.havingColumn(havingIdx);
res.forUpdate(isForUpdate);
processSortOrder(select.getSortOrder(), res);
res.limit(parseExpression(select.getLimit(), false));
res.offset(parseExpression(select.getOffset(), false));
return res;
}
use of org.apache.ignite.internal.processors.query.h2.sql.GridSqlAlias in project ignite by apache.
the class GridSqlQueryParser method parseExpression0.
/**
* @param expression Expression.
* @param calcTypes Calculate types for all the expressions.
* @return Parsed expression.
*/
private GridSqlElement parseExpression0(Expression expression, boolean calcTypes) {
if (expression instanceof ExpressionColumn) {
ExpressionColumn expCol = (ExpressionColumn) expression;
return new GridSqlColumn(expCol.getColumn(), parseTableFilter(expCol.getTableFilter()), SCHEMA_NAME.get(expCol), expCol.getOriginalTableAliasName(), expCol.getColumnName());
}
if (expression instanceof Alias)
return new GridSqlAlias(expression.getAlias(), parseExpression(expression.getNonAliasExpression(), calcTypes), true);
if (expression instanceof ValueExpression)
// == comparison is legit, see ValueExpression#getSQL()
return expression == ValueExpression.getDefault() ? GridSqlKeyword.DEFAULT : new GridSqlConst(expression.getValue(null));
if (expression instanceof Operation) {
Operation operation = (Operation) expression;
Operation.OpType type = OPERATION_TYPE.get(operation);
if (type == Operation.OpType.NEGATE) {
assert OPERATION_RIGHT.get(operation) == null;
return new GridSqlOperation(GridSqlOperationType.NEGATE, parseExpression(OPERATION_LEFT.get(operation), calcTypes));
}
return new GridSqlOperation(mapOperationType(type), parseExpression(OPERATION_LEFT.get(operation), calcTypes), parseExpression(OPERATION_RIGHT.get(operation), calcTypes));
}
if (expression instanceof Comparison) {
Comparison cmp = (Comparison) expression;
GridSqlOperationType opType = COMPARISON_TYPES[COMPARISON_TYPE.get(cmp)];
assert opType != null : COMPARISON_TYPE.get(cmp);
Expression leftExp = COMPARISON_LEFT.get(cmp);
GridSqlElement left = parseExpression(leftExp, calcTypes);
if (opType.childrenCount() == 1)
return new GridSqlOperation(opType, left);
Expression rightExp = COMPARISON_RIGHT.get(cmp);
GridSqlElement right = parseExpression(rightExp, calcTypes);
return new GridSqlOperation(opType, left, right);
}
if (expression instanceof ConditionNot)
return new GridSqlOperation(NOT, parseExpression(expression.getNotIfPossible(null), calcTypes));
if (expression instanceof ConditionAndOr) {
ConditionAndOr andOr = (ConditionAndOr) expression;
int type = ANDOR_TYPE.get(andOr);
assert type == ConditionAndOr.AND || type == ConditionAndOr.OR;
return new GridSqlOperation(type == ConditionAndOr.AND ? AND : OR, parseExpression(ANDOR_LEFT.get(andOr), calcTypes), parseExpression(ANDOR_RIGHT.get(andOr), calcTypes));
}
if (expression instanceof Subquery) {
Query qry = ((Subquery) expression).getQuery();
return parseQueryExpression(qry);
}
if (expression instanceof ConditionIn) {
GridSqlOperation res = new GridSqlOperation(IN);
res.addChild(parseExpression(LEFT_CI.get((ConditionIn) expression), calcTypes));
List<Expression> vals = VALUE_LIST_CI.get((ConditionIn) expression);
for (Expression val : vals) res.addChild(parseExpression(val, calcTypes));
return res;
}
if (expression instanceof ConditionInConstantSet) {
GridSqlOperation res = new GridSqlOperation(IN);
res.addChild(parseExpression(LEFT_CICS.get((ConditionInConstantSet) expression), calcTypes));
List<Expression> vals = VALUE_LIST_CICS.get((ConditionInConstantSet) expression);
for (Expression val : vals) res.addChild(parseExpression(val, calcTypes));
return res;
}
if (expression instanceof ConditionInSelect) {
GridSqlOperation res = new GridSqlOperation(IN);
boolean all = ALL.get((ConditionInSelect) expression);
int compareType = COMPARE_TYPE.get((ConditionInSelect) expression);
assert0(!all, expression);
assert0(compareType == Comparison.EQUAL, expression);
res.addChild(parseExpression(LEFT_CIS.get((ConditionInSelect) expression), calcTypes));
Query qry = QUERY_IN.get((ConditionInSelect) expression);
res.addChild(parseQueryExpression(qry));
return res;
}
if (expression instanceof CompareLike) {
assert0(ESCAPE.get((CompareLike) expression) == null, expression);
boolean regexp = REGEXP_CL.get((CompareLike) expression);
return new GridSqlOperation(regexp ? REGEXP : LIKE, parseExpression(LEFT.get((CompareLike) expression), calcTypes), parseExpression(RIGHT.get((CompareLike) expression), calcTypes));
}
if (expression instanceof Function) {
Function f = (Function) expression;
GridSqlFunction res = new GridSqlFunction(null, f.getName());
if (f.getArgs() != null) {
if (f.getFunctionType() == Function.TABLE || f.getFunctionType() == Function.TABLE_DISTINCT) {
Column[] cols = FUNC_TBL_COLS.get((TableFunction) f);
Expression[] args = f.getArgs();
assert cols.length == args.length;
for (int i = 0; i < cols.length; i++) {
GridSqlElement arg = parseExpression(args[i], calcTypes);
GridSqlAlias alias = new GridSqlAlias(cols[i].getName(), arg, false);
alias.resultType(fromColumn(cols[i]));
res.addChild(alias);
}
} else {
for (Expression arg : f.getArgs()) {
if (arg == null) {
if (f.getFunctionType() != Function.CASE)
throw new IllegalStateException("Function type with null arg: " + f.getFunctionType());
res.addChild(GridSqlPlaceholder.EMPTY);
} else
res.addChild(parseExpression(arg, calcTypes));
}
}
}
if (f.getFunctionType() == Function.CAST || f.getFunctionType() == Function.CONVERT) {
checkTypeSupported(f.getType(), "[expSql=" + f.getSQL() + ']');
res.resultType(fromExpression(f));
}
return res;
}
if (expression instanceof JavaFunction) {
JavaFunction f = (JavaFunction) expression;
FunctionAlias alias = FUNC_ALIAS.get(f);
GridSqlFunction res = new GridSqlFunction(alias.getSchema().getName(), f.getName());
if (f.getArgs() != null) {
for (Expression arg : f.getArgs()) res.addChild(parseExpression(arg, calcTypes));
}
return res;
}
if (expression instanceof Parameter)
return new GridSqlParameter(((Parameter) expression).getIndex());
if (expression instanceof Aggregate) {
Aggregate.AggregateType type = TYPE.get((Aggregate) expression);
if (GridSqlAggregateFunction.isValidType(type)) {
GridSqlAggregateFunction res = new GridSqlAggregateFunction(DISTINCT.get((Aggregate) expression), type);
Expression on = ON.get((Aggregate) expression);
if (on != null)
res.addChild(parseExpression(on, calcTypes));
ArrayList<SelectOrderBy> orders = GROUP_CONCAT_ORDER_LIST.get((Aggregate) expression);
if (!F.isEmpty(orders))
parseGroupConcatOrder(res, orders, calcTypes);
Expression separator = GROUP_CONCAT_SEPARATOR.get((Aggregate) expression);
if (separator != null)
res.setGroupConcatSeparator(parseExpression(separator, calcTypes));
return res;
}
}
if (expression instanceof ExpressionList) {
Expression[] exprs = EXPR_LIST.get((ExpressionList) expression);
GridSqlArray res = new GridSqlArray(exprs.length);
for (Expression expr : exprs) res.addChild(parseExpression(expr, calcTypes));
return res;
}
if (expression instanceof ConditionExists) {
Query qry = QUERY_EXISTS.get((ConditionExists) expression);
GridSqlOperation res = new GridSqlOperation(EXISTS);
res.addChild(parseQueryExpression(qry));
return res;
}
throw new IgniteException("Unsupported expression: " + expression + " [type=" + expression.getClass().getSimpleName() + ']');
}
use of org.apache.ignite.internal.processors.query.h2.sql.GridSqlAlias in project ignite by apache.
the class GridSqlQueryParser method tablesForDml.
/**
* Extract all tables participating in DML statement.
*
* @return List of tables participate at query.
* @throws IgniteSQLException in case query contains virtual tables.
*/
public List<GridH2Table> tablesForDml() throws IgniteSQLException {
Collection<?> parserObjects = h2ObjToGridObj.values();
List<GridH2Table> tbls = new ArrayList<>(parserObjects.size());
// check all involved caches
for (Object o : parserObjects) {
if (o instanceof GridSqlMerge)
o = ((GridSqlMerge) o).into();
else if (o instanceof GridSqlInsert)
o = ((GridSqlInsert) o).into();
else if (o instanceof GridSqlUpdate)
o = ((GridSqlUpdate) o).target();
else if (o instanceof GridSqlDelete)
o = ((GridSqlDelete) o).from();
if (o instanceof GridSqlAlias)
o = GridSqlAlias.unwrap((GridSqlAst) o);
if (o instanceof GridSqlTable) {
GridH2Table h2tbl = ((GridSqlTable) o).dataTable();
if (h2tbl == null) {
// Check for virtual tables.
throw new IgniteSQLException("Operation not supported for table '" + ((GridSqlTable) o).tableName() + "'", IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
}
tbls.add(h2tbl);
}
}
return tbls;
}
Aggregations