create table lwt (a int, b int, primary key (a,b)); { "status" : "ok" } -- basic batch: ok begin batch insert into lwt (a, b) values (1, 1) if not exists apply batch; { "rows" : [ { "[applied]" : "true" } ] } -- begin unlogged batch + lwt: ok; unlogged is ignored -- (same in c*) begin unlogged batch insert into lwt (a, b) values (1, 1) if not exists apply batch; { "rows" : [ { "[applied]" : "false", "a" : "1", "b" : "1" } ] } -- begin counter batch + lwt: error begin counter batch insert into lwt (a, b) values (1, 1) if not exists apply batch; { "message" : "exceptions::invalid_request_exception (Cannot include non-counter statement in a counter batch)", "status" : "error" } -- a batch affecting two partitions: error begin batch insert into lwt (a, b) values (1, 1) if not exists insert into lwt (a, b) values (2, 1) if not exists apply batch; { "message" : "exceptions::invalid_request_exception (BATCH with conditions cannot span multiple partitions)", "status" : "error" } -- a batch with an LWT statement and other statement affecting another -- partition: error begin batch insert into lwt (a, b) values (1, 1) if not exists insert into lwt (a, b) values (2, 1) apply batch; { "message" : "exceptions::invalid_request_exception (BATCH with conditions cannot span multiple partitions)", "status" : "error" } -- a batch affecting different clustering keys of the same partition: ok begin batch insert into lwt (a, b) values (1, 1) if not exists insert into lwt (a, b) values (1, 2) if not exists apply batch; { "rows" : [ { "[applied]" : "false", "a" : "1", "b" : "1" }, { "[applied]" : "false" } ] } -- a batch and non-batch statement, on the same partition: ok begin batch insert into lwt (a, b) values (1, 1) if not exists insert into lwt (a, b) values (1, 2) apply batch; { "rows" : [ { "[applied]" : "false", "a" : "1", "b" : "1" }, { "[applied]" : "false" } ] } -- a batch affecting two tables: error create table two (a int primary key, b int); { "status" : "ok" } begin batch insert into lwt (a, b) values (1, 1) if not exists insert into two (a, b) values (1, 1) apply batch; { "message" : "exceptions::invalid_request_exception (BATCH with conditions cannot span multiple tables)", "status" : "error" } drop table two; { "status" : "ok" } -- a batch with custom timestamp set: error begin batch using timestamp 1 insert into lwt (a, b) values (1, 1) if not exists apply batch; { "message" : "exceptions::invalid_request_exception (Cannot provide custom timestamp for conditional BATCH)", "status" : "error" } -- a batch with a statement with a custom timestamp: error begin batch insert into lwt (a, b) values (1, 1) if not exists using timestamp 1 apply batch; { "message" : "exceptions::invalid_request_exception (Cannot provide custom timestamp for conditional updates)", "status" : "error" } -- a batch with an LWT statement and another statement with a custom timestamp set: ok begin batch insert into lwt (a, b) values (1, 1) if not exists insert into lwt (a, b) values (1, 1) using timestamp 1 apply batch; { "rows" : [ { "[applied]" : "false", "a" : "1", "b" : "1" }, { "[applied]" : "false", "a" : "1", "b" : "1" } ] } -- a batch with if condition and counters: error -- if a table has a counter, all its non-primary key columns -- must be counters create table lcounter (a int primary key, c counter); { "status" : "ok" } begin batch update lcounter set c = c + 1 where a = 1 if c = null apply batch; { "message" : "exceptions::invalid_request_exception (Conditional updates are not supported on counter tables)", "status" : "error" } drop table lcounter; { "status" : "ok" } drop table lwt; { "status" : "ok" } create table lwt (a int, b int, c int, primary key (a,b)); { "status" : "ok" } -- a batch with IF condition on primary key: error begin batch update lwt set c = 2 where a = 1 and b = 1 if a > 0 apply batch; { "message" : "exceptions::invalid_request_exception (PRIMARY KEY column 'a' cannot have IF conditions)", "status" : "error" } begin batch update lwt set c = 2 where a = 1 and b = 1 if b > 0 apply batch; { "message" : "exceptions::invalid_request_exception (PRIMARY KEY column 'b' cannot have IF conditions)", "status" : "error" } begin batch update lwt set c = 2 where a = 1 if c = null apply batch; { "message" : "exceptions::invalid_request_exception (Missing mandatory PRIMARY KEY part b)", "status" : "error" } -- a batch with a statement that has IN prediacte and IF condition: error begin batch update lwt set c = 2 where a = 1 and b in (1, 2) if c = null apply batch; { "message" : "exceptions::invalid_request_exception (IN on the clustering key columns is not supported with conditional updates)", "status" : "error" } -- a batch with a statement that has IN prediacte and *another* statement -- with IF condition: OK. This is an error in C* but I see no reason -- why it should be an error in Scylla. delete from lwt where a = 1; { "status" : "ok" } begin batch update lwt set c = 2 where a = 1 and b = 1 if c = null update lwt set c = 2 where a = 1 and b in (1, 2) apply batch; { "rows" : [ { "[applied]" : "true" }, { "[applied]" : "true" } ] } select a, b, c from lwt where a = 1 and b in (1, 2); { "rows" : [ { "a" : "1", "b" : "1", "c" : "2" }, { "a" : "1", "b" : "2", "c" : "2" } ] } drop table lwt; { "status" : "ok" } -- -- BATCH LWT with multiple statements on LIST data type, -- append/discard operations on the type: all append/discard -- operations from all stsatemetns of the batch are applied -- create table lwt (a int, b int, c list, d list static, primary key (a, b)); { "status" : "ok" } begin batch insert into lwt (a, b, c, d ) values (1, 1, ['1'], ['1']) if not exists insert into lwt (a, b, c, d ) values (1, 2, ['2'], ['2']) if not exists apply batch; { "rows" : [ { "[applied]" : "true" }, { "[applied]" : "true" } ] } select b, c, d from lwt where a = 1; { "rows" : [ { "b" : "1", "c" : "[\"1\"]", "d" : "[\"1\", \"2\"]" }, { "b" : "2", "c" : "[\"2\"]", "d" : "[\"1\", \"2\"]" } ] } begin batch update lwt set c = c + ['3'], d = d + ['3'] where a = 1 and b = 1 if exists update lwt set c = c + ['4'], d = d + ['4'] where a = 1 and b = 2 apply batch; { "rows" : [ { "[applied]" : "true", "a" : "1", "b" : "1", "c" : "[\"1\"]", "d" : "[\"1\", \"2\"]" }, { "[applied]" : "true" } ] } select b, c, d from lwt where a = 1; { "rows" : [ { "b" : "1", "c" : "[\"1\", \"3\"]", "d" : "[\"1\", \"2\", \"3\", \"4\"]" }, { "b" : "2", "c" : "[\"2\", \"4\"]", "d" : "[\"1\", \"2\", \"3\", \"4\"]" } ] } begin batch update lwt set c = c + ['5'], d = d + ['5'] where a = 1 and b = 1 if c[0] = '1' and c[1] = '3' update lwt set c = c + ['6'], d = d + ['6'] where a = 1 and b = 2 apply batch; { "rows" : [ { "[applied]" : "true", "a" : "1", "b" : "1", "c" : "[\"1\", \"3\"]" }, { "[applied]" : "true" } ] } select b, c, d from lwt where a = 1; { "rows" : [ { "b" : "1", "c" : "[\"1\", \"3\", \"5\"]", "d" : "[\"1\", \"2\", \"3\", \"4\", \"5\", \"6\"]" }, { "b" : "2", "c" : "[\"2\", \"4\", \"6\"]", "d" : "[\"1\", \"2\", \"3\", \"4\", \"5\", \"6\"]" } ] } -- multiple conditions: -- two simple conditions, effects of all statements are applied atomically -- or not applied at all: ok begin batch update lwt set c = c + ['7'], d = d + ['7'] where a = 1 and b = 1 if c[0] = '1' and c[1] = '2' update lwt set c = c + ['8'], d = d + ['8'] where a = 1 and b = 2 if c[3] = '3' and c[4] = '4' apply batch; { "rows" : [ { "[applied]" : "false", "a" : "1", "b" : "1", "c" : "[\"1\", \"3\", \"5\"]" }, { "[applied]" : "false", "a" : "1", "b" : "2", "c" : "[\"2\", \"4\", \"6\"]" } ] } select b, c, d from lwt where a = 1; { "rows" : [ { "b" : "1", "c" : "[\"1\", \"3\", \"5\"]", "d" : "[\"1\", \"2\", \"3\", \"4\", \"5\", \"6\"]" }, { "b" : "2", "c" : "[\"2\", \"4\", \"6\"]", "d" : "[\"1\", \"2\", \"3\", \"4\", \"5\", \"6\"]" } ] } begin batch update lwt set c = c + ['7'], d = d + ['7'] where a = 1 and b = 1 if c[0] = '1' and c[1] = '3' update lwt set c = c + ['8'], d = d + ['8'] where a = 1 and b = 2 if c[1] = '4' and c[2] = '6' apply batch; { "rows" : [ { "[applied]" : "true", "a" : "1", "b" : "1", "c" : "[\"1\", \"3\", \"5\"]" }, { "[applied]" : "true", "a" : "1", "b" : "2", "c" : "[\"2\", \"4\", \"6\"]" } ] } select b, c, d from lwt where a = 1; { "rows" : [ { "b" : "1", "c" : "[\"1\", \"3\", \"5\", \"7\"]", "d" : "[\"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\"]" }, { "b" : "2", "c" : "[\"2\", \"4\", \"6\", \"8\"]", "d" : "[\"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\"]" } ] } drop table lwt; { "status" : "ok" } -- batch + lwt + range UPDATE of multiple rows, clustering key is not fully restricted: ok -- batch + lwt + range DELETE of multiple rows, clustering key is not fully restricted: ok -- usually within the same partition key create table lwt (a int, b int, c int, d int, primary key (a, b, c)); { "status" : "ok" } insert into lwt (a, b, c, d) values (1,1,1,1); { "status" : "ok" } insert into lwt (a, b, c, d) values (1,1,2,0); { "status" : "ok" } insert into lwt (a, b, c, d) values (1,1,3,1); { "status" : "ok" } insert into lwt (a, b, c, d) values (1,2,1,1); { "status" : "ok" } insert into lwt (a, b, c, d) values (1,2,2,0); { "status" : "ok" } insert into lwt (a, b, c, d) values (1,2,3,1); { "status" : "ok" } -- update begin batch update lwt set d = 7 where a = 1 and b = 1 and c = 1 if exists update lwt set d = 7 where a = 1 and b in (1,2) and c in (1,2,3) apply batch; { "rows" : [ { "[applied]" : "true", "a" : "1", "b" : "1", "c" : "1", "d" : "1" }, { "[applied]" : "true", "a" : "1", "b" : "1", "c" : "1", "d" : "1" } ] } select a, b, c, d from lwt where a = 1; { "rows" : [ { "a" : "1", "b" : "1", "c" : "1", "d" : "7" }, { "a" : "1", "b" : "1", "c" : "2", "d" : "7" }, { "a" : "1", "b" : "1", "c" : "3", "d" : "7" }, { "a" : "1", "b" : "2", "c" : "1", "d" : "7" }, { "a" : "1", "b" : "2", "c" : "2", "d" : "7" }, { "a" : "1", "b" : "2", "c" : "3", "d" : "7" } ] } -- delete begin batch delete from lwt where a = 1 and b = 1 if exists delete from lwt where a = 1 and b = 2 if exists apply batch; { "message" : "exceptions::invalid_request_exception (DELETE statements must restrict all PRIMARY KEY columns with equality relations in order to delete non static columns)", "status" : "error" } -- select a, b, c, d from lwt where a = 1; drop table lwt; { "status" : "ok" } -- Rows fetched for statements that require read but has no conditions -- must not be included into the result set. create table lwt(p int, c int, i int, l list, primary key(p, c)); { "status" : "ok" } insert into lwt(p, c, i, l) values(1, 1, 1, [1, 2]); { "status" : "ok" } insert into lwt(p, c, i, l) values(1, 2, 2, [1, 2, 3, 4]); { "status" : "ok" } -- doesn't apply begin batch update lwt set i = 3 where p = 1 and c = 1 if i = 2 update lwt set l = l - [1] where p = 1 and c = 2 apply batch; { "rows" : [ { "[applied]" : "false", "c" : "1", "i" : "1", "p" : "1" }, { "[applied]" : "false", "c" : "2", "i" : "2", "p" : "1" } ] } -- applies begin batch update lwt set i = 2 where p = 1 and c = 1 if i = 1 update lwt set l = l - [2] where p = 1 and c = 2 apply batch; { "rows" : [ { "[applied]" : "true", "c" : "1", "i" : "1", "p" : "1" }, { "[applied]" : "true", "c" : "2", "i" : "2", "p" : "1" } ] } -- doesn't apply begin batch delete l from lwt where p = 1 and c = 3 if exists update lwt set l = l - [3] where p = 1 and c = 2 apply batch; { "rows" : [ { "[applied]" : "false" }, { "[applied]" : "false", "c" : "2", "i" : "2", "l" : "[1, 3, 4]", "p" : "1" } ] } -- applies begin batch delete l from lwt where p = 1 and c = 1 if exists update lwt set l = l - [4] where p = 1 and c = 2 apply batch; { "rows" : [ { "[applied]" : "true", "c" : "1", "i" : "2", "l" : "[1, 2]", "p" : "1" }, { "[applied]" : "true", "c" : "2", "i" : "2", "l" : "[1, 3, 4]", "p" : "1" } ] } select * from lwt; { "rows" : [ { "c" : "1", "i" : "2", "p" : "1" }, { "c" : "2", "i" : "2", "l" : "[1, 3]", "p" : "1" } ] } drop table lwt; { "status" : "ok" } -- Suppose there's a batch with two statements, one of which has clustering -- column restrictions that select no row, another has static conditions. -- In this case we must fetch the static row (provided it exists, of course) -- to check the static column conditions. create table lwt (p int, c int, s int static, primary key (p, c)); { "status" : "ok" } insert into lwt(p, s) values(1, 1); { "status" : "ok" } begin batch insert into lwt(p, c) values(1, 1) if not exists update lwt set s = 2 where p = 1 if s = 1 apply batch; { "rows" : [ { "[applied]" : "true" }, { "[applied]" : "true", "p" : "1", "s" : "1" } ] } select * from lwt; { "rows" : [ { "c" : "1", "p" : "1", "s" : "2" } ] } drop table lwt; { "status" : "ok" } -- -- -- condtitions on different list columns and different rows of the same -- partition, these columns are retreived fine and the appropriate row -- is found when checking the conds -- -- correct read command: statement 1 condition is on column a and list update -- is on column b, while statement b condition is on column c and list -- update is on column d -- a composite read command is built and both rows are retreieved, -- conditions are executed correctly and mutations are applied accordingly -- -- -- Issue: #6273 -- Delete have priority above Insert. create table lwt (key bigint, ck int, cv set, PRIMARY KEY((key), ck)); { "status" : "ok" } insert into lwt (key, ck, cv) values (1, 0, {'a', 'b'}) if not exists; { "rows" : [ { "[applied]" : "true" } ] } begin batch delete from lwt where key=1 and ck=0 if exists insert into lwt (key, ck, cv) values (1, 0, {'b', 'c'}) apply batch; { "rows" : [ { "[applied]" : "true", "ck" : "0", "cv" : "[\"a\", \"b\"]", "key" : "1" }, { "[applied]" : "true", "ck" : "0", "cv" : "[\"a\", \"b\"]", "key" : "1" } ] } select * from lwt; { "rows" : null } drop table lwt; { "status" : "ok" } -- -- Workaround for Issue #6273. -- Delete individual cells instead of entire partition. -- create table lwt (key bigint, ck int, cv set, PRIMARY KEY((key), ck)); { "status" : "ok" } insert into lwt (key, ck, cv) values (1, 0, {'a', 'b'}) if not exists; { "rows" : [ { "[applied]" : "true" } ] } begin batch update lwt set cv=null where key=1 and ck=0 if exists insert into lwt (key, ck, cv) values (1, 0, {'b', 'c'}) apply batch; { "rows" : [ { "[applied]" : "true", "ck" : "0", "cv" : "[\"a\", \"b\"]", "key" : "1" }, { "[applied]" : "true", "ck" : "0", "cv" : "[\"a\", \"b\"]", "key" : "1" } ] } select * from lwt; { "rows" : [ { "ck" : "0", "cv" : "[\"b\", \"c\"]", "key" : "1" } ] } drop table lwt; { "status" : "ok" } -- -- A test case for Issue #7113 -- Return one row per each LWT statement -- in a batch, in statement order. -- CREATE TABLE IF NOT EXISTS gh7113 ( part int, key int, lwt_trivial int, int1 int, int2 int, PRIMARY KEY (part, key) ); { "status" : "ok" } BEGIN BATCH UPDATE gh7113 SET int1 = 6 WHERE part = 0 AND key = 4 IF lwt_trivial = null APPLY BATCH; { "rows" : [ { "[applied]" : "true" } ] } BEGIN BATCH UPDATE gh7113 SET int2 = 0, int1 = 0 WHERE part = 0 AND key = 0 IF lwt_trivial = null UPDATE gh7113 SET int2 = 1, int1 = 6 WHERE part = 0 AND key = 7 IF lwt_trivial = null APPLY BATCH; { "rows" : [ { "[applied]" : "true" }, { "[applied]" : "true" } ] } BEGIN BATCH UPDATE gh7113 SET int2 = 0, int1 = 2 WHERE part = 0 AND key = 9 IF lwt_trivial = null UPDATE gh7113 SET int1 = 7 WHERE part = 0 AND key = 0 IF lwt_trivial = null APPLY BATCH; { "rows" : [ { "[applied]" : "true" }, { "[applied]" : "true", "key" : "0", "part" : "0" } ] } BEGIN BATCH UPDATE gh7113 SET int1 = 6, int2 = 7 WHERE part = 0 AND key = 1 IF lwt_trivial = null UPDATE gh7113 SET int2 = 4 WHERE part = 0 AND key = 0 IF lwt_trivial = null UPDATE gh7113 SET int2 = 2 WHERE part = 0 AND key = 3 IF lwt_trivial = null APPLY BATCH; { "rows" : [ { "[applied]" : "true" }, { "[applied]" : "true", "key" : "0", "part" : "0" }, { "[applied]" : "true" } ] } BEGIN BATCH UPDATE gh7113 SET int2 = 1 WHERE part = 0 AND key = 4 IF lwt_trivial = null UPDATE gh7113 SET int2 = 1 WHERE part = 0 AND key = 0 IF lwt_trivial = null UPDATE gh7113 SET int1 = 4, int2 = 8 WHERE part = 0 AND key = 9 IF lwt_trivial = null UPDATE gh7113 SET int1 = 0, int2 = 9 WHERE part = 0 AND key = 0 IF lwt_trivial = null APPLY BATCH; { "rows" : [ { "[applied]" : "true", "key" : "4", "part" : "0" }, { "[applied]" : "true", "key" : "0", "part" : "0" }, { "[applied]" : "true", "key" : "9", "part" : "0" }, { "[applied]" : "true", "key" : "0", "part" : "0" } ] }