You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by ms...@apache.org on 2016/08/16 22:42:40 UTC
[39/50] [abbrv] cassandra git commit: Fix queries with empty
ByteBuffer values in clustering column restrictions
Fix queries with empty ByteBuffer values in clustering column restrictions
patch by Benjamin Lerer; reviewed by jason Brown and Tyler Hobbs for CASSANDRA-12127
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/527d1897
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/527d1897
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/527d1897
Branch: refs/heads/cassandra-3.8
Commit: 527d1897c0973491bb0db098ce5ea1e0bd78898f
Parents: bd66547
Author: Benjamin Lerer <b....@gmail.com>
Authored: Tue Aug 16 15:17:59 2016 +0200
Committer: Benjamin Lerer <b....@gmail.com>
Committed: Tue Aug 16 15:17:59 2016 +0200
----------------------------------------------------------------------
CHANGES.txt | 1 +
NEWS.txt | 10 +
.../cql3/statements/SelectStatement.java | 90 ++++-
.../cql3/statements/UpdateStatement.java | 2 +-
.../cassandra/db/compaction/Scrubber.java | 157 ++++++--
.../cassandra/db/marshal/ReversedType.java | 10 -
.../validation/entities/SecondaryIndexTest.java | 142 ++++++-
.../cql3/validation/operations/DeleteTest.java | 42 +++
.../cql3/validation/operations/SelectTest.java | 373 +++++++++++++++++++
.../cassandra/db/marshal/ReversedTypeTest.java | 4 +-
10 files changed, 782 insertions(+), 49 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/527d1897/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 1275631..dee669a 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
2.1.16
+ * Fix queries with empty ByteBuffer values in clustering column restrictions (CASSANDRA-12127)
* Disable passing control to post-flush after flush failure to prevent data loss (CASSANDRA-11828)
* Allow STCS-in-L0 compactions to reduce scope with LCS (CASSANDRA-12040)
* cannot use cql since upgrading python to 2.7.11+ (CASSANDRA-11850)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/527d1897/NEWS.txt
----------------------------------------------------------------------
diff --git a/NEWS.txt b/NEWS.txt
index 7f1b54a..6a70adc 100644
--- a/NEWS.txt
+++ b/NEWS.txt
@@ -13,6 +13,16 @@ restore snapshots created with the previous major version using the
'sstableloader' tool. You can upgrade the file format of your snapshots
using the provided 'sstableupgrade' tool.
+2.1.16
+======
+
+Upgrading
+---------
+ - The ReversedType behaviour has been corrected for clustering columns of
+ BYTES type containing empty value. Scrub should be run on the existing
+ SSTables containing a descending clustering column of BYTES type to correct
+ their ordering. See CASSANDRA-12127 for details.
+
2.1.15
======
http://git-wip-us.apache.org/repos/asf/cassandra/blob/527d1897/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
index 245e64e..40f3f33 100644
--- a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
@@ -30,6 +30,7 @@ import com.google.common.collect.Iterators;
import org.apache.cassandra.auth.Permission;
import org.apache.cassandra.cql3.*;
+import org.apache.cassandra.cql3.statements.Restriction.Slice;
import org.apache.cassandra.cql3.statements.SingleColumnRestriction.Contains;
import org.apache.cassandra.db.composites.*;
import org.apache.cassandra.transport.messages.ResultMessage;
@@ -246,6 +247,9 @@ public class SelectStatement implements CQLStatement
private Pageable getPageableCommand(QueryOptions options, int limit, long now) throws RequestValidationException
{
+ if (isNotReturningAnyRows(options))
+ return null;
+
int limitForQuery = updateLimitForQuery(limit);
if (isKeyRange || usesSecondaryIndexing)
return getRangeCommand(options, limitForQuery, now);
@@ -254,6 +258,47 @@ public class SelectStatement implements CQLStatement
return commands == null ? null : new Pageable.ReadCommands(commands, limitForQuery);
}
+ /**
+ * Checks if the query will never return any rows.
+ *
+ * @param options the query options
+ * @return {@code true} if the query will never return any rows, {@false} otherwise
+ * @throws InvalidRequestException if the request is invalid
+ */
+ private boolean isNotReturningAnyRows(QueryOptions options) throws InvalidRequestException
+ {
+ // Dense non-compound tables do not accept empty ByteBuffers. By consequence, we know that:
+ // - any query with an EQ restriction containing an empty value will not return any result
+ // - any query with a slice restriction with an empty value for the END bound will not return any result
+
+ if (cfm.comparator.isDense() && !cfm.comparator.isCompound())
+ {
+ for (Restriction restriction : columnRestrictions)
+ {
+ if (restriction != null)
+ {
+ if (restriction.isEQ())
+ {
+ for (ByteBuffer value : restriction.values(options))
+ {
+ if (!value.hasRemaining())
+ return true;
+ }
+ }
+ else if (restriction.isSlice() && ((Slice) restriction).hasBound(Bound.END))
+ {
+ ByteBuffer value = restriction.isMultiColumn()
+ ? ((MultiColumnRestriction.Slice) restriction).componentBounds(Bound.END, options).get(0)
+ : ((Slice) restriction).bound(Bound.END, options);
+
+ return !value.hasRemaining();
+ }
+ }
+ }
+ }
+ return false;
+ }
+
public Pageable getPageableCommand(QueryOptions options) throws RequestValidationException
{
return getPageableCommand(options, getLimit(options), System.currentTimeMillis());
@@ -820,6 +865,9 @@ public class SelectStatement implements CQLStatement
if (val == null)
throw new InvalidRequestException(String.format("Invalid null value for clustering key part %s", def.name));
+ if (ignoreInValue(val))
+ continue;
+
Composite prefix = builder.buildWith(val);
columns.addAll(addSelectedColumns(prefix));
}
@@ -836,6 +884,9 @@ public class SelectStatement implements CQLStatement
throw new InvalidRequestException("Invalid null value in condition for column "
+ cfm.clusteringColumns().get(i + def.position()).name);
+ if (ignoreInValue(components))
+ continue;
+
Composite prefix = builder.buildWith(components);
inValues.addAll(addSelectedColumns(prefix));
}
@@ -846,6 +897,32 @@ public class SelectStatement implements CQLStatement
return addSelectedColumns(builder.build());
}
+ /**
+ * Checks if we should ignore the specified IN value for a clustering column as it will not return any result.
+ *
+ * @param val the IN value to check
+ * @return {@code true} if we should ignore the value, {@code false} otherwise.
+ */
+ private boolean ignoreInValue(ByteBuffer val)
+ {
+ // Dense non-compound tables do not accept empty ByteBuffers. By consequence, we know that we can
+ // ignore any IN value which is an empty byte buffer an which otherwise will trigger an error.
+ return !cfm.comparator.isCompound() && !val.hasRemaining();
+ }
+
+ /**
+ * Checks if we should ignore the specified IN components for a clustering column as it will not return any result.
+ *
+ * @param components the IN components to check
+ * @return {@code true} if we should ignore the value, {@code false} otherwise.
+ */
+ private boolean ignoreInValue(List<ByteBuffer> components)
+ {
+ // Dense non-compound tables do not accept empty ByteBuffers. By consequence, we know that we can
+ // ignore any IN value which is an empty byte buffer an which otherwise will trigger an error.
+ return !cfm.comparator.isCompound() && !components.get(0).hasRemaining();
+ }
+
private SortedSet<CellName> addSelectedColumns(Composite prefix)
{
if (cfm.comparator.isDense())
@@ -1200,12 +1277,17 @@ public class SelectStatement implements CQLStatement
if (sliceRestriction.isInclusive(bound))
return null;
- if (sliceRestriction.isMultiColumn())
- return type.makeCellName(((MultiColumnRestriction.Slice) sliceRestriction).componentBounds(bound, options).toArray());
- else
- return type.makeCellName(sliceRestriction.bound(bound, options));
+ // We can only reach that point if cfm.comparator.isCompound() = false and the table has some clustering columns.
+ // By consequence, we know that the table is a COMPACT table with only one clustering column.
+ ByteBuffer value = sliceRestriction.isMultiColumn() ? ((MultiColumnRestriction.Slice) sliceRestriction).componentBounds(bound, options).get(0)
+ : sliceRestriction.bound(bound, options);
+
+ // Dense non-compound tables do not accept empty ByteBuffers. By consequence, if the slice value is empty
+ // we know that we can treat the slice as inclusive.
+ return value.hasRemaining() ? type.makeCellName(value) : null;
}
+
private Iterator<Cell> applySliceRestriction(final Iterator<Cell> cells, final QueryOptions options) throws InvalidRequestException
{
assert sliceRestriction != null;
http://git-wip-us.apache.org/repos/asf/cassandra/blob/527d1897/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java b/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java
index bf9a059..39e632a 100644
--- a/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java
@@ -84,7 +84,7 @@ public class UpdateStatement extends ModificationStatement
if (cfm.comparator.isDense())
{
if (prefix.isEmpty())
- throw new InvalidRequestException(String.format("Missing PRIMARY KEY part %s", cfm.clusteringColumns().iterator().next()));
+ throw new InvalidRequestException(String.format("Missing PRIMARY KEY part %s", cfm.clusteringColumns().iterator().next().name));
// An empty name for the compact value is what we use to recognize the case where there is not column
// outside the PK, see CreateStatement.
http://git-wip-us.apache.org/repos/asf/cassandra/blob/527d1897/src/java/org/apache/cassandra/db/compaction/Scrubber.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/compaction/Scrubber.java b/src/java/org/apache/cassandra/db/compaction/Scrubber.java
index 8bfd37b..2df3665 100644
--- a/src/java/org/apache/cassandra/db/compaction/Scrubber.java
+++ b/src/java/org/apache/cassandra/db/compaction/Scrubber.java
@@ -23,9 +23,11 @@ import java.util.*;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Throwables;
+import com.google.common.collect.AbstractIterator;
import com.google.common.collect.Sets;
import org.apache.cassandra.db.*;
+import org.apache.cassandra.db.columniterator.OnDiskAtomIterator;
import org.apache.cassandra.io.sstable.*;
import org.apache.cassandra.io.util.FileUtils;
import org.apache.cassandra.io.util.RandomAccessReader;
@@ -223,20 +225,8 @@ public class Scrubber implements Closeable
if (indexFile != null && dataSize != dataSizeFromIndex)
outputHandler.warn(String.format("Data file row size %d different from index file row size %d", dataSize, dataSizeFromIndex));
- SSTableIdentityIterator atoms = new SSTableIdentityIterator(sstable, dataFile, key, dataSize, validateColumns);
- if (prevKey != null && prevKey.compareTo(key) > 0)
- {
- saveOutOfOrderRow(prevKey, key, atoms);
- continue;
- }
-
- AbstractCompactedRow compactedRow = new LazilyCompactedRow(controller, Collections.singletonList(atoms));
- if (writer.tryAppend(compactedRow) == null)
- emptyRows++;
- else
- goodRows++;
-
- prevKey = key;
+ if (tryAppend(prevKey, key, dataSize, writer))
+ prevKey = key;
}
catch (Throwable th)
{
@@ -252,21 +242,8 @@ public class Scrubber implements Closeable
try
{
dataFile.seek(dataStartFromIndex);
-
- SSTableIdentityIterator atoms = new SSTableIdentityIterator(sstable, dataFile, key, dataSize, validateColumns);
- if (prevKey != null && prevKey.compareTo(key) > 0)
- {
- saveOutOfOrderRow(prevKey, key, atoms);
- continue;
- }
-
- AbstractCompactedRow compactedRow = new LazilyCompactedRow(controller, Collections.singletonList(atoms));
- if (writer.tryAppend(compactedRow) == null)
- emptyRows++;
- else
- goodRows++;
-
- prevKey = key;
+ if (tryAppend(prevKey, key, dataSize, writer))
+ prevKey = key;
}
catch (Throwable th2)
{
@@ -339,6 +316,32 @@ public class Scrubber implements Closeable
}
}
+ @SuppressWarnings("resource")
+ private boolean tryAppend(DecoratedKey prevKey, DecoratedKey key, long dataSize, SSTableRewriter writer)
+ {
+ // OrderCheckerIterator will check, at iteration time, that the cells are in the proper order. If it detects
+ // that one cell is out of order, it will stop returning them. The remaining cells will be sorted and added
+ // to the outOfOrderRows that will be later written to a new SSTable.
+ OrderCheckerIterator atoms = new OrderCheckerIterator(new SSTableIdentityIterator(sstable, dataFile, key, dataSize, validateColumns),
+ cfs.metadata.comparator.onDiskAtomComparator());
+ if (prevKey != null && prevKey.compareTo(key) > 0)
+ {
+ saveOutOfOrderRow(prevKey, key, atoms);
+ return false;
+ }
+
+ AbstractCompactedRow compactedRow = new LazilyCompactedRow(controller, Collections.singletonList(atoms));
+ if (writer.tryAppend(compactedRow) == null)
+ emptyRows++;
+ else
+ goodRows++;
+
+ if (atoms.hasOutOfOrderCells())
+ saveOutOfOrderRow(key, atoms);
+
+ return true;
+ }
+
private void updateIndexKey()
{
currentIndexKey = nextIndexKey;
@@ -385,12 +388,12 @@ public class Scrubber implements Closeable
}
}
- private void saveOutOfOrderRow(DecoratedKey prevKey, DecoratedKey key, SSTableIdentityIterator atoms)
+ private void saveOutOfOrderRow(DecoratedKey prevKey, DecoratedKey key, OnDiskAtomIterator atoms)
{
saveOutOfOrderRow(key, atoms, String.format("Out of order row detected (%s found after %s)", key, prevKey));
}
- void saveOutOfOrderRow(DecoratedKey key, SSTableIdentityIterator atoms, String message)
+ void saveOutOfOrderRow(DecoratedKey key, OnDiskAtomIterator atoms, String message)
{
// TODO bitch if the row is too large? if it is there's not much we can do ...
outputHandler.warn(message);
@@ -405,6 +408,12 @@ public class Scrubber implements Closeable
outOfOrderRows.add(new Row(key, cf));
}
+ void saveOutOfOrderRow(DecoratedKey key, OrderCheckerIterator atoms)
+ {
+ outputHandler.warn(String.format("Out of order cells found at key %s", key));
+ outOfOrderRows.add(new Row(key, atoms.getOutOfOrderCells()));
+ }
+
public SSTableReader getNewSSTable()
{
return newSstable;
@@ -506,4 +515,90 @@ public class Scrubber implements Closeable
this.emptyRows = scrubber.emptyRows;
}
}
+
+ /**
+ * In some case like CASSANDRA-12127 the cells might have been stored in the wrong order. This decorator check the
+ * cells order and collect the out of order cells to correct the problem.
+ */
+ private static final class OrderCheckerIterator extends AbstractIterator<OnDiskAtom> implements OnDiskAtomIterator
+ {
+ /**
+ * The decorated iterator.
+ */
+ private final OnDiskAtomIterator iterator;
+
+ /**
+ * The atom comparator.
+ */
+ private final Comparator<OnDiskAtom> comparator;
+
+ /**
+ * The Column family containing the cells which are out of order.
+ */
+ private ColumnFamily outOfOrderCells;
+
+ /**
+ * The previous atom returned
+ */
+ private OnDiskAtom previous;
+
+ public OrderCheckerIterator(OnDiskAtomIterator iterator, Comparator<OnDiskAtom> comparator)
+ {
+ this.iterator = iterator;
+ this.comparator = comparator;
+ }
+
+ public ColumnFamily getColumnFamily()
+ {
+ return iterator.getColumnFamily();
+ }
+
+ public DecoratedKey getKey()
+ {
+ return iterator.getKey();
+ }
+
+ public void close() throws IOException
+ {
+ iterator.close();
+ }
+
+ @Override
+ protected OnDiskAtom computeNext()
+ {
+ if (!iterator.hasNext())
+ return endOfData();
+
+ OnDiskAtom next = iterator.next();
+
+ // If we detect that some cells are out of order we will store and sort the remaining once to insert them
+ // in a separate SSTable.
+ if (previous != null && comparator.compare(next, previous) < 0)
+ {
+ outOfOrderCells = collectOutOfOrderCells(next, iterator);
+ return endOfData();
+ }
+ previous = next;
+ return next;
+ }
+
+ public boolean hasOutOfOrderCells()
+ {
+ return outOfOrderCells != null;
+ }
+
+ public ColumnFamily getOutOfOrderCells()
+ {
+ return outOfOrderCells;
+ }
+
+ private static ColumnFamily collectOutOfOrderCells(OnDiskAtom atom, OnDiskAtomIterator iterator)
+ {
+ ColumnFamily cf = iterator.getColumnFamily().cloneMeShallow(ArrayBackedSortedColumns.factory, false);
+ cf.addAtom(atom);
+ while (iterator.hasNext())
+ cf.addAtom(iterator.next());
+ return cf;
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/527d1897/src/java/org/apache/cassandra/db/marshal/ReversedType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/ReversedType.java b/src/java/org/apache/cassandra/db/marshal/ReversedType.java
index 0389a32..53798f8 100644
--- a/src/java/org/apache/cassandra/db/marshal/ReversedType.java
+++ b/src/java/org/apache/cassandra/db/marshal/ReversedType.java
@@ -60,16 +60,6 @@ public class ReversedType<T> extends AbstractType<T>
public int compare(ByteBuffer o1, ByteBuffer o2)
{
- // An empty byte buffer is always smaller
- if (o1.remaining() == 0)
- {
- return o2.remaining() == 0 ? 0 : -1;
- }
- if (o2.remaining() == 0)
- {
- return 1;
- }
-
return baseType.compare(o2, o1);
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/527d1897/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java
index a433d06..4a54a9a 100644
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java
@@ -34,6 +34,8 @@ import org.apache.cassandra.utils.FBUtilities;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.apache.cassandra.utils.ByteBufferUtil.EMPTY_BYTE_BUFFER;
+import static org.apache.cassandra.utils.ByteBufferUtil.bytes;
public class SecondaryIndexTest extends CQLTester
{
@@ -562,7 +564,7 @@ public class SecondaryIndexTest extends CQLTester
{
createTable("CREATE TABLE %s(a int, b frozen<map<int, blob>>, PRIMARY KEY (a))");
createIndex("CREATE INDEX ON %s(full(b))");
- Map<Integer, ByteBuffer> map = new HashMap();
+ Map<Integer, ByteBuffer> map = new HashMap<>();
map.put(0, ByteBuffer.allocate(1024 * 65));
failInsert("INSERT INTO %s (a, b) VALUES (0, ?)", map);
}
@@ -641,4 +643,142 @@ public class SecondaryIndexTest extends CQLTester
assertInvalid("CREATE INDEX ON %s (c)");
}
+ @Test
+ public void testWithEmptyRestrictionValueAndSecondaryIndex() throws Throwable
+ {
+ createTable("CREATE TABLE %s (pk blob, c blob, v blob, PRIMARY KEY ((pk), c))");
+ createIndex("CREATE INDEX on %s(c)");
+ createIndex("CREATE INDEX on %s(v)");
+
+ execute("INSERT INTO %s (pk, c, v) VALUES (?, ?, ?)", bytes("foo123"), bytes("1"), bytes("1"));
+ execute("INSERT INTO %s (pk, c, v) VALUES (?, ?, ?)", bytes("foo123"), bytes("2"), bytes("1"));
+
+ for (boolean flush : new boolean[]{false, true})
+ {
+ if (flush)
+ flush();
+
+ // Test clustering columns restrictions
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c = textAsBlob('');"));
+
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) = (textAsBlob(''));"));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c IN (textAsBlob(''), textAsBlob('1'));"),
+ row(bytes("foo123"), bytes("1"), bytes("1")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) IN ((textAsBlob('')), (textAsBlob('1')));"),
+ row(bytes("foo123"), bytes("1"), bytes("1")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c > textAsBlob('') AND v = textAsBlob('1') ALLOW FILTERING;"),
+ row(bytes("foo123"), bytes("1"), bytes("1")),
+ row(bytes("foo123"), bytes("2"), bytes("1")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c >= textAsBlob('') AND v = textAsBlob('1') ALLOW FILTERING;"),
+ row(bytes("foo123"), bytes("1"), bytes("1")),
+ row(bytes("foo123"), bytes("2"), bytes("1")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) >= (textAsBlob('')) AND v = textAsBlob('1') ALLOW FILTERING;"),
+ row(bytes("foo123"), bytes("1"), bytes("1")),
+ row(bytes("foo123"), bytes("2"), bytes("1")));
+
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c <= textAsBlob('') AND v = textAsBlob('1') ALLOW FILTERING;"));
+
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) <= (textAsBlob('')) AND v = textAsBlob('1') ALLOW FILTERING;"));
+
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) < (textAsBlob('')) AND v = textAsBlob('1') ALLOW FILTERING;"));
+
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c < textAsBlob('') AND v = textAsBlob('1') ALLOW FILTERING;"));
+
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c > textAsBlob('') AND c < textAsBlob('') AND v = textAsBlob('1') ALLOW FILTERING;"));
+
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) > (textAsBlob('')) AND (c) < (textAsBlob('')) AND v = textAsBlob('1') ALLOW FILTERING;"));
+ }
+
+ execute("INSERT INTO %s (pk, c, v) VALUES (?, ?, ?)",
+ bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("1"));
+
+ for (boolean flush : new boolean[]{false, true})
+ {
+ if (flush)
+ flush();
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c = textAsBlob('');"),
+ row(bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("1")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) = (textAsBlob(''));"),
+ row(bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("1")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c IN (textAsBlob(''), textAsBlob('1'));"),
+ row(bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("1")),
+ row(bytes("foo123"), bytes("1"), bytes("1")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) IN ((textAsBlob('')), (textAsBlob('1')));"),
+ row(bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("1")),
+ row(bytes("foo123"), bytes("1"), bytes("1")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c > textAsBlob('') AND v = textAsBlob('1') ALLOW FILTERING;"),
+ row(bytes("foo123"), bytes("1"), bytes("1")),
+ row(bytes("foo123"), bytes("2"), bytes("1")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c >= textAsBlob('') AND v = textAsBlob('1') ALLOW FILTERING;"),
+ row(bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("1")),
+ row(bytes("foo123"), bytes("1"), bytes("1")),
+ row(bytes("foo123"), bytes("2"), bytes("1")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) >= (textAsBlob('')) AND v = textAsBlob('1') ALLOW FILTERING;"),
+ row(bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("1")),
+ row(bytes("foo123"), bytes("1"), bytes("1")),
+ row(bytes("foo123"), bytes("2"), bytes("1")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c <= textAsBlob('') AND v = textAsBlob('1') ALLOW FILTERING;"),
+ row(bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("1")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) <= (textAsBlob('')) AND v = textAsBlob('1') ALLOW FILTERING;"),
+ row(bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("1")));
+
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c < textAsBlob('') AND v = textAsBlob('1') ALLOW FILTERING;"));
+
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) < (textAsBlob('')) AND v = textAsBlob('1') ALLOW FILTERING;"));
+
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c >= textAsBlob('') AND c < textAsBlob('') AND v = textAsBlob('1') ALLOW FILTERING;"));
+
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) >= (textAsBlob('')) AND c < textAsBlob('') AND v = textAsBlob('1') ALLOW FILTERING;"));
+
+ // Test restrictions on non-primary key value
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND v = textAsBlob('');"));
+ }
+
+ execute("INSERT INTO %s (pk, c, v) VALUES (?, ?, ?)",
+ bytes("foo123"), bytes("3"), EMPTY_BYTE_BUFFER);
+
+ for (boolean flush : new boolean[]{false, true})
+ {
+ if (flush)
+ flush();
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND v = textAsBlob('');"),
+ row(bytes("foo123"), bytes("3"), EMPTY_BYTE_BUFFER));
+ }
+ }
+
+ @Test
+ public void testEmptyRestrictionValueWithSecondaryIndexAndCompactTables() throws Throwable
+ {
+ createTable("CREATE TABLE %s (pk blob, c blob, v blob, PRIMARY KEY ((pk), c)) WITH COMPACT STORAGE");
+ assertInvalidMessage("Secondary indexes are not supported on PRIMARY KEY columns in COMPACT STORAGE tables",
+ "CREATE INDEX on %s(c)");
+
+ createTable("CREATE TABLE %s (pk blob PRIMARY KEY, v blob) WITH COMPACT STORAGE");
+ createIndex("CREATE INDEX on %s(v)");
+
+ execute("INSERT INTO %s (pk, v) VALUES (?, ?)", bytes("foo123"), bytes("1"));
+
+ // Test restrictions on non-primary key value
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND v = textAsBlob('');"));
+
+ execute("INSERT INTO %s (pk, v) VALUES (?, ?)", bytes("foo124"), EMPTY_BYTE_BUFFER);
+
+ assertRows(execute("SELECT * FROM %s WHERE v = textAsBlob('');"),
+ row(bytes("foo124"), EMPTY_BYTE_BUFFER));
+ }
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/527d1897/test/unit/org/apache/cassandra/cql3/validation/operations/DeleteTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/validation/operations/DeleteTest.java b/test/unit/org/apache/cassandra/cql3/validation/operations/DeleteTest.java
index 476ec83..6bd5f26 100644
--- a/test/unit/org/apache/cassandra/cql3/validation/operations/DeleteTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/operations/DeleteTest.java
@@ -23,11 +23,15 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import org.apache.commons.lang3.StringUtils;
+
import org.junit.Test;
import org.apache.cassandra.cql3.CQLTester;
import static org.junit.Assert.assertEquals;
+import static org.apache.cassandra.utils.ByteBufferUtil.EMPTY_BYTE_BUFFER;
+import static org.apache.cassandra.utils.ByteBufferUtil.bytes;
public class DeleteTest extends CQLTester
{
@@ -326,4 +330,42 @@ public class DeleteTest extends CQLTester
assertEmpty(execute("select * from %s where a=1 and b=1"));
}
+
+ @Test
+ public void testDeleteWithEmptyRestrictionValue() throws Throwable
+ {
+ for (String options : new String[] { "", " WITH COMPACT STORAGE" })
+ {
+ createTable("CREATE TABLE %s (pk blob, c blob, v blob, PRIMARY KEY (pk, c))" + options);
+
+ if (StringUtils.isEmpty(options))
+ {
+ execute("INSERT INTO %s (pk, c, v) VALUES (?, ?, ?)", bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("1"));
+ execute("DELETE FROM %s WHERE pk = textAsBlob('foo123') AND c = textAsBlob('');");
+
+ assertEmpty(execute("SELECT * FROM %s"));
+ }
+ else
+ {
+ assertInvalid("Invalid empty or null value for column c",
+ "DELETE FROM %s WHERE pk = textAsBlob('foo123') AND c = textAsBlob('')");
+ assertInvalid("Invalid empty or null value for column c",
+ "DELETE FROM %s WHERE pk = textAsBlob('foo123') AND c IN (textAsBlob(''), textAsBlob('1'))");
+ }
+ }
+ }
+
+ @Test
+ public void testDeleteWithMultipleClusteringColumnsAndEmptyRestrictionValue() throws Throwable
+ {
+ for (String options : new String[] { "", " WITH COMPACT STORAGE" })
+ {
+ createTable("CREATE TABLE %s (pk blob, c1 blob, c2 blob, v blob, PRIMARY KEY (pk, c1, c2))" + options);
+
+ execute("INSERT INTO %s (pk, c1, c2, v) VALUES (?, ?, ?, ?)", bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("1"), bytes("1"));
+ execute("DELETE FROM %s WHERE pk = textAsBlob('foo123') AND c1 = textAsBlob('');");
+
+ assertEmpty(execute("SELECT * FROM %s"));
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/527d1897/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java
index 68cf6f8..cef4635 100644
--- a/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java
@@ -32,6 +32,8 @@ import org.apache.cassandra.exceptions.InvalidRequestException;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import static org.apache.cassandra.utils.ByteBufferUtil.EMPTY_BYTE_BUFFER;
+import static org.apache.cassandra.utils.ByteBufferUtil.bytes;
/**
* Test column ranges and ordering with static column in table
@@ -1328,4 +1330,375 @@ public class SelectTest extends CQLTester
row(1, 2, 3),
row(1, 1, 3));
}
+
+ @Test
+ public void testEmptyRestrictionValue() throws Throwable
+ {
+ for (String options : new String[] { "", " WITH COMPACT STORAGE" })
+ {
+ createTable("CREATE TABLE %s (pk blob, c blob, v blob, PRIMARY KEY ((pk), c))" + options);
+ execute("INSERT INTO %s (pk, c, v) VALUES (?, ?, ?)",
+ bytes("foo123"), bytes("1"), bytes("1"));
+ execute("INSERT INTO %s (pk, c, v) VALUES (?, ?, ?)",
+ bytes("foo123"), bytes("2"), bytes("2"));
+
+ for (boolean flush : new boolean[]{false, true})
+ {
+ if (flush)
+ flush();
+
+ assertInvalidMessage("Key may not be empty", "SELECT * FROM %s WHERE pk = textAsBlob('');");
+ assertInvalidMessage("Key may not be empty", "SELECT * FROM %s WHERE pk IN (textAsBlob(''), textAsBlob('1'));");
+
+ assertInvalidMessage("Key may not be empty",
+ "INSERT INTO %s (pk, c, v) VALUES (?, ?, ?)",
+ EMPTY_BYTE_BUFFER, bytes("2"), bytes("2"));
+
+ // Test clustering columns restrictions
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c = textAsBlob('');"));
+
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) = (textAsBlob(''));"));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c IN (textAsBlob(''), textAsBlob('1'));"),
+ row(bytes("foo123"), bytes("1"), bytes("1")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) IN ((textAsBlob('')), (textAsBlob('1')));"),
+ row(bytes("foo123"), bytes("1"), bytes("1")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c > textAsBlob('');"),
+ row(bytes("foo123"), bytes("1"), bytes("1")),
+ row(bytes("foo123"), bytes("2"), bytes("2")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) > (textAsBlob(''));"),
+ row(bytes("foo123"), bytes("1"), bytes("1")),
+ row(bytes("foo123"), bytes("2"), bytes("2")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c >= textAsBlob('');"),
+ row(bytes("foo123"), bytes("1"), bytes("1")),
+ row(bytes("foo123"), bytes("2"), bytes("2")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) >= (textAsBlob(''));"),
+ row(bytes("foo123"), bytes("1"), bytes("1")),
+ row(bytes("foo123"), bytes("2"), bytes("2")));
+
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c <= textAsBlob('');"));
+
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) <= (textAsBlob(''));"));
+
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c < textAsBlob('');"));
+
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) < (textAsBlob(''));"));
+
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c > textAsBlob('') AND c < textAsBlob('');"));
+ }
+
+ if (options.contains("COMPACT"))
+ {
+ assertInvalidMessage("Missing PRIMARY KEY part c",
+ "INSERT INTO %s (pk, c, v) VALUES (?, ?, ?)",
+ bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("4"));
+
+ // Test restrictions on non-primary key value
+ assertInvalidMessage("Predicates on the non-primary-key column (v) of a COMPACT table are not yet supported",
+ "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND v = textAsBlob('') ALLOW FILTERING;");
+ }
+ else
+ {
+ execute("INSERT INTO %s (pk, c, v) VALUES (?, ?, ?)",
+ bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("4"));
+
+ for (boolean flush : new boolean[]{false, true})
+ {
+ if (flush)
+ flush();
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c = textAsBlob('');"),
+ row(bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("4")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) = (textAsBlob(''));"),
+ row(bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("4")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c IN (textAsBlob(''), textAsBlob('1'));"),
+ row(bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("4")),
+ row(bytes("foo123"), bytes("1"), bytes("1")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) IN ((textAsBlob('')), (textAsBlob('1')));"),
+ row(bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("4")),
+ row(bytes("foo123"), bytes("1"), bytes("1")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c > textAsBlob('');"),
+ row(bytes("foo123"), bytes("1"), bytes("1")),
+ row(bytes("foo123"), bytes("2"), bytes("2")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) > (textAsBlob(''));"),
+ row(bytes("foo123"), bytes("1"), bytes("1")),
+ row(bytes("foo123"), bytes("2"), bytes("2")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c >= textAsBlob('');"),
+ row(bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("4")),
+ row(bytes("foo123"), bytes("1"), bytes("1")),
+ row(bytes("foo123"), bytes("2"), bytes("2")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) >= (textAsBlob(''));"),
+ row(bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("4")),
+ row(bytes("foo123"), bytes("1"), bytes("1")),
+ row(bytes("foo123"), bytes("2"), bytes("2")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c <= textAsBlob('');"),
+ row(bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("4")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) <= (textAsBlob(''));"),
+ row(bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("4")));
+
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c < textAsBlob('');"));
+
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c) < (textAsBlob(''));"));
+
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c >= textAsBlob('') AND c < textAsBlob('');"));
+
+ // Test restrictions on non-primary key value
+ assertInvalidMessage("No secondary indexes on the restricted columns support the provided operators",
+ "SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND v = textAsBlob('') ALLOW FILTERING;");
+ }
+ }
+ }
+ }
+
+ @Test
+ public void testEmptyRestrictionValueWithMultipleClusteringColumns() throws Throwable
+ {
+ for (String options : new String[] { "", " WITH COMPACT STORAGE" })
+ {
+ createTable("CREATE TABLE %s (pk blob, c1 blob, c2 blob, v blob, PRIMARY KEY (pk, c1, c2))" + options);
+ execute("INSERT INTO %s (pk, c1, c2, v) VALUES (?, ?, ?, ?)", bytes("foo123"), bytes("1"), bytes("1"), bytes("1"));
+ execute("INSERT INTO %s (pk, c1, c2, v) VALUES (?, ?, ?, ?)", bytes("foo123"), bytes("1"), bytes("2"), bytes("2"));
+
+ for (boolean flush : new boolean[]{false, true})
+ {
+ if (flush)
+ flush();
+
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c1 = textAsBlob('');"));
+
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c1 = textAsBlob('1') AND c2 = textAsBlob('');"));
+
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c1, c2) = (textAsBlob('1'), textAsBlob(''));"));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c1 = textAsBlob('1') AND c2 IN (textAsBlob(''), textAsBlob('1'));"),
+ row(bytes("foo123"), bytes("1"), bytes("1"), bytes("1")));
+
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c1 = textAsBlob('') AND c2 = textAsBlob('1');"));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c1, c2) IN ((textAsBlob(''), textAsBlob('1')), (textAsBlob('1'), textAsBlob('1')));"),
+ row(bytes("foo123"), bytes("1"), bytes("1"), bytes("1")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c1 > textAsBlob('');"),
+ row(bytes("foo123"), bytes("1"), bytes("1"), bytes("1")),
+ row(bytes("foo123"), bytes("1"), bytes("2"), bytes("2")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c1 = textAsBlob('1') AND c2 > textAsBlob('');"),
+ row(bytes("foo123"), bytes("1"), bytes("1"), bytes("1")),
+ row(bytes("foo123"), bytes("1"), bytes("2"), bytes("2")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c1, c2) > (textAsBlob(''), textAsBlob('1'));"),
+ row(bytes("foo123"), bytes("1"), bytes("1"), bytes("1")),
+ row(bytes("foo123"), bytes("1"), bytes("2"), bytes("2")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c1 = textAsBlob('1') AND c2 >= textAsBlob('');"),
+ row(bytes("foo123"), bytes("1"), bytes("1"), bytes("1")),
+ row(bytes("foo123"), bytes("1"), bytes("2"), bytes("2")));
+
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c1 = textAsBlob('1') AND c2 <= textAsBlob('');"));
+
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c1, c2) <= (textAsBlob('1'), textAsBlob(''));"));
+ }
+
+ execute("INSERT INTO %s (pk, c1, c2, v) VALUES (?, ?, ?, ?)",
+ bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("1"), bytes("4"));
+
+ for (boolean flush : new boolean[]{false, true})
+ {
+ if (flush)
+ flush();
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c1 = textAsBlob('');"),
+ row(bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("1"), bytes("4")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c1 = textAsBlob('') AND c2 = textAsBlob('1');"),
+ row(bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("1"), bytes("4")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c1, c2) = (textAsBlob(''), textAsBlob('1'));"),
+ row(bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("1"), bytes("4")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c1 = textAsBlob('') AND c2 IN (textAsBlob(''), textAsBlob('1'));"),
+ row(bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("1"), bytes("4")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c1 = textAsBlob('1') AND c2 IN (textAsBlob(''), textAsBlob('1'));"),
+ row(bytes("foo123"), bytes("1"), bytes("1"), bytes("1")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c1, c2) IN ((textAsBlob(''), textAsBlob('1')), (textAsBlob('1'), textAsBlob('1')));"),
+ row(bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("1"), bytes("4")),
+ row(bytes("foo123"), bytes("1"), bytes("1"), bytes("1")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c1, c2) > (textAsBlob(''), textAsBlob('1'));"),
+ row(bytes("foo123"), bytes("1"), bytes("1"), bytes("1")),
+ row(bytes("foo123"), bytes("1"), bytes("2"), bytes("2")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c1, c2) >= (textAsBlob(''), textAsBlob('1'));"),
+ row(bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("1"), bytes("4")),
+ row(bytes("foo123"), bytes("1"), bytes("1"), bytes("1")),
+ row(bytes("foo123"), bytes("1"), bytes("2"), bytes("2")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c1, c2) <= (textAsBlob(''), textAsBlob('1'));"),
+ row(bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("1"), bytes("4")));
+
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c1, c2) < (textAsBlob(''), textAsBlob('1'));"));
+ }
+ }
+ }
+
+ @Test
+ public void testEmptyRestrictionValueWithOrderBy() throws Throwable
+ {
+ for (String options : new String[] { "",
+ " WITH COMPACT STORAGE",
+ " WITH CLUSTERING ORDER BY (c DESC)",
+ " WITH COMPACT STORAGE AND CLUSTERING ORDER BY (c DESC)"})
+ {
+ String orderingClause = options.contains("ORDER") ? "" : "ORDER BY c DESC" ;
+
+ createTable("CREATE TABLE %s (pk blob, c blob, v blob, PRIMARY KEY ((pk), c))" + options);
+ execute("INSERT INTO %s (pk, c, v) VALUES (?, ?, ?)",
+ bytes("foo123"),
+ bytes("1"),
+ bytes("1"));
+ execute("INSERT INTO %s (pk, c, v) VALUES (?, ?, ?)",
+ bytes("foo123"),
+ bytes("2"),
+ bytes("2"));
+
+ for (boolean flush : new boolean[]{false, true})
+ {
+ if (flush)
+ flush();
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c > textAsBlob('')" + orderingClause),
+ row(bytes("foo123"), bytes("2"), bytes("2")),
+ row(bytes("foo123"), bytes("1"), bytes("1")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c >= textAsBlob('')" + orderingClause),
+ row(bytes("foo123"), bytes("2"), bytes("2")),
+ row(bytes("foo123"), bytes("1"), bytes("1")));
+
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c < textAsBlob('')" + orderingClause));
+
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c <= textAsBlob('')" + orderingClause));
+
+ }
+
+ if (options.contains("COMPACT"))
+ {
+ assertInvalidMessage("Missing PRIMARY KEY part c",
+ "INSERT INTO %s (pk, c, v) VALUES (?, ?, ?)",
+ bytes("foo123"),
+ EMPTY_BYTE_BUFFER,
+ bytes("4"));
+ }
+ else
+ {
+ execute("INSERT INTO %s (pk, c, v) VALUES (?, ?, ?)",
+ bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("4"));
+
+ for (boolean flush : new boolean[]{false, true})
+ {
+ if (flush)
+ flush();
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c IN (textAsBlob(''), textAsBlob('1'))" + orderingClause),
+ row(bytes("foo123"), bytes("1"), bytes("1")),
+ row(bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("4")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c > textAsBlob('')" + orderingClause),
+ row(bytes("foo123"), bytes("2"), bytes("2")),
+ row(bytes("foo123"), bytes("1"), bytes("1")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c >= textAsBlob('')" + orderingClause),
+ row(bytes("foo123"), bytes("2"), bytes("2")),
+ row(bytes("foo123"), bytes("1"), bytes("1")),
+ row(bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("4")));
+
+ assertEmpty(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c < textAsBlob('')" + orderingClause));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c <= textAsBlob('')" + orderingClause),
+ row(bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("4")));
+ }
+ }
+ }
+ }
+
+ @Test
+ public void testEmptyRestrictionValueWithMultipleClusteringColumnsAndOrderBy() throws Throwable
+ {
+ for (String options : new String[] { "",
+ " WITH COMPACT STORAGE",
+ " WITH CLUSTERING ORDER BY (c1 DESC, c2 DESC)",
+ " WITH COMPACT STORAGE AND CLUSTERING ORDER BY (c1 DESC, c2 DESC)"})
+ {
+ String orderingClause = options.contains("ORDER") ? "" : "ORDER BY c1 DESC, c2 DESC" ;
+
+ createTable("CREATE TABLE %s (pk blob, c1 blob, c2 blob, v blob, PRIMARY KEY (pk, c1, c2))" + options);
+ execute("INSERT INTO %s (pk, c1, c2, v) VALUES (?, ?, ?, ?)", bytes("foo123"), bytes("1"), bytes("1"), bytes("1"));
+ execute("INSERT INTO %s (pk, c1, c2, v) VALUES (?, ?, ?, ?)", bytes("foo123"), bytes("1"), bytes("2"), bytes("2"));
+
+ for (boolean flush : new boolean[]{false, true})
+ {
+ if (flush)
+ flush();
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c1 > textAsBlob('')" + orderingClause),
+ row(bytes("foo123"), bytes("1"), bytes("2"), bytes("2")),
+ row(bytes("foo123"), bytes("1"), bytes("1"), bytes("1")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c1 = textAsBlob('1') AND c2 > textAsBlob('')" + orderingClause),
+ row(bytes("foo123"), bytes("1"), bytes("2"), bytes("2")),
+ row(bytes("foo123"), bytes("1"), bytes("1"), bytes("1")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c1, c2) > (textAsBlob(''), textAsBlob('1'))" + orderingClause),
+ row(bytes("foo123"), bytes("1"), bytes("2"), bytes("2")),
+ row(bytes("foo123"), bytes("1"), bytes("1"), bytes("1")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c1 = textAsBlob('1') AND c2 >= textAsBlob('')" + orderingClause),
+ row(bytes("foo123"), bytes("1"), bytes("2"), bytes("2")),
+ row(bytes("foo123"), bytes("1"), bytes("1"), bytes("1")));
+ }
+
+ execute("INSERT INTO %s (pk, c1, c2, v) VALUES (?, ?, ?, ?)",
+ bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("1"), bytes("4"));
+
+ for (boolean flush : new boolean[]{false, true})
+ {
+ if (flush)
+ flush();
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c1 = textAsBlob('1') AND c2 IN (textAsBlob(''), textAsBlob('1'))" + orderingClause),
+ row(bytes("foo123"), bytes("1"), bytes("1"), bytes("1")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND c1 = textAsBlob('') AND c2 IN (textAsBlob(''), textAsBlob('1'))" + orderingClause),
+ row(bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("1"), bytes("4")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c1, c2) IN ((textAsBlob(''), textAsBlob('1')), (textAsBlob('1'), textAsBlob('1')))" + orderingClause),
+ row(bytes("foo123"), bytes("1"), bytes("1"), bytes("1")),
+ row(bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("1"), bytes("4")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c1, c2) > (textAsBlob(''), textAsBlob('1'))" + orderingClause),
+ row(bytes("foo123"), bytes("1"), bytes("2"), bytes("2")),
+ row(bytes("foo123"), bytes("1"), bytes("1"), bytes("1")));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = textAsBlob('foo123') AND (c1, c2) >= (textAsBlob(''), textAsBlob('1'))" + orderingClause),
+ row(bytes("foo123"), bytes("1"), bytes("2"), bytes("2")),
+ row(bytes("foo123"), bytes("1"), bytes("1"), bytes("1")),
+ row(bytes("foo123"), EMPTY_BYTE_BUFFER, bytes("1"), bytes("4")));
+ }
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/527d1897/test/unit/org/apache/cassandra/db/marshal/ReversedTypeTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/db/marshal/ReversedTypeTest.java b/test/unit/org/apache/cassandra/db/marshal/ReversedTypeTest.java
index 1553a20..7dfbc27 100644
--- a/test/unit/org/apache/cassandra/db/marshal/ReversedTypeTest.java
+++ b/test/unit/org/apache/cassandra/db/marshal/ReversedTypeTest.java
@@ -34,7 +34,7 @@ public class ReversedTypeTest
assert t.compare(bytes(4L), bytes(2L)) < 0;
// the empty byte buffer is always the smaller
- assert t.compare(EMPTY_BYTE_BUFFER, bytes(2L)) < 0;
- assert t.compare(bytes(2L), EMPTY_BYTE_BUFFER) > 0;
+ assert t.compare(EMPTY_BYTE_BUFFER, bytes(2L)) > 0;
+ assert t.compare(bytes(2L), EMPTY_BYTE_BUFFER) < 0;
}
}