Merge branch cassandra-3.0 into cassandra-3.11
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/95cfee62 Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/95cfee62 Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/95cfee62 Branch: refs/heads/cassandra-3.11 Commit: 95cfee623456f1df51ce548cc6cf42fe5a78050c Parents: 845243d 598008d Author: Benjamin Lerer <[email protected]> Authored: Tue Apr 17 12:14:58 2018 +0200 Committer: Benjamin Lerer <[email protected]> Committed: Tue Apr 17 12:27:25 2018 +0200 ---------------------------------------------------------------------- CHANGES.txt | 1 + .../org/apache/cassandra/cql3/ResultSet.java | 5 ++ .../cassandra/cql3/selection/Selection.java | 70 +++++++++++++++++--- .../cql3/statements/SelectStatement.java | 20 +++--- .../cql3/validation/entities/JsonTest.java | 41 +++++++++++- 5 files changed, 116 insertions(+), 21 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/95cfee62/CHANGES.txt ---------------------------------------------------------------------- diff --cc CHANGES.txt index 4c513d7,d3d8036..42ea3b4 --- a/CHANGES.txt +++ b/CHANGES.txt @@@ -25,6 -15,8 +25,7 @@@ Merged from 3.0 * Fully utilise specified compaction threads (CASSANDRA-14210) * Pre-create deletion log records to finish compactions quicker (CASSANDRA-12763) Merged from 2.2: + * Fix JSON queries with IN restrictions and ORDER BY clause (CASSANDRA-14286) - * CQL fromJson(null) throws NullPointerException (CASSANDRA-13891) * Backport circleci yaml (CASSANDRA-14240) Merged from 2.1: * Check checksum before decompressing data (CASSANDRA-14284) http://git-wip-us.apache.org/repos/asf/cassandra/blob/95cfee62/src/java/org/apache/cassandra/cql3/ResultSet.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/95cfee62/src/java/org/apache/cassandra/cql3/selection/Selection.java ---------------------------------------------------------------------- diff --cc src/java/org/apache/cassandra/cql3/selection/Selection.java index 7b4e80c,6227158..fb0b60c --- a/src/java/org/apache/cassandra/cql3/selection/Selection.java +++ b/src/java/org/apache/cassandra/cql3/selection/Selection.java @@@ -271,41 -288,13 +311,43 @@@ public abstract class Selectio @Override public String toString() { - return Objects.toStringHelper(this) - .add("columns", columns) - .add("columnMapping", columnMapping) - .add("metadata", metadata) - .add("collectTimestamps", collectTimestamps) - .add("collectTTLs", collectTTLs) - .toString(); + return MoreObjects.toStringHelper(this) + .add("columns", columns) + .add("columnMapping", columnMapping) + .add("metadata", metadata) + .add("collectTimestamps", collectTimestamps) + .add("collectTTLs", collectTTLs) + .toString(); + } + + public static List<ByteBuffer> rowToJson(List<ByteBuffer> row, ProtocolVersion protocolVersion, ResultSet.ResultMetadata metadata) + { + StringBuilder sb = new StringBuilder("{"); - for (int i = 0; i < metadata.names.size(); i++) ++ for (int i = 0; i < metadata.getColumnCount(); i++) + { + if (i > 0) + sb.append(", "); + + ColumnSpecification spec = metadata.names.get(i); + String columnName = spec.name.toString(); + if (!columnName.equals(columnName.toLowerCase(Locale.US))) + columnName = "\"" + columnName + "\""; + + ByteBuffer buffer = row.get(i); + sb.append('"'); + sb.append(Json.quoteAsJsonString(columnName)); + sb.append("\": "); + if (buffer == null) + sb.append("null"); + else if (!buffer.hasRemaining()) + sb.append("\"\""); + else + sb.append(spec.type.toJSONString(buffer, protocolVersion)); + } + sb.append("}"); - return Collections.singletonList(UTF8Type.instance.getSerializer().serialize(sb.toString())); ++ List<ByteBuffer> jsonRow = new ArrayList<>(); ++ jsonRow.add(UTF8Type.instance.getSerializer().serialize(sb.toString())); ++ return jsonRow; } public class ResultSetBuilder @@@ -445,12 -409,51 +487,24 @@@ return resultSet; } - private List<ByteBuffer> getOutputRow(int protocolVersion) + private List<ByteBuffer> getOutputRow() { List<ByteBuffer> outputRow = selectors.getOutputRow(protocolVersion); - return isJson ? rowToJson(outputRow, protocolVersion, metadata) - : outputRow; + if (isJson) + { - List<ByteBuffer> jsonRow = rowToJson(outputRow, protocolVersion); ++ // Keep all columns around for possible post-query ordering. (CASSANDRA-14286) ++ List<ByteBuffer> jsonRow = rowToJson(outputRow, protocolVersion, metadata); + + // Keep ordering columns around for possible post-query ordering. (CASSANDRA-14286) + if (orderingIndex != null) + { + for (Integer orderingColumnIndex : orderingIndex.values()) + jsonRow.add(outputRow.get(orderingColumnIndex)); + } + outputRow = jsonRow; + } + return outputRow; } - - private List<ByteBuffer> rowToJson(List<ByteBuffer> row, int protocolVersion) - { - StringBuilder sb = new StringBuilder("{"); - for (int i = 0; i < metadata.getColumnCount(); i++) - { - if (i > 0) - sb.append(", "); - - ColumnSpecification spec = metadata.names.get(i); - String columnName = spec.name.toString(); - if (!columnName.equals(columnName.toLowerCase(Locale.US))) - columnName = "\"" + columnName + "\""; - - ByteBuffer buffer = row.get(i); - sb.append('"'); - sb.append(Json.quoteAsJsonString(columnName)); - sb.append("\": "); - if (buffer == null || !buffer.hasRemaining()) - sb.append("null"); - else - sb.append(spec.type.toJSONString(buffer, protocolVersion)); - } - sb.append("}"); - List<ByteBuffer> jsonRow = new ArrayList<>(); - jsonRow.add(UTF8Type.instance.getSerializer().serialize(sb.toString())); - return jsonRow; - } } private static interface Selectors http://git-wip-us.apache.org/repos/asf/cassandra/blob/95cfee62/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java ---------------------------------------------------------------------- diff --cc src/java/org/apache/cassandra/cql3/statements/SelectStatement.java index a7ba6aa,a5e6254..348fa52 --- a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java @@@ -22,7 -22,7 +22,6 @@@ import java.util.ArrayList import java.util.Collection; import java.util.Collections; import java.util.Comparator; --import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; @@@ -1159,10 -1028,11 +1159,10 @@@ public class SelectStatement implement List<Integer> idToSort = new ArrayList<Integer>(); List<Comparator<ByteBuffer>> sorters = new ArrayList<Comparator<ByteBuffer>>(); - for (ColumnIdentifier.Raw raw : parameters.orderings.keySet()) + for (ColumnDefinition.Raw raw : parameters.orderings.keySet()) { - ColumnIdentifier identifier = raw.prepare(cfm); - ColumnDefinition orderingColumn = cfm.getColumnDefinition(identifier); + ColumnDefinition orderingColumn = raw.prepare(cfm); - idToSort.add(orderingIndexes.get(orderingColumn.name)); + idToSort.add(orderingIndexes.get(orderingColumn)); sorters.add(orderingColumn.type); } return idToSort.size() == 1 ? new SingleColumnComparator(idToSort.get(0), sorters.get(0)) @@@ -1175,16 -1045,15 +1175,12 @@@ // If we order post-query (see orderResults), the sorted column needs to be in the ResultSet for sorting, // even if we don't // ultimately ship them to the client (CASSANDRA-4911). - Map<ColumnIdentifier, Integer> orderingIndexes = new HashMap<>(); - for (ColumnIdentifier.Raw raw : parameters.orderings.keySet()) + for (ColumnDefinition.Raw raw : parameters.orderings.keySet()) { - ColumnIdentifier column = raw.prepare(cfm); - final ColumnDefinition def = cfm.getColumnDefinition(column); - if (def == null) - handleUnrecognizedOrderingColumn(column); + final ColumnDefinition def = raw.prepare(cfm); - int index = selection.getResultSetIndex(def); - if (index < 0) - index = selection.addColumnForOrdering(def); - orderingIndexes.put(def.name, index); + selection.addColumnForOrdering(def); } - return orderingIndexes; + return selection.getOrderingIndex(isJson); } private boolean isReversed(CFMetaData cfm) throws InvalidRequestException http://git-wip-us.apache.org/repos/asf/cassandra/blob/95cfee62/test/unit/org/apache/cassandra/cql3/validation/entities/JsonTest.java ---------------------------------------------------------------------- diff --cc test/unit/org/apache/cassandra/cql3/validation/entities/JsonTest.java index a475671,e6537d0..16df6e1 --- a/test/unit/org/apache/cassandra/cql3/validation/entities/JsonTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/JsonTest.java @@@ -1356,17 -1267,24 +1356,56 @@@ public class JsonTest extends CQLTeste Assert.assertTrue(executor.awaitTermination(30, TimeUnit.SECONDS)); } - @Test ++ @Test + public void emptyStringJsonSerializationTest() throws Throwable + { + createTable("create table %s(id INT, name TEXT, PRIMARY KEY(id));"); + execute("insert into %s(id, name) VALUES (0, 'Foo');"); + execute("insert into %s(id, name) VALUES (2, '');"); + execute("insert into %s(id, name) VALUES (3, null);"); + + assertRows(execute("SELECT JSON * FROM %s"), + row("{\"id\": 0, \"name\": \"Foo\"}"), + row("{\"id\": 2, \"name\": \"\"}"), + row("{\"id\": 3, \"name\": null}")); + } ++ + // CASSANDRA-14286 + @Test + public void testJsonOrdering() throws Throwable + { + createTable("CREATE TABLE %s( PRIMARY KEY (a, b), a INT, b INT);"); + execute("INSERT INTO %s(a, b) VALUES (20, 30);"); + execute("INSERT INTO %s(a, b) VALUES (100, 200);"); + + assertRows(execute("SELECT JSON a, b FROM %s WHERE a IN (20, 100) ORDER BY b"), + row("{\"a\": 20, \"b\": 30}"), + row("{\"a\": 100, \"b\": 200}")); + + assertRows(execute("SELECT JSON a, b FROM %s WHERE a IN (20, 100) ORDER BY b DESC"), + row("{\"a\": 100, \"b\": 200}"), + row("{\"a\": 20, \"b\": 30}")); + + assertRows(execute("SELECT JSON a FROM %s WHERE a IN (20, 100) ORDER BY b DESC"), + row("{\"a\": 100}"), + row("{\"a\": 20}")); ++ ++ // Check ordering with alias ++ assertRows(execute("SELECT JSON a, b as c FROM %s WHERE a IN (20, 100) ORDER BY b"), ++ row("{\"a\": 20, \"c\": 30}"), ++ row("{\"a\": 100, \"c\": 200}")); ++ ++ assertRows(execute("SELECT JSON a, b as c FROM %s WHERE a IN (20, 100) ORDER BY b DESC"), ++ row("{\"a\": 100, \"c\": 200}"), ++ row("{\"a\": 20, \"c\": 30}")); ++ ++ // Check ordering with CAST ++ assertRows(execute("SELECT JSON a, CAST(b AS FLOAT) FROM %s WHERE a IN (20, 100) ORDER BY b"), ++ row("{\"a\": 20, \"cast(b as float)\": 30.0}"), ++ row("{\"a\": 100, \"cast(b as float)\": 200.0}")); ++ ++ assertRows(execute("SELECT JSON a, CAST(b AS FLOAT) FROM %s WHERE a IN (20, 100) ORDER BY b DESC"), ++ row("{\"a\": 100, \"cast(b as float)\": 200.0}"), ++ row("{\"a\": 20, \"cast(b as float)\": 30.0}")); + } } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
