You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by ca...@apache.org on 2016/06/14 14:26:37 UTC
[1/3] cassandra git commit: Allow LWT operation on static column with
only partition keys
Repository: cassandra
Updated Branches:
refs/heads/cassandra-2.1 72acbcd00 -> 1d2d0749a
refs/heads/cassandra-2.2 05f8a008f -> 52a827b4d
Allow LWT operation on static column with only partition keys
Patch by Carl Yeksigian, reviewed by Benjamin Lerer for CASSANDRA-10532
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/1d2d0749
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/1d2d0749
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/1d2d0749
Branch: refs/heads/cassandra-2.1
Commit: 1d2d0749a8b72c4c8cdd5b85b210157e8d7d6a41
Parents: 72acbcd
Author: Carl Yeksigian <ca...@apache.org>
Authored: Tue Jun 14 08:32:26 2016 -0400
Committer: Carl Yeksigian <ca...@apache.org>
Committed: Tue Jun 14 08:32:26 2016 -0400
----------------------------------------------------------------------
CHANGES.txt | 1 +
.../cql3/statements/DeleteStatement.java | 37 +++---
.../cql3/statements/ModificationStatement.java | 14 ++-
.../operations/InsertUpdateIfConditionTest.java | 113 +++++++++++++++++++
4 files changed, 150 insertions(+), 15 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/1d2d0749/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index ebcc90c..7d70902 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
2.1.15
+ * Allow LWT operation on static column with only partition keys (CASSANDRA-10532)
* Create interval tree over canonical sstables to avoid missing sstables during streaming (CASSANDRA-11886)
* cqlsh COPY FROM: shutdown parent cluster after forking, to avoid corrupting SSL connections (CASSANDRA-11749)
* Updated cqlsh Python driver to fix DESCRIBE problem for legacy tables (CASSANDRA-11055)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/1d2d0749/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java b/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java
index 33c61e7..d8fa467 100644
--- a/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java
@@ -50,15 +50,6 @@ public class DeleteStatement extends ModificationStatement
{
List<Operation> deletions = getOperations();
- if (prefix.size() < cfm.clusteringColumns().size() && !deletions.isEmpty())
- {
- // In general, we can't delete specific columns if not all clustering columns have been specified.
- // However, if we delete only static colums, it's fine since we won't really use the prefix anyway.
- for (Operation deletion : deletions)
- if (!deletion.column.isStatic())
- throw new InvalidRequestException(String.format("Primary key column '%s' must be specified in order to delete column '%s'", getFirstEmptyKey().name, deletion.column.name));
- }
-
if (deletions.isEmpty())
{
// We delete the slice selected by the prefix.
@@ -88,19 +79,39 @@ public class DeleteStatement extends ModificationStatement
protected void validateWhereClauseForConditions() throws InvalidRequestException
{
- Iterator<ColumnDefinition> iterator = Iterators.concat(cfm.partitionKeyColumns().iterator(), cfm.clusteringColumns().iterator());
+ boolean onlyHasConditionsOnStaticColumns = hasStaticConditions() && !hasRegularConditions();
+
+ // In general, we can't delete specific columns if not all clustering columns have been specified.
+ // However, if we delete only static colums, it's fine since we won't really use the prefix anyway.
+ Iterator<ColumnDefinition> iterator = appliesOnlyToStaticColumns()
+ ? cfm.partitionKeyColumns().iterator()
+ : Iterators.concat(cfm.partitionKeyColumns().iterator(), cfm.clusteringColumns().iterator());
while (iterator.hasNext())
{
ColumnDefinition def = iterator.next();
Restriction restriction = processedKeys.get(def.name);
if (restriction == null || !(restriction.isEQ() || restriction.isIN()))
{
+ if (onlyHasConditionsOnStaticColumns)
+ {
+ for (Operation oper : getOperations())
+ {
+ if (!oper.column.isStatic())
+ {
+ throw new InvalidRequestException(String.format("Primary key column '%s' must be specified in order to delete column '%s'",
+ def.name,
+ oper.column.name));
+ }
+ }
+ }
+
throw new InvalidRequestException(
- String.format("DELETE statements must restrict all PRIMARY KEY columns with equality relations in order " +
- "to use IF conditions, but column '%s' is not restricted", def.name));
+ String.format("DELETE statements must restrict all %s KEY columns with equality relations in order " +
+ "to use IF conditions%s, but column '%s' is not restricted",
+ onlyHasConditionsOnStaticColumns ? "PARTITION" : "PRIMARY",
+ onlyHasConditionsOnStaticColumns ? " on static columns" : "", def.name));
}
}
-
}
public static class Parsed extends ModificationStatement.Parsed
http://git-wip-us.apache.org/repos/asf/cassandra/blob/1d2d0749/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java b/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
index 75a3b40..a9f65e1 100644
--- a/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
@@ -211,6 +211,16 @@ public abstract class ModificationStatement implements CQLStatement
return ifExists;
}
+ public boolean hasStaticConditions()
+ {
+ return staticConditions != null && !staticConditions.isEmpty();
+ }
+
+ public boolean hasRegularConditions()
+ {
+ return columnConditions != null && !columnConditions.isEmpty();
+ }
+
private void addKeyValues(ColumnDefinition def, Restriction values) throws InvalidRequestException
{
if (def.kind == ColumnDefinition.Kind.CLUSTERING_COLUMN)
@@ -364,7 +374,7 @@ public abstract class ModificationStatement implements CQLStatement
* Checks that the modification only apply to static columns.
* @return <code>true</code> if the modification only apply to static columns, <code>false</code> otherwise.
*/
- private boolean appliesOnlyToStaticColumns()
+ protected boolean appliesOnlyToStaticColumns()
{
return setsStaticColumns && !appliesToRegularColumns();
}
@@ -373,7 +383,7 @@ public abstract class ModificationStatement implements CQLStatement
* Checks that the modification apply to regular columns.
* @return <code>true</code> if the modification apply to regular columns, <code>false</code> otherwise.
*/
- private boolean appliesToRegularColumns()
+ protected boolean appliesToRegularColumns()
{
// If we have regular operations, this applies to regular columns.
// Otherwise, if the statement is a DELETE and columnOperations is empty, this means we have no operations,
http://git-wip-us.apache.org/repos/asf/cassandra/blob/1d2d0749/test/unit/org/apache/cassandra/cql3/validation/operations/InsertUpdateIfConditionTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/validation/operations/InsertUpdateIfConditionTest.java b/test/unit/org/apache/cassandra/cql3/validation/operations/InsertUpdateIfConditionTest.java
index e94011b..05ba09d 100644
--- a/test/unit/org/apache/cassandra/cql3/validation/operations/InsertUpdateIfConditionTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/operations/InsertUpdateIfConditionTest.java
@@ -311,6 +311,119 @@ public class InsertUpdateIfConditionTest extends CQLTester
}
/**
+ * Test CASSANDRA-10532
+ */
+ @Test
+ public void testStaticColumnsCasDelete() throws Throwable
+ {
+ createTable("CREATE TABLE %s (pk int, ck int, static_col int static, value int, PRIMARY KEY (pk, ck))");
+ execute("INSERT INTO %s (pk, ck, value) VALUES (?, ?, ?)", 1, 1, 2);
+ execute("INSERT INTO %s (pk, ck, value) VALUES (?, ?, ?)", 1, 3, 4);
+ execute("INSERT INTO %s (pk, ck, value) VALUES (?, ?, ?)", 1, 5, 6);
+ execute("INSERT INTO %s (pk, ck, value) VALUES (?, ?, ?)", 1, 7, 8);
+ execute("INSERT INTO %s (pk, ck, value) VALUES (?, ?, ?)", 2, 1, 2);
+ execute("INSERT INTO %s (pk, static_col) VALUES (?, ?)", 1, 1);
+
+ assertRows(execute("DELETE static_col FROM %s WHERE pk = ? IF static_col = ?", 1, 2), row(false, 1));
+ assertRows(execute("DELETE static_col FROM %s WHERE pk = ? IF static_col = ?", 1, 1), row(true));
+
+ assertRows(execute("SELECT pk, ck, static_col, value FROM %s WHERE pk = 1"),
+ row(1, 1, null, 2),
+ row(1, 3, null, 4),
+ row(1, 5, null, 6),
+ row(1, 7, null, 8));
+ execute("INSERT INTO %s (pk, static_col) VALUES (?, ?)", 1, 1);
+
+ assertInvalidMessage("DELETE statements must restrict all PARTITION KEY columns with equality relations in order " +
+ "to use IF conditions on static columns, but column 'pk' is not restricted",
+ "DELETE static_col FROM %s WHERE ck = ? IF static_col = ?", 1, 1);
+
+ assertInvalidMessage("Invalid restriction on clustering column ck since the DELETE statement modifies only static columns",
+ "DELETE static_col FROM %s WHERE pk = ? AND ck = ? IF static_col = ?", 1, 1, 1);
+
+ assertInvalidMessage("Primary key column 'ck' must be specified in order to delete column 'value'",
+ "DELETE static_col, value FROM %s WHERE pk = ? IF static_col = ?", 1, 1);
+
+ // Same query but with an invalid condition
+ assertInvalidMessage("Primary key column 'ck' must be specified in order to delete column 'value'",
+ "DELETE static_col, value FROM %s WHERE pk = ? IF static_col = ?", 1, 2);
+
+ // DELETE of an underspecified PRIMARY KEY should not succeed if static is not only restriction
+ assertInvalidMessage("DELETE statements must restrict all PRIMARY KEY columns with equality relations in order " +
+ "to use IF conditions, but column 'ck' is not restricted",
+ "DELETE static_col FROM %s WHERE pk = ? IF value = ? AND static_col = ?", 1, 2, 1);
+
+ assertRows(execute("DELETE value FROM %s WHERE pk = ? AND ck = ? IF value = ? AND static_col = ?", 1, 1, 2, 2), row(false, 2, 1));
+ assertRows(execute("DELETE value FROM %s WHERE pk = ? AND ck = ? IF value = ? AND static_col = ?", 1, 1, 2, 1), row(true));
+ assertRows(execute("SELECT pk, ck, static_col, value FROM %s WHERE pk = 1"),
+ row(1, 1, 1, null),
+ row(1, 3, 1, 4),
+ row(1, 5, 1, 6),
+ row(1, 7, 1, 8));
+
+ assertRows(execute("DELETE static_col FROM %s WHERE pk = ? AND ck = ? IF value = ?", 1, 5, 10), row(false, 6));
+ assertRows(execute("DELETE static_col FROM %s WHERE pk = ? AND ck = ? IF value = ?", 1, 5, 6), row(true));
+ assertRows(execute("SELECT pk, ck, static_col, value FROM %s WHERE pk = 1"),
+ row(1, 1, null, null),
+ row(1, 3, null, 4),
+ row(1, 5, null, 6),
+ row(1, 7, null, 8));
+ }
+
+ @Test
+ public void testStaticColumnsCasUpdate() throws Throwable
+ {
+ createTable("CREATE TABLE %s (pk int, ck int, static_col int static, value int, PRIMARY KEY (pk, ck))");
+ execute("INSERT INTO %s (pk, ck, value) VALUES (?, ?, ?)", 1, 1, 2);
+ execute("INSERT INTO %s (pk, ck, value) VALUES (?, ?, ?)", 1, 3, 4);
+ execute("INSERT INTO %s (pk, ck, value) VALUES (?, ?, ?)", 1, 5, 6);
+ execute("INSERT INTO %s (pk, ck, value) VALUES (?, ?, ?)", 1, 7, 8);
+ execute("INSERT INTO %s (pk, ck, value) VALUES (?, ?, ?)", 2, 1, 2);
+ execute("INSERT INTO %s (pk, static_col) VALUES (?, ?)", 1, 1);
+
+ assertRows(execute("UPDATE %s SET static_col = ? WHERE pk = ? IF static_col = ?", 3, 1, 2), row(false, 1));
+ assertRows(execute("UPDATE %s SET static_col = ? WHERE pk = ? IF static_col = ?", 2, 1, 1), row(true));
+
+ assertRows(execute("SELECT pk, ck, static_col, value FROM %s WHERE pk = 1"),
+ row(1, 1, 2, 2),
+ row(1, 3, 2, 4),
+ row(1, 5, 2, 6),
+ row(1, 7, 2, 8));
+
+ assertInvalidMessage("Missing mandatory PRIMARY KEY part pk",
+ "UPDATE %s SET static_col = ? WHERE ck = ? IF static_col = ?", 3, 1, 1);
+
+ assertInvalidMessage("Invalid restriction on clustering column ck since the UPDATE statement modifies only static columns",
+ "UPDATE %s SET static_col = ? WHERE pk = ? AND ck = ? IF static_col = ?", 3, 1, 1, 1);
+
+ assertInvalidMessage("Missing mandatory PRIMARY KEY part ck",
+ "UPDATE %s SET static_col = ?, value = ? WHERE pk = ? IF static_col = ?", 3, 1, 1, 2);
+
+ // Same query but with an invalid condition
+ assertInvalidMessage("Missing mandatory PRIMARY KEY part ck",
+ "UPDATE %s SET static_col = ?, value = ? WHERE pk = ? IF static_col = ?", 3, 1, 1, 1);
+
+ assertInvalidMessage("Missing mandatory PRIMARY KEY part ck",
+ "UPDATE %s SET static_col = ? WHERE pk = ? IF value = ? AND static_col = ?", 3, 1, 4, 2);
+
+ assertRows(execute("UPDATE %s SET value = ? WHERE pk = ? AND ck = ? IF value = ? AND static_col = ?", 3, 1, 1, 3, 2), row(false, 2, 2));
+ assertRows(execute("UPDATE %s SET value = ? WHERE pk = ? AND ck = ? IF value = ? AND static_col = ?", 1, 1, 1, 2, 2), row(true));
+ assertRows(execute("SELECT pk, ck, static_col, value FROM %s WHERE pk = 1"),
+ row(1, 1, 2, 1),
+ row(1, 3, 2, 4),
+ row(1, 5, 2, 6),
+ row(1, 7, 2, 8));
+
+ assertRows(execute("UPDATE %s SET static_col = ? WHERE pk = ? AND ck = ? IF value = ?", 3, 1, 1, 2), row(false, 1));
+ assertRows(execute("UPDATE %s SET static_col = ? WHERE pk = ? AND ck = ? IF value = ?", 1, 1, 1, 1), row(true));
+ assertRows(execute("SELECT pk, ck, static_col, value FROM %s WHERE pk = 1"),
+ row(1, 1, 1, 1),
+ row(1, 3, 1, 4),
+ row(1, 5, 1, 6),
+ row(1, 7, 1, 8));
+ }
+
+ /**
* Migrated from cql_tests.py:TestCQL.bug_6069_test()
*/
@Test
[3/3] cassandra git commit: Merge branch 'cassandra-2.1' into
cassandra-2.2
Posted by ca...@apache.org.
Merge branch 'cassandra-2.1' into cassandra-2.2
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/52a827b4
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/52a827b4
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/52a827b4
Branch: refs/heads/cassandra-2.2
Commit: 52a827b4d22edc4506adfbe83345216bc725d57f
Parents: 05f8a00 1d2d074
Author: Carl Yeksigian <ca...@apache.org>
Authored: Tue Jun 14 08:55:58 2016 -0400
Committer: Carl Yeksigian <ca...@apache.org>
Committed: Tue Jun 14 08:55:58 2016 -0400
----------------------------------------------------------------------
CHANGES.txt | 1 +
.../cql3/statements/DeleteStatement.java | 37 +++---
.../cql3/statements/ModificationStatement.java | 14 ++-
.../operations/InsertUpdateIfConditionTest.java | 113 +++++++++++++++++++
4 files changed, 150 insertions(+), 15 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/52a827b4/CHANGES.txt
----------------------------------------------------------------------
diff --cc CHANGES.txt
index 491f72a,7d70902..d0ca37f
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@@ -1,32 -1,8 +1,33 @@@
-2.1.15
+2.2.7
+ * StorageService shutdown hook should use a volatile variable (CASSANDRA-11984)
+ * Persist local metadata earlier in startup sequence (CASSANDRA-11742)
+ * Run CommitLog tests with different compression settings (CASSANDRA-9039)
+ * cqlsh: fix tab completion for case-sensitive identifiers (CASSANDRA-11664)
+ * Avoid showing estimated key as -1 in tablestats (CASSANDRA-11587)
+ * Fix possible race condition in CommitLog.recover (CASSANDRA-11743)
+ * Enable client encryption in sstableloader with cli options (CASSANDRA-11708)
+ * Possible memory leak in NIODataInputStream (CASSANDRA-11867)
+ * Fix commit log replay after out-of-order flush completion (CASSANDRA-9669)
+ * Add seconds to cqlsh tracing session duration (CASSANDRA-11753)
+ * Prohibit Reverse Counter type as part of the PK (CASSANDRA-9395)
+ * cqlsh: correctly handle non-ascii chars in error messages (CASSANDRA-11626)
+ * Exit JVM if JMX server fails to startup (CASSANDRA-11540)
+ * Produce a heap dump when exiting on OOM (CASSANDRA-9861)
+ * Avoid read repairing purgeable tombstones on range slices (CASSANDRA-11427)
+ * Restore ability to filter on clustering columns when using a 2i (CASSANDRA-11510)
+ * JSON datetime formatting needs timezone (CASSANDRA-11137)
+ * Fix is_dense recalculation for Thrift-updated tables (CASSANDRA-11502)
+ * Remove unnescessary file existence check during anticompaction (CASSANDRA-11660)
+ * Add missing files to debian packages (CASSANDRA-11642)
+ * Avoid calling Iterables::concat in loops during ModificationStatement::getFunctions (CASSANDRA-11621)
+ * cqlsh: COPY FROM should use regular inserts for single statement batches and
+ report errors correctly if workers processes crash on initialization (CASSANDRA-11474)
+ * Always close cluster with connection in CqlRecordWriter (CASSANDRA-11553)
+ * Fix slice queries on ordered COMPACT tables (CASSANDRA-10988)
+Merged from 2.1:
+ * Allow LWT operation on static column with only partition keys (CASSANDRA-10532)
* Create interval tree over canonical sstables to avoid missing sstables during streaming (CASSANDRA-11886)
* cqlsh COPY FROM: shutdown parent cluster after forking, to avoid corrupting SSL connections (CASSANDRA-11749)
- * Updated cqlsh Python driver to fix DESCRIBE problem for legacy tables (CASSANDRA-11055)
* cqlsh: apply current keyspace to source command (CASSANDRA-11152)
* Backport CASSANDRA-11578 (CASSANDRA-11750)
* Clear out parent repair session if repair coordinator dies (CASSANDRA-11824)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/52a827b4/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/52a827b4/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/52a827b4/test/unit/org/apache/cassandra/cql3/validation/operations/InsertUpdateIfConditionTest.java
----------------------------------------------------------------------
[2/3] cassandra git commit: Allow LWT operation on static column with
only partition keys
Posted by ca...@apache.org.
Allow LWT operation on static column with only partition keys
Patch by Carl Yeksigian, reviewed by Benjamin Lerer for CASSANDRA-10532
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/1d2d0749
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/1d2d0749
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/1d2d0749
Branch: refs/heads/cassandra-2.2
Commit: 1d2d0749a8b72c4c8cdd5b85b210157e8d7d6a41
Parents: 72acbcd
Author: Carl Yeksigian <ca...@apache.org>
Authored: Tue Jun 14 08:32:26 2016 -0400
Committer: Carl Yeksigian <ca...@apache.org>
Committed: Tue Jun 14 08:32:26 2016 -0400
----------------------------------------------------------------------
CHANGES.txt | 1 +
.../cql3/statements/DeleteStatement.java | 37 +++---
.../cql3/statements/ModificationStatement.java | 14 ++-
.../operations/InsertUpdateIfConditionTest.java | 113 +++++++++++++++++++
4 files changed, 150 insertions(+), 15 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/1d2d0749/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index ebcc90c..7d70902 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
2.1.15
+ * Allow LWT operation on static column with only partition keys (CASSANDRA-10532)
* Create interval tree over canonical sstables to avoid missing sstables during streaming (CASSANDRA-11886)
* cqlsh COPY FROM: shutdown parent cluster after forking, to avoid corrupting SSL connections (CASSANDRA-11749)
* Updated cqlsh Python driver to fix DESCRIBE problem for legacy tables (CASSANDRA-11055)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/1d2d0749/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java b/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java
index 33c61e7..d8fa467 100644
--- a/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java
@@ -50,15 +50,6 @@ public class DeleteStatement extends ModificationStatement
{
List<Operation> deletions = getOperations();
- if (prefix.size() < cfm.clusteringColumns().size() && !deletions.isEmpty())
- {
- // In general, we can't delete specific columns if not all clustering columns have been specified.
- // However, if we delete only static colums, it's fine since we won't really use the prefix anyway.
- for (Operation deletion : deletions)
- if (!deletion.column.isStatic())
- throw new InvalidRequestException(String.format("Primary key column '%s' must be specified in order to delete column '%s'", getFirstEmptyKey().name, deletion.column.name));
- }
-
if (deletions.isEmpty())
{
// We delete the slice selected by the prefix.
@@ -88,19 +79,39 @@ public class DeleteStatement extends ModificationStatement
protected void validateWhereClauseForConditions() throws InvalidRequestException
{
- Iterator<ColumnDefinition> iterator = Iterators.concat(cfm.partitionKeyColumns().iterator(), cfm.clusteringColumns().iterator());
+ boolean onlyHasConditionsOnStaticColumns = hasStaticConditions() && !hasRegularConditions();
+
+ // In general, we can't delete specific columns if not all clustering columns have been specified.
+ // However, if we delete only static colums, it's fine since we won't really use the prefix anyway.
+ Iterator<ColumnDefinition> iterator = appliesOnlyToStaticColumns()
+ ? cfm.partitionKeyColumns().iterator()
+ : Iterators.concat(cfm.partitionKeyColumns().iterator(), cfm.clusteringColumns().iterator());
while (iterator.hasNext())
{
ColumnDefinition def = iterator.next();
Restriction restriction = processedKeys.get(def.name);
if (restriction == null || !(restriction.isEQ() || restriction.isIN()))
{
+ if (onlyHasConditionsOnStaticColumns)
+ {
+ for (Operation oper : getOperations())
+ {
+ if (!oper.column.isStatic())
+ {
+ throw new InvalidRequestException(String.format("Primary key column '%s' must be specified in order to delete column '%s'",
+ def.name,
+ oper.column.name));
+ }
+ }
+ }
+
throw new InvalidRequestException(
- String.format("DELETE statements must restrict all PRIMARY KEY columns with equality relations in order " +
- "to use IF conditions, but column '%s' is not restricted", def.name));
+ String.format("DELETE statements must restrict all %s KEY columns with equality relations in order " +
+ "to use IF conditions%s, but column '%s' is not restricted",
+ onlyHasConditionsOnStaticColumns ? "PARTITION" : "PRIMARY",
+ onlyHasConditionsOnStaticColumns ? " on static columns" : "", def.name));
}
}
-
}
public static class Parsed extends ModificationStatement.Parsed
http://git-wip-us.apache.org/repos/asf/cassandra/blob/1d2d0749/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java b/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
index 75a3b40..a9f65e1 100644
--- a/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
@@ -211,6 +211,16 @@ public abstract class ModificationStatement implements CQLStatement
return ifExists;
}
+ public boolean hasStaticConditions()
+ {
+ return staticConditions != null && !staticConditions.isEmpty();
+ }
+
+ public boolean hasRegularConditions()
+ {
+ return columnConditions != null && !columnConditions.isEmpty();
+ }
+
private void addKeyValues(ColumnDefinition def, Restriction values) throws InvalidRequestException
{
if (def.kind == ColumnDefinition.Kind.CLUSTERING_COLUMN)
@@ -364,7 +374,7 @@ public abstract class ModificationStatement implements CQLStatement
* Checks that the modification only apply to static columns.
* @return <code>true</code> if the modification only apply to static columns, <code>false</code> otherwise.
*/
- private boolean appliesOnlyToStaticColumns()
+ protected boolean appliesOnlyToStaticColumns()
{
return setsStaticColumns && !appliesToRegularColumns();
}
@@ -373,7 +383,7 @@ public abstract class ModificationStatement implements CQLStatement
* Checks that the modification apply to regular columns.
* @return <code>true</code> if the modification apply to regular columns, <code>false</code> otherwise.
*/
- private boolean appliesToRegularColumns()
+ protected boolean appliesToRegularColumns()
{
// If we have regular operations, this applies to regular columns.
// Otherwise, if the statement is a DELETE and columnOperations is empty, this means we have no operations,
http://git-wip-us.apache.org/repos/asf/cassandra/blob/1d2d0749/test/unit/org/apache/cassandra/cql3/validation/operations/InsertUpdateIfConditionTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/validation/operations/InsertUpdateIfConditionTest.java b/test/unit/org/apache/cassandra/cql3/validation/operations/InsertUpdateIfConditionTest.java
index e94011b..05ba09d 100644
--- a/test/unit/org/apache/cassandra/cql3/validation/operations/InsertUpdateIfConditionTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/operations/InsertUpdateIfConditionTest.java
@@ -311,6 +311,119 @@ public class InsertUpdateIfConditionTest extends CQLTester
}
/**
+ * Test CASSANDRA-10532
+ */
+ @Test
+ public void testStaticColumnsCasDelete() throws Throwable
+ {
+ createTable("CREATE TABLE %s (pk int, ck int, static_col int static, value int, PRIMARY KEY (pk, ck))");
+ execute("INSERT INTO %s (pk, ck, value) VALUES (?, ?, ?)", 1, 1, 2);
+ execute("INSERT INTO %s (pk, ck, value) VALUES (?, ?, ?)", 1, 3, 4);
+ execute("INSERT INTO %s (pk, ck, value) VALUES (?, ?, ?)", 1, 5, 6);
+ execute("INSERT INTO %s (pk, ck, value) VALUES (?, ?, ?)", 1, 7, 8);
+ execute("INSERT INTO %s (pk, ck, value) VALUES (?, ?, ?)", 2, 1, 2);
+ execute("INSERT INTO %s (pk, static_col) VALUES (?, ?)", 1, 1);
+
+ assertRows(execute("DELETE static_col FROM %s WHERE pk = ? IF static_col = ?", 1, 2), row(false, 1));
+ assertRows(execute("DELETE static_col FROM %s WHERE pk = ? IF static_col = ?", 1, 1), row(true));
+
+ assertRows(execute("SELECT pk, ck, static_col, value FROM %s WHERE pk = 1"),
+ row(1, 1, null, 2),
+ row(1, 3, null, 4),
+ row(1, 5, null, 6),
+ row(1, 7, null, 8));
+ execute("INSERT INTO %s (pk, static_col) VALUES (?, ?)", 1, 1);
+
+ assertInvalidMessage("DELETE statements must restrict all PARTITION KEY columns with equality relations in order " +
+ "to use IF conditions on static columns, but column 'pk' is not restricted",
+ "DELETE static_col FROM %s WHERE ck = ? IF static_col = ?", 1, 1);
+
+ assertInvalidMessage("Invalid restriction on clustering column ck since the DELETE statement modifies only static columns",
+ "DELETE static_col FROM %s WHERE pk = ? AND ck = ? IF static_col = ?", 1, 1, 1);
+
+ assertInvalidMessage("Primary key column 'ck' must be specified in order to delete column 'value'",
+ "DELETE static_col, value FROM %s WHERE pk = ? IF static_col = ?", 1, 1);
+
+ // Same query but with an invalid condition
+ assertInvalidMessage("Primary key column 'ck' must be specified in order to delete column 'value'",
+ "DELETE static_col, value FROM %s WHERE pk = ? IF static_col = ?", 1, 2);
+
+ // DELETE of an underspecified PRIMARY KEY should not succeed if static is not only restriction
+ assertInvalidMessage("DELETE statements must restrict all PRIMARY KEY columns with equality relations in order " +
+ "to use IF conditions, but column 'ck' is not restricted",
+ "DELETE static_col FROM %s WHERE pk = ? IF value = ? AND static_col = ?", 1, 2, 1);
+
+ assertRows(execute("DELETE value FROM %s WHERE pk = ? AND ck = ? IF value = ? AND static_col = ?", 1, 1, 2, 2), row(false, 2, 1));
+ assertRows(execute("DELETE value FROM %s WHERE pk = ? AND ck = ? IF value = ? AND static_col = ?", 1, 1, 2, 1), row(true));
+ assertRows(execute("SELECT pk, ck, static_col, value FROM %s WHERE pk = 1"),
+ row(1, 1, 1, null),
+ row(1, 3, 1, 4),
+ row(1, 5, 1, 6),
+ row(1, 7, 1, 8));
+
+ assertRows(execute("DELETE static_col FROM %s WHERE pk = ? AND ck = ? IF value = ?", 1, 5, 10), row(false, 6));
+ assertRows(execute("DELETE static_col FROM %s WHERE pk = ? AND ck = ? IF value = ?", 1, 5, 6), row(true));
+ assertRows(execute("SELECT pk, ck, static_col, value FROM %s WHERE pk = 1"),
+ row(1, 1, null, null),
+ row(1, 3, null, 4),
+ row(1, 5, null, 6),
+ row(1, 7, null, 8));
+ }
+
+ @Test
+ public void testStaticColumnsCasUpdate() throws Throwable
+ {
+ createTable("CREATE TABLE %s (pk int, ck int, static_col int static, value int, PRIMARY KEY (pk, ck))");
+ execute("INSERT INTO %s (pk, ck, value) VALUES (?, ?, ?)", 1, 1, 2);
+ execute("INSERT INTO %s (pk, ck, value) VALUES (?, ?, ?)", 1, 3, 4);
+ execute("INSERT INTO %s (pk, ck, value) VALUES (?, ?, ?)", 1, 5, 6);
+ execute("INSERT INTO %s (pk, ck, value) VALUES (?, ?, ?)", 1, 7, 8);
+ execute("INSERT INTO %s (pk, ck, value) VALUES (?, ?, ?)", 2, 1, 2);
+ execute("INSERT INTO %s (pk, static_col) VALUES (?, ?)", 1, 1);
+
+ assertRows(execute("UPDATE %s SET static_col = ? WHERE pk = ? IF static_col = ?", 3, 1, 2), row(false, 1));
+ assertRows(execute("UPDATE %s SET static_col = ? WHERE pk = ? IF static_col = ?", 2, 1, 1), row(true));
+
+ assertRows(execute("SELECT pk, ck, static_col, value FROM %s WHERE pk = 1"),
+ row(1, 1, 2, 2),
+ row(1, 3, 2, 4),
+ row(1, 5, 2, 6),
+ row(1, 7, 2, 8));
+
+ assertInvalidMessage("Missing mandatory PRIMARY KEY part pk",
+ "UPDATE %s SET static_col = ? WHERE ck = ? IF static_col = ?", 3, 1, 1);
+
+ assertInvalidMessage("Invalid restriction on clustering column ck since the UPDATE statement modifies only static columns",
+ "UPDATE %s SET static_col = ? WHERE pk = ? AND ck = ? IF static_col = ?", 3, 1, 1, 1);
+
+ assertInvalidMessage("Missing mandatory PRIMARY KEY part ck",
+ "UPDATE %s SET static_col = ?, value = ? WHERE pk = ? IF static_col = ?", 3, 1, 1, 2);
+
+ // Same query but with an invalid condition
+ assertInvalidMessage("Missing mandatory PRIMARY KEY part ck",
+ "UPDATE %s SET static_col = ?, value = ? WHERE pk = ? IF static_col = ?", 3, 1, 1, 1);
+
+ assertInvalidMessage("Missing mandatory PRIMARY KEY part ck",
+ "UPDATE %s SET static_col = ? WHERE pk = ? IF value = ? AND static_col = ?", 3, 1, 4, 2);
+
+ assertRows(execute("UPDATE %s SET value = ? WHERE pk = ? AND ck = ? IF value = ? AND static_col = ?", 3, 1, 1, 3, 2), row(false, 2, 2));
+ assertRows(execute("UPDATE %s SET value = ? WHERE pk = ? AND ck = ? IF value = ? AND static_col = ?", 1, 1, 1, 2, 2), row(true));
+ assertRows(execute("SELECT pk, ck, static_col, value FROM %s WHERE pk = 1"),
+ row(1, 1, 2, 1),
+ row(1, 3, 2, 4),
+ row(1, 5, 2, 6),
+ row(1, 7, 2, 8));
+
+ assertRows(execute("UPDATE %s SET static_col = ? WHERE pk = ? AND ck = ? IF value = ?", 3, 1, 1, 2), row(false, 1));
+ assertRows(execute("UPDATE %s SET static_col = ? WHERE pk = ? AND ck = ? IF value = ?", 1, 1, 1, 1), row(true));
+ assertRows(execute("SELECT pk, ck, static_col, value FROM %s WHERE pk = 1"),
+ row(1, 1, 1, 1),
+ row(1, 3, 1, 4),
+ row(1, 5, 1, 6),
+ row(1, 7, 1, 8));
+ }
+
+ /**
* Migrated from cql_tests.py:TestCQL.bug_6069_test()
*/
@Test