private static void projectAllColumnFamilies(PTable table, Scan scan) { // Will project all known/declared column families scan.getFamilyMap().clear(); for (PColumnFamily family : table.getColumnFamilies()) { scan.addFamily(family.getName().getBytes()); } }
/** * @param scan the scan specification * @throws Exception */ public static ScannerModel fromScan(Scan scan) throws Exception { ScannerModel model = new ScannerModel(); model.setStartRow(scan.getStartRow()); model.setEndRow(scan.getStopRow()); Map<byte[], NavigableSet<byte[]>> families = scan.getFamilyMap(); if (families != null) { for (Map.Entry<byte[], NavigableSet<byte[]>> entry : families.entrySet()) { if (entry.getValue() != null) { for (byte[] qualifier : entry.getValue()) { model.addColumn(Bytes.add(entry.getKey(), COLUMN_DIVIDER, qualifier)); } } else { model.addColumn(entry.getKey()); } } } model.setStartTime(scan.getTimeRange().getMin()); model.setEndTime(scan.getTimeRange().getMax()); int caching = scan.getCaching(); if (caching > 0) { model.setBatch(caching); } int maxVersions = scan.getMaxVersions(); if (maxVersions > 0) { model.setMaxVersions(maxVersions); } Filter filter = scan.getFilter(); if (filter != null) { model.setFilter(stringifyFilter(filter)); } return model; }
private RowFilter createColumnFamilyFilter(Scan scan) { // Build a filter of the form: // (fam1 | (qual1 + qual2 + qual3)) + (fam2 | qual1) + (fam3) RowFilter.Interleave.Builder interleaveBuilder = RowFilter.Interleave.newBuilder(); Map<byte[], NavigableSet<byte[]>> familyMap = scan.getFamilyMap(); if (!scan.getFamilyMap().isEmpty()) { for (Map.Entry<byte[], NavigableSet<byte[]>> entry : familyMap.entrySet()) { if (entry.getValue() == null) { // No qualifier, add the entire family: interleaveBuilder.addFilters(createFamilyFilter(entry.getKey())); } else if (entry.getValue().size() == 1) { // Build filter of the form "family | qual" Chain.Builder familyBuilder = interleaveBuilder.addFiltersBuilder().getChainBuilder(); familyBuilder.addFilters(createFamilyFilter(entry.getKey())); familyBuilder.addFilters(createColumnQualifierFilter(entry.getValue().first())); } else { // Build filter of the form "family | (qual1 + qual2 + qual3)" Chain.Builder familyBuilder = interleaveBuilder.addFiltersBuilder().getChainBuilder(); familyBuilder.addFilters(createFamilyFilter(entry.getKey())); // Add a qualifier filter for each specified qualifier: Interleave.Builder columnFilters = familyBuilder.addFiltersBuilder().getInterleaveBuilder(); for (byte[] qualifier : entry.getValue()) { columnFilters.addFilters(createColumnQualifierFilter(qualifier)); } } } } else { // Simplify processing a bit and add an explicit inclusion of all families: interleaveBuilder.addFiltersBuilder().setFamilyNameRegexFilter(".*"); } if (interleaveBuilder.getFiltersCount() > 1) { return RowFilter.newBuilder().setInterleave(interleaveBuilder).build(); } else { return interleaveBuilder.getFilters(0); } }
public static Scan newScan(Scan scan) { try { Scan newScan = new Scan(scan); // Clone the underlying family map instead of sharing it between // the existing and cloned Scan (which is the retarded default // behavior). TreeMap<byte[], NavigableSet<byte[]>> existingMap = (TreeMap<byte[], NavigableSet<byte[]>>) scan.getFamilyMap(); Map<byte[], NavigableSet<byte[]>> clonedMap = new TreeMap<byte[], NavigableSet<byte[]>>(existingMap); newScan.setFamilyMap(clonedMap); // Carry over the reversed attribute newScan.setReversed(scan.isReversed()); newScan.setSmall(scan.isSmall()); return newScan; } catch (IOException e) { throw new RuntimeException(e); } }
/** * Attempts to run a Get on some queue. Will only return a non-null result if we currently own the * queue. * * @param get The Get that we want to query * @return The result of the Get if this server is the owner of the queue. Else it returns null. * @throws IOException */ private Result getResultIfOwner(Get get) throws IOException { Scan scan = new Scan(get); // Check if the Get currently contains all columns or only specific columns if (scan.getFamilyMap().size() > 0) { // Add the OWNER column if the scan is already only over specific columns scan.addColumn(CF_QUEUE, COL_QUEUE_OWNER); } scan.setMaxResultSize(1); SingleColumnValueFilter checkOwner = new SingleColumnValueFilter( CF_QUEUE, COL_QUEUE_OWNER, CompareFilter.CompareOp.EQUAL, serverNameBytes); scan.setFilter(checkOwner); ResultScanner scanner = null; try { scanner = replicationTable.getScanner(scan); Result result = scanner.next(); return (result == null || result.isEmpty()) ? null : result; } finally { if (scanner != null) { scanner.close(); } } }
/** * Builds the projection for the scan * * @param context query context kept between compilation of different query clauses * @param statement TODO * @param groupBy compiled GROUP BY clause * @param targetColumns list of columns, parallel to aliasedNodes, that are being set for an * UPSERT SELECT statement. Used to coerce expression types to the expected target type. * @return projector used to access row values during scan * @throws SQLException */ public static RowProjector compile( StatementContext context, SelectStatement statement, GroupBy groupBy, List<? extends PDatum> targetColumns) throws SQLException { List<AliasedNode> aliasedNodes = statement.getSelect(); // Setup projected columns in Scan SelectClauseVisitor selectVisitor = new SelectClauseVisitor(context, groupBy); List<ExpressionProjector> projectedColumns = new ArrayList<ExpressionProjector>(); TableRef tableRef = context.getResolver().getTables().get(0); PTable table = tableRef.getTable(); boolean isWildcard = false; Scan scan = context.getScan(); int index = 0; List<Expression> projectedExpressions = Lists.newArrayListWithExpectedSize(aliasedNodes.size()); List<byte[]> projectedFamilies = Lists.newArrayListWithExpectedSize(aliasedNodes.size()); for (AliasedNode aliasedNode : aliasedNodes) { ParseNode node = aliasedNode.getNode(); // TODO: visitor? if (node instanceof WildcardParseNode) { if (statement.isAggregate()) { ExpressionCompiler.throwNonAggExpressionInAggException(node.toString()); } isWildcard = true; if (tableRef.getTable().getType() == PTableType.INDEX && ((WildcardParseNode) node).isRewrite()) { projectAllIndexColumns(context, tableRef, projectedExpressions, projectedColumns); } else { projectAllTableColumns(context, tableRef, projectedExpressions, projectedColumns); } } else if (node instanceof FamilyWildcardParseNode) { // Project everything for SELECT cf.* // TODO: support cf.* expressions for multiple tables the same way with *. String cfName = ((FamilyWildcardParseNode) node).getName(); // Delay projecting to scan, as when any other column in the column family gets // added to the scan, it overwrites that we want to project the entire column // family. Instead, we do the projection at the end. // TODO: consider having a ScanUtil.addColumn and ScanUtil.addFamily to work // around this, as this code depends on this function being the last place where // columns are projected (which is currently true, but could change). projectedFamilies.add(Bytes.toBytes(cfName)); if (tableRef.getTable().getType() == PTableType.INDEX && ((FamilyWildcardParseNode) node).isRewrite()) { projectIndexColumnFamily( context, cfName, tableRef, projectedExpressions, projectedColumns); } else { projectTableColumnFamily( context, cfName, tableRef, projectedExpressions, projectedColumns); } } else { Expression expression = node.accept(selectVisitor); projectedExpressions.add(expression); if (index < targetColumns.size()) { PDatum targetColumn = targetColumns.get(index); if (targetColumn.getDataType() != expression.getDataType()) { PDataType targetType = targetColumn.getDataType(); // Check if coerce allowed using more relaxed isCastableTo check, since we promote // INTEGER to LONG // during expression evaluation and then convert back to INTEGER on UPSERT SELECT (and // we don't have // (an actual value we can specifically check against). if (expression.getDataType() != null && !expression.getDataType().isCastableTo(targetType)) { throw new ArgumentTypeMismatchException( targetType, expression.getDataType(), "column: " + targetColumn); } expression = CoerceExpression.create(expression, targetType); } } if (node instanceof BindParseNode) { context.getBindManager().addParamMetaData((BindParseNode) node, expression); } if (!node.isStateless()) { if (!selectVisitor.isAggregate() && statement.isAggregate()) { ExpressionCompiler.throwNonAggExpressionInAggException(expression.toString()); } } String columnAlias = aliasedNode.getAlias() != null ? aliasedNode.getAlias() : SchemaUtil.normalizeIdentifier(aliasedNode.getNode().getAlias()); boolean isCaseSensitive = (columnAlias != null && (aliasedNode.isCaseSensitve() || SchemaUtil.isCaseSensitive(columnAlias))) || selectVisitor.isCaseSensitive; String name = columnAlias == null ? expression.toString() : columnAlias; projectedColumns.add( new ExpressionProjector( name, table.getName().getString(), expression, isCaseSensitive)); } selectVisitor.reset(); index++; } table = context.getCurrentTable().getTable(); // switch to current table for scan projection // TODO make estimatedByteSize more accurate by counting the joined columns. int estimatedKeySize = table.getRowKeySchema().getEstimatedValueLength(); int estimatedByteSize = 0; for (Map.Entry<byte[], NavigableSet<byte[]>> entry : scan.getFamilyMap().entrySet()) { PColumnFamily family = table.getColumnFamily(entry.getKey()); if (entry.getValue() == null) { for (PColumn column : family.getColumns()) { Integer byteSize = column.getByteSize(); estimatedByteSize += SizedUtil.KEY_VALUE_SIZE + estimatedKeySize + (byteSize == null ? RowKeySchema.ESTIMATED_VARIABLE_LENGTH_SIZE : byteSize); } } else { for (byte[] cq : entry.getValue()) { PColumn column = family.getColumn(cq); Integer byteSize = column.getByteSize(); estimatedByteSize += SizedUtil.KEY_VALUE_SIZE + estimatedKeySize + (byteSize == null ? RowKeySchema.ESTIMATED_VARIABLE_LENGTH_SIZE : byteSize); } } } selectVisitor.compile(); // Since we don't have the empty key value in read-only tables, // we must project everything. boolean isProjectEmptyKeyValue = table.getType() != PTableType.VIEW && table.getViewType() != ViewType.MAPPED && !isWildcard; if (isProjectEmptyKeyValue) { for (byte[] family : projectedFamilies) { projectColumnFamily(table, scan, family); } } else { /* * TODO: this could be optimized by detecting: * - if a column is projected that's not in the where clause * - if a column is grouped by that's not in the where clause * - if we're not using IS NULL or CASE WHEN expressions */ projectAllColumnFamilies(table, scan); } return new RowProjector(projectedColumns, estimatedByteSize, isProjectEmptyKeyValue); }