This is an automated email from the ASF dual-hosted git repository.

dcapwell pushed a commit to branch cep-15-accord
in repository https://gitbox.apache.org/repos/asf/cassandra.git


The following commit(s) were added to refs/heads/cep-15-accord by this push:
     new 885f4362af CEP-15 (Accord): When starting a transaction in a table 
where Accord is not enabled, should fail fast rather than fail with lack of 
ranges
885f4362af is described below

commit 885f4362afdca43f0a98b03128b2b4993a6701e9
Author: Youki Shiraishi <[email protected]>
AuthorDate: Tue Jul 23 12:50:58 2024 -0700

    CEP-15 (Accord): When starting a transaction in a table where Accord is not 
enabled, should fail fast rather than fail with lack of ranges
    
    patch by Youki Shiraishi; reviewed by Caleb Rackliffe, David Capwell for 
CASSANDRA-19759
---
 accord_demo.txt                                    | 15 +++----
 .../cql3/statements/TransactionStatement.java      |  6 +++
 .../cql3/statements/TransactionStatementTest.java  | 52 +++++++++++++++++++---
 .../compaction/CompactionAccordIteratorsTest.java  |  2 +-
 .../service/accord/AccordKeyspaceTest.java         |  2 +-
 5 files changed, 59 insertions(+), 18 deletions(-)

diff --git a/accord_demo.txt b/accord_demo.txt
index b883451522..63b7d21201 100644
--- a/accord_demo.txt
+++ b/accord_demo.txt
@@ -1,19 +1,14 @@
-
 ccm create accord-cql-poc -n 3
 ccm start
 
-bin/cqlsh -e "create keyspace ks with replication={'class':'SimpleStrategy', 
'replication_factor':3};"
-bin/cqlsh -e "create table ks.tbl1 (k int primary key, v int);"
-bin/cqlsh -e "create table ks.tbl2 (k int primary key, v int);"
-
-bin/nodetool -h 0000:0000:0000:0000:0000:ffff:7f00:0001 -p 7100 
createepochunsafe
-bin/nodetool -h 0000:0000:0000:0000:0000:ffff:7f00:0001 -p 7200 
createepochunsafe
-bin/nodetool -h 0000:0000:0000:0000:0000:ffff:7f00:0001 -p 7300 
createepochunsafe
+bin/cqlsh -e "CREATE KEYSPACE ks WITH replication={'class':'SimpleStrategy', 
'replication_factor':3};"
+bin/cqlsh -e "CREATE TABLE ks.tbl1 (k int PRIMARY KEY, v int) WITH 
transactional_mode = 'full';"
+bin/cqlsh -e "CREATE TABLE ks.tbl2 (k int PRIMARY KEY, v int) WITH 
transactional_mode = 'full';"
 
 BEGIN TRANSACTION
   LET row1 = (SELECT * FROM ks.tbl1 WHERE k = 1);
   SELECT row1.v;
   IF row1 IS NULL THEN
-    INSERT INTO ks.tbl1 (k, v) VALUES (1, 2);
+    INSERT INTO ks.tbl2 (k, v) VALUES (1, 2);
   END IF
-COMMIT TRANSACTION;
\ No newline at end of file
+COMMIT TRANSACTION;
diff --git 
a/src/java/org/apache/cassandra/cql3/statements/TransactionStatement.java 
b/src/java/org/apache/cassandra/cql3/statements/TransactionStatement.java
index f2266557e9..46c620ddc0 100644
--- a/src/java/org/apache/cassandra/cql3/statements/TransactionStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/TransactionStatement.java
@@ -100,6 +100,7 @@ public class TransactionStatement implements 
CQLStatement.CompositeCQLStatement,
     public static final String INCOMPLETE_PRIMARY_KEY_SELECT_MESSAGE = "SELECT 
must specify either all primary key elements or all partition key elements and 
LIMIT 1. In both cases partition key elements must be always specified with 
equality operators; %s %s";
     public static final String NO_CONDITIONS_IN_UPDATES_MESSAGE = "Updates 
