Repository: hbase Updated Branches: refs/heads/branch-1 158607bf2 -> 4256d38ba refs/heads/branch-1.4 aa28cf7e9 -> 4b5d2def3
HBASE-21174 [REST] Failed to parse empty qualifier in TableResource#getScanResource Signed-off-by: tedyu <yuzhih...@gmail.com> Project: http://git-wip-us.apache.org/repos/asf/hbase/repo Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/4256d38b Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/4256d38b Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/4256d38b Branch: refs/heads/branch-1 Commit: 4256d38bac0b02946f269d6332449dd87f522578 Parents: 158607b Author: Guangxu Cheng <guangxuch...@gmail.com> Authored: Wed Sep 12 22:51:03 2018 +0800 Committer: Guangxu Cheng <guangxuch...@gmail.com> Committed: Wed Sep 12 23:00:34 2018 +0800 ---------------------------------------------------------------------- .../apache/hadoop/hbase/rest/TableResource.java | 37 ++++++------- .../apache/hadoop/hbase/rest/TestTableScan.java | 55 +++++++++++++++++--- 2 files changed, 64 insertions(+), 28 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/hbase/blob/4256d38b/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/TableResource.java ---------------------------------------------------------------------- diff --git a/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/TableResource.java b/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/TableResource.java index a1a60bb..b208c96 100644 --- a/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/TableResource.java +++ b/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/TableResource.java @@ -24,16 +24,14 @@ import java.util.List; import javax.ws.rs.DefaultValue; import javax.ws.rs.Encoded; -import javax.ws.rs.HeaderParam; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.UriInfo; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.hbase.client.Scan; @@ -129,7 +127,7 @@ public class TableResource extends ResourceBase { @QueryParam(Constants.SCAN_LIMIT) int userRequestedLimit, @DefaultValue("") @QueryParam(Constants.SCAN_START_ROW) String startRow, @DefaultValue("") @QueryParam(Constants.SCAN_END_ROW) String endRow, - @DefaultValue("") @QueryParam(Constants.SCAN_COLUMN) List<String> column, + @QueryParam(Constants.SCAN_COLUMN) List<String> column, @DefaultValue("1") @QueryParam(Constants.SCAN_MAX_VERSIONS) int maxVersions, @DefaultValue("-1") @QueryParam(Constants.SCAN_BATCH_SIZE) int batchSize, @DefaultValue("0") @QueryParam(Constants.SCAN_START_TIME) long startTime, @@ -162,26 +160,21 @@ public class TableResource extends ResourceBase { tableScan.setStartRow(Bytes.toBytes(startRow)); } tableScan.setStopRow(Bytes.toBytes(endRow)); - for (String csplit : column) { - String[] familysplit = csplit.trim().split(":"); - if (familysplit.length == 2) { - if (familysplit[1].length() > 0) { - if (LOG.isTraceEnabled()) { - LOG.trace("Scan family and column : " + familysplit[0] + " " + familysplit[1]); - } - tableScan.addColumn(Bytes.toBytes(familysplit[0]), Bytes.toBytes(familysplit[1])); - } else { - tableScan.addFamily(Bytes.toBytes(familysplit[0])); - if (LOG.isTraceEnabled()) { - LOG.trace("Scan family : " + familysplit[0] + " and empty qualifier."); - } - tableScan.addColumn(Bytes.toBytes(familysplit[0]), null); + for (String col : column) { + byte [][] parts = KeyValue.parseColumn(Bytes.toBytes(col.trim())); + if (parts.length == 1) { + if (LOG.isTraceEnabled()) { + LOG.trace("Scan family : " + Bytes.toStringBinary(parts[0])); } - } else if (StringUtils.isNotEmpty(familysplit[0])) { + tableScan.addFamily(parts[0]); + } else if (parts.length == 2) { if (LOG.isTraceEnabled()) { - LOG.trace("Scan family : " + familysplit[0]); + LOG.trace("Scan family and column : " + Bytes.toStringBinary(parts[0]) + + " " + Bytes.toStringBinary(parts[1])); } - tableScan.addFamily(Bytes.toBytes(familysplit[0])); + tableScan.addColumn(parts[0], parts[1]); + } else { + throw new IllegalArgumentException("Invalid column specifier."); } } @@ -205,7 +198,7 @@ public class TableResource extends ResourceBase { tableScan.setCaching(fetchSize); tableScan.setReversed(reversed); tableScan.setCacheBlocks(cacheBlocks); - return new TableScanResource(hTable.getScanner(tableScan), userRequestedLimit); + return new TableScanResource(hTable.getScanner(tableScan), userRequestedLimit); } catch (Exception exp) { servlet.getMetrics().incrementFailedScanRequests(1); processException(exp); http://git-wip-us.apache.org/repos/asf/hbase/blob/4256d38b/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/TestTableScan.java ---------------------------------------------------------------------- diff --git a/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/TestTableScan.java b/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/TestTableScan.java index d3e618b..0c7d6d8 100644 --- a/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/TestTableScan.java +++ b/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/TestTableScan.java @@ -81,9 +81,11 @@ public class TestTableScan { private static final String CFB = "b"; private static final String COLUMN_1 = CFA + ":1"; private static final String COLUMN_2 = CFB + ":2"; + private static final String COLUMN_EMPTY = CFA + ":"; private static Client client; private static int expectedRows1; private static int expectedRows2; + private static int expectedRows3; private static Configuration conf; private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(); @@ -100,12 +102,13 @@ public class TestTableScan { REST_TEST_UTIL.getServletPort())); Admin admin = TEST_UTIL.getHBaseAdmin(); if (!admin.tableExists(TABLE)) { - HTableDescriptor htd = new HTableDescriptor(TABLE); - htd.addFamily(new HColumnDescriptor(CFA)); - htd.addFamily(new HColumnDescriptor(CFB)); - admin.createTable(htd); - expectedRows1 = TestScannerResource.insertData(conf, TABLE, COLUMN_1, 1.0); - expectedRows2 = TestScannerResource.insertData(conf, TABLE, COLUMN_2, 0.5); + HTableDescriptor htd = new HTableDescriptor(TABLE); + htd.addFamily(new HColumnDescriptor(CFA)); + htd.addFamily(new HColumnDescriptor(CFB)); + admin.createTable(htd); + expectedRows1 = TestScannerResource.insertData(conf, TABLE, COLUMN_1, 1.0); + expectedRows2 = TestScannerResource.insertData(conf, TABLE, COLUMN_2, 0.5); + expectedRows3 = TestScannerResource.insertData(conf, TABLE, COLUMN_EMPTY, 1.0); } } @@ -620,6 +623,46 @@ public class TestTableScan { } } + @Test + public void testColumnWithEmptyQualifier() throws IOException, JAXBException { + // Test scanning with empty qualifier + StringBuilder builder = new StringBuilder(); + builder.append("/*"); + builder.append("?"); + builder.append(Constants.SCAN_COLUMN + "=" + COLUMN_EMPTY); + Response response = client.get("/" + TABLE + builder.toString(), + Constants.MIMETYPE_JSON); + assertEquals(200, response.getCode()); + assertEquals(Constants.MIMETYPE_JSON, response.getHeader("content-type")); + ObjectMapper mapper = new JacksonProvider() + .locateMapper(CellSetModel.class, MediaType.APPLICATION_JSON_TYPE); + CellSetModel model = mapper.readValue(response.getStream(), CellSetModel.class); + int count = TestScannerResource.countCellSet(model); + assertEquals(expectedRows3, count); + checkRowsNotNull(model); + RowModel startRow = model.getRows().get(0); + assertEquals("aaa", Bytes.toString(startRow.getKey())); + assertEquals(1, startRow.getCells().size()); + + // Test scanning with empty qualifier and normal qualifier + builder = new StringBuilder(); + builder.append("/*"); + builder.append("?"); + builder.append(Constants.SCAN_COLUMN + "=" + COLUMN_1); + builder.append("&"); + builder.append(Constants.SCAN_COLUMN + "=" + COLUMN_EMPTY); + response = client.get("/" + TABLE + builder.toString(), + Constants.MIMETYPE_JSON); + assertEquals(200, response.getCode()); + assertEquals(Constants.MIMETYPE_JSON, response.getHeader("content-type")); + mapper = new JacksonProvider() + .locateMapper(CellSetModel.class, MediaType.APPLICATION_JSON_TYPE); + model = mapper.readValue(response.getStream(), CellSetModel.class); + count = TestScannerResource.countCellSet(model); + assertEquals(expectedRows1 + expectedRows3, count); + checkRowsNotNull(model); + } + public static class CustomFilter extends PrefixFilter { private byte[] key = null;