use of org.apache.phoenix.schema.PDatum 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.schema.PDatum in project phoenix by apache.
the class ExpressionCompiler method visitLeave.
@Override
public Expression visitLeave(InListParseNode node, List<Expression> l) throws SQLException {
List<Expression> inChildren = l;
Expression firstChild = inChildren.get(0);
ImmutableBytesWritable ptr = context.getTempPtr();
PDataType firstChildType = firstChild.getDataType();
ParseNode firstChildNode = node.getChildren().get(0);
if (firstChildNode instanceof BindParseNode) {
PDatum datum = firstChild;
if (firstChildType == null) {
datum = inferBindDatum(inChildren);
}
context.getBindManager().addParamMetaData((BindParseNode) firstChildNode, datum);
}
for (int i = 1; i < l.size(); i++) {
ParseNode childNode = node.getChildren().get(i);
if (childNode instanceof BindParseNode) {
context.getBindManager().addParamMetaData((BindParseNode) childNode, firstChild);
}
}
return wrapGroupByExpression(InListExpression.create(inChildren, node.isNegate(), ptr, context.getCurrentTable().getTable().rowKeyOrderOptimizable()));
}
use of org.apache.phoenix.schema.PDatum in project phoenix by apache.
the class ExpressionCompiler method inferBindDatum.
private static PDatum inferBindDatum(List<Expression> children) {
boolean isChildTypeUnknown = false;
PDatum datum = children.get(1);
for (int i = 2; i < children.size(); i++) {
Expression child = children.get(i);
PDataType childType = child.getDataType();
if (childType == null) {
isChildTypeUnknown = true;
} else if (datum.getDataType() == null) {
datum = child;
isChildTypeUnknown = true;
} else if (datum.getDataType() == childType || childType.isCoercibleTo(datum.getDataType())) {
continue;
} else if (datum.getDataType().isCoercibleTo(childType)) {
datum = child;
}
}
// TODO: same for TIMESTAMP for DATE/TIME?
if (isChildTypeUnknown && datum.getDataType() != null && datum.getDataType().isCoercibleTo(PDecimal.INSTANCE)) {
return DECIMAL_DATUM;
}
return datum;
}
use of org.apache.phoenix.schema.PDatum in project phoenix by apache.
the class ExpressionCompiler method visitLeave.
@Override
public Expression visitLeave(SubtractParseNode node, List<Expression> children) throws SQLException {
return visitLeave(node, children, new ArithmeticExpressionBinder() {
@Override
public PDatum getBindMetaData(int i, List<Expression> children, final Expression expression) {
final PDataType type;
// we know that the first parameter must be a date type too.
if (i == 0 && (type = children.get(1).getDataType()) != null && type.isCoercibleTo(PDate.INSTANCE)) {
return new PDatum() {
@Override
public boolean isNullable() {
return expression.isNullable();
}
@Override
public PDataType getDataType() {
return type;
}
@Override
public Integer getMaxLength() {
return expression.getMaxLength();
}
@Override
public Integer getScale() {
return expression.getScale();
}
@Override
public SortOrder getSortOrder() {
return expression.getSortOrder();
}
};
} else if (expression.getDataType() != null && expression.getDataType().isCoercibleTo(PDate.INSTANCE)) {
return new // Same as with addition
PDatum() {
@Override
public boolean isNullable() {
return expression.isNullable();
}
@Override
public PDataType getDataType() {
return PDecimal.INSTANCE;
}
@Override
public Integer getMaxLength() {
return expression.getMaxLength();
}
@Override
public Integer getScale() {
return expression.getScale();
}
@Override
public SortOrder getSortOrder() {
return expression.getSortOrder();
}
};
}
// Otherwise just go with what was calculated for the expression
return expression;
}
}, new ArithmeticExpressionFactory() {
@Override
public Expression create(ArithmeticParseNode node, List<Expression> children) throws SQLException {
int i = 0;
PDataType theType = null;
Expression e1 = children.get(0);
Expression e2 = children.get(1);
Determinism determinism = e1.getDeterminism().combine(e2.getDeterminism());
PDataType type1 = e1.getDataType();
PDataType type2 = e2.getDataType();
// TODO: simplify this special case for DATE conversion
/**
* For date1-date2, we want to coerce to a LONG because this
* cannot be compared against another date. It has essentially
* become a number. For date1-5, we want to preserve the DATE
* type because this can still be compared against another date
* and cannot be multiplied or divided. Any other time occurs is
* an error. For example, 5-date1 is an error. The nulls occur if
* we have bind variables.
*/
boolean isType1Date = type1 != null && type1 != PTimestamp.INSTANCE && type1 != PUnsignedTimestamp.INSTANCE && type1.isCoercibleTo(PDate.INSTANCE);
boolean isType2Date = type2 != null && type2 != PTimestamp.INSTANCE && type2 != PUnsignedTimestamp.INSTANCE && type2.isCoercibleTo(PDate.INSTANCE);
if (isType1Date || isType2Date) {
if (isType1Date && isType2Date) {
i = 2;
theType = PDecimal.INSTANCE;
} else if (isType1Date && type2 != null && type2.isCoercibleTo(PDecimal.INSTANCE)) {
i = 2;
theType = PDate.INSTANCE;
} else if (type1 == null || type2 == null) {
/*
* FIXME: Could be either a Date or BigDecimal, but we
* don't know if we're comparing to a date or a number
* which would be disambiguate it.
*/
i = 2;
theType = null;
}
} else if (type1 == PTimestamp.INSTANCE || type2 == PTimestamp.INSTANCE) {
i = 2;
theType = PTimestamp.INSTANCE;
} else if (type1 == PUnsignedTimestamp.INSTANCE || type2 == PUnsignedTimestamp.INSTANCE) {
i = 2;
theType = PUnsignedTimestamp.INSTANCE;
}
for (; i < children.size(); i++) {
// This logic finds the common type to which all child types are coercible
// without losing precision.
Expression e = children.get(i);
determinism = determinism.combine(e.getDeterminism());
PDataType type = e.getDataType();
if (type == null) {
continue;
} else if (type.isCoercibleTo(PLong.INSTANCE)) {
if (theType == null) {
theType = PLong.INSTANCE;
}
} else if (type == PDecimal.INSTANCE) {
// unless we're doing date arithmetic.
if (theType == null || !theType.isCoercibleTo(PDate.INSTANCE)) {
theType = PDecimal.INSTANCE;
}
} else if (type.isCoercibleTo(PDouble.INSTANCE)) {
// unless we're doing date arithmetic or we've found another child of type DECIMAL
if (theType == null || (theType != PDecimal.INSTANCE && !theType.isCoercibleTo(PDate.INSTANCE))) {
theType = PDouble.INSTANCE;
}
} else {
throw TypeMismatchException.newException(type, node.toString());
}
}
if (theType == PDecimal.INSTANCE) {
return new DecimalSubtractExpression(children);
} else if (theType == PLong.INSTANCE) {
return new LongSubtractExpression(children);
} else if (theType == PDouble.INSTANCE) {
return new DoubleSubtractExpression(children);
} else if (theType == null) {
return LiteralExpression.newConstant(null, theType, determinism);
} else if (theType == PTimestamp.INSTANCE || theType == PUnsignedTimestamp.INSTANCE) {
return new TimestampSubtractExpression(children);
} else if (theType.isCoercibleTo(PDate.INSTANCE)) {
return new DateSubtractExpression(children);
} else {
throw TypeMismatchException.newException(theType, node.toString());
}
}
});
}
use of org.apache.phoenix.schema.PDatum in project phoenix by apache.
the class SaltedScanRangesTest method foreach.
private static Collection<?> foreach(KeyRange[][] ranges, int[] widths, KeyRange keyRange, boolean useSkipScan, boolean expectedResult) {
List<List<KeyRange>> slots = Lists.transform(Lists.newArrayList(ranges), ARRAY_TO_LIST);
slots = new ArrayList<>(slots);
slots.add(0, Collections.singletonList(KeyRange.getKeyRange(new byte[] { 0 })));
RowKeySchemaBuilder builder = new RowKeySchemaBuilder(10);
builder.addField(SaltingUtil.SALTING_COLUMN, false, SortOrder.getDefault());
for (final int width : widths) {
if (width > 0) {
builder.addField(new PDatum() {
@Override
public boolean isNullable() {
return false;
}
@Override
public PDataType getDataType() {
return PChar.INSTANCE;
}
@Override
public Integer getMaxLength() {
return width;
}
@Override
public Integer getScale() {
return null;
}
@Override
public SortOrder getSortOrder() {
return SortOrder.getDefault();
}
}, false, SortOrder.getDefault());
} else {
builder.addField(new PDatum() {
@Override
public boolean isNullable() {
return false;
}
@Override
public PDataType getDataType() {
return PVarchar.INSTANCE;
}
@Override
public Integer getMaxLength() {
return width;
}
@Override
public Integer getScale() {
return null;
}
@Override
public SortOrder getSortOrder() {
return SortOrder.getDefault();
}
}, false, SortOrder.getDefault());
}
}
ScanRanges scanRanges = ScanRanges.createSingleSpan(builder.build(), slots, nBuckets, useSkipScan);
return foreach(scanRanges, widths, keyRange, expectedResult);
}
Aggregations