def test_short_ints(cql, test_keyspace, table1, scylla_with_wasm_only): table = table1 plus_name = "plus_" + unique_name() plus_source = f""" (module (type (;0;) (func (param i32 i32) (result i32))) (func ${plus_name} (type 0) (param i32 i32) (result i32) local.get 1 local.get 0 i32.add) (table (;0;) 1 1 funcref) (table (;1;) 32 externref) (memory (;0;) 17) (export "{plus_name}" (func ${plus_name})) (elem (;0;) (i32.const 0) func)) """ src = f"(input tinyint, input2 tinyint) RETURNS NULL ON NULL INPUT RETURNS tinyint LANGUAGE xwasm AS '{plus_source}'" with new_function(cql, test_keyspace, src, plus_name): cql.execute(f"INSERT INTO {table} (p, t, t2, s, s2) VALUES (42, 42, 24, 33, 55)") cql.execute(f"INSERT INTO {table} (p, t, t2, s, s2) VALUES (43, 120, 112, 32000, 24001)") res = [row for row in cql.execute(f"SELECT {test_keyspace}.{plus_name}(t, t2) AS result FROM {table} WHERE p = 42")] assert len(res) == 1 and res[0].result == 66 # Overflow is fine res = [row for row in cql.execute(f"SELECT {test_keyspace}.{plus_name}(t, t2) AS result FROM {table} WHERE p = 43")] assert len(res) == 1 and res[0].result == -24 # A similar run for 16bit ints - note that the exact same source code is used src = f"(input smallint, input2 smallint) RETURNS NULL ON NULL INPUT RETURNS smallint LANGUAGE xwasm AS '{plus_source}'" with new_function(cql, test_keyspace, src, plus_name): res = [row for row in cql.execute(f"SELECT {test_keyspace}.{plus_name}(s, s2) AS result FROM {table} WHERE p = 42")] assert len(res) == 1 and res[0].result == 88 # Overflow is fine res = [row for row in cql.execute(f"SELECT {test_keyspace}.{plus_name}(s, s2) AS result FROM {table} WHERE p = 43")] assert len(res) == 1 and res[0].result == -9535
def test_validate_params(cql, test_keyspace, table1, scylla_with_wasm_only): table = table1 inc_float_name = "inc_float_" + unique_name() inc_float_source = f""" (module (type (;0;) (func (param f32) (result f32))) (func ${inc_float_name} (type 0) (param f32) (result f32) local.get 0 f32.const 0x1p+0 (;=1;) f32.add) (table (;0;) 1 1 funcref) (table (;1;) 32 externref) (memory (;0;) 17) (export "memory" (memory 0)) (export "{inc_float_name}" (func ${inc_float_name})) (elem (;0;) (i32.const 0) func)) """ src = f"(input int) RETURNS NULL ON NULL INPUT RETURNS float LANGUAGE xwasm AS '{inc_float_source}'" with new_function(cql, test_keyspace, src, inc_float_name): cql.execute(f"INSERT INTO {table} (p, i, f, txt) VALUES (700, 7, 7., 'oi')") with pytest.raises(InvalidRequest, match="type mismatch"): cql.execute(f"SELECT {test_keyspace}.{inc_float_name}(i) AS result FROM {table} WHERE p = 700") src = f"(input text) RETURNS NULL ON NULL INPUT RETURNS int LANGUAGE xwasm AS '{inc_float_source}'" with new_function(cql, test_keyspace, src, inc_float_name): with pytest.raises(InvalidRequest, match="failed"): cql.execute(f"SELECT {test_keyspace}.{inc_float_name}(txt) AS result FROM {table} WHERE p = 700") src = f"(input float) RETURNS NULL ON NULL INPUT RETURNS int LANGUAGE xwasm AS '{inc_float_source}'" with new_function(cql, test_keyspace, src, inc_float_name): with pytest.raises(InvalidRequest, match="Expected i32, got f32"): cql.execute(f"SELECT {test_keyspace}.{inc_float_name}(f) AS result FROM {table} WHERE p = 700") with pytest.raises(InvalidRequest, match="number.*arguments"): cql.execute(f"SELECT {test_keyspace}.{inc_float_name}(i, f) AS result FROM {table} WHERE p = 700")
def test_wrong_sfunc_or_ffunc(scylla_only, cql, test_keyspace): avg_partial_body = "(state tuple<bigint, text>, val bigint) CALLED ON NULL INPUT RETURNS tuple<bigint, text> LANGUAGE lua AS 'return {state[1] + val, \"hello\"}'" div_body = "(state tuple<bigint, bigint>) CALLED ON NULL INPUT RETURNS bigint LANGUAGE lua AS 'return state[1]//state[2]'" div_body2 = "(state tuple<bigint, bigint>) CALLED ON NULL INPUT RETURNS float LANGUAGE lua AS 'return state[1]/state[2]'" with new_function(cql, test_keyspace, avg_partial_body) as avg_partial, new_function( cql, test_keyspace, div_body) as div_fun, new_function( cql, test_keyspace, div_body2) as div_fun2: custom_avg_body = f"(bigint) SFUNC {avg_partial} STYPE tuple<bigint, bigint> FINALFUNC {div_fun} INITCOND (0,0)" with pytest.raises(InvalidRequest, match="not found"): cql.execute( f"CREATE AGGREGATE {test_keyspace}.{unique_name()} {custom_avg_body}" ) custom_avg_body = f"(bigint) SFUNC {avg_partial} STYPE tuple<bigint, bigint> FINALFUNC {div_fun2} INITCOND (0,0)" with pytest.raises(InvalidRequest, match="not found"): cql.execute( f"CREATE AGGREGATE {test_keyspace}.{unique_name()} {custom_avg_body}" ) custom_avg_body = f"(bigint) SFUNC i_do_not_exist STYPE tuple<bigint, bigint> FINALFUNC {div_fun2} INITCOND (0,0)" with pytest.raises(InvalidRequest, match="not found"): cql.execute( f"CREATE AGGREGATE {test_keyspace}.{unique_name()} {custom_avg_body}" ) custom_avg_body = f"(bigint) SFUNC {avg_partial} STYPE tuple<bigint, bigint> FINALFUNC i_do_not_exist_either INITCOND (0,0)" with pytest.raises(InvalidRequest, match="not found"): cql.execute( f"CREATE AGGREGATE {test_keyspace}.{unique_name()} {custom_avg_body}" )
def test_drop_sfunc_or_ffunc(scylla_only, cql, test_keyspace): avg_partial_body = "(state tuple<bigint, bigint>, val bigint) CALLED ON NULL INPUT RETURNS tuple<bigint, bigint> LANGUAGE lua AS 'return {state[1] + val, state[2] + 1}'" div_body = "(state tuple<bigint, bigint>) CALLED ON NULL INPUT RETURNS bigint LANGUAGE lua AS 'return state[1]//state[2]'" with new_function(cql, test_keyspace, avg_partial_body) as avg_partial, new_function( cql, test_keyspace, div_body) as div_fun: custom_avg_body = f"(bigint) SFUNC {avg_partial} STYPE tuple<bigint, bigint> FINALFUNC {div_fun} INITCOND (0,0)" with new_aggregate(cql, test_keyspace, custom_avg_body) as custom_avg: with pytest.raises(InvalidRequest, match="it is used"): cql.execute(f"DROP FUNCTION {test_keyspace}.{avg_partial}") with pytest.raises(InvalidRequest, match="it is used"): cql.execute(f"DROP FUNCTION {test_keyspace}.{div_fun}")
def test_bool_negate(cql, test_keyspace, table1, scylla_with_wasm_only): table = table1 negate_name = "negate_" + unique_name() negate_source = f""" (module (type (;0;) (func (param i32) (result i32))) (func ${negate_name} (type 0) (param i32) (result i32) local.get 0 i32.eqz) (table (;0;) 1 1 funcref) (table (;1;) 32 externref) (memory (;0;) 17) (export "{negate_name}" (func ${negate_name})) (elem (;0;) (i32.const 0) func) (global (;0;) i32 (i32.const 1024)) (export "_scylla_abi" (global 0)) (data $.rodata (i32.const 1024) "\\01")) """ src = f"(input boolean) RETURNS NULL ON NULL INPUT RETURNS boolean LANGUAGE xwasm AS '{negate_source}'" with new_function(cql, test_keyspace, src, negate_name): cql.execute(f"INSERT INTO {table} (p, bl) VALUES (19, true)") cql.execute(f"INSERT INTO {table} (p, bl) VALUES (21, false)") res = [ row for row in cql.execute( f"SELECT {test_keyspace}.{negate_name}(bl) AS result FROM {table} WHERE p = 19" ) ] assert len(res) == 1 and res[0].result == False res = [ row for row in cql.execute( f"SELECT {test_keyspace}.{negate_name}(bl) AS result FROM {table} WHERE p = 21" ) ] assert len(res) == 1 and res[0].result == True
def test_f32_param(cql, test_keyspace, table1, scylla_with_wasm_only): table = table1 inc_float_name = "inc_float_" + unique_name() inc_float_source = f""" (module (type (;0;) (func (param f32) (result f32))) (func ${inc_float_name} (type 0) (param f32) (result f32) local.get 0 f32.const 0x1p+0 (;=1;) f32.add) (table (;0;) 1 1 funcref) (table (;1;) 32 externref) (memory (;0;) 17) (export "{inc_float_name}" (func ${inc_float_name})) (elem (;0;) (i32.const 0) func) (global (;0;) i32 (i32.const 1024)) (export "_scylla_abi" (global 0)) (data $.rodata (i32.const 1024) "\\01")) """ src = f"(input float) RETURNS NULL ON NULL INPUT RETURNS float LANGUAGE xwasm AS '{inc_float_source}'" with new_function(cql, test_keyspace, src, inc_float_name): cql.execute(f"INSERT INTO {table} (p, f) VALUES (121, 121.00390625)") res = [ row for row in cql.execute( f"SELECT {test_keyspace}.{inc_float_name}(f) AS result FROM {table} WHERE p = 121" ) ] assert len(res) == 1 and res[0].result == 122.00390625
def test_f64_param(cql, test_keyspace, table1, scylla_with_wasm_only): table = table1 dec_double_name = "dec_double_" + unique_name() dec_double_source = f""" (module (type (;0;) (func (param f64) (result f64))) (func ${dec_double_name} (type 0) (param f64) (result f64) local.get 0 f64.const -0x1p+0 (;=-1;) f64.add) (table (;0;) 1 1 funcref) (table (;1;) 32 externref) (memory (;0;) 17) (export "{dec_double_name}" (func ${dec_double_name})) (elem (;0;) (i32.const 0) func) (global (;0;) i32 (i32.const 1024)) (export "_scylla_abi" (global 0)) (data $.rodata (i32.const 1024) "\\01")) """ src = f"(input double) RETURNS NULL ON NULL INPUT RETURNS double LANGUAGE xwasm AS '{dec_double_source}'" with new_function(cql, test_keyspace, src, dec_double_name): cql.execute(f"INSERT INTO {table} (p,d) VALUES (17,17.015625)") res = [ row for row in cql.execute( f"SELECT {test_keyspace}.{dec_double_name}(d) AS result FROM {table} WHERE p = 17" ) ] assert len(res) == 1 and res[0].result == 16.015625
def test_infinite_loop(cql, test_keyspace, table1, scylla_with_wasm_only): table = table1 inf_loop_name = "inf_loop_" + unique_name() inf_loop_source = f""" (module (type (;0;) (func (param i32) (result i32))) (func ${inf_loop_name} (type 0) (param i32) (result i32) loop (result i32) ;; label = @1 br 0 (;@1;) end) (table (;0;) 1 1 funcref) (table (;1;) 32 externref) (memory (;0;) 17) (export "{inf_loop_name}" (func ${inf_loop_name})) (elem (;0;) (i32.const 0) func) (global (;0;) i32 (i32.const 1024)) (export "_scylla_abi" (global 0)) (data $.rodata (i32.const 1024) "\\01")) """ src = f"(input int) RETURNS NULL ON NULL INPUT RETURNS int LANGUAGE xwasm AS '{inf_loop_source}'" with new_function(cql, test_keyspace, src, inf_loop_name): cql.execute(f"INSERT INTO {table} (p,i) VALUES (10, 10)") import time start = time.monotonic() with pytest.raises(InvalidRequest, match="fuel consumed"): cql.execute( f"SELECT {test_keyspace}.{inf_loop_name}(i) AS result FROM {table} WHERE p = 10" ) elapsed_s = time.monotonic() - start print(f"Breaking the loop took {elapsed_s*1000:.2f}ms")
def test_no_initcond(scylla_only, cql, test_keyspace): rows = 5 schema = "id int primary key" # This aggregate will return `1000 - #rows` if there is no initcond and `initcond - #rows` otherwise state_body = "(acc int, val int) CALLED ON NULL INPUT RETURNS int LANGUAGE lua AS 'if acc == null then return 999 else return acc - 1 end'" final_body = "(acc int) CALLED ON NULL INPUT RETURNS int LANGUAGE lua AS 'return acc'" with new_test_table(cql, test_keyspace, schema) as table: for i in range(rows): cql.execute(f"INSERT INTO {table} (id) VALUES ({i})") with new_function(cql, test_keyspace, state_body) as state_func, new_function( cql, test_keyspace, final_body) as final_func: aggr_body = f"(int) SFUNC {state_func} STYPE int FINALFUNC {final_func}" with new_aggregate(cql, test_keyspace, aggr_body) as aggr_func: result = cql.execute( f"SELECT {aggr_func}(id) AS result FROM {table}").one() assert result.result == (1000 - rows)
def test_incorrect_state_func(scylla_only, cql, test_keyspace): avg_partial_body = "(state tuple<bigint, bigint>, val bigint, redundant int) CALLED ON NULL INPUT RETURNS tuple<bigint, bigint> LANGUAGE lua AS 'return {state[1] + val, state[2] + 1}'" div_body = "(state tuple<bigint, bigint>) CALLED ON NULL INPUT RETURNS bigint LANGUAGE lua AS 'return state[1]//state[2]'" with new_function(cql, test_keyspace, avg_partial_body) as avg_partial, new_function( cql, test_keyspace, div_body) as div_fun: custom_avg_body = f"(bigint) SFUNC {avg_partial} STYPE tuple<bigint, bigint> FINALFUNC {div_fun} INITCOND (0,0)" with pytest.raises(InvalidRequest, match="State function not found"): cql.execute( f"CREATE AGGREGATE {test_keyspace}.{unique_name()} {custom_avg_body}" ) avg2_partial_body = "(state tuple<bigint, bigint>) CALLED ON NULL INPUT RETURNS tuple<bigint, bigint> LANGUAGE lua AS 'return {state[1] + 42, state[2] + 1}'" div_body = "(state tuple<bigint, bigint>) CALLED ON NULL INPUT RETURNS bigint LANGUAGE lua AS 'return state[1]//state[2]'" with new_function(cql, test_keyspace, avg2_partial_body) as avg2_partial, new_function( cql, test_keyspace, div_body) as div_fun: custom_avg_body = f"(bigint) SFUNC {avg2_partial} STYPE tuple<bigint, bigint> FINALFUNC {div_fun} INITCOND (0,0)" with pytest.raises(InvalidRequest, match="State function not found"): cql.execute( f"CREATE AGGREGATE {test_keyspace}.{unique_name()} {custom_avg_body}" )
def test_map_literal_builder(scylla_only, cql, test_keyspace): schema = 'id int, k text, val int, primary key (id, k)' with new_test_table(cql, test_keyspace, schema) as table: for i in range(8): cql.execute( f"INSERT INTO {table} (id, k, val) VALUES (0, '{chr(ord('a') + i)}', {i})" ) map_literal_partial_body = "(state text, id text, val int) RETURNS NULL ON NULL INPUT RETURNS text LANGUAGE lua AS 'return state..id..\":\"..tostring(val)..\",\"'" finish_body = "(state text) CALLED ON NULL INPUT RETURNS text LANGUAGE lua AS 'return state..\"}\"'" with new_function( cql, test_keyspace, map_literal_partial_body) as map_literal_partial, new_function( cql, test_keyspace, finish_body) as finish_fun: map_literal_body = f"(text, int) SFUNC {map_literal_partial} STYPE text FINALFUNC {finish_fun} INITCOND '{{'" with new_aggregate(cql, test_keyspace, map_literal_body) as map_literal: map_res = [ row for row in cql.execute( f"SELECT {test_keyspace}.{map_literal}(k, val) AS result FROM {table}" ) ] assert len(map_res) == 1 and map_res[ 0].result == '{a:0,b:1,c:2,d:3,e:4,f:5,g:6,h:7,}'
def test_custom_avg(scylla_only, cql, test_keyspace): schema = 'id bigint primary key' with new_test_table(cql, test_keyspace, schema) as table: for i in range(8): cql.execute(f"INSERT INTO {table} (id) VALUES ({10**i})") avg_partial_body = "(state tuple<bigint, bigint>, val bigint) CALLED ON NULL INPUT RETURNS tuple<bigint, bigint> LANGUAGE lua AS 'return {state[1] + val, state[2] + 1}'" div_body = "(state tuple<bigint, bigint>) CALLED ON NULL INPUT RETURNS bigint LANGUAGE lua AS 'return state[1]//state[2]'" with new_function(cql, test_keyspace, avg_partial_body) as avg_partial, new_function( cql, test_keyspace, div_body) as div_fun: custom_avg_body = f"(bigint) SFUNC {avg_partial} STYPE tuple<bigint, bigint> FINALFUNC {div_fun} INITCOND (0,0)" with new_aggregate(cql, test_keyspace, custom_avg_body) as custom_avg: custom_res = [ row for row in cql.execute( f"SELECT {test_keyspace}.{custom_avg}(id) AS result FROM {table}" ) ] avg_res = [ row for row in cql.execute( f"SELECT avg(id) AS result FROM {table}") ] assert custom_res == avg_res
def test_fib(cql, test_keyspace, table1, scylla_with_wasm_only): table = table1 fib_name = unique_name() fib_source = f""" (module (func ${fib_name} (param $n i64) (result i64) (if (i64.lt_s (local.get $n) (i64.const 2)) (return (local.get $n)) ) (i64.add (call ${fib_name} (i64.sub (local.get $n) (i64.const 1))) (call ${fib_name} (i64.sub (local.get $n) (i64.const 2))) ) ) (export "{fib_name}" (func ${fib_name})) ) """ src = f"(input bigint) RETURNS NULL ON NULL INPUT RETURNS bigint LANGUAGE xwasm AS '{fib_source}'" with new_function(cql, test_keyspace, src, fib_name): cql.execute(f"INSERT INTO {table1} (p) VALUES (10)") res = [ row for row in cql.execute( f"SELECT {test_keyspace}.{fib_name}(p) AS result FROM {table} WHERE p = 10" ) ] assert len(res) == 1 and res[0].result == 55 cql.execute(f"INSERT INTO {table} (p) VALUES (14)") res = [ row for row in cql.execute( f"SELECT {test_keyspace}.{fib_name}(p) AS result FROM {table} WHERE p = 14" ) ] assert len(res) == 1 and res[0].result == 377 # This function returns null on null values res = [ row for row in cql.execute( f"SELECT {test_keyspace}.{fib_name}(p2) AS result FROM {table} WHERE p = 14" ) ] assert len(res) == 1 and res[0].result is None cql.execute(f"INSERT INTO {table} (p) VALUES (997)") # The call request takes too much time and resources, and should therefore fail with pytest.raises(InvalidRequest, match="wasm"): cql.execute( f"SELECT {test_keyspace}.{fib_name}(p) AS result FROM {table} WHERE p = 997" )
def test_no_final_func(scylla_only, cql, test_keyspace): schema = "id int primary key" sum_partial_body = "(acc int, val int) RETURNS NULL ON NULL INPUT RETURNS int LANGUAGE lua AS 'return acc + val'" with new_test_table(cql, test_keyspace, schema) as table: for i in range(5): cql.execute(f"INSERT INTO {table} (id) VALUES ({i})") with new_function(cql, test_keyspace, sum_partial_body) as sum_partial: custom_sum_body = f"(int) SFUNC {sum_partial} STYPE int INITCOND 0" with new_aggregate(cql, test_keyspace, custom_sum_body) as custom_sum: custom_res = cql.execute( f"SELECT {custom_sum}(id) AS result FROM {table}").one() avg_res = cql.execute( f"SELECT sum(id) AS result FROM {table}").one() assert custom_res == avg_res
def test_9_params(cql, test_keyspace, table1, scylla_with_wasm_only): table = table1 sum9_name = "sum9_" + unique_name() sum9_source = f""" (module (type (;0;) (func (param i32 i32 i32 i32 i32 i32 i32 i32 i32) (result i32))) (func ${sum9_name} (type 0) (param i32 i32 i32 i32 i32 i32 i32 i32 i32) (result i32) local.get 1 local.get 0 i32.add local.get 2 i32.add local.get 3 i32.add local.get 4 i32.add local.get 5 i32.add local.get 6 i32.add local.get 7 i32.add local.get 8 i32.add) (table (;0;) 1 1 funcref) (table (;1;) 32 externref) (memory (;0;) 17) (export "{sum9_name}" (func ${sum9_name})) (elem (;0;) (i32.const 0) func) (global (;0;) i32 (i32.const 1024)) (export "_scylla_abi" (global 0)) (data $.rodata (i32.const 1024) "\\01")) """ src = f"(a int, b int, c int, d int, e int, f int, g int, h int, i int) RETURNS NULL ON NULL INPUT RETURNS int LANGUAGE xwasm AS '{sum9_source}'" with new_function(cql, test_keyspace, src, sum9_name): cql.execute(f"INSERT INTO {table} (p, i, i2) VALUES (777, 1,2)") res = [ row for row in cql.execute( f"SELECT {test_keyspace}.{sum9_name}(i,i2,i2,i,i2,i,i2,i,i2) AS result FROM {table} WHERE p = 777" ) ] assert len(res) == 1 and res[0].result == 14
def test_fib_called_on_null(cql, test_keyspace, table1, scylla_with_wasm_only): table = table1 fib_name = unique_name() fib_source = f""" (module (type (;0;) (func)) (type (;1;) (func (param i64) (result i64))) (type (;2;) (func (param i32) (result i32))) (func $__wasm_call_ctors (type 0)) (func $fib_aux (type 1) (param i64) (result i64) (local i64 i32 i64) block ;; label = @1 local.get 0 i64.const 2 i64.ge_s br_if 0 (;@1;) local.get 0 i64.const 0 i64.add return end i64.const 0 local.set 1 loop ;; label = @1 local.get 0 i64.const -1 i64.add call $fib_aux local.get 1 i64.add local.set 1 local.get 0 i64.const 3 i64.gt_s local.set 2 local.get 0 i64.const -2 i64.add local.tee 3 local.set 0 local.get 2 br_if 0 (;@1;) end local.get 3 local.get 1 i64.add) (func $fib (type 2) (param i32) (result i32) (local i32 i64) memory.size local.set 1 i32.const 12 memory.grow drop local.get 1 i32.const 8 i32.store align=1 block ;; label = @1 local.get 0 i32.load align=1 i32.const -1 i32.ne br_if 0 (;@1;) local.get 1 i64.const 3026418949592973312 i64.store offset=4 align=1 local.get 1 return end local.get 1 local.get 0 i64.load offset=4 align=1 local.tee 2 i64.const 56 i64.shl local.get 2 i64.const 40 i64.shl i64.const 71776119061217280 i64.and i64.or local.get 2 i64.const 24 i64.shl i64.const 280375465082880 i64.and local.get 2 i64.const 8 i64.shl i64.const 1095216660480 i64.and i64.or i64.or local.get 2 i64.const 8 i64.shr_u i64.const 4278190080 i64.and local.get 2 i64.const 24 i64.shr_u i64.const 16711680 i64.and i64.or local.get 2 i64.const 40 i64.shr_u i64.const 65280 i64.and local.get 2 i64.const 56 i64.shr_u i64.or i64.or i64.or call $fib_aux local.tee 2 i64.const 56 i64.shl local.get 2 i64.const 40 i64.shl i64.const 71776119061217280 i64.and i64.or local.get 2 i64.const 24 i64.shl i64.const 280375465082880 i64.and local.get 2 i64.const 8 i64.shl i64.const 1095216660480 i64.and i64.or i64.or local.get 2 i64.const 8 i64.shr_u i64.const 4278190080 i64.and local.get 2 i64.const 24 i64.shr_u i64.const 16711680 i64.and i64.or local.get 2 i64.const 40 i64.shr_u i64.const 65280 i64.and local.get 2 i64.const 56 i64.shr_u i64.or i64.or i64.or i64.store offset=4 align=1 local.get 1) (memory (;0;) 2) (global (;0;) (mut i32) (i32.const 66560)) (global (;1;) i32 (i32.const 1024)) (global (;2;) i32 (i32.const 1024)) (global (;3;) i32 (i32.const 1024)) (global (;4;) i32 (i32.const 66560)) (global (;5;) i32 (i32.const 0)) (global (;6;) i32 (i32.const 1)) (export "memory" (memory 0)) (export "{fib_name}" (func $fib))) """ src = f"(input bigint) CALLED ON NULL INPUT RETURNS bigint LANGUAGE xwasm AS '{fib_source}'" with new_function(cql, test_keyspace, src, fib_name): cql.execute(f"INSERT INTO {table1} (p) VALUES (3)") res = [row for row in cql.execute(f"SELECT {test_keyspace}.{fib_name}(p) AS result FROM {table} WHERE p = 3")] assert len(res) == 1 and res[0].result == 2 cql.execute(f"INSERT INTO {table} (p) VALUES (7)") res = [row for row in cql.execute(f"SELECT {test_keyspace}.{fib_name}(p) AS result FROM {table} WHERE p = 7")] assert len(res) == 1 and res[0].result == 13 # Special semantics defined for null input in our function is to return "42" res = [row for row in cql.execute(f"SELECT {test_keyspace}.{fib_name}(p2) AS result FROM {table} WHERE p = 7")] assert len(res) == 1 and res[0].result == 42 cql.execute(f"INSERT INTO {table} (p) VALUES (997)") # The call request takes too much time and resources, and should therefore fail with pytest.raises(InvalidRequest, match="wasm"): cql.execute(f"SELECT {test_keyspace}.{fib_name}(p) AS result FROM {table} WHERE p = 997")
def test_word_double(cql, test_keyspace, table1, scylla_with_wasm_only): table = table1 dbl_name = unique_name() dbl_source = f""" (module (type (;0;) (func (param i64) (result i64))) (func $dbl (type 0) (param i64) (result i64) (local i32 i32 i32 i64 i64 i64 i32 i64 i64 i64 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i64 i64 i64 i64 i64 i32 i32 i64 i64 i64) global.get $__stack_pointer local.set 1 i32.const 48 local.set 2 local.get 1 local.get 2 i32.sub local.set 3 local.get 3 local.get 0 i64.store offset=40 local.get 3 i64.load offset=40 local.set 4 i64.const 32 local.set 5 local.get 4 local.get 5 i64.shr_s local.set 6 local.get 6 i32.wrap_i64 local.set 7 local.get 3 local.get 7 i32.store offset=36 local.get 3 i64.load offset=40 local.set 8 i64.const 4294967295 local.set 9 local.get 8 local.get 9 i64.and local.set 10 local.get 10 i32.wrap_i64 local.set 11 local.get 3 local.get 11 i32.store offset=32 memory.size local.set 12 i32.const 16 local.set 13 local.get 12 local.get 13 i32.shl local.set 14 local.get 3 local.get 14 i32.store offset=28 local.get 3 i32.load offset=36 local.set 15 i32.const 1 local.set 16 local.get 15 local.get 16 i32.shl local.set 17 i32.const 1 local.set 18 local.get 17 local.get 18 i32.sub local.set 19 i32.const 65536 local.set 20 local.get 19 local.get 20 i32.div_s local.set 21 i32.const 1 local.set 22 local.get 21 local.get 22 i32.add local.set 23 local.get 23 memory.grow drop i32.const 0 local.set 24 local.get 3 local.get 24 i32.store offset=24 i32.const 0 local.set 25 local.get 3 local.get 25 i32.store offset=20 block ;; label = @1 loop ;; label = @2 local.get 3 i32.load offset=20 local.set 26 local.get 3 i32.load offset=36 local.set 27 local.get 26 local.set 28 local.get 27 local.set 29 local.get 28 local.get 29 i32.lt_s local.set 30 i32.const 1 local.set 31 local.get 30 local.get 31 i32.and local.set 32 local.get 32 i32.eqz br_if 1 (;@1;) local.get 3 i32.load offset=24 local.set 33 local.get 3 i32.load offset=32 local.set 34 local.get 3 i32.load offset=20 local.set 35 local.get 34 local.get 35 i32.add local.set 36 local.get 33 local.get 36 i32.add local.set 37 local.get 37 i32.load8_u local.set 38 local.get 3 i32.load offset=24 local.set 39 local.get 3 i32.load offset=28 local.set 40 local.get 3 i32.load offset=20 local.set 41 local.get 40 local.get 41 i32.add local.set 42 local.get 39 local.get 42 i32.add local.set 43 local.get 43 local.get 38 i32.store8 local.get 3 i32.load offset=24 local.set 44 local.get 3 i32.load offset=32 local.set 45 local.get 3 i32.load offset=20 local.set 46 local.get 45 local.get 46 i32.add local.set 47 local.get 44 local.get 47 i32.add local.set 48 local.get 48 i32.load8_u local.set 49 local.get 3 i32.load offset=24 local.set 50 local.get 3 i32.load offset=28 local.set 51 local.get 3 i32.load offset=36 local.set 52 local.get 51 local.get 52 i32.add local.set 53 local.get 3 i32.load offset=20 local.set 54 local.get 53 local.get 54 i32.add local.set 55 local.get 50 local.get 55 i32.add local.set 56 local.get 56 local.get 49 i32.store8 local.get 3 i32.load offset=20 local.set 57 i32.const 1 local.set 58 local.get 57 local.get 58 i32.add local.set 59 local.get 3 local.get 59 i32.store offset=20 br 0 (;@2;) end end local.get 3 i32.load offset=36 local.set 60 local.get 60 local.set 61 local.get 61 i64.extend_i32_s local.set 62 i64.const 1 local.set 63 local.get 62 local.get 63 i64.shl local.set 64 i64.const 32 local.set 65 local.get 64 local.get 65 i64.shl local.set 66 local.get 3 i32.load offset=28 local.set 67 local.get 67 local.set 68 local.get 68 i64.extend_i32_s local.set 69 local.get 66 local.get 69 i64.or local.set 70 local.get 3 local.get 70 i64.store offset=8 local.get 3 i64.load offset=8 local.set 71 local.get 71 return) (memory (;0;) 2) (global $__stack_pointer (mut i32) (i32.const 66576)) (global (;1;) i32 (i32.const 1024)) (export "memory" (memory 0)) (export "{dbl_name}" (func $dbl)) (export "_scylla_abi" (global 1)) (data $.rodata (i32.const 1024) "\\01")) """ src = f"(input text) RETURNS NULL ON NULL INPUT RETURNS text LANGUAGE xwasm AS '{dbl_source}'" with new_function(cql, test_keyspace, src, dbl_name): cql.execute(f"INSERT INTO {table1} (p, txt) VALUES (1000, 'doggo')") res = [ row for row in cql.execute( f"SELECT {test_keyspace}.{dbl_name}(txt) AS result FROM {table} WHERE p = 1000" ) ] assert len(res) == 1 and res[0].result == 'doggodoggo' cql.execute(f"INSERT INTO {table} (p, txt) VALUES (1001, 'cat42')") res = [ row for row in cql.execute( f"SELECT {test_keyspace}.{dbl_name}(txt) AS result FROM {table} WHERE p = 1001" ) ] assert len(res) == 1 and res[0].result == 'cat42cat42'
def test_pow(cql, test_keyspace, table1, scylla_with_wasm_only): table = table1 pow_name = "pow_" + unique_name() pow_source = f""" (module (type (;0;) (func (param i32 i32) (result i32))) (func ${pow_name} (type 0) (param i32 i32) (result i32) (local i32 i32) i32.const 1 local.set 2 block ;; label = @1 block ;; label = @2 block ;; label = @3 local.get 1 br_table 2 (;@1;) 1 (;@2;) 0 (;@3;) end local.get 1 local.set 2 i32.const 1 local.set 1 loop ;; label = @3 local.get 0 i32.const 1 local.get 2 i32.const 1 i32.and select local.get 1 i32.mul local.set 1 local.get 2 i32.const 3 i32.gt_u local.set 3 local.get 0 local.get 0 i32.mul local.set 0 local.get 2 i32.const 1 i32.shr_u local.set 2 local.get 3 br_if 0 (;@3;) end end local.get 0 local.get 1 i32.mul local.set 2 end local.get 2) (table (;0;) 1 1 funcref) (table (;1;) 32 externref) (memory (;0;) 17) (global (;0;) i32 (i32.const 1024)) (export "{pow_name}" (func ${pow_name})) (elem (;0;) (i32.const 0) func) (export "_scylla_abi" (global 0)) (data $.rodata (i32.const 1024) "\\01")) """ src = f"(base int, pow int) RETURNS NULL ON NULL INPUT RETURNS int LANGUAGE xwasm AS '{pow_source}'" with new_function(cql, test_keyspace, src, pow_name): cql.execute(f"INSERT INTO {table} (p, i, i2) VALUES (311, 3, 11)") res = [ row for row in cql.execute( f"SELECT {test_keyspace}.{pow_name}(i, i2) AS result FROM {table} WHERE p = 311" ) ] assert len(res) == 1 and res[0].result == 177147
def test_fib_called_on_null(cql, test_keyspace, table1, scylla_with_wasm_only): table = table1 fib_name = unique_name() fib_source = f""" (module (type (;0;) (func (param i64) (result i64))) (func (;0;) (type 0) (param i64) (result i64) (local i64 i32) local.get 0 i64.const 2 i64.lt_s if ;; label = @1 local.get 0 return end loop ;; label = @1 local.get 0 i64.const 1 i64.sub call 0 local.get 1 i64.add local.set 1 local.get 0 i64.const 3 i64.gt_s local.set 2 local.get 0 i64.const 2 i64.sub local.set 0 local.get 2 br_if 0 (;@1;) end local.get 0 local.get 1 i64.add) (func (;1;) (type 0) (param i64) (result i64) (local i32 i64) memory.size local.set 1 i32.const 1 memory.grow drop i64.const 3026418949592973312 local.set 2 local.get 1 i32.const 16 i32.shl local.tee 1 local.get 0 i64.const -4294967297 i64.le_u if (result i64) ;; label = @1 local.get 0 i32.wrap_i64 i64.load local.tee 0 i64.const 56 i64.shl local.get 0 i64.const 40 i64.shl i64.const 71776119061217280 i64.and i64.or local.get 0 i64.const 24 i64.shl i64.const 280375465082880 i64.and local.get 0 i64.const 8 i64.shl i64.const 1095216660480 i64.and i64.or i64.or local.get 0 i64.const 8 i64.shr_u i64.const 4278190080 i64.and local.get 0 i64.const 24 i64.shr_u i64.const 16711680 i64.and i64.or local.get 0 i64.const 40 i64.shr_u i64.const 65280 i64.and local.get 0 i64.const 56 i64.shr_u i64.or i64.or i64.or call 0 local.tee 0 i64.const 56 i64.shl local.get 0 i64.const 40 i64.shl i64.const 71776119061217280 i64.and i64.or local.get 0 i64.const 24 i64.shl i64.const 280375465082880 i64.and local.get 0 i64.const 8 i64.shl i64.const 1095216660480 i64.and i64.or i64.or local.get 0 i64.const 8 i64.shr_u i64.const 4278190080 i64.and local.get 0 i64.const 24 i64.shr_u i64.const 16711680 i64.and i64.or local.get 0 i64.const 40 i64.shr_u i64.const 65280 i64.and local.get 0 i64.const 56 i64.shr_u i64.or i64.or i64.or else local.get 2 end i64.store local.get 1 i64.extend_i32_u i64.const 34359738368 i64.or) (memory (;0;) 2) (global (;0;) i32 (i32.const 1024)) (export "memory" (memory 0)) (export "{fib_name}" (func 1)) (export "_scylla_abi" (global 0)) (data (;0;) (i32.const 1024) "\\01")) """ src = f"(input bigint) CALLED ON NULL INPUT RETURNS bigint LANGUAGE xwasm AS '{fib_source}'" with new_function(cql, test_keyspace, src, fib_name): cql.execute(f"INSERT INTO {table1} (p) VALUES (3)") res = [ row for row in cql.execute( f"SELECT {test_keyspace}.{fib_name}(p) AS result FROM {table} WHERE p = 3" ) ] assert len(res) == 1 and res[0].result == 2 cql.execute(f"INSERT INTO {table} (p) VALUES (7)") res = [ row for row in cql.execute( f"SELECT {test_keyspace}.{fib_name}(p) AS result FROM {table} WHERE p = 7" ) ] assert len(res) == 1 and res[0].result == 13 # Special semantics defined for null input in our function is to return "42" res = [ row for row in cql.execute( f"SELECT {test_keyspace}.{fib_name}(p2) AS result FROM {table} WHERE p = 7" ) ] assert len(res) == 1 and res[0].result == 42 cql.execute(f"INSERT INTO {table} (p) VALUES (997)") # The call request takes too much time and resources, and should therefore fail with pytest.raises(InvalidRequest, match="wasm"): cql.execute( f"SELECT {test_keyspace}.{fib_name}(p) AS result FROM {table} WHERE p = 997" )
def test_word_double(cql, test_keyspace, table1, scylla_with_wasm_only): table = table1 dbl_name = unique_name() dbl_source = f""" (module (type (;0;) (func)) (type (;1;) (func (param i32) (result i32))) (func $__wasm_call_ctors (type 0)) (func $dbl (type 1) (param i32) (result i32) (local i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32) global.get 0 local.set 1 i32.const 48 local.set 2 local.get 1 local.get 2 i32.sub local.set 3 local.get 3 local.get 0 i32.store offset=44 local.get 3 i32.load offset=44 local.set 4 local.get 4 i32.load local.set 5 local.get 3 local.get 5 i32.store offset=40 local.get 3 i32.load offset=44 local.set 6 i32.const 4 local.set 7 local.get 6 local.get 7 i32.add local.set 8 local.get 3 local.get 8 i32.store offset=36 memory.size local.set 9 local.get 3 local.get 9 i32.store offset=32 local.get 3 i32.load offset=32 local.set 10 i32.const 4 local.set 11 local.get 10 local.get 11 i32.add local.set 12 local.get 3 local.get 12 i32.store offset=28 local.get 3 i32.load offset=40 local.set 13 i32.const 1 local.set 14 local.get 13 local.get 14 i32.shl local.set 15 i32.const 4 local.set 16 local.get 15 local.get 16 i32.add local.set 17 local.get 17 memory.grow drop i32.const 0 local.set 18 local.get 3 local.get 18 i32.store offset=24 i32.const 0 local.set 19 local.get 3 local.get 19 i32.store offset=20 block ;; label = @1 loop ;; label = @2 local.get 3 i32.load offset=20 local.set 20 local.get 3 i32.load offset=40 local.set 21 local.get 20 local.set 22 local.get 21 local.set 23 local.get 22 local.get 23 i32.lt_s local.set 24 i32.const 1 local.set 25 local.get 24 local.get 25 i32.and local.set 26 local.get 26 i32.eqz br_if 1 (;@1;) local.get 3 i32.load offset=24 local.set 27 local.get 3 i32.load offset=36 local.set 28 local.get 3 i32.load offset=20 local.set 29 local.get 28 local.get 29 i32.add local.set 30 local.get 27 local.get 30 i32.add local.set 31 local.get 31 i32.load8_u local.set 32 local.get 3 i32.load offset=24 local.set 33 local.get 3 i32.load offset=28 local.set 34 local.get 3 i32.load offset=20 local.set 35 local.get 34 local.get 35 i32.add local.set 36 local.get 33 local.get 36 i32.add local.set 37 local.get 37 local.get 32 i32.store8 local.get 3 i32.load offset=24 local.set 38 local.get 3 i32.load offset=36 local.set 39 local.get 3 i32.load offset=20 local.set 40 local.get 39 local.get 40 i32.add local.set 41 local.get 38 local.get 41 i32.add local.set 42 local.get 42 i32.load8_u local.set 43 local.get 3 i32.load offset=24 local.set 44 local.get 3 i32.load offset=28 local.set 45 local.get 3 i32.load offset=40 local.set 46 local.get 45 local.get 46 i32.add local.set 47 local.get 3 i32.load offset=20 local.set 48 local.get 47 local.get 48 i32.add local.set 49 local.get 44 local.get 49 i32.add local.set 50 local.get 50 local.get 43 i32.store8 local.get 3 i32.load offset=20 local.set 51 i32.const 1 local.set 52 local.get 51 local.get 52 i32.add local.set 53 local.get 3 local.get 53 i32.store offset=20 br 0 (;@2;) end end local.get 3 i32.load offset=40 local.set 54 i32.const 1 local.set 55 local.get 54 local.get 55 i32.shl local.set 56 local.get 3 local.get 56 i32.store offset=16 local.get 3 i32.load offset=32 local.set 57 local.get 3 local.get 57 i32.store offset=12 i32.const 0 local.set 58 local.get 3 local.get 58 i32.store offset=8 block ;; label = @1 loop ;; label = @2 local.get 3 i32.load offset=8 local.set 59 i32.const 4 local.set 60 local.get 59 local.set 61 local.get 60 local.set 62 local.get 61 local.get 62 i32.lt_s local.set 63 i32.const 1 local.set 64 local.get 63 local.get 64 i32.and local.set 65 local.get 65 i32.eqz br_if 1 (;@1;) local.get 3 i32.load offset=16 local.set 66 local.get 3 i32.load offset=8 local.set 67 i32.const 3 local.set 68 local.get 68 local.get 67 i32.sub local.set 69 i32.const 3 local.set 70 local.get 69 local.get 70 i32.shl local.set 71 local.get 66 local.get 71 i32.shr_s local.set 72 local.get 3 i32.load offset=12 local.set 73 local.get 73 local.get 72 i32.store8 local.get 3 i32.load offset=8 local.set 74 i32.const 1 local.set 75 local.get 74 local.get 75 i32.add local.set 76 local.get 3 local.get 76 i32.store offset=8 br 0 (;@2;) end end local.get 3 i32.load offset=32 local.set 77 local.get 77 return) (memory (;0;) 2) (global (;0;) (mut i32) (i32.const 66560)) (global (;1;) i32 (i32.const 1024)) (global (;2;) i32 (i32.const 1024)) (global (;3;) i32 (i32.const 1024)) (global (;4;) i32 (i32.const 66560)) (global (;5;) i32 (i32.const 0)) (global (;6;) i32 (i32.const 1)) (export "memory" (memory 0)) (export "{dbl_name}" (func $dbl))) """ src = f"(input text) RETURNS NULL ON NULL INPUT RETURNS text LANGUAGE xwasm AS '{dbl_source}'" with new_function(cql, test_keyspace, src, dbl_name): cql.execute(f"INSERT INTO {table1} (p, txt) VALUES (1000, 'doggo')") res = [row for row in cql.execute(f"SELECT {test_keyspace}.{dbl_name}(txt) AS result FROM {table} WHERE p = 1000")] assert len(res) == 1 and res[0].result == 'doggodoggo' cql.execute(f"INSERT INTO {table} (p, txt) VALUES (1001, 'cat42')") res = [row for row in cql.execute(f"SELECT {test_keyspace}.{dbl_name}(txt) AS result FROM {table} WHERE p = 1001")] assert len(res) == 1 and res[0].result == 'cat42cat42'