use of org.apache.phoenix.parse.ParseNode in project phoenix by apache.
the class WhereCompiler method compile.
/**
* Optimize scan ranges by applying dynamically generated filter expressions.
* @param context the shared context during query compilation
* @param statement TODO
* @throws SQLException if mismatched types are found, bind value do not match binds,
* or invalid function arguments are encountered.
* @throws SQLFeatureNotSupportedException if an unsupported expression is encountered.
* @throws ColumnNotFoundException if column name could not be resolved
* @throws AmbiguousColumnException if an unaliased column name is ambiguous across multiple tables
*/
public static Expression compile(StatementContext context, FilterableStatement statement, ParseNode viewWhere, List<Expression> dynamicFilters, boolean hashJoinOptimization, Set<SubqueryParseNode> subqueryNodes) throws SQLException {
ParseNode where = statement.getWhere();
if (subqueryNodes != null) {
// if the subqueryNodes passed in is null, we assume there will be no sub-queries in the WHERE clause.
SubqueryParseNodeVisitor subqueryVisitor = new SubqueryParseNodeVisitor(context, subqueryNodes);
if (where != null) {
where.accept(subqueryVisitor);
}
if (viewWhere != null) {
viewWhere.accept(subqueryVisitor);
}
if (!subqueryNodes.isEmpty()) {
return null;
}
}
Set<Expression> extractedNodes = Sets.<Expression>newHashSet();
WhereExpressionCompiler whereCompiler = new WhereExpressionCompiler(context);
Expression expression = where == null ? LiteralExpression.newConstant(true, PBoolean.INSTANCE, Determinism.ALWAYS) : where.accept(whereCompiler);
if (whereCompiler.isAggregate()) {
throw new SQLExceptionInfo.Builder(SQLExceptionCode.AGGREGATE_IN_WHERE).build().buildException();
}
if (expression.getDataType() != PBoolean.INSTANCE) {
throw TypeMismatchException.newException(PBoolean.INSTANCE, expression.getDataType(), expression.toString());
}
if (viewWhere != null) {
WhereExpressionCompiler viewWhereCompiler = new WhereExpressionCompiler(context, true);
Expression viewExpression = viewWhere.accept(viewWhereCompiler);
expression = AndExpression.create(Lists.newArrayList(expression, viewExpression));
}
if (!dynamicFilters.isEmpty()) {
List<Expression> filters = Lists.newArrayList(expression);
filters.addAll(dynamicFilters);
expression = AndExpression.create(filters);
}
if (context.getCurrentTable().getTable().getType() != PTableType.PROJECTED && context.getCurrentTable().getTable().getType() != PTableType.SUBQUERY) {
expression = WhereOptimizer.pushKeyExpressionsToScan(context, statement, expression, extractedNodes);
}
setScanFilter(context, statement, expression, whereCompiler.disambiguateWithFamily, hashJoinOptimization);
return expression;
}
use of org.apache.phoenix.parse.ParseNode in project phoenix by apache.
the class QueryCompiler method compileSingleFlatQuery.
protected QueryPlan compileSingleFlatQuery(StatementContext context, SelectStatement select, List<Object> binds, boolean asSubquery, boolean allowPageFilter, QueryPlan innerPlan, TupleProjector innerPlanTupleProjector, boolean isInRowKeyOrder) throws SQLException {
PTable projectedTable = null;
if (this.projectTuples) {
projectedTable = TupleProjectionCompiler.createProjectedTable(select, context);
if (projectedTable != null) {
context.setResolver(FromCompiler.getResolverForProjectedTable(projectedTable, context.getConnection(), select.getUdfParseNodes()));
}
}
ColumnResolver resolver = context.getResolver();
TableRef tableRef = context.getCurrentTable();
PTable table = tableRef.getTable();
ParseNode viewWhere = null;
if (table.getViewStatement() != null) {
viewWhere = new SQLParser(table.getViewStatement()).parseQuery().getWhere();
}
Integer limit = LimitCompiler.compile(context, select);
Integer offset = OffsetCompiler.compile(context, select);
GroupBy groupBy = GroupByCompiler.compile(context, select, isInRowKeyOrder);
// Optimize the HAVING clause by finding any group by expressions that can be moved
// to the WHERE clause
select = HavingCompiler.rewrite(context, select, groupBy);
Expression having = HavingCompiler.compile(context, select, groupBy);
// expressions as group by key expressions since they're pre, not post filtered.
if (innerPlan == null && !tableRef.equals(resolver.getTables().get(0))) {
context.setResolver(FromCompiler.getResolver(context.getConnection(), tableRef, select.getUdfParseNodes()));
}
Set<SubqueryParseNode> subqueries = Sets.<SubqueryParseNode>newHashSet();
Expression where = WhereCompiler.compile(context, select, viewWhere, subqueries);
// Recompile GROUP BY now that we've figured out our ScanRanges so we know
// definitively whether or not we'll traverse in row key order.
groupBy = groupBy.compile(context, innerPlanTupleProjector);
// recover resolver
context.setResolver(resolver);
RowProjector projector = ProjectionCompiler.compile(context, select, groupBy, asSubquery ? Collections.<PDatum>emptyList() : targetColumns, where);
OrderBy orderBy = OrderByCompiler.compile(context, select, groupBy, limit, offset, projector, groupBy == GroupBy.EMPTY_GROUP_BY ? innerPlanTupleProjector : null, isInRowKeyOrder);
context.getAggregationManager().compile(context, groupBy);
// Final step is to build the query plan
if (!asSubquery) {
int maxRows = statement.getMaxRows();
if (maxRows > 0) {
if (limit != null) {
limit = Math.min(limit, maxRows);
} else {
limit = maxRows;
}
}
}
if (projectedTable != null) {
TupleProjector.serializeProjectorIntoScan(context.getScan(), new TupleProjector(projectedTable));
}
QueryPlan plan = innerPlan;
if (plan == null) {
ParallelIteratorFactory parallelIteratorFactory = asSubquery ? null : this.parallelIteratorFactory;
plan = select.getFrom() == null ? new LiteralResultIterationPlan(context, select, tableRef, projector, limit, offset, orderBy, parallelIteratorFactory) : (select.isAggregate() || select.isDistinct() ? new AggregatePlan(context, select, tableRef, projector, limit, offset, orderBy, parallelIteratorFactory, groupBy, having) : new ScanPlan(context, select, tableRef, projector, limit, offset, orderBy, parallelIteratorFactory, allowPageFilter));
}
if (!subqueries.isEmpty()) {
int count = subqueries.size();
WhereClauseSubPlan[] subPlans = new WhereClauseSubPlan[count];
int i = 0;
for (SubqueryParseNode subqueryNode : subqueries) {
SelectStatement stmt = subqueryNode.getSelectNode();
subPlans[i++] = new WhereClauseSubPlan(compileSubquery(stmt, false), stmt, subqueryNode.expectSingleRow());
}
plan = HashJoinPlan.create(select, plan, null, subPlans);
}
if (innerPlan != null) {
if (LiteralExpression.isTrue(where)) {
// we do not pass "true" as filter
where = null;
}
plan = select.isAggregate() || select.isDistinct() ? new ClientAggregatePlan(context, select, tableRef, projector, limit, offset, where, orderBy, groupBy, having, plan) : new ClientScanPlan(context, select, tableRef, projector, limit, offset, where, orderBy, plan);
}
return plan;
}
use of org.apache.phoenix.parse.ParseNode in project phoenix by apache.
the class SequenceManager method newSequenceReference.
public SequenceValueExpression newSequenceReference(SequenceValueParseNode node) throws SQLException {
PName tenantName = statement.getConnection().getTenantId();
String tenantId = tenantName == null ? null : tenantName.getString();
TableName tableName = node.getTableName();
if (tableName.getSchemaName() == null && statement.getConnection().getSchema() != null) {
tableName = TableName.create(statement.getConnection().getSchema(), tableName.getTableName());
}
int nSaltBuckets = statement.getConnection().getQueryServices().getSequenceSaltBuckets();
ParseNode numToAllocateNode = node.getNumToAllocateNode();
long numToAllocate = determineNumToAllocate(tableName, numToAllocateNode);
SequenceKey key = new SequenceKey(tenantId, tableName.getSchemaName(), tableName.getTableName(), nSaltBuckets);
SequenceValueExpression expression = sequenceMap.get(key);
if (expression == null) {
int index = sequenceMap.size();
expression = new SequenceValueExpression(key, node.getOp(), index, numToAllocate);
sequenceMap.put(key, expression);
} else if (expression.op != node.getOp() || expression.getNumToAllocate() < numToAllocate) {
// Keep the maximum allocation size we see in a statement
SequenceValueExpression oldExpression = expression;
expression = new SequenceValueExpression(key, node.getOp(), expression.getIndex(), Math.max(expression.getNumToAllocate(), numToAllocate));
if (oldExpression.getNumToAllocate() < numToAllocate) {
// If we found a NEXT VALUE expression with a higher number to allocate
// We override the original expression
sequenceMap.put(key, expression);
}
}
// If we see a NEXT and a CURRENT, treat the CURRENT just like a NEXT
if (node.getOp() == Op.NEXT_VALUE) {
isNextSequence.set(expression.getIndex());
}
return expression;
}
use of org.apache.phoenix.parse.ParseNode in project phoenix by apache.
the class StatementNormalizer method visitLeave.
@Override
public ParseNode visitLeave(final BetweenParseNode node, List<ParseNode> nodes) throws SQLException {
LessThanOrEqualParseNode lhsNode = NODE_FACTORY.lte(node.getChildren().get(1), node.getChildren().get(0));
LessThanOrEqualParseNode rhsNode = NODE_FACTORY.lte(node.getChildren().get(0), node.getChildren().get(2));
List<ParseNode> parseNodes = Lists.newArrayListWithExpectedSize(2);
parseNodes.add(this.visitLeave(lhsNode, lhsNode.getChildren()));
parseNodes.add(this.visitLeave(rhsNode, rhsNode.getChildren()));
return super.visitLeave(node, parseNodes);
}
use of org.apache.phoenix.parse.ParseNode in project phoenix by apache.
the class StatementNormalizer method normalize.
/**
* Rewrite the select statement by switching any constants to the right hand side
* of the expression.
* @param statement the select statement
* @param resolver
* @return new select statement
* @throws SQLException
*/
public static SelectStatement normalize(SelectStatement statement, ColumnResolver resolver) throws SQLException {
boolean multiTable = statement.isJoin();
// Replace WildcardParse with a list of TableWildcardParseNode for multi-table queries
if (multiTable) {
List<AliasedNode> selectNodes = statement.getSelect();
List<AliasedNode> normSelectNodes = selectNodes;
for (int i = 0; i < selectNodes.size(); i++) {
AliasedNode aliasedNode = selectNodes.get(i);
ParseNode selectNode = aliasedNode.getNode();
if (selectNode == WildcardParseNode.INSTANCE) {
if (selectNodes == normSelectNodes) {
normSelectNodes = Lists.newArrayList(selectNodes.subList(0, i));
}
List<TableName> tableNames = statement.getFrom().accept(new TableNameVisitor());
for (TableName tableName : tableNames) {
TableWildcardParseNode node = NODE_FACTORY.tableWildcard(tableName);
normSelectNodes.add(NODE_FACTORY.aliasedNode(null, node));
}
} else if (selectNodes != normSelectNodes) {
normSelectNodes.add(aliasedNode);
}
}
if (selectNodes != normSelectNodes) {
statement = NODE_FACTORY.select(statement.getFrom(), statement.getHint(), statement.isDistinct(), normSelectNodes, statement.getWhere(), statement.getGroupBy(), statement.getHaving(), statement.getOrderBy(), statement.getLimit(), statement.getOffset(), statement.getBindCount(), statement.isAggregate(), statement.hasSequence(), statement.getSelects(), statement.getUdfParseNodes());
}
}
return rewrite(statement, new StatementNormalizer(resolver, statement.getSelect().size(), multiTable));
}
Aggregations