private void appendScanRow(StringBuilder buf, Bound bound) { ScanRanges scanRanges = context.getScanRanges(); KeyRange minMaxRange = context.getMinMaxRange(); Iterator<byte[]> minMaxIterator = Iterators.emptyIterator(); if (minMaxRange != null) { RowKeySchema schema = tableRef.getTable().getRowKeySchema(); if (!minMaxRange.isUnbound(bound)) { minMaxIterator = new RowKeyValueIterator(schema, minMaxRange.getRange(bound)); } } int nRanges = scanRanges.getRanges().size(); for (int i = 0, minPos = 0; minPos < nRanges || minMaxIterator.hasNext(); i++) { List<KeyRange> ranges = minPos >= nRanges ? EVERYTHING : scanRanges.getRanges().get(minPos++); KeyRange range = bound == Bound.LOWER ? ranges.get(0) : ranges.get(ranges.size() - 1); byte[] b = range.getRange(bound); Boolean isNull = KeyRange.IS_NULL_RANGE == range ? Boolean.TRUE : KeyRange.IS_NOT_NULL_RANGE == range ? Boolean.FALSE : null; if (minMaxIterator.hasNext()) { byte[] bMinMax = minMaxIterator.next(); int cmp = Bytes.compareTo(bMinMax, b) * (bound == Bound.LOWER ? 1 : -1); if (cmp > 0) { minPos = nRanges; b = bMinMax; isNull = null; } else if (cmp < 0) { minMaxIterator = Iterators.emptyIterator(); } } appendPKColumnValue(buf, b, isNull, i); buf.append(','); } }
public static boolean forceRowKeyOrder(StatementContext context) { return context .getConnection() .getQueryServices() .getProps() .getBoolean( QueryServices.FORCE_ROW_KEY_ORDER_ATTRIB, QueryServicesOptions.DEFAULT_FORCE_ROW_KEY_ORDER); }
private void appendKeyRanges(StringBuilder buf) { ScanRanges scanRanges = context.getScanRanges(); KeyRange minMaxRange = context.getMinMaxRange(); if (minMaxRange == null && (scanRanges == ScanRanges.EVERYTHING || scanRanges == ScanRanges.NOTHING)) { return; } buf.append(" ["); StringBuilder buf1 = new StringBuilder(); appendScanRow(buf1, Bound.LOWER); buf.append(buf1); buf.setCharAt(buf.length() - 1, ']'); StringBuilder buf2 = new StringBuilder(); appendScanRow(buf2, Bound.UPPER); if (!StringUtil.equals(buf1, buf2)) { buf.append(" - ["); buf.append(buf2); } buf.setCharAt(buf.length() - 1, ']'); }
public static boolean isRoundRobinPossible(OrderBy orderBy, StatementContext context) throws SQLException { int fetchSize = context.getStatement().getFetchSize(); /* * Selecting underlying scanners in a round-robin fashion is possible if there is no ordering of rows needed, * not even row key order. Also no point doing round robin of scanners if fetch size * is 1. */ return fetchSize > 1 && !shouldRowsBeInRowKeyOrder(orderBy, context) && orderBy.getOrderByExpressions().isEmpty(); }
private void appendPKColumnValue(StringBuilder buf, byte[] range, Boolean isNull, int slotIndex) { if (Boolean.TRUE.equals(isNull)) { buf.append("null"); return; } if (Boolean.FALSE.equals(isNull)) { buf.append("not null"); return; } if (range.length == 0) { buf.append('*'); return; } ScanRanges scanRanges = context.getScanRanges(); PDataType type = scanRanges.getSchema().getField(slotIndex).getDataType(); ColumnModifier modifier = tableRef.getTable().getPKColumns().get(slotIndex).getColumnModifier(); if (modifier != null) { buf.append('~'); range = modifier.apply(range, 0, new byte[range.length], 0, range.length); } Format formatter = context.getConnection().getFormatter(type); buf.append(type.toStringLiteral(range, formatter)); }
public DegenerateQueryPlan( StatementContext context, FilterableStatement statement, TableRef table) { super( context, statement, table, RowProjector.EMPTY_PROJECTOR, PhoenixParameterMetaData.EMPTY_PARAMETER_META_DATA, null, OrderBy.EMPTY_ORDER_BY, GroupBy.EMPTY_GROUP_BY, null); context.setScanRanges(ScanRanges.NOTHING); }
public SortMergeJoinPlan( StatementContext context, FilterableStatement statement, TableRef table, JoinType type, QueryPlan lhsPlan, QueryPlan rhsPlan, List<Expression> lhsKeyExpressions, List<Expression> rhsKeyExpressions, PTable joinedTable, PTable lhsTable, PTable rhsTable, int rhsFieldPosition, boolean isSingleValueOnly) { if (type == JoinType.Right) throw new IllegalArgumentException("JoinType should not be " + type); this.context = context; this.statement = statement; this.table = table; this.type = type; this.lhsPlan = lhsPlan; this.rhsPlan = rhsPlan; this.lhsKeyExpressions = lhsKeyExpressions; this.rhsKeyExpressions = rhsKeyExpressions; this.joinedSchema = buildSchema(joinedTable); this.lhsSchema = buildSchema(lhsTable); this.rhsSchema = buildSchema(rhsTable); this.rhsFieldPosition = rhsFieldPosition; this.isSingleValueOnly = isSingleValueOnly; this.tableRefs = Sets.newHashSetWithExpectedSize( lhsPlan.getSourceRefs().size() + rhsPlan.getSourceRefs().size()); this.tableRefs.addAll(lhsPlan.getSourceRefs()); this.tableRefs.addAll(rhsPlan.getSourceRefs()); this.thresholdBytes = context .getConnection() .getQueryServices() .getProps() .getInt( QueryServices.SPOOL_THRESHOLD_BYTES_ATTRIB, QueryServicesOptions.DEFAULT_SPOOL_THRESHOLD_BYTES); }
private boolean explainSkipScan(StringBuilder buf) { ScanRanges scanRanges = context.getScanRanges(); if (scanRanges.isPointLookup()) { int keyCount = scanRanges.getPointLookupCount(); buf.append("POINT LOOKUP ON " + keyCount + " KEY" + (keyCount > 1 ? "S " : " ")); } else if (scanRanges.useSkipScanFilter()) { buf.append("SKIP SCAN "); int count = 1; boolean hasRanges = false; for (List<KeyRange> ranges : scanRanges.getRanges()) { count *= ranges.size(); for (KeyRange range : ranges) { hasRanges |= !range.isSingleKey(); } } buf.append("ON "); buf.append(count); buf.append(hasRanges ? " RANGE" : " KEY"); buf.append(count > 1 ? "S " : " "); } else { buf.append("RANGE SCAN "); } return scanRanges.useSkipScanFilter(); }
protected void explain(String prefix, List<String> planSteps) { StringBuilder buf = new StringBuilder(prefix); ScanRanges scanRanges = context.getScanRanges(); boolean hasSkipScanFilter = false; if (scanRanges.isEverything()) { buf.append("FULL SCAN "); } else { hasSkipScanFilter = explainSkipScan(buf); } buf.append("OVER " + tableRef.getTable().getName().getString()); if (!scanRanges.isPointLookup()) { appendKeyRanges(buf); } planSteps.add(buf.toString()); Scan scan = context.getScan(); Filter filter = scan.getFilter(); PageFilter pageFilter = null; if (filter != null) { int offset = 0; boolean hasFirstKeyOnlyFilter = false; String filterDesc = ""; if (hasSkipScanFilter) { if (filter instanceof FilterList) { List<Filter> filterList = ((FilterList) filter).getFilters(); if (filterList.get(0) instanceof FirstKeyOnlyFilter) { hasFirstKeyOnlyFilter = true; offset = 1; } if (filterList.size() > offset + 1) { filterDesc = filterList.get(offset + 1).toString(); if (filterList.size() > offset + 2) { pageFilter = (PageFilter) filterList.get(offset + 2); } } } } else if (filter instanceof FilterList) { List<Filter> filterList = ((FilterList) filter).getFilters(); if (filterList.get(0) instanceof FirstKeyOnlyFilter) { hasFirstKeyOnlyFilter = true; offset = 1; } if (filterList.size() > offset) { filterDesc = filterList.get(offset).toString(); if (filterList.size() > offset + 1) { pageFilter = (PageFilter) filterList.get(offset + 1); } } } else { if (filter instanceof FirstKeyOnlyFilter) { hasFirstKeyOnlyFilter = true; } else { filterDesc = filter.toString(); } } if (filterDesc.length() > 0) { planSteps.add( " SERVER FILTER BY " + (hasFirstKeyOnlyFilter ? "FIRST KEY ONLY AND " : "") + filterDesc); } else if (hasFirstKeyOnlyFilter) { planSteps.add(" SERVER FILTER BY FIRST KEY ONLY"); } if (pageFilter != null) { planSteps.add(" SERVER " + pageFilter.getPageSize() + " ROW LIMIT"); } } groupBy.explain(planSteps); }
private static List<KeyRange> getSplits( final TableRef tableRef, final Scan scan, final List<HRegionLocation> regions, final ScanRanges scanRanges) throws SQLException { final List<TableRef> tableRefs = Collections.singletonList(tableRef); ColumnResolver resolver = new ColumnResolver() { @Override public List<PFunction> getFunctions() { return Collections.emptyList(); } @Override public List<TableRef> getTables() { return tableRefs; } @Override public TableRef resolveTable(String schemaName, String tableName) throws SQLException { throw new UnsupportedOperationException(); } @Override public ColumnRef resolveColumn(String schemaName, String tableName, String colName) throws SQLException { throw new UnsupportedOperationException(); } @Override public PFunction resolveFunction(String functionName) throws SQLException { throw new UnsupportedOperationException(); } @Override public boolean hasUDFs() { return false; } }; PhoenixConnection connection = DriverManager.getConnection(getUrl(), PropertiesUtil.deepCopy(TEST_PROPERTIES)) .unwrap(PhoenixConnection.class); final PhoenixStatement statement = new PhoenixStatement(connection); final StatementContext context = new StatementContext(statement, resolver, scan, new SequenceManager(statement)); context.setScanRanges(scanRanges); ParallelIterators parallelIterators = new ParallelIterators( new QueryPlan() { @Override public StatementContext getContext() { return context; } @Override public ParameterMetaData getParameterMetaData() { return PhoenixParameterMetaData.EMPTY_PARAMETER_META_DATA; } @Override public ExplainPlan getExplainPlan() throws SQLException { return ExplainPlan.EMPTY_PLAN; } @Override public ResultIterator iterator(ParallelScanGrouper scanGrouper) throws SQLException { return ResultIterator.EMPTY_ITERATOR; } @Override public ResultIterator iterator() throws SQLException { return ResultIterator.EMPTY_ITERATOR; } @Override public long getEstimatedSize() { return 0; } @Override public TableRef getTableRef() { return tableRef; } @Override public RowProjector getProjector() { return RowProjector.EMPTY_PROJECTOR; } @Override public Integer getLimit() { return null; } @Override public OrderBy getOrderBy() { return OrderBy.EMPTY_ORDER_BY; } @Override public GroupBy getGroupBy() { return GroupBy.EMPTY_GROUP_BY; } @Override public List<KeyRange> getSplits() { return null; } @Override public FilterableStatement getStatement() { return SelectStatement.SELECT_ONE; } @Override public boolean isDegenerate() { return false; } @Override public boolean isRowKeyOrdered() { return true; } @Override public List<List<Scan>> getScans() { return null; } @Override public boolean useRoundRobinIterator() { return false; } }, null, new SpoolingResultIterator.SpoolingResultIteratorFactory( context.getConnection().getQueryServices())); List<KeyRange> keyRanges = parallelIterators.getSplits(); return keyRanges; }