within transactions may not specify their own conditions; %s statement %s";
     public static final String NO_TIMESTAMPS_IN_UPDATES_MESSAGE = "Updates 
within transactions may not specify custom timestamps; %s statement %s";
+    public static final String TRANSACTIONS_DISABLED_ON_TABLE_MESSAGE = 
"Accord transactions are disabled on table (See transactional_mode in table 
options); %s statement %s";
     public static final String NO_COUNTERS_IN_TXNS_MESSAGE = "Counter columns 
cannot be accessed within a transaction; %s statement %s";
     public static final String EMPTY_TRANSACTION_MESSAGE = "Transaction 
contains no reads or writes";
     public static final String SELECT_REFS_NEED_COLUMN_MESSAGE = "SELECT 
references must specify a column.";
@@ -521,6 +522,8 @@ public class TransactionStatement implements 
CQLStatement.CompositeCQLStatement,
 
                 SelectStatement prepared = select.prepare(bindVariables);
 
+                if (!prepared.table.isAccordEnabled())
+                    throw 
invalidRequest(TRANSACTIONS_DISABLED_ON_TABLE_MESSAGE, "SELECT", 
prepared.source);
                 if (prepared.table.isCounter())
                     throw invalidRequest(NO_COUNTERS_IN_TXNS_MESSAGE, 
"SELECT", prepared.source);
 
@@ -539,6 +542,8 @@ public class TransactionStatement implements 
CQLStatement.CompositeCQLStatement,
             {
                 SelectStatement prepared = select.prepare(bindVariables);
 
+                if (!prepared.table.isAccordEnabled())
+                    throw 
invalidRequest(TRANSACTIONS_DISABLED_ON_TABLE_MESSAGE, "SELECT", 
prepared.source);
                 if (prepared.table.isCounter())
                     throw invalidRequest(NO_COUNTERS_IN_TXNS_MESSAGE, 
"SELECT", prepared.source);
 
@@ -564,6 +569,7 @@ public class TransactionStatement implements 
CQLStatement.CompositeCQLStatement,
                 ModificationStatement.Parsed parsed = updates.get(i);
 
                 ModificationStatement prepared = parsed.prepare(state, 
bindVariables);
+                checkTrue(prepared.metadata().isAccordEnabled(), 
TRANSACTIONS_DISABLED_ON_TABLE_MESSAGE, prepared.type, prepared.source);
                 checkFalse(prepared.hasConditions(), 
NO_CONDITIONS_IN_UPDATES_MESSAGE, prepared.type, prepared.source);
                 checkFalse(prepared.isTimestampSet(), 
NO_TIMESTAMPS_IN_UPDATES_MESSAGE, prepared.type, prepared.source);
 
diff --git 
a/test/unit/org/apache/cassandra/cql3/statements/TransactionStatementTest.java 
b/test/unit/org/apache/cassandra/cql3/statements/TransactionStatementTest.java
index a5dca45ae5..0f4f1aa731 100644
--- 
a/test/unit/org/apache/cassandra/cql3/statements/TransactionStatementTest.java
+++ 
b/test/unit/org/apache/cassandra/cql3/statements/TransactionStatementTest.java
@@ -41,6 +41,7 @@ import static 
org.apache.cassandra.cql3.statements.TransactionStatement.NO_CONDI
 import static 
org.apache.cassandra.cql3.statements.TransactionStatement.NO_COUNTERS_IN_TXNS_MESSAGE;
 import static 
org.apache.cassandra.cql3.statements.TransactionStatement.NO_TIMESTAMPS_IN_UPDATES_MESSAGE;
 import static 
org.apache.cassandra.cql3.statements.TransactionStatement.SELECT_REFS_NEED_COLUMN_MESSAGE;
+import static 
org.apache.cassandra.cql3.statements.TransactionStatement.TRANSACTIONS_DISABLED_ON_TABLE_MESSAGE;
 import static 
org.apache.cassandra.cql3.statements.UpdateStatement.CANNOT_SET_KEY_WITH_REFERENCE_MESSAGE;
 import static 
org.apache.cassandra.cql3.statements.UpdateStatement.UPDATING_PRIMARY_KEY_MESSAGE;
 import static 
org.apache.cassandra.cql3.statements.schema.CreateTableStatement.parse;
@@ -56,18 +57,20 @@ public class TransactionStatementTest
     private static final TableId TABLE4_ID = 
TableId.fromString("00000000-0000-0000-0000-000000000004");
     private static final TableId TABLE5_ID = 
TableId.fromString("00000000-0000-0000-0000-000000000005");
     private static final TableId TABLE6_ID = 
TableId.fromString("00000000-0000-0000-0000-000000000006");
+    private static final TableId TABLE7_ID = 
TableId.fromString("00000000-0000-0000-0000-000000000007");
 
     @BeforeClass
     public static void beforeClass() throws Exception
     {
         SchemaLoader.prepareServer();
         SchemaLoader.createKeyspace("ks", KeyspaceParams.simple(1),
-                                    parse("CREATE TABLE tbl1 (k int, c int, v 
int, primary key (k, c))", "ks").id(TABLE1_ID),
-                                    parse("CREATE TABLE tbl2 (k int, c int, v 
int, primary key (k, c))", "ks").id(TABLE2_ID),
-                                    parse("CREATE TABLE tbl3 (k int PRIMARY 
KEY, \"with spaces\" int, \"with\"\"quote\" int, \"MiXeD_CaSe\" int)", 
"ks").id(TABLE3_ID),
-                                    parse("CREATE TABLE tbl4 (k int PRIMARY 
KEY, int_list list<int>)", "ks").id(TABLE4_ID),
-                                    parse("CREATE TABLE tbl5 (k int PRIMARY 
KEY, v int)", "ks").id(TABLE5_ID),
-                                    parse("CREATE TABLE tbl6 (k int PRIMARY 
KEY, c counter)", "ks").id(TABLE6_ID));
+                                    parse("CREATE TABLE tbl1 (k int, c int, v 
int, PRIMARY KEY (k, c)) WITH transactional_mode = 'full'", "ks").id(TABLE1_ID),
+                                    parse("CREATE TABLE tbl2 (k int, c int, v 
int, primary key (k, c)) WITH transactional_mode = 'full'", "ks").id(TABLE2_ID),
+                                    parse("CREATE TABLE tbl3 (k int PRIMARY 
KEY, \"with spaces\" int, \"with\"\"quote\" int, \"MiXeD_CaSe\" int) WITH 
transactional_mode = 'full'", "ks").id(TABLE3_ID),
+                                    parse("CREATE TABLE tbl4 (k int PRIMARY 
KEY, int_list list<int>) WITH transactional_mode = 'full'", "ks").id(TABLE4_ID),
+                                    parse("CREATE TABLE tbl5 (k int PRIMARY 
KEY, v int) WITH transactional_mode = 'full'", "ks").id(TABLE5_ID),
+                                    parse("CREATE TABLE tbl6 (k int PRIMARY 
KEY, c counter) WITH transactional_mode = 'full'", "ks").id(TABLE6_ID),
+                                    parse("CREATE TABLE tbl7 (k int PRIMARY 
KEY, v int) WITH transactional_mode = 'off'", "ks").id(TABLE7_ID));
     }
 
     @Test
@@ -399,6 +402,43 @@ public class TransactionStatementTest
                   
.hasMessageContaining(String.format(ILLEGAL_RANGE_QUERY_MESSAGE, "LET 
assignment row1", "at [2:15]"));
     }
 
+    @Test
+    public void shouldRejectLetSelectOnNonTransactionalTable()
+    {
+        String query = "BEGIN TRANSACTION\n" +
+                       "  LET row1 = (SELECT * FROM ks.tbl7 WHERE k = 0);\n" +
+                       "  INSERT INTO ks.tbl5 (k, v) VALUES (1, 2);\n" +
+                       "COMMIT TRANSACTION;";
+
+        Assertions.assertThatThrownBy(() -> prepare(query))
+                .isInstanceOf(InvalidRequestException.class)
+                
.hasMessageContaining(String.format(TRANSACTIONS_DISABLED_ON_TABLE_MESSAGE, 
"SELECT", "at [2:15]"));
+    }
+
+    @Test
+    public void shouldRejectSelectOnNonTransactionalTable()
+    {
+        String query = "BEGIN TRANSACTION\n" +
+                       "  SELECT * FROM ks.tbl7 WHERE k = 0;\n" +
+                       "COMMIT TRANSACTION;";
+
+        Assertions.assertThatThrownBy(() -> prepare(query))
+                .isInstanceOf(InvalidRequestException.class)
+                
.hasMessageContaining(String.format(TRANSACTIONS_DISABLED_ON_TABLE_MESSAGE, 
"SELECT", "at [2:3]"));
+    }
+
+    @Test
+    public void shouldRejectUpdateOnNonTransactionalTable()
+    {
+        String query = "BEGIN TRANSACTION\n" +
+                       "  INSERT INTO ks.tbl7 (k, v) VALUES (1, 2);\n" +
+                       "COMMIT TRANSACTION;";
+
+        Assertions.assertThatThrownBy(() -> prepare(query))
+                .isInstanceOf(InvalidRequestException.class)
+                
.hasMessageContaining(String.format(TRANSACTIONS_DISABLED_ON_TABLE_MESSAGE, 
"INSERT", "at [2:3]"));
+    }
+
     private static CQLStatement prepare(String query)
     {
         TransactionStatement.Parsed parsed = (TransactionStatement.Parsed) 
QueryProcessor.parseStatement(query);
diff --git 
a/test/unit/org/apache/cassandra/db/compaction/CompactionAccordIteratorsTest.java
 
b/test/unit/org/apache/cassandra/db/compaction/CompactionAccordIteratorsTest.java
index 5cbf0915b5..71594055bd 100644
--- 
a/test/unit/org/apache/cassandra/db/compaction/CompactionAccordIteratorsTest.java
+++ 
b/test/unit/org/apache/cassandra/db/compaction/CompactionAccordIteratorsTest.java
@@ -146,7 +146,7 @@ public class CompactionAccordIteratorsTest
         SchemaLoader.prepareServer();
         // Schema doesn't matter since this is a metadata only test
         SchemaLoader.createKeyspace("ks", KeyspaceParams.simple(1),
-                                    parse("CREATE TABLE tbl (k int, c int, v 
int, primary key (k, c))", "ks"));
+                                    parse("CREATE TABLE tbl (k int, c int, v 
int, PRIMARY KEY (k, c)) WITH transactional_mode = 'full'", "ks"));
         StorageService.instance.initServer();
 
         commands = 
ColumnFamilyStore.getIfExists(SchemaConstants.ACCORD_KEYSPACE_NAME, 
AccordKeyspace.COMMANDS);
diff --git 
a/test/unit/org/apache/cassandra/service/accord/AccordKeyspaceTest.java 
b/test/unit/org/apache/cassandra/service/accord/AccordKeyspaceTest.java
index 9c613624fe..f922c6f0ce 100644
--- a/test/unit/org/apache/cassandra/service/accord/AccordKeyspaceTest.java
+++ b/test/unit/org/apache/cassandra/service/accord/AccordKeyspaceTest.java
@@ -97,7 +97,7 @@ public class AccordKeyspaceTest extends CQLTester.InMemory
     {
         AtomicLong now = new AtomicLong();
 
-        String tableName = createTable("CREATE TABLE %s (k int, c int, v int, 
PRIMARY KEY (k, c))");
+        String tableName = createTable("CREATE TABLE %s (k int, c int, v int, 
PRIMARY KEY (k, c)) WITH transactional_mode = 'full'");
         TableId tableId = Schema.instance.getTableMetadata(KEYSPACE, 
tableName).id;
         Ranges scope = Ranges.of(new 
TokenRange(AccordRoutingKey.SentinelKey.min(tableId), 
AccordRoutingKey.SentinelKey.max(tableId)));
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to