diff --git a/src/blake3/compare.sql b/src/blake3/compare.sql new file mode 100644 index 0000000..50b0ef6 --- /dev/null +++ b/src/blake3/compare.sql @@ -0,0 +1,61 @@ +-- REQUIRE: src/schema.sql +-- REQUIRE: src/blake3/types.sql +-- REQUIRE: src/blake3/functions.sql + + +CREATE FUNCTION eql_v2.compare_blake3(a eql_v2_encrypted, b eql_v2_encrypted) + RETURNS integer + IMMUTABLE STRICT PARALLEL SAFE +AS $$ + DECLARE + a_term eql_v2.blake3; + b_term eql_v2.blake3; + BEGIN + + IF a IS NULL AND b IS NULL THEN + RETURN 0; + END IF; + + IF a IS NULL THEN + RETURN -1; + END IF; + + IF b IS NULL THEN + RETURN 1; + END IF; + + IF eql_v2.has_blake3(a) THEN + a_term = eql_v2.blake3(a); + END IF; + + IF eql_v2.has_blake3(b) THEN + b_term = eql_v2.blake3(b); + END IF; + + IF a_term IS NULL AND b_term IS NULL THEN + RETURN 0; + END IF; + + IF a_term IS NULL THEN + RETURN -1; + END IF; + + IF b_term IS NULL THEN + RETURN 1; + END IF; + + -- Using the underlying text type comparison + IF a_term = b_term THEN + RETURN 0; + END IF; + + IF a_term < b_term THEN + RETURN -1; + END IF; + + IF a_term > b_term THEN + RETURN 1; + END IF; + + END; +$$ LANGUAGE plpgsql; diff --git a/src/blake3/compare_test.sql b/src/blake3/compare_test.sql new file mode 100644 index 0000000..b6a49de --- /dev/null +++ b/src/blake3/compare_test.sql @@ -0,0 +1,26 @@ +\set ON_ERROR_STOP on + +DO $$ + DECLARE + a eql_v2_encrypted; + b eql_v2_encrypted; + c eql_v2_encrypted; + BEGIN + a := create_encrypted_json(1, 'b3'); + b := create_encrypted_json(2, 'b3'); + c := create_encrypted_json(3, 'b3'); + + ASSERT eql_v2.compare_blake3(a, a) = 0; + ASSERT eql_v2.compare_blake3(a, b) = -1; + ASSERT eql_v2.compare_blake3(a, c) = -1; + + ASSERT eql_v2.compare_blake3(b, b) = 0; + ASSERT eql_v2.compare_blake3(b, a) = 1; + ASSERT eql_v2.compare_blake3(b, c) = -1; + + ASSERT eql_v2.compare_blake3(c, c) = 0; + ASSERT eql_v2.compare_blake3(c, b) = 1; + ASSERT eql_v2.compare_blake3(c, a) = 1; + END; +$$ LANGUAGE plpgsql; + diff --git a/src/encrypted/compare.sql b/src/encrypted/compare.sql new file mode 100644 index 0000000..34aa499 --- /dev/null +++ b/src/encrypted/compare.sql @@ -0,0 +1,42 @@ +-- REQUIRE: src/schema.sql +-- REQUIRE: src/encrypted/types.sql + +-- +-- Compare two eql_v2_encrypted values as literal jsonb values +-- Used as a fallback when no suitable search term is available +-- +CREATE FUNCTION eql_v2.compare_literal(a eql_v2_encrypted, b eql_v2_encrypted) + RETURNS integer + IMMUTABLE STRICT PARALLEL SAFE +AS $$ + DECLARE + a_data jsonb; + b_data jsonb; + BEGIN + + IF a IS NULL AND b IS NULL THEN + RETURN 0; + END IF; + + IF a IS NULL THEN + RETURN -1; + END IF; + + IF b IS NULL THEN + RETURN 1; + END IF; + + a_data := a.data; + b_data := b.data; + + IF a_data < b_data THEN + RETURN -1; + END IF; + + IF a_data > b_data THEN + RETURN 1; + END IF; + + RETURN 0; + END; +$$ LANGUAGE plpgsql; diff --git a/src/hmac_256/compare.sql b/src/hmac_256/compare.sql new file mode 100644 index 0000000..0e6aced --- /dev/null +++ b/src/hmac_256/compare.sql @@ -0,0 +1,61 @@ +-- REQUIRE: src/schema.sql +-- REQUIRE: src/hmac_256/types.sql +-- REQUIRE: src/hmac_256/functions.sql + + +CREATE FUNCTION eql_v2.compare_hmac_256(a eql_v2_encrypted, b eql_v2_encrypted) + RETURNS integer + IMMUTABLE STRICT PARALLEL SAFE +AS $$ + DECLARE + a_term eql_v2.hmac_256; + b_term eql_v2.hmac_256; + BEGIN + + IF a IS NULL AND b IS NULL THEN + RETURN 0; + END IF; + + IF a IS NULL THEN + RETURN -1; + END IF; + + IF b IS NULL THEN + RETURN 1; + END IF; + + IF eql_v2.has_hmac_256(a) THEN + a_term = eql_v2.hmac_256(a); + END IF; + + IF eql_v2.has_hmac_256(b) THEN + b_term = eql_v2.hmac_256(b); + END IF; + + IF a_term IS NULL AND b_term IS NULL THEN + RETURN 0; + END IF; + + IF a_term IS NULL THEN + RETURN -1; + END IF; + + IF b_term IS NULL THEN + RETURN 1; + END IF; + + -- Using the underlying text type comparison + IF a_term = b_term THEN + RETURN 0; + END IF; + + IF a_term < b_term THEN + RETURN -1; + END IF; + + IF a_term > b_term THEN + RETURN 1; + END IF; + + END; +$$ LANGUAGE plpgsql; diff --git a/src/hmac_256/compare_test.sql b/src/hmac_256/compare_test.sql new file mode 100644 index 0000000..3529bfe --- /dev/null +++ b/src/hmac_256/compare_test.sql @@ -0,0 +1,26 @@ +\set ON_ERROR_STOP on + +DO $$ + DECLARE + a eql_v2_encrypted; + b eql_v2_encrypted; + c eql_v2_encrypted; + BEGIN + a := create_encrypted_json(1, 'hm'); + b := create_encrypted_json(2, 'hm'); + c := create_encrypted_json(3, 'hm'); + + ASSERT eql_v2.compare_hmac_256(a, a) = 0; + ASSERT eql_v2.compare_hmac_256(a, b) = -1; + ASSERT eql_v2.compare_hmac_256(a, c) = -1; + + ASSERT eql_v2.compare_hmac_256(b, b) = 0; + ASSERT eql_v2.compare_hmac_256(b, a) = 1; + ASSERT eql_v2.compare_hmac_256(b, c) = -1; + + ASSERT eql_v2.compare_hmac_256(c, c) = 0; + ASSERT eql_v2.compare_hmac_256(c, b) = 1; + ASSERT eql_v2.compare_hmac_256(c, a) = 1; + END; +$$ LANGUAGE plpgsql; + diff --git a/src/operators/<.sql b/src/operators/<.sql index 746009b..356a048 100644 --- a/src/operators/<.sql +++ b/src/operators/<.sql @@ -1,50 +1,18 @@ -- REQUIRE: src/schema.sql --- REQUIRE: src/ore_block_u64_8_256/types.sql --- REQUIRE: src/ore_block_u64_8_256/functions.sql --- REQUIRE: src/ore_block_u64_8_256/operators.sql +-- REQUIRE: src/encrypted/types.sql +-- REQUIRE: src/operators/compare.sql -- Operators for < less than comparisons of eql_v2_encrypted types -- --- Support for the following comparisons: +-- Uses `eql_v2.compare` for the actual comparison logic. -- --- eql_v2_encrypted = eql_v2_encrypted --- eql_v2_encrypted = jsonb --- jsonb = eql_v2_encrypted -- --- There are multiple index terms that provide equality comparisons --- - ore_block_u64_8_256 --- - ore_cllw_8_v2 --- --- We check these index terms in this order and use the first one that exists for both parameters --- --- - - CREATE FUNCTION eql_v2.lt(a eql_v2_encrypted, b eql_v2_encrypted) RETURNS boolean AS $$ BEGIN - - BEGIN - RETURN eql_v2.ore_cllw_u64_8(a) < eql_v2.ore_cllw_u64_8(b); - EXCEPTION WHEN OTHERS THEN - -- PERFORM eql_v2.log('eql_v2.lt no ore_cllw_u64_8 index'); - END; - - BEGIN - RETURN eql_v2.ore_cllw_var_8(a) < eql_v2.ore_cllw_var_8(b); - EXCEPTION WHEN OTHERS THEN - -- PERFORM eql_v2.log('eql_v2.lt no ore_cllw_var_8 index'); - END; - - BEGIN - RETURN eql_v2.ore_block_u64_8_256(a) < eql_v2.ore_block_u64_8_256(b); - EXCEPTION WHEN OTHERS THEN - -- PERFORM eql_v2.log('eql_v2.lt no ore_block_u64_8_256 index'); - END; - - RETURN false; + RETURN eql_v2.compare(a, b) = -1; END; $$ LANGUAGE plpgsql; diff --git a/src/operators/<=.sql b/src/operators/<=.sql index d6ac765..3448276 100644 --- a/src/operators/<=.sql +++ b/src/operators/<=.sql @@ -1,50 +1,18 @@ +-- REQUIRE: src/schema.sql -- REQUIRE: src/encrypted/types.sql --- REQUIRE: src/ore_block_u64_8_256/types.sql --- REQUIRE: src/ore_block_u64_8_256/functions.sql --- REQUIRE: src/ore_block_u64_8_256/operators.sql +-- REQUIRE: src/operators/compare.sql --- Operators for < less than comparisons of eql_v2_encrypted types +-- Operators for <= less than or equal to comparisons of eql_v2_encrypted types -- --- Support for the following comparisons: +-- Uses `eql_v2.compare` for the actual comparison logic. -- --- eql_v2_encrypted = eql_v2_encrypted --- eql_v2_encrypted = jsonb --- jsonb = eql_v2_encrypted -- --- There are multiple index terms that provide equality comparisons --- - ore_block_u64_8_256 --- - ore_cllw_8_v2 --- --- We check these index terms in this order and use the first one that exists for both parameters --- --- - - CREATE FUNCTION eql_v2.lte(a eql_v2_encrypted, b eql_v2_encrypted) RETURNS boolean AS $$ BEGIN - - BEGIN - RETURN eql_v2.ore_cllw_u64_8(a) <= eql_v2.ore_cllw_u64_8(b); - EXCEPTION WHEN OTHERS THEN - -- PERFORM eql_v2.log('eql_v2.lte no ore_cllw_u64_8 index'); - END; - - BEGIN - RETURN eql_v2.ore_cllw_var_8(a) <= eql_v2.ore_cllw_var_8(b); - EXCEPTION WHEN OTHERS THEN - -- PERFORM eql_v2.log('eql_v2.lte no ore_cllw_var_8 index'); - END; - - BEGIN - RETURN eql_v2.ore_block_u64_8_256(a) <= eql_v2.ore_block_u64_8_256(b); - EXCEPTION WHEN OTHERS THEN - -- PERFORM eql_v2.log('eql_v2.lte no ore_block_u64_8_256 index'); - END; - - RETURN false; + RETURN eql_v2.compare(a, b) <= 0; END; $$ LANGUAGE plpgsql; diff --git a/src/operators/<=_ore_cllw_u64_8_test.sql b/src/operators/<=_ore_cllw_u64_8_test.sql new file mode 100644 index 0000000..0db355d --- /dev/null +++ b/src/operators/<=_ore_cllw_u64_8_test.sql @@ -0,0 +1,57 @@ +\set ON_ERROR_STOP on + +SELECT create_table_with_encrypted(); +SELECT seed_encrypted_json(); + + +-- ======================================================================== + + +-- ------------------------------------------------------------------------ +-- ------------------------------------------------------------------------ +-- +-- ore_cllw_u64_8 less than or equal to <= +-- +-- Test data is in form '{"hello": "{one | two | three}", "n": {10 | 20 | 30} }' +-- +-- Paths +-- $ -> bca213de9ccce676fa849ff9c4807963 +-- $.hello -> a7cea93975ed8c01f861ccb6bd082784 +-- $.n -> 2517068c0d1f9d4d41d2c666211f785e +-- +-- +DO $$ +DECLARE + sv eql_v2_encrypted; + term eql_v2_encrypted; + BEGIN + + -- This extracts the data associated with the field from the test eql_v2_encrypted + -- json n: 10 + sv := get_numeric_ste_vec_20()::eql_v2_encrypted; + -- extract the term at $.n returned as eql_v2_encrypted + term := sv->'2517068c0d1f9d4d41d2c666211f785e'::text; + + -- -- -- -- $.n + PERFORM assert_result( + format('eql_v2_encrypted <= eql_v2_encrypted with ore_cllw_u64_8 index term'), + format('SELECT e FROM encrypted WHERE (e->''2517068c0d1f9d4d41d2c666211f785e''::text) <= %L::eql_v2_encrypted', term)); + + PERFORM assert_count( + format('eql_v2_encrypted <= eql_v2_encrypted with ore index term'), + format('SELECT e FROM encrypted WHERE e->''2517068c0d1f9d4d41d2c666211f785e''::text <= %L::eql_v2_encrypted', term), + 2); + + -- Check the $.hello path + -- Returned encrypted does not have ore_cllw_u64_8 + -- Falls back to jsonb literal comparison + PERFORM assert_no_result( + format('eql_v2_encrypted <= eql_v2_encrypted with ore index term'), + format('SELECT e FROM encrypted WHERE e->''a7cea93975ed8c01f861ccb6bd082784''::text <= %L::eql_v2_encrypted', term)); + + END; +$$ LANGUAGE plpgsql; + + + +SELECT drop_table_with_encrypted(); \ No newline at end of file diff --git a/src/operators/<=_ore_cllw_var_8_test.sql b/src/operators/<=_ore_cllw_var_8_test.sql new file mode 100644 index 0000000..b8255ae --- /dev/null +++ b/src/operators/<=_ore_cllw_var_8_test.sql @@ -0,0 +1,53 @@ +\set ON_ERROR_STOP on + +SELECT create_table_with_encrypted(); +SELECT seed_encrypted_json(); + + +-- ------------------------------------------------------------------------ +-- ------------------------------------------------------------------------ +-- +-- ore_cllw_u64_8 less than or equal to <= +-- +-- Test data is in form '{"hello": "{one | two | three}", "n": {10 | 20 | 30} }' +-- +-- Paths +-- $ -> bca213de9ccce676fa849ff9c4807963 +-- $.hello -> a7cea93975ed8c01f861ccb6bd082784 +-- $.n -> 2517068c0d1f9d4d41d2c666211f785e +-- +-- +DO $$ +DECLARE + sv eql_v2_encrypted; + term eql_v2_encrypted; + BEGIN + + -- This extracts the data associated with the field from the test eql_v2_encrypted + -- json n: 10 + sv := get_numeric_ste_vec_20()::eql_v2_encrypted; + -- extract the term at $.n returned as eql_v2_encrypted + term := sv->'a7cea93975ed8c01f861ccb6bd082784'::text; + + -- -- -- -- $.n + PERFORM assert_result( + format('eql_v2_encrypted <= eql_v2_encrypted with ore_cllw_u64_8 index term'), + format('SELECT e FROM encrypted WHERE (e->''a7cea93975ed8c01f861ccb6bd082784''::text) <= %L::eql_v2_encrypted', term)); + + PERFORM assert_count( + format('eql_v2_encrypted <= eql_v2_encrypted with ore index term'), + format('SELECT e FROM encrypted WHERE e->''a7cea93975ed8c01f861ccb6bd082784''::text <= %L::eql_v2_encrypted', term), + 3); + + -- -- Check the $.n path + -- -- Returned encrypted does not have ore_cllw_u64_8 + PERFORM assert_result( + format('eql_v2_encrypted <= eql_v2_encrypted with ore index term'), + format('SELECT e FROM encrypted WHERE e->''2517068c0d1f9d4d41d2c666211f785e''::text <= %L::eql_v2_encrypted', term)); + + END; +$$ LANGUAGE plpgsql; + + + +SELECT drop_table_with_encrypted(); \ No newline at end of file diff --git a/src/operators/<=_test.sql b/src/operators/<=_test.sql index 6581a4d..d0ac226 100644 --- a/src/operators/<=_test.sql +++ b/src/operators/<=_test.sql @@ -3,98 +3,6 @@ SELECT create_table_with_encrypted(); SELECT seed_encrypted_json(); -SELECT e FROM encrypted WHERE e->'a7cea93975ed8c01f861ccb6bd082784'::text <= '("{""c"": ""mBbM0#UZON2jQ3@LiWcvns2Yf6y3L;hykEh`}*fX#aF;n*=>+*o5Uarod39C7TF-SiCD-NgkG)l%Vw=l!tX>H*P bca213de9ccce676fa849ff9c4807963 --- $.hello -> a7cea93975ed8c01f861ccb6bd082784 --- $.n -> 2517068c0d1f9d4d41d2c666211f785e --- --- -- -DO $$ -DECLARE - sv eql_v2_encrypted; - term eql_v2_encrypted; - BEGIN - - -- This extracts the data associated with the field from the test eql_v2_encrypted - -- json n: 30 - sv := get_numeric_ste_vec_30()::eql_v2_encrypted; - -- extract the term at $.n returned as eql_v2_encrypted - term := sv->'2517068c0d1f9d4d41d2c666211f785e'::text; - - -- -- -- -- $.n - PERFORM assert_result( - format('eql_v2_encrypted <= eql_v2_encrypted with ore_cllw_u64_8 index term'), - format('SELECT e FROM encrypted WHERE e->''2517068c0d1f9d4d41d2c666211f785e''::text <= %L::eql_v2_encrypted', term)); - - PERFORM assert_count( - format('eql_v2_encrypted <= eql_v2_encrypted with ore index term'), - format('SELECT e FROM encrypted WHERE e->''2517068c0d1f9d4d41d2c666211f785e''::text <= %L::eql_v2_encrypted', term), - 3); - - -- -- Check the $.hello path - -- -- Returned encrypted does not have ore_cllw_u64_8 - PERFORM assert_no_result( - format('eql_v2_encrypted <= eql_v2_encrypted with ore_cllw_u64_8 index term'), - format('SELECT e FROM encrypted WHERE e->''a7cea93975ed8c01f861ccb6bd082784''::text <= %L::eql_v2_encrypted', term)); - - END; -$$ LANGUAGE plpgsql; - --- ------------------------------------------------------------------------ --- ------------------------------------------------------------------------ --- --- eql_v2_encrypted < eql_v2_encrypted with ore_cllw_var_8 index --- --- Test data is in form '{"hello": "{one | two | three}", "n": {10 | 20 | 30} }' --- --- Paths --- $ -> bca213de9ccce676fa849ff9c4807963 --- $.hello -> a7cea93975ed8c01f861ccb6bd082784 --- $.n -> 2517068c0d1f9d4d41d2c666211f785e --- --- -- -DO $$ -DECLARE - sv eql_v2_encrypted; - term eql_v2_encrypted; - BEGIN - - -- This extracts the data associated with the field from the test eql_v2_encrypted - -- json n: 30 - sv := get_numeric_ste_vec_30()::eql_v2_encrypted; - -- extract the term at $.n returned as eql_v2_encrypted - term := sv->'a7cea93975ed8c01f861ccb6bd082784'::text; - - -- -- -- -- $.n - PERFORM assert_result( - format('eql_v2_encrypted <= eql_v2_encrypted with ore_cllw_var_8 index term'), - format('SELECT e FROM encrypted WHERE e->''a7cea93975ed8c01f861ccb6bd082784''::text <= %L::eql_v2_encrypted', term)); - - PERFORM assert_count( - format('eql_v2_encrypted <= eql_v2_encrypted with ore_cllw_var_8 index term'), - format('SELECT e FROM encrypted WHERE e->''a7cea93975ed8c01f861ccb6bd082784''::text <= %L::eql_v2_encrypted', term), - 2); - - -- -- Check the $.n path - -- -- Returned encrypted does not have ore_cllw_u64_8 - PERFORM assert_no_result( - format('eql_v2_encrypted <= eql_v2_encrypted with ore_cllw_var_8 index term'), - format('SELECT e FROM encrypted WHERE e->''2517068c0d1f9d4d41d2c666211f785e''::text <= %L::eql_v2_encrypted', term)); - - END; -$$ LANGUAGE plpgsql; - - -- -- ORE - eql_v2_encrypted <= eql_v2_encrypted @@ -133,7 +41,7 @@ $$ LANGUAGE plpgsql; -- --- ORE - eql_v2.gte(a eql_v2_encrypted, b eql_v2_encrypted) +-- ORE - eql_v2.lte(a eql_v2_encrypted, b eql_v2_encrypted) -- DO $$ DECLARE @@ -172,4 +80,5 @@ DECLARE $$ LANGUAGE plpgsql; + SELECT drop_table_with_encrypted(); \ No newline at end of file diff --git a/src/operators/<>.sql b/src/operators/<>.sql index d589a1c..f5c934a 100644 --- a/src/operators/<>.sql +++ b/src/operators/<>.sql @@ -1,33 +1,19 @@ +-- REQUIRE: src/schema.sql -- REQUIRE: src/encrypted/types.sql --- REQUIRE: src/hmac_256/types.sql --- REQUIRE: src/hmac_256/functions.sql --- REQUIRE: src/ore_block_u64_8_256/types.sql --- REQUIRE: src/ore_block_u64_8_256/functions.sql --- REQUIRE: src/operators/=.sql +-- REQUIRE: src/operators/compare.sql --- Operators for equality comparisons of eql_v2_encrypted types --- --- Support for the following comparisons: --- --- eql_v2_encrypted <> eql_v2_encrypted --- eql_v2_encrypted <> jsonb --- jsonb <> eql_v2_encrypted --- --- There are multiple index terms that provide equality comparisons --- - hmac_256 --- - ore_block_u64_8_256 --- - ore_cllw_8_v2 + +-- Operators for <> not equal comparisons of eql_v2_encrypted types -- --- We check these index terms in this order and use the first one that exists for both parameters +-- Uses `eql_v2.compare` for the actual comparison logic. -- -- - CREATE FUNCTION eql_v2.neq(a eql_v2_encrypted, b eql_v2_encrypted) RETURNS boolean IMMUTABLE STRICT PARALLEL SAFE AS $$ BEGIN - RETURN NOT eql_v2.eq(a, b ); + RETURN eql_v2.compare(a, b) <> 0; END; $$ LANGUAGE plpgsql; diff --git a/src/operators/<_test.sql b/src/operators/<_test.sql index d04f9d8..a872cc5 100644 --- a/src/operators/<_test.sql +++ b/src/operators/<_test.sql @@ -41,7 +41,8 @@ DECLARE -- -- Check the $.hello path -- -- Returned encrypted does not have ore_cllw_u64_8 - PERFORM assert_no_result( + -- Falls back to jsonb literal comparison + PERFORM assert_result( format('eql_v2_encrypted < eql_v2_encrypted with ore index term'), format('SELECT e FROM encrypted WHERE e->''a7cea93975ed8c01f861ccb6bd082784''::text < %L::eql_v2_encrypted', term)); @@ -85,7 +86,8 @@ DECLARE -- -- Check the $.n path -- -- Returned encrypted does not have ore_cllw_var_8 - PERFORM assert_no_result( + -- Falls back to jsonb literal comparison + PERFORM assert_result( format('eql_v2_encrypted < eql_v2_encrypted with ore_cllw_var_8 index term'), format('SELECT e FROM encrypted WHERE e->''2517068c0d1f9d4d41d2c666211f785e''::text < %L::eql_v2_encrypted', term)); diff --git a/src/operators/=.sql b/src/operators/=.sql index b8b5802..e14d9ca 100644 --- a/src/operators/=.sql +++ b/src/operators/=.sql @@ -1,68 +1,19 @@ +-- REQUIRE: src/schema.sql -- REQUIRE: src/encrypted/types.sql --- REQUIRE: src/hmac_256/types.sql --- REQUIRE: src/hmac_256/functions.sql --- REQUIRE: src/ore_block_u64_8_256/types.sql --- REQUIRE: src/ore_block_u64_8_256/functions.sql --- REQUIRE: src/ore_block_u64_8_256/operators.sql --- REQUIRE: src/blake3/types.sql --- REQUIRE: src/blake3/functions.sql --- REQUIRE: src/ore_cllw_u64_8/types.sql --- REQUIRE: src/ore_cllw_u64_8/functions.sql --- REQUIRE: src/ore_cllw_u64_8/operators.sql +-- REQUIRE: src/operators/compare.sql --- Operators for equality comparisons of eql_v2_encrypted types --- --- Support for the following comparisons: --- --- eql_v2_encrypted = eql_v2_encrypted --- eql_v2_encrypted = jsonb --- jsonb = eql_v2_encrypted --- --- There are multiple index terms that provide equality comparisons --- + +-- Operators for = equality comparisons of eql_v2_encrypted types -- --- We check these index terms in this order and use the first one that exists for both parameters +-- Uses `eql_v2.compare` for the actual comparison logic. -- -- - - CREATE FUNCTION eql_v2.eq(a eql_v2_encrypted, b eql_v2_encrypted) RETURNS boolean IMMUTABLE STRICT PARALLEL SAFE AS $$ BEGIN - - BEGIN - RETURN eql_v2.hmac_256(a) = eql_v2.hmac_256(b); - EXCEPTION WHEN OTHERS THEN - -- PERFORM eql_v2.log('No hmac_256 index'); - END; - - BEGIN - RETURN eql_v2.blake3(a) = eql_v2.blake3(b); - EXCEPTION WHEN OTHERS THEN - -- PERFORM eql_v2.log('No blake3 index'); - END; - - BEGIN - RETURN eql_v2.ore_cllw_u64_8(a) = eql_v2.ore_cllw_u64_8(b); - EXCEPTION WHEN OTHERS THEN - -- PERFORM eql_v2.log('No ore_cllw_u64_8 index'); - END; - - BEGIN - RETURN eql_v2.ore_cllw_var_8(a) = eql_v2.ore_cllw_var_8(b); - EXCEPTION WHEN OTHERS THEN - -- PERFORM eql_v2.log('No ore_cllw_u64_8 index'); - END; - - BEGIN - RETURN eql_v2.ore_block_u64_8_256(a) = eql_v2.ore_block_u64_8_256(b); - EXCEPTION WHEN OTHERS THEN - -- PERFORM eql_v2.log('No ore_block_u64_8_256 index'); - END; - - RETURN false; + RETURN eql_v2.compare(a, b) = 0; END; $$ LANGUAGE plpgsql; diff --git a/src/operators/>.sql b/src/operators/>.sql index 49a4c6e..7d8bee2 100644 --- a/src/operators/>.sql +++ b/src/operators/>.sql @@ -1,55 +1,18 @@ +-- REQUIRE: src/schema.sql -- REQUIRE: src/encrypted/types.sql --- REQUIRE: src/ore_block_u64_8_256/types.sql --- REQUIRE: src/ore_block_u64_8_256/functions.sql --- REQUIRE: src/ore_block_u64_8_256/operators.sql +-- REQUIRE: src/operators/compare.sql --- Operators for < less than comparisons of eql_v2_encrypted types +-- Operators for > greater than comparisons of eql_v2_encrypted types -- --- Support for the following comparisons: +-- Uses `eql_v2.compare` for the actual comparison logic. -- --- eql_v2_encrypted = eql_v2_encrypted --- eql_v2_encrypted = jsonb --- jsonb = eql_v2_encrypted -- --- There are multiple index terms that provide equality comparisons --- - ore_block_u64_8_256 --- - ore_cllw_8_v2 --- --- We check these index terms in this order and use the first one that exists for both parameters --- --- - --- WHERE a > b --- WHERE eql_v2.gt(a, b) --- - - - CREATE FUNCTION eql_v2.gt(a eql_v2_encrypted, b eql_v2_encrypted) RETURNS boolean AS $$ BEGIN - - BEGIN - RETURN eql_v2.ore_cllw_u64_8(a) > eql_v2.ore_cllw_u64_8(b); - EXCEPTION WHEN OTHERS THEN - -- PERFORM eql_v2.log('eql_v2.gt no ore_cllw_u64_8 index'); - END; - - BEGIN - RETURN eql_v2.ore_cllw_var_8(a) > eql_v2.ore_cllw_var_8(b); - EXCEPTION WHEN OTHERS THEN - -- PERFORM eql_v2.log('eql_v2.gt no ore_cllw_var_8 index'); - END; - - BEGIN - RETURN eql_v2.ore_block_u64_8_256(a) > eql_v2.ore_block_u64_8_256(b); - EXCEPTION WHEN OTHERS THEN - -- PERFORM eql_v2.log('eql_v2.gt no ore_block_u64_8_256 index'); - END; - - RETURN false; + RETURN eql_v2.compare(a, b) = 1; END; $$ LANGUAGE plpgsql; diff --git a/src/operators/>=.sql b/src/operators/>=.sql index 5970ea5..d6a36a1 100644 --- a/src/operators/>=.sql +++ b/src/operators/>=.sql @@ -1,56 +1,18 @@ +-- REQUIRE: src/schema.sql -- REQUIRE: src/encrypted/types.sql +-- REQUIRE: src/operators/compare.sql - - - - --- REQUIRE: src/ore_block_u64_8_256/types.sql --- REQUIRE: src/ore_block_u64_8_256/functions.sql --- REQUIRE: src/ore_block_u64_8_256/operators.sql - - --- Operators for < less than comparisons of eql_v2_encrypted types +-- Operators for >= greater than or equal to comparisons of eql_v2_encrypted types -- --- Support for the following comparisons: +-- Uses `eql_v2.compare` for the actual comparison logic. -- --- eql_v2_encrypted = eql_v2_encrypted --- eql_v2_encrypted = jsonb --- jsonb = eql_v2_encrypted -- --- There are multiple index terms that provide equality comparisons --- - ore_block_u64_8_256 --- - ore_cllw_8_v2 --- --- We check these index terms in this order and use the first one that exists for both parameters --- --- - - CREATE FUNCTION eql_v2.gte(a eql_v2_encrypted, b eql_v2_encrypted) RETURNS boolean AS $$ BEGIN - - BEGIN - RETURN eql_v2.ore_cllw_u64_8(a) >= eql_v2.ore_cllw_u64_8(b); - EXCEPTION WHEN OTHERS THEN - -- PERFORM eql_v2.log('eql_v2.gte no ore_cllw_u64_8 index'); - END; - - BEGIN - RETURN eql_v2.ore_cllw_var_8(a) >= eql_v2.ore_cllw_var_8(b); - EXCEPTION WHEN OTHERS THEN - -- PERFORM eql_v2.log('eql_v2.gte no ore_cllw_var_8 index'); - END; - - BEGIN - RETURN eql_v2.ore_block_u64_8_256(a) >= eql_v2.ore_block_u64_8_256(b); - EXCEPTION WHEN OTHERS THEN - -- PERFORM eql_v2.log('eql_v2.gte no ore_block_u64_8_256 index'); - END; - - RETURN false; + RETURN eql_v2.compare(a, b) >= 0; END; $$ LANGUAGE plpgsql; diff --git a/src/operators/>=_test.sql b/src/operators/>=_test.sql index 7fbb78e..82e22e8 100644 --- a/src/operators/>=_test.sql +++ b/src/operators/>=_test.sql @@ -41,7 +41,8 @@ DECLARE -- -- Check the $.hello path -- -- Returned encrypted does not have ore_cllw_u64_8 - PERFORM assert_no_result( + -- Falls back to jsonb literal comparison + PERFORM assert_result( format('eql_v2_encrypted >= eql_v2_encrypted with ore index term'), format('SELECT e FROM encrypted WHERE e->''a7cea93975ed8c01f861ccb6bd082784''::text >= %L::eql_v2_encrypted', term)); @@ -86,7 +87,8 @@ DECLARE -- -- Check the $.hello path -- -- Returned encrypted does not have ore_cllw_u64_8 - PERFORM assert_no_result( + -- Falls back to jsonb literal comparison + PERFORM assert_result( format('eql_v2_encrypted >= eql_v2_encrypted with ore index term'), format('SELECT e FROM encrypted WHERE e->''2517068c0d1f9d4d41d2c666211f785e''::text >= %L::eql_v2_encrypted', term)); diff --git a/src/operators/>_test.sql b/src/operators/>_test.sql index f1a4385..d242950 100644 --- a/src/operators/>_test.sql +++ b/src/operators/>_test.sql @@ -39,9 +39,10 @@ DECLARE format('SELECT e FROM encrypted WHERE e->''2517068c0d1f9d4d41d2c666211f785e''::text > %L::eql_v2_encrypted', term), 1); - -- -- Check the $.hello path - -- -- Returned encrypted does not have ore_cllw_u64_8 - PERFORM assert_no_result( + -- Check the $.hello path + -- Returned encrypted does not have ore_cllw_u64_8 + -- Falls back to jsonb literal comparison + PERFORM assert_result( format('eql_v2_encrypted > eql_v2_encrypted with ore index term'), format('SELECT e FROM encrypted WHERE e->''a7cea93975ed8c01f861ccb6bd082784''::text > %L::eql_v2_encrypted', term)); @@ -84,8 +85,9 @@ DECLARE format('SELECT e FROM encrypted WHERE e->''a7cea93975ed8c01f861ccb6bd082784''::text > %L::eql_v2_encrypted', term), 1); - -- -- Check the $.hello path - -- -- Returned encrypted does not have ore_cllw_var_8 + -- Check the $.hello path + -- Returned encrypted does not have ore_cllw_var_8 + -- Falls back to jsonb literal comparison PERFORM assert_no_result( format('eql_v2_encrypted > eql_v2_encrypted with ore index term'), format('SELECT e FROM encrypted WHERE e->''2517068c0d1f9d4d41d2c666211f785e''::text > %L::eql_v2_encrypted', term)); diff --git a/src/operators/compare.sql b/src/operators/compare.sql new file mode 100644 index 0000000..eb74ce9 --- /dev/null +++ b/src/operators/compare.sql @@ -0,0 +1,90 @@ +-- REQUIRE: src/schema.sql +-- REQUIRE: src/encrypted/types.sql +-- REQUIRE: src/encrypted/functions.sql + +-- REQUIRE: src/blake3/types.sql +-- REQUIRE: src/blake3/functions.sql + +-- REQUIRE: src/hmac_256/types.sql +-- REQUIRE: src/hmac_256/functions.sql + +-- REQUIRE: src/ore_block_u64_8_256/types.sql +-- REQUIRE: src/ore_block_u64_8_256/functions.sql + +-- REQUIRE: src/ore_cllw_u64_8/types.sql +-- REQUIRE: src/ore_cllw_u64_8/functions.sql + +-- REQUIRE: src/ore_cllw_var_8/types.sql +-- REQUIRE: src/ore_cllw_var_8/functions.sql + + +-- +-- Compare two eql_v2_encrypted values +-- +-- Function is used to implement all operators required for btree indexing" +-- - `<` +-- - `<=` +-- - `=` +-- - `>=` +-- - `>` +-- +-- +-- Index terms are checked in the following order: +-- - `ore_block_u64_8_256` +-- - `ore_cllw_u64_8` +-- - `ore_cllw_var_8` +-- - `hmac_256` +-- - `blake3` +-- +-- The first index term present for both values is used for comparsion. +-- +-- If no index terms are found, the encrypted data is compared as a jsonb literal. +-- Btree index must have a consistent ordering for a given state, without this text fallback, database errors with "lock BufferContent is not held" +-- +CREATE FUNCTION eql_v2.compare(a eql_v2_encrypted, b eql_v2_encrypted) + RETURNS integer + IMMUTABLE STRICT PARALLEL SAFE +AS $$ + BEGIN + + IF a IS NULL AND b IS NULL THEN + RETURN 0; + END IF; + + IF a IS NULL THEN + RETURN -1; + END IF; + + IF b IS NULL THEN + RETURN 1; + END IF; + + -- Use ORE if both parameters have ore index + IF eql_v2.has_ore_block_u64_8_256(a) AND eql_v2.has_ore_block_u64_8_256(b) THEN + RETURN eql_v2.compare_ore_block_u64_8_256(a, b); + END IF; + + IF eql_v2.has_ore_cllw_u64_8(a) AND eql_v2.has_ore_cllw_u64_8(b) THEN + RETURN eql_v2.compare_ore_cllw_u64_8(a, b); + END IF; + + IF eql_v2.has_ore_cllw_var_8(a) AND eql_v2.has_ore_cllw_var_8(b) THEN + RETURN eql_v2.compare_ore_cllw_var_8(a, b); + END IF; + + -- Fallback to hmac if both parameters have hmac index + IF eql_v2.has_hmac_256(a) AND eql_v2.has_hmac_256(b) THEN + RETURN eql_v2.compare_hmac_256(a, b); + END IF; + + IF eql_v2.has_blake3(a) AND eql_v2.has_blake3(b) THEN + RETURN eql_v2.compare_blake3(a, b); + END IF; + + -- Fallback to literal comparison of the encrypted data + -- Compare must have consistent ordering for a given state + -- Without this text fallback, database errors with "lock BufferContent is not held" + RETURN eql_v2.compare_literal(a, b); + + END; +$$ LANGUAGE plpgsql; diff --git a/src/operators/compare_test.sql b/src/operators/compare_test.sql new file mode 100644 index 0000000..63c3dbe --- /dev/null +++ b/src/operators/compare_test.sql @@ -0,0 +1,166 @@ +\set ON_ERROR_STOP on + + +-- Compare compare_ore_cllw_var_8 +DO $$ + DECLARE + a eql_v2_encrypted; + b eql_v2_encrypted; + c eql_v2_encrypted; + BEGIN + + -- {"hello": "world{N}"} + -- $.hello: d90b97b5207d30fe867ca816ed0fe4a7 + a := eql_v2.jsonb_path_query(create_encrypted_ste_vec_json(1), 'd90b97b5207d30fe867ca816ed0fe4a7'); + b := eql_v2.jsonb_path_query(create_encrypted_ste_vec_json(2), 'd90b97b5207d30fe867ca816ed0fe4a7'); + c := eql_v2.jsonb_path_query(create_encrypted_ste_vec_json(3), 'd90b97b5207d30fe867ca816ed0fe4a7'); + + ASSERT eql_v2.compare(a, a) = 0; + ASSERT eql_v2.compare(a, b) = -1; + ASSERT eql_v2.compare(a, c) = -1; + + ASSERT eql_v2.compare(b, b) = 0; + ASSERT eql_v2.compare(b, a) = 1; + ASSERT eql_v2.compare(b, c) = -1; + + ASSERT eql_v2.compare(c, c) = 0; + ASSERT eql_v2.compare(c, b) = 1; + ASSERT eql_v2.compare(c, a) = 1; + END; +$$ LANGUAGE plpgsql; + + +-- Compare compare_ore_cllw_var_8 +DO $$ + DECLARE + a eql_v2_encrypted; + b eql_v2_encrypted; + c eql_v2_encrypted; + BEGIN + + -- {"number": {N}} + -- $.number: 3dba004f4d7823446e7cb71f6681b344 + a := eql_v2.jsonb_path_query(create_encrypted_ste_vec_json(1), '3dba004f4d7823446e7cb71f6681b344'); + b := eql_v2.jsonb_path_query(create_encrypted_ste_vec_json(5), '3dba004f4d7823446e7cb71f6681b344'); + c := eql_v2.jsonb_path_query(create_encrypted_ste_vec_json(10), '3dba004f4d7823446e7cb71f6681b344'); + + ASSERT eql_v2.compare(a, a) = 0; + ASSERT eql_v2.compare(a, b) = -1; + ASSERT eql_v2.compare(a, c) = -1; + + ASSERT eql_v2.compare(b, b) = 0; + ASSERT eql_v2.compare(b, a) = 1; + ASSERT eql_v2.compare(b, c) = -1; + + ASSERT eql_v2.compare(c, c) = 0; + ASSERT eql_v2.compare(c, b) = 1; + ASSERT eql_v2.compare(c, a) = 1; + END; +$$ LANGUAGE plpgsql; + + +-- Compare ore_block_u64_8_256 +DO $$ + DECLARE + a eql_v2_encrypted; + b eql_v2_encrypted; + c eql_v2_encrypted; + BEGIN + + a := create_encrypted_ore_json(1); + b := create_encrypted_ore_json(21); + c := create_encrypted_ore_json(42); + + ASSERT eql_v2.compare(a, a) = 0; + ASSERT eql_v2.compare(a, b) = -1; + ASSERT eql_v2.compare(a, c) = -1; + + ASSERT eql_v2.compare(b, b) = 0; + ASSERT eql_v2.compare(b, a) = 1; + ASSERT eql_v2.compare(b, c) = -1; + + ASSERT eql_v2.compare(c, c) = 0; + ASSERT eql_v2.compare(c, b) = 1; + ASSERT eql_v2.compare(c, a) = 1; + END; +$$ LANGUAGE plpgsql; + + +-- Compare blake3 +DO $$ + DECLARE + a eql_v2_encrypted; + b eql_v2_encrypted; + c eql_v2_encrypted; + BEGIN + a := create_encrypted_json(1, 'b3'); + b := create_encrypted_json(2, 'b3'); + c := create_encrypted_json(3, 'b3'); + + ASSERT eql_v2.compare(a, a) = 0; + ASSERT eql_v2.compare(a, b) = -1; + ASSERT eql_v2.compare(a, c) = -1; + + ASSERT eql_v2.compare(b, b) = 0; + ASSERT eql_v2.compare(b, a) = 1; + ASSERT eql_v2.compare(b, c) = -1; + + ASSERT eql_v2.compare(c, c) = 0; + ASSERT eql_v2.compare(c, b) = 1; + ASSERT eql_v2.compare(c, a) = 1; + END; +$$ LANGUAGE plpgsql; + + +-- Compare hmac_256 +DO $$ + DECLARE + a eql_v2_encrypted; + b eql_v2_encrypted; + c eql_v2_encrypted; + BEGIN + a := create_encrypted_json(1, 'hm'); + b := create_encrypted_json(2, 'hm'); + c := create_encrypted_json(3, 'hm'); + + ASSERT eql_v2.compare(a, a) = 0; + ASSERT eql_v2.compare(a, b) = -1; + ASSERT eql_v2.compare(a, c) = -1; + + ASSERT eql_v2.compare(b, b) = 0; + ASSERT eql_v2.compare(b, a) = 1; + ASSERT eql_v2.compare(b, c) = -1; + + ASSERT eql_v2.compare(c, c) = 0; + ASSERT eql_v2.compare(c, b) = 1; + ASSERT eql_v2.compare(c, a) = 1; + END; +$$ LANGUAGE plpgsql; + + + +-- Compare with no index terms +-- This is a fallback to literal comparison of the encrypted data +DO $$ + DECLARE + a eql_v2_encrypted; + b eql_v2_encrypted; + c eql_v2_encrypted; + BEGIN + a := '{"a": 1}'::jsonb::eql_v2_encrypted; + b := '{"b": 2}'::jsonb::eql_v2_encrypted; + c := '{"c": 3}'::jsonb::eql_v2_encrypted; + + ASSERT eql_v2.compare(a, a) = 0; + ASSERT eql_v2.compare(a, b) = -1; + ASSERT eql_v2.compare(a, c) = -1; + + ASSERT eql_v2.compare(b, b) = 0; + ASSERT eql_v2.compare(b, a) = 1; + ASSERT eql_v2.compare(b, c) = -1; + + ASSERT eql_v2.compare(c, c) = 0; + ASSERT eql_v2.compare(c, b) = 1; + ASSERT eql_v2.compare(c, a) = 1; + END; +$$ LANGUAGE plpgsql; \ No newline at end of file diff --git a/src/operators/operator_class.sql b/src/operators/operator_class.sql index efb3668..0a847ff 100644 --- a/src/operators/operator_class.sql +++ b/src/operators/operator_class.sql @@ -1,8 +1,7 @@ -- REQUIRE: src/schema.sql -- REQUIRE: src/encrypted/types.sql -- REQUIRE: src/encrypted/functions.sql --- REQUIRE: src/ore_block_u64_8_256/types.sql --- REQUIRE: src/ore_block_u64_8_256/functions.sql +-- REQUIRE: src/encrypted/compare.sql -- REQUIRE: src/operators/<.sql -- REQUIRE: src/operators/<=.sql -- REQUIRE: src/operators/=.sql @@ -10,139 +9,11 @@ -- REQUIRE: src/operators/>.sql --- --- Compare two eql_v2_encrypted values --- Uses `ore_block_u64_8_256` or `has_hmac_256` index terms for comparison if defined on ONE of the compared value --- --- Important note: -- Index order of operations is reversed from equality operator. --- In equality operations, `has_hmac_256` is preferred as it reduces to a text comparison and is more efficient --- As compare is used for ordering, `ore_block_u64_8_256` provides more complete ordering and is checked first. --- THe assumption is that if you add ore you are adding it because you want to use it specifically for comparison. - --- Thusly, the logic for determining which index term to use: --- Use ORE if BOTH parameters have ore index --- Fallback to hmac if BOTH parameters have hmac index --- Fallback to ORE if ONE of the parameters has ore index (will compare against a NULL term for the other parameter) --- Fallback to hmac if ONE of the parameters has hmac index (will compare against a NULL term term for the other parameter) --- --- As a general rule, columns should have the same index terms as they are encrypted with the same configuration. --- Index terms should only be different during an encryption config migration. --- eg, when adding an ore index to a column any existing values will NOT have the ore index until encryptindexed/migrated --- -CREATE FUNCTION eql_v2.compare(a eql_v2_encrypted, b eql_v2_encrypted) - RETURNS integer - IMMUTABLE STRICT PARALLEL SAFE -AS $$ - BEGIN - - -- PERFORM eql_v2.log('eql_v2.has_hmac_256(a)', eql_v2.has_hmac_256(a)::text); - -- PERFORM eql_v2.log('eql_v2.has_hmac_256(b)', eql_v2.has_hmac_256(b)::text); - -- PERFORM eql_v2.log('eql_v2.has_ore_block_u64_8_256(b)', eql_v2.has_ore_block_u64_8_256(b)::text); - -- PERFORM eql_v2.log('eql_v2.has_ore_block_u64_8_256(b)', eql_v2.has_ore_block_u64_8_256(b)::text); - - - -- Use ORE if BOTH parameters have ore index - IF eql_v2.has_ore_block_u64_8_256(a) AND eql_v2.has_ore_block_u64_8_256(b) THEN - RETURN eql_v2.compare_ore_block_u64_8_256(a, b); - END IF; - - -- Fallback to hmac if BOTH parameters have hmac index - IF eql_v2.has_hmac_256(a) AND eql_v2.has_hmac_256(b) THEN - RETURN eql_v2.compare_hmac(a, b); - END IF; - - -- Fallback to ORE if one of the parameters has ore index - IF eql_v2.has_ore_block_u64_8_256(a) OR eql_v2.has_ore_block_u64_8_256(b) THEN - RETURN eql_v2.compare_ore_block_u64_8_256(a, b); - END IF; - - -- Fallback to hmac if ONE of the parameters has hmac index - IF eql_v2.has_hmac_256(a) OR eql_v2.has_hmac_256(b) THEN - RETURN eql_v2.compare_hmac(a, b); - END IF; - - RAISE 'Expected an hmac_256 (hm) or ore_block_u64_8_256 (ob) value in json: %', val; - END; -$$ LANGUAGE plpgsql; - -------------------- -CREATE FUNCTION eql_v2.compare_ore_block_u64_8_256(a eql_v2_encrypted, b eql_v2_encrypted) - RETURNS integer - IMMUTABLE STRICT PARALLEL SAFE -AS $$ - DECLARE - a_ore eql_v2.ore_block_u64_8_256; - b_ore eql_v2.ore_block_u64_8_256; - BEGIN - - a_ore := eql_v2.ore_block_u64_8_256(a); - b_ore := eql_v2.ore_block_u64_8_256(b); - - IF a_ore IS NULL AND b_ore IS NULL THEN - RETURN 0; - END IF; - - IF a_ore IS NULL THEN - RETURN -1; - END IF; +CREATE OPERATOR FAMILY eql_v2.encrypted_operator_family USING btree; - IF b_ore IS NULL THEN - RETURN 1; - END IF; - - RETURN eql_v2.compare_ore_array(a_ore.terms, b_ore.terms); - END; -$$ LANGUAGE plpgsql; - - --------------------- - -CREATE FUNCTION eql_v2.compare_hmac(a eql_v2_encrypted, b eql_v2_encrypted) - RETURNS integer - IMMUTABLE STRICT PARALLEL SAFE -AS $$ - DECLARE - a_hmac eql_v2.hmac_256; - b_hmac eql_v2.hmac_256; - BEGIN - - a_hmac = eql_v2.hmac_256(a); - b_hmac = eql_v2.hmac_256(b); - - IF a_hmac IS NULL AND b_hmac IS NULL THEN - RETURN 0; - END IF; - - IF a_hmac IS NULL THEN - RETURN -1; - END IF; - - IF b_hmac IS NULL THEN - RETURN 1; - END IF; - - IF a_hmac = b_hmac THEN - RETURN 0; - END IF; - - IF a_hmac < b_hmac THEN - RETURN -1; - END IF; - - IF a_hmac > b_hmac THEN - RETURN 1; - END IF; - - END; -$$ LANGUAGE plpgsql; - - --------------------- - -CREATE OPERATOR FAMILY eql_v2.encrypted_operator USING btree; - -CREATE OPERATOR CLASS eql_v2.encrypted_operator DEFAULT FOR TYPE eql_v2_encrypted USING btree FAMILY eql_v2.encrypted_operator AS +CREATE OPERATOR CLASS eql_v2.encrypted_operator_class DEFAULT FOR TYPE eql_v2_encrypted USING btree FAMILY eql_v2.encrypted_operator_family AS OPERATOR 1 <, OPERATOR 2 <=, OPERATOR 3 =, @@ -153,9 +24,9 @@ CREATE OPERATOR CLASS eql_v2.encrypted_operator DEFAULT FOR TYPE eql_v2_encrypte -------------------- --- CREATE OPERATOR FAMILY eql_v2.encrypted_operator_ore_block_u64_8_256 USING btree; +-- CREATE OPERATOR FAMILY eql_v2.encrypted_operator_ordered USING btree; --- CREATE OPERATOR CLASS eql_v2.encrypted_operator_ore_block_u64_8_256 FOR TYPE eql_v2_encrypted USING btree FAMILY eql_v2.encrypted_operator_ore_block_u64_8_256 AS +-- CREATE OPERATOR CLASS eql_v2.encrypted_operator_ordered FOR TYPE eql_v2_encrypted USING btree FAMILY eql_v2.encrypted_operator_ordered AS -- OPERATOR 1 <, -- OPERATOR 2 <=, -- OPERATOR 3 =, @@ -163,7 +34,7 @@ CREATE OPERATOR CLASS eql_v2.encrypted_operator DEFAULT FOR TYPE eql_v2_encrypte -- OPERATOR 5 >, -- FUNCTION 1 eql_v2.compare_ore_block_u64_8_256(a eql_v2_encrypted, b eql_v2_encrypted); --- -------------------- +-------------------- -- CREATE OPERATOR FAMILY eql_v2.encrypted_hmac_256_operator USING btree; diff --git a/src/operators/operator_class_test.sql b/src/operators/operator_class_test.sql index 8502cba..e901ed7 100644 --- a/src/operators/operator_class_test.sql +++ b/src/operators/operator_class_test.sql @@ -1,45 +1,13 @@ \set ON_ERROR_STOP on -SELECT create_table_with_encrypted(); -SELECT seed_encrypted_json(); - --- --- ORE ORDER BY --- -DO $$ -DECLARE - ore_term eql_v2_encrypted; - BEGIN - - PERFORM assert_id( - 'ORDER BY eql_v2_encrypted DESC', - 'SELECT id FROM ore ORDER BY e DESC LIMIT 1', - 99); - - PERFORM assert_id( - 'ORDER BY eql_v2_encrypted DESC', - 'SELECT id FROM ore ORDER BY e ASC LIMIT 1', - 1); - - - SELECT e FROM ore WHERE id = 42 INTO ore_term; - - PERFORM assert_id( - 'eql_v2_encrypted < eql_v2_encrypted', - format('SELECT id FROM ore WHERE e < %L ORDER BY e DESC LIMIT 1', ore_term), - 41); - - END; -$$ LANGUAGE plpgsql; - - - -- -- ORE GROUP BY -- DO $$ BEGIN + PERFORM create_table_with_encrypted(); + -- Copy ORE data into encrypted INSERT INTO encrypted(e) SELECT e FROM ore WHERE ore.id=42; INSERT INTO encrypted(e) SELECT e FROM ore WHERE ore.id=42; @@ -53,15 +21,11 @@ DO $$ 'GROUP BY eql_v2_encrypted', 'SELECT count(id) FROM encrypted GROUP BY e ORDER BY count(id) DESC', 4); - - END; $$ LANGUAGE plpgsql; -SELECT * FROM encrypted; - -- --- ORE GROUP BY +-- Confirm index used correctly -- DO $$ DECLARE @@ -71,9 +35,9 @@ DO $$ PERFORM create_table_with_encrypted(); - EXECUTE 'EXPLAIN ANALYZE SELECT e::jsonb FROM encrypted WHERE e = ''("{\"hm\": \"abc\"}")'';' into result; + EXECUTE 'EXPLAIN ANALYZE SELECT e::jsonb FROM encrypted WHERE e = ''("{\"ob\": \"abc\"}")'';' into result; - PERFORM eql_v2.log('', result); + -- PERFORM eql_v2.log('', result); IF position('Bitmap Heap Scan on encrypted' in result) > 0 THEN RAISE EXCEPTION 'Unexpected Bitmap Heap Scan: %', result; @@ -81,54 +45,145 @@ DO $$ ASSERT true; END IF; - EXECUTE 'EXPLAIN ANALYZE SELECT e::jsonb FROM encrypted WHERE e = ''("{\"ob\": \"abc\"}")'';' into result; + -- Add index + CREATE INDEX ON encrypted (e eql_v2.encrypted_operator_class); - PERFORM eql_v2.log('', result); + SELECT ore.e FROM ore WHERE id = 42 INTO ore_term; + EXECUTE format('EXPLAIN ANALYZE SELECT e::jsonb FROM encrypted WHERE e = %L::eql_v2_encrypted;', ore_term) into result; IF position('Bitmap Heap Scan on encrypted' in result) > 0 THEN - RAISE EXCEPTION 'Unexpected Bitmap Heap Scan: %', result; + ASSERT true; + ELSE + RAISE EXCEPTION 'Expected Bitmap Heap Scan: %', result; + END IF; + + -- INDEX WILL BE USED + EXECUTE 'EXPLAIN ANALYZE SELECT e::jsonb FROM encrypted WHERE e = ''("{\"hm\": \"abc\"}")'';' into result; + + IF position('Bitmap Heap Scan on encrypted' in result) > 0 THEN + ASSERT true; ELSE + RAISE EXCEPTION 'Expected Bitmap Heap Scan: %', result; + END IF; + + --- + EXECUTE 'EXPLAIN ANALYZE SELECT e::jsonb FROM encrypted WHERE e = ''("{\"blah\": \"vtha\"}")'';' into result; + + IF position('Bitmap Heap Scan on encrypted' in result) > 0 THEN ASSERT true; + ELSE + RAISE EXCEPTION 'Expected Bitmap Heap Scan: %', result; END IF; + END; +$$ LANGUAGE plpgsql; + + + +-- +-- Adding index to table where values do not have an appropriate search term +-- +DO $$ + DECLARE + ore_term eql_v2_encrypted; + result text; + BEGIN + + PERFORM create_table_with_encrypted(); + + INSERT INTO encrypted (e) VALUES ('("{\"bf\": \"[1, 2, 3]\"}")'); -- Add index - CREATE INDEX ON encrypted (e); + CREATE INDEX encrypted_index ON encrypted (e eql_v2.encrypted_operator_class); + + ANALYZE encrypted; + + EXECUTE 'EXPLAIN ANALYZE SELECT e::jsonb FROM encrypted WHERE e = ''("{\"bf\": \"[1,2,3]\"}")'';' into result; + IF position('Seq Scan on encrypted' in result) > 0 THEN + ASSERT true; + ELSE + RAISE EXCEPTION 'Unexpected Seq Scan: %', result; + END IF; + + -- NO INDEX WILL BE USED EXECUTE 'EXPLAIN ANALYZE SELECT e::jsonb FROM encrypted WHERE e = ''("{\"hm\": \"abc\"}")'';' into result; - PERFORM eql_v2.log(result); + IF position('Seq Scan on encrypted' in result) > 0 THEN + ASSERT true; + ELSE + RAISE EXCEPTION 'Unexpected Seq Scan: %', result; + END IF; - IF position('Bitmap Heap Scan on encrypted' in result) > 0 THEN + INSERT INTO encrypted (e) VALUES ('("{\"hm\": \"abc\"}")'); + INSERT INTO encrypted (e) VALUES ('("{\"hm\": \"def\"}")'); + INSERT INTO encrypted (e) VALUES ('("{\"hm\": \"ghi\"}")'); + + ANALYZE encrypted; + + -- STILL NO INDEX WILL BE USED + EXECUTE 'EXPLAIN ANALYZE SELECT e::jsonb FROM encrypted WHERE e = ''("{\"hm\": \"abc\"}")'';' into result; + + IF position('Seq Scan on encrypted' in result) > 0 THEN ASSERT true; ELSE - RAISE EXCEPTION 'Expected Bitmap Heap Scan: %', result; + RAISE EXCEPTION 'Unexpected Seq Scan: %', result; END IF; - PERFORM seed_encrypted_json(); + DROP INDEX encrypted_index; + CREATE INDEX encrypted_index ON encrypted (e eql_v2.encrypted_operator_class); + + ANALYZE encrypted; + + EXECUTE 'EXPLAIN ANALYZE SELECT e::jsonb FROM encrypted WHERE e = ''("{\"hm\": \"abc\"}")'';' into result; + + -- -- AND STILL NOPE + IF position('Seq Scan on encrypted' in result) > 0 THEN + ASSERT true; + ELSE + RAISE EXCEPTION 'Unexpected Seq Scan: %', result; + END IF; + + + TRUNCATE encrypted; + DROP INDEX encrypted_index; + CREATE INDEX encrypted_index ON encrypted (e eql_v2.encrypted_operator_class); + + INSERT INTO encrypted (e) VALUES ('("{\"hm\": \"abc\"}")'); + INSERT INTO encrypted (e) VALUES ('("{\"hm\": \"def\"}")'); + INSERT INTO encrypted (e) VALUES ('("{\"hm\": \"ghi\"}")'); + + EXECUTE 'EXPLAIN ANALYZE SELECT e::jsonb FROM encrypted WHERE e = ''("{\"hm\": \"abc\"}")'';' into result; + IF position('Index Only Scan using encrypted' in result) > 0 THEN + ASSERT true; + ELSE + RAISE EXCEPTION 'Expected Index Only Scan: %', result; + END IF; + + -- SELECT ore.e FROM ore WHERE id = 42 INTO ore_term; EXECUTE format('EXPLAIN ANALYZE SELECT e::jsonb FROM encrypted WHERE e = %L::eql_v2_encrypted;', ore_term) into result; - PERFORM eql_v2.log(result); - - IF position('Bitmap Heap Scan on encrypted' in result) > 0 THEN + IF position('Index Only Scan using encrypted' in result) > 0 THEN ASSERT true; ELSE - RAISE EXCEPTION 'Expected Bitmap Heap Scan: %', result; + RAISE EXCEPTION 'Expected Index Only Scan: %', result; END IF; - -- --- - -- EXECUTE 'EXPLAIN ANALYZE SELECT e::jsonb FROM encrypted WHERE e = ''("{\"blah\": \"vtha\"}")'';' into result; + TRUNCATE encrypted; + PERFORM seed_encrypted_json(); + + EXECUTE 'EXPLAIN ANALYZE SELECT e::jsonb FROM encrypted WHERE e = ''("{\"blah\": \"vtha\"}")'';' into result; - -- IF position('Bitmap Heap Scan on encrypted' in result) > 0 THEN - -- ASSERT true; - -- ELSE - -- RAISE EXCEPTION 'Expected Bitmap Heap Scan: %', result; - -- END IF; + IF position('Index Only Scan using encrypted' in result) > 0 THEN + ASSERT true; + ELSE + RAISE EXCEPTION 'Expected Index Only Scan: %', result; + END IF; END; $$ LANGUAGE plpgsql; -SELECT drop_table_with_encrypted(); \ No newline at end of file + diff --git a/src/operators/order_by.sql b/src/operators/order_by.sql index 67801f3..5c6aa61 100644 --- a/src/operators/order_by.sql +++ b/src/operators/order_by.sql @@ -8,64 +8,15 @@ -- order_by function for ordering when operators are not available. -- --- There are multiple index terms that provide equality comparisons --- - ore_cllw_u64_8 --- - ore_cllw_var_8 --- - ore_block_u64_8_256 -- --- We check these index terms in this order and use the first one that exists for both parameters --- --- - - CREATE FUNCTION eql_v2.order_by(a eql_v2_encrypted) RETURNS eql_v2.ore_block_u64_8_256 IMMUTABLE STRICT PARALLEL SAFE AS $$ BEGIN - BEGIN - RETURN eql_v2.ore_block_u64_8_256(a); - EXCEPTION WHEN OTHERS THEN - -- PERFORM eql_v2.log('No ore_block_u64_8_256 index'); - END; - - RETURN false; + RETURN eql_v2.ore_block_u64_8_256(a); END; $$ LANGUAGE plpgsql; --- TODO: make this work --- fails with jsonb format issue, which I think is due to the type casting --- -CREATE FUNCTION eql_v2.order_by_any(a anyelement) - RETURNS anyelement - IMMUTABLE STRICT PARALLEL SAFE -AS $$ - DECLARE - e eql_v2_encrypted; - result ALIAS FOR $0; - BEGIN - - e := a::eql_v2_encrypted; - - BEGIN - result := eql_v2.ore_cllw_u64_8(e); - EXCEPTION WHEN OTHERS THEN - -- PERFORM eql_v2.log('No ore_cllw_u64_8 index'); - END; - - BEGIN - result := eql_v2.ore_cllw_var_8(e); - EXCEPTION WHEN OTHERS THEN - -- PERFORM eql_v2.log('No ore_cllw_u64_8 index'); - END; - BEGIN - result := eql_v2.ore_block_u64_8_256(e); - EXCEPTION WHEN OTHERS THEN - -- PERFORM eql_v2.log('No ore_block_u64_8_256 index'); - END; - - RETURN result; - END; -$$ LANGUAGE plpgsql; diff --git a/src/operators/order_by_test.sql b/src/operators/order_by_test.sql index 6e20117..35e7207 100644 --- a/src/operators/order_by_test.sql +++ b/src/operators/order_by_test.sql @@ -1,31 +1,5 @@ \set ON_ERROR_STOP on --- --- ORE - ORDER BY ore_block_u64_8_256(eql_v2_encrypted) --- -DO $$ -DECLARE - e eql_v2_encrypted; - ore_term eql_v2_encrypted; - BEGIN - SELECT ore.e FROM ore WHERE id = 42 INTO ore_term; - - PERFORM assert_count( - 'ORDER BY eql_v2.order_by(e) DESC', - format('SELECT id FROM ore WHERE e < %L ORDER BY eql_v2.order_by(e) DESC', ore_term), - 41); - - PERFORM assert_result( - 'ORDER BY eql_v2.order_by(e) DESC returns correct record', - format('SELECT id FROM ore WHERE e < %L ORDER BY eql_v2.order_by(e) DESC LIMIT 1', ore_term), - '41'); - - PERFORM assert_result( - 'ORDER BY eql_v2.order_by(e) ASC', - format('SELECT id FROM ore WHERE e < %L ORDER BY eql_v2.order_by(e) ASC LIMIT 1', ore_term), - '1'); - END; -$$ LANGUAGE plpgsql; -- @@ -144,4 +118,32 @@ DECLARE END; $$ LANGUAGE plpgsql; + +-- +-- ORE - ORDER BY ore_block_u64_8_256(eql_v2_encrypted) + +DO $$ +DECLARE + e eql_v2_encrypted; + ore_term eql_v2_encrypted; + BEGIN + SELECT ore.e FROM ore WHERE id = 42 INTO ore_term; + + PERFORM assert_count( + 'ORDER BY eql_v2.order_by(e) DESC', + format('SELECT id FROM ore WHERE e < %L ORDER BY eql_v2.order_by(e) DESC', ore_term), + 41); + + PERFORM assert_result( + 'ORDER BY eql_v2.order_by(e) DESC returns correct record', + format('SELECT id FROM ore WHERE e < %L ORDER BY eql_v2.order_by(e) DESC LIMIT 1', ore_term), + '41'); + + PERFORM assert_result( + 'ORDER BY eql_v2.order_by(e) ASC', + format('SELECT id FROM ore WHERE e < %L ORDER BY eql_v2.order_by(e) ASC LIMIT 1', ore_term), + '1'); + END; +$$ LANGUAGE plpgsql; + SELECT drop_table_with_encrypted(); \ No newline at end of file diff --git a/src/ore_block_u64_8_256/compare.sql b/src/ore_block_u64_8_256/compare.sql new file mode 100644 index 0000000..ccad691 --- /dev/null +++ b/src/ore_block_u64_8_256/compare.sql @@ -0,0 +1,50 @@ +-- REQUIRE: src/schema.sql +-- REQUIRE: src/ore_block_u64_8_256/types.sql +-- REQUIRE: src/ore_block_u64_8_256/functions.sql + + +CREATE FUNCTION eql_v2.compare_ore_block_u64_8_256(a eql_v2_encrypted, b eql_v2_encrypted) + RETURNS integer + IMMUTABLE STRICT PARALLEL SAFE +AS $$ + DECLARE + a_term eql_v2.ore_block_u64_8_256; + b_term eql_v2.ore_block_u64_8_256; + BEGIN + + IF a IS NULL AND b IS NULL THEN + RETURN 0; + END IF; + + IF a IS NULL THEN + RETURN -1; + END IF; + + IF b IS NULL THEN + RETURN 1; + END IF; + + IF eql_v2.has_ore_block_u64_8_256(a) THEN + a_term := eql_v2.ore_block_u64_8_256(a); + END IF; + + IF eql_v2.has_ore_block_u64_8_256(a) THEN + b_term := eql_v2.ore_block_u64_8_256(b); + END IF; + + IF a_term IS NULL AND b_term IS NULL THEN + RETURN 0; + END IF; + + IF a_term IS NULL THEN + RETURN -1; + END IF; + + IF b_term IS NULL THEN + RETURN 1; + END IF; + + RETURN eql_v2.compare_ore_block_u64_8_256_terms(a_term.terms, b_term.terms); + END; +$$ LANGUAGE plpgsql; + diff --git a/src/ore_block_u64_8_256/compare_test.sql b/src/ore_block_u64_8_256/compare_test.sql new file mode 100644 index 0000000..83c9093 --- /dev/null +++ b/src/ore_block_u64_8_256/compare_test.sql @@ -0,0 +1,27 @@ +\set ON_ERROR_STOP on + +DO $$ + DECLARE + a eql_v2_encrypted; + b eql_v2_encrypted; + c eql_v2_encrypted; + BEGIN + + a := create_encrypted_ore_json(1); + b := create_encrypted_ore_json(21); + c := create_encrypted_ore_json(42); + + ASSERT eql_v2.compare_ore_block_u64_8_256(a, a) = 0; + ASSERT eql_v2.compare_ore_block_u64_8_256(a, b) = -1; + ASSERT eql_v2.compare_ore_block_u64_8_256(a, c) = -1; + + ASSERT eql_v2.compare_ore_block_u64_8_256(b, b) = 0; + ASSERT eql_v2.compare_ore_block_u64_8_256(b, a) = 1; + ASSERT eql_v2.compare_ore_block_u64_8_256(b, c) = -1; + + ASSERT eql_v2.compare_ore_block_u64_8_256(c, c) = 0; + ASSERT eql_v2.compare_ore_block_u64_8_256(c, b) = 1; + ASSERT eql_v2.compare_ore_block_u64_8_256(c, a) = 1; + END; +$$ LANGUAGE plpgsql; + diff --git a/src/ore_block_u64_8_256/functions.sql b/src/ore_block_u64_8_256/functions.sql index a82aa17..2769367 100644 --- a/src/ore_block_u64_8_256/functions.sql +++ b/src/ore_block_u64_8_256/functions.sql @@ -100,19 +100,8 @@ AS $$ $$ LANGUAGE plpgsql; --- This function uses lexicographic comparison -CREATE FUNCTION eql_v2.compare_ore_block_u64_8_256(a eql_v2.ore_block_u64_8_256, b eql_v2.ore_block_u64_8_256) -RETURNS integer AS $$ - BEGIN - -- Recursively compare blocks bailing as soon as we can make a decision - RETURN eql_v2.compare_ore_array(a.terms, b.terms); - END -$$ LANGUAGE plpgsql; - - - -CREATE FUNCTION eql_v2.ore_block_u64_8_256_term(a eql_v2.ore_block_u64_8_256_term, b eql_v2.ore_block_u64_8_256_term) +CREATE FUNCTION eql_v2.compare_ore_block_u64_8_256_term(a eql_v2.ore_block_u64_8_256_term, b eql_v2.ore_block_u64_8_256_term) RETURNS integer AS $$ DECLARE @@ -176,11 +165,6 @@ AS $$ data_block := substr(a.bytes, 9 + (left_block_size * unequal_block), left_block_size); - -- PERFORM eql_v2.log('substr', data_block::text); - -- PERFORM eql_v2.log('hash_key', hash_key::text); - -- PERFORM eql_v2.log('data_block', pg_typeof(data_block)::text); - -- PERFORM eql_v2.log('hash_key', pg_typeof(hash_key)::text); - encrypt_block := public.encrypt(data_block::bytea, hash_key::bytea, 'aes-ecb'); indicator := ( @@ -206,7 +190,7 @@ $$ LANGUAGE plpgsql; -- If both are non-empty, we compare the first element. If they are equal -- we need to consider the next block so we recurse, otherwise we return the comparison result. -CREATE FUNCTION eql_v2.compare_ore_array(a eql_v2.ore_block_u64_8_256_term[], b eql_v2.ore_block_u64_8_256_term[]) +CREATE FUNCTION eql_v2.compare_ore_block_u64_8_256_terms(a eql_v2.ore_block_u64_8_256_term[], b eql_v2.ore_block_u64_8_256_term[]) RETURNS integer AS $$ DECLARE cmp_result integer; @@ -232,12 +216,21 @@ RETURNS integer AS $$ RETURN 1; END IF; - cmp_result := eql_v2.ore_block_u64_8_256_term(a[1], b[1]); + cmp_result := eql_v2.compare_ore_block_u64_8_256_term(a[1], b[1]); + IF cmp_result = 0 THEN -- Removes the first element in the array, and calls this fn again to compare the next element/s in the array. - RETURN eql_v2.compare_ore_array(a[2:array_length(a,1)], b[2:array_length(b,1)]); + RETURN eql_v2.compare_ore_block_u64_8_256_terms(a[2:array_length(a,1)], b[2:array_length(b,1)]); END IF; RETURN cmp_result; END $$ LANGUAGE plpgsql; + + +CREATE FUNCTION eql_v2.compare_ore_block_u64_8_256_terms(a eql_v2.ore_block_u64_8_256, b eql_v2.ore_block_u64_8_256) +RETURNS integer AS $$ + BEGIN + RETURN eql_v2.compare_ore_block_u64_8_256_terms(a.terms, b.terms); + END +$$ LANGUAGE plpgsql; diff --git a/src/ore_block_u64_8_256/functions_test.sql b/src/ore_block_u64_8_256/functions_test.sql index e7e7035..0ecfaa2 100644 --- a/src/ore_block_u64_8_256/functions_test.sql +++ b/src/ore_block_u64_8_256/functions_test.sql @@ -29,27 +29,30 @@ $$ LANGUAGE plpgsql; -- -- ORE - ORDER BY ore_block_u64_8_256(eql_v2_encrypted) --- -DO $$ -DECLARE - e eql_v2_encrypted; - ore_term eql_v2_encrypted; - BEGIN - SELECT ore.e FROM ore WHERE id = 42 INTO ore_term; - - PERFORM assert_count( - 'ORDER BY eql_v2.ore_block_u64_8_256(e) DESC', - format('SELECT id FROM ore WHERE e < %L ORDER BY eql_v2.ore_block_u64_8_256(e) DESC', ore_term), - 41); - - PERFORM assert_result( - 'ORDER BY eql_v2.ore_block_u64_8_256(e) DESC returns correct record', - format('SELECT id FROM ore WHERE e < %L ORDER BY eql_v2.ore_block_u64_8_256(e) DESC LIMIT 1', ore_term), - '41'); - - -- PERFORM assert_result( - -- 'ORDER BY eql_v2.ore_block_u64_8_256(e) ASC', - -- format('SELECT id FROM ore WHERE e < %L ORDER BY eql_v2.ore_block_u64_8_256(e) ASC LIMIT 1', ore_term), - -- '1'); - END; -$$ LANGUAGE plpgsql; +-- SKIP THIS TEST +-- Individual term operators are currently disabled because we may not need them anymore + + +-- DO $$ +-- DECLARE +-- e eql_v2_encrypted; +-- ore_term eql_v2_encrypted; +-- BEGIN +-- SELECT ore.e FROM ore WHERE id = 42 INTO ore_term; + +-- PERFORM assert_count( +-- 'ORDER BY eql_v2.ore_block_u64_8_256(e) DESC', +-- format('SELECT id FROM ore WHERE e < %L ORDER BY eql_v2.ore_block_u64_8_256(e) DESC', ore_term), +-- 41); + +-- PERFORM assert_result( +-- 'ORDER BY eql_v2.ore_block_u64_8_256(e) DESC returns correct record', +-- format('SELECT id FROM ore WHERE e < %L ORDER BY eql_v2.ore_block_u64_8_256(e) DESC LIMIT 1', ore_term), +-- '41'); + +-- PERFORM assert_result( +-- 'ORDER BY eql_v2.ore_block_u64_8_256(e) ASC', +-- format('SELECT id FROM ore WHERE e < %L ORDER BY eql_v2.ore_block_u64_8_256(e) ASC LIMIT 1', ore_term), +-- '1'); +-- END; +-- $$ LANGUAGE plpgsql; diff --git a/src/ore_block_u64_8_256/operator_class.sql b/src/ore_block_u64_8_256/operator_class.sql index 5bacc27..e4156ff 100644 --- a/src/ore_block_u64_8_256/operator_class.sql +++ b/src/ore_block_u64_8_256/operator_class.sql @@ -1,13 +1,16 @@ --- REQUIRE: src/schema.sql --- REQUIRE: src/ore_block_u64_8_256/types.sql +-- NOTE FILE IS DISABLED +-- REPLACE `!REQUIRE` with `REQUIRE` to enable in the build +-- !REQUIRE: src/schema.sql +-- !REQUIRE: src/ore_block_u64_8_256/types.sql -CREATE OPERATOR FAMILY eql_v2.ore_block_u64_8_256_btree_ops USING btree; -CREATE OPERATOR CLASS eql_v2.ore_block_u64_8_256_btree_ops DEFAULT FOR TYPE eql_v2.ore_block_u64_8_256 USING btree FAMILY eql_v2.ore_block_u64_8_256_btree_ops AS +CREATE OPERATOR FAMILY eql_v2.ore_block_u64_8_256_operator_family USING btree; + +CREATE OPERATOR CLASS eql_v2.ore_block_u64_8_256_operator_class DEFAULT FOR TYPE eql_v2.ore_block_u64_8_256 USING btree FAMILY eql_v2.ore_block_u64_8_256_operator_family AS OPERATOR 1 <, OPERATOR 2 <=, OPERATOR 3 =, OPERATOR 4 >=, OPERATOR 5 >, - FUNCTION 1 eql_v2.compare_ore_block_u64_8_256(a eql_v2.ore_block_u64_8_256, b eql_v2.ore_block_u64_8_256); + FUNCTION 1 eql_v2.compare_ore_block_u64_8_256_terms(a eql_v2.ore_block_u64_8_256, b eql_v2.ore_block_u64_8_256); diff --git a/src/ore_block_u64_8_256/operators.sql b/src/ore_block_u64_8_256/operators.sql index 806cb8a..1f923a0 100644 --- a/src/ore_block_u64_8_256/operators.sql +++ b/src/ore_block_u64_8_256/operators.sql @@ -1,47 +1,49 @@ --- REQUIRE: src/schema.sql --- REQUIRE: src/crypto.sql --- REQUIRE: src/ore_block_u64_8_256/types.sql --- REQUIRE: src/ore_block_u64_8_256/functions.sql +-- NOTE FILE IS DISABLED +-- REPLACE `!REQUIRE` with `REQUIRE` to enable in the build +-- !REQUIRE: src/schema.sql +-- !REQUIRE: src/crypto.sql +-- !REQUIRE: src/ore_block_u64_8_256/types.sql +-- !REQUIRE: src/ore_block_u64_8_256/functions.sql CREATE FUNCTION eql_v2.ore_block_u64_8_256_eq(a eql_v2.ore_block_u64_8_256, b eql_v2.ore_block_u64_8_256) RETURNS boolean AS $$ - SELECT eql_v2.compare_ore_block_u64_8_256(a, b) = 0 + SELECT eql_v2.compare_ore_block_u64_8_256_terms(a, b) = 0 $$ LANGUAGE SQL; CREATE FUNCTION eql_v2.ore_block_u64_8_256_neq(a eql_v2.ore_block_u64_8_256, b eql_v2.ore_block_u64_8_256) RETURNS boolean AS $$ - SELECT eql_v2.compare_ore_block_u64_8_256(a, b) <> 0 + SELECT eql_v2.compare_ore_block_u64_8_256_terms(a, b) <> 0 $$ LANGUAGE SQL; CREATE FUNCTION eql_v2.ore_block_u64_8_256_lt(a eql_v2.ore_block_u64_8_256, b eql_v2.ore_block_u64_8_256) RETURNS boolean AS $$ - SELECT eql_v2.compare_ore_block_u64_8_256(a, b) = -1 + SELECT eql_v2.compare_ore_block_u64_8_256_terms(a, b) = -1 $$ LANGUAGE SQL; CREATE FUNCTION eql_v2.ore_block_u64_8_256_lte(a eql_v2.ore_block_u64_8_256, b eql_v2.ore_block_u64_8_256) RETURNS boolean AS $$ - SELECT eql_v2.compare_ore_block_u64_8_256(a, b) != 1 + SELECT eql_v2.compare_ore_block_u64_8_256_terms(a, b) != 1 $$ LANGUAGE SQL; CREATE FUNCTION eql_v2.ore_block_u64_8_256_gt(a eql_v2.ore_block_u64_8_256, b eql_v2.ore_block_u64_8_256) RETURNS boolean AS $$ - SELECT eql_v2.compare_ore_block_u64_8_256(a, b) = 1 + SELECT eql_v2.compare_ore_block_u64_8_256_terms(a, b) = 1 $$ LANGUAGE SQL; CREATE FUNCTION eql_v2.ore_block_u64_8_256_gte(a eql_v2.ore_block_u64_8_256, b eql_v2.ore_block_u64_8_256) RETURNS boolean AS $$ - SELECT eql_v2.compare_ore_block_u64_8_256(a, b) != -1 + SELECT eql_v2.compare_ore_block_u64_8_256_terms(a, b) != -1 $$ LANGUAGE SQL; diff --git a/src/ore_cllw_u64_8/compare.sql b/src/ore_cllw_u64_8/compare.sql new file mode 100644 index 0000000..d590883 --- /dev/null +++ b/src/ore_cllw_u64_8/compare.sql @@ -0,0 +1,54 @@ +-- REQUIRE: src/schema.sql +-- REQUIRE: src/ore_cllw_u64_8/types.sql +-- REQUIRE: src/ore_cllw_u64_8/functions.sql + + +CREATE FUNCTION eql_v2.compare_ore_cllw_u64_8(a eql_v2_encrypted, b eql_v2_encrypted) + RETURNS integer + IMMUTABLE STRICT PARALLEL SAFE +AS $$ + DECLARE + a_term eql_v2.ore_cllw_u64_8; + b_term eql_v2.ore_cllw_u64_8; + BEGIN + + -- PERFORM eql_v2.log('eql_v2.compare_ore_cllw_u64_8'); + -- PERFORM eql_v2.log('a', a::text); + -- PERFORM eql_v2.log('b', b::text); + + IF a IS NULL AND b IS NULL THEN + RETURN 0; + END IF; + + IF a IS NULL THEN + RETURN -1; + END IF; + + IF b IS NULL THEN + RETURN 1; + END IF; + + IF eql_v2.has_ore_cllw_u64_8(a) THEN + a_term := eql_v2.ore_cllw_u64_8(a); + END IF; + + IF eql_v2.has_ore_cllw_u64_8(a) THEN + b_term := eql_v2.ore_cllw_u64_8(b); + END IF; + + IF a_term IS NULL AND b_term IS NULL THEN + RETURN 0; + END IF; + + IF a_term IS NULL THEN + RETURN -1; + END IF; + + IF b_term IS NULL THEN + RETURN 1; + END IF; + + RETURN eql_v2.compare_ore_cllw_term_bytes(a_term.bytes, b_term.bytes); + END; +$$ LANGUAGE plpgsql; + diff --git a/src/ore_cllw_u64_8/compare_test.sql b/src/ore_cllw_u64_8/compare_test.sql new file mode 100644 index 0000000..d9219b9 --- /dev/null +++ b/src/ore_cllw_u64_8/compare_test.sql @@ -0,0 +1,29 @@ +\set ON_ERROR_STOP on + +DO $$ + DECLARE + a eql_v2_encrypted; + b eql_v2_encrypted; + c eql_v2_encrypted; + BEGIN + + -- {"number": {N}} + -- $.number: 3dba004f4d7823446e7cb71f6681b344 + a := eql_v2.jsonb_path_query(create_encrypted_ste_vec_json(1), '3dba004f4d7823446e7cb71f6681b344'); + b := eql_v2.jsonb_path_query(create_encrypted_ste_vec_json(5), '3dba004f4d7823446e7cb71f6681b344'); + c := eql_v2.jsonb_path_query(create_encrypted_ste_vec_json(10), '3dba004f4d7823446e7cb71f6681b344'); + + ASSERT eql_v2.compare_ore_cllw_u64_8(a, a) = 0; + ASSERT eql_v2.compare_ore_cllw_u64_8(a, b) = -1; + ASSERT eql_v2.compare_ore_cllw_u64_8(a, c) = -1; + + ASSERT eql_v2.compare_ore_cllw_u64_8(b, b) = 0; + ASSERT eql_v2.compare_ore_cllw_u64_8(b, a) = 1; + ASSERT eql_v2.compare_ore_cllw_u64_8(b, c) = -1; + + ASSERT eql_v2.compare_ore_cllw_u64_8(c, c) = 0; + ASSERT eql_v2.compare_ore_cllw_u64_8(c, b) = 1; + ASSERT eql_v2.compare_ore_cllw_u64_8(c, a) = 1; + END; +$$ LANGUAGE plpgsql; + diff --git a/src/ore_cllw_u64_8/functions.sql b/src/ore_cllw_u64_8/functions.sql index 4a2593f..3732f7c 100644 --- a/src/ore_cllw_u64_8/functions.sql +++ b/src/ore_cllw_u64_8/functions.sql @@ -68,16 +68,24 @@ $$ LANGUAGE plpgsql; -- Used by both fixed and variable ore cllw variants -- -CREATE FUNCTION eql_v2.compare_ore_cllw(a bytea, b bytea) +CREATE FUNCTION eql_v2.compare_ore_cllw_term_bytes(a bytea, b bytea) RETURNS int AS $$ DECLARE len_a INT; + len_b INT; x BYTEA; y BYTEA; i INT; - differing RECORD; + differing boolean; BEGIN + + -- Check if the lengths of the two bytea arguments are the same len_a := LENGTH(a); + len_b := LENGTH(b); + + IF len_a != len_b THEN + RAISE EXCEPTION 'ore_cllw index terms are not the same length'; + END IF; -- Iterate over each byte and compare them FOR i IN 1..len_a LOOP @@ -86,13 +94,13 @@ BEGIN -- Check if there's a difference IF x != y THEN - differing := (x, y); + differing := true; EXIT; END IF; END LOOP; -- If a difference is found, compare the bytes as in Rust logic - IF differing IS NOT NULL THEN + IF differing THEN IF (get_byte(y, 0) + 1) % 256 = get_byte(x, 0) THEN RETURN 1; ELSE @@ -105,27 +113,3 @@ END; $$ LANGUAGE plpgsql; - - -CREATE FUNCTION eql_v2.compare_ore_cllw_u64_8(a eql_v2.ore_cllw_u64_8, b eql_v2.ore_cllw_u64_8) -RETURNS int AS $$ -DECLARE - len_a INT; - len_b INT; -BEGIN - IF a IS NULL OR b IS NULL THEN - RETURN NULL; - END IF; - - -- Check if the lengths of the two bytea arguments are the same - len_a := LENGTH(a.bytes); - len_b := LENGTH(b.bytes); - - IF len_a != len_b THEN - RAISE EXCEPTION 'ore_cllw_u64_8 index terms are not the same length'; - END IF; - - RETURN eql_v2.compare_ore_cllw(a.bytes, b.bytes); -END; -$$ LANGUAGE plpgsql; - diff --git a/src/ore_cllw_u64_8/operator_class.sql b/src/ore_cllw_u64_8/operator_class.sql.skip similarity index 63% rename from src/ore_cllw_u64_8/operator_class.sql rename to src/ore_cllw_u64_8/operator_class.sql.skip index 015fa31..5567977 100644 --- a/src/ore_cllw_u64_8/operator_class.sql +++ b/src/ore_cllw_u64_8/operator_class.sql.skip @@ -1,7 +1,10 @@ --- REQUIRE: src/schema.sql --- REQUIRE: src/ore_cllw_u64_8/types.sql --- REQUIRE: src/ore_cllw_u64_8/functions.sql --- REQUIRE: src/ore_cllw_u64_8/operators.sql +-- NOTE FILE IS DISABLED +-- REPLACE `!REQUIRE` with `REQUIRE` to enable in the build + +-- !REQUIRE: src/schema.sql +-- !REQUIRE: src/ore_cllw_u64_8/types.sql +-- !REQUIRE: src/ore_cllw_u64_8/functions.sql +-- !REQUIRE: src/ore_cllw_u64_8/operators.sql diff --git a/src/ore_cllw_u64_8/operators.sql b/src/ore_cllw_u64_8/operators.sql.skip similarity index 91% rename from src/ore_cllw_u64_8/operators.sql rename to src/ore_cllw_u64_8/operators.sql.skip index d11d18f..266eb9f 100644 --- a/src/ore_cllw_u64_8/operators.sql +++ b/src/ore_cllw_u64_8/operators.sql.skip @@ -1,7 +1,10 @@ --- REQUIRE: src/schema.sql --- REQUIRE: src/common.sql --- REQUIRE: src/ore_cllw_u64_8/types.sql --- REQUIRE: src/ore_cllw_u64_8/functions.sql +-- NOTE FILE IS DISABLED +-- REPLACE `!REQUIRE` with `REQUIRE` to enable in the build + +-- !REQUIRE: src/schema.sql +-- !REQUIRE: src/common.sql +-- !REQUIRE: src/ore_cllw_u64_8/types.sql +-- !REQUIRE: src/ore_cllw_u64_8/functions.sql CREATE FUNCTION eql_v2.ore_cllw_u64_8_eq(a eql_v2.ore_cllw_u64_8, b eql_v2.ore_cllw_u64_8) diff --git a/src/ore_cllw_u64_8/operators_test.sql b/src/ore_cllw_u64_8/operators_test.sql.skip similarity index 100% rename from src/ore_cllw_u64_8/operators_test.sql rename to src/ore_cllw_u64_8/operators_test.sql.skip diff --git a/src/ore_cllw_var_8/compare.sql b/src/ore_cllw_var_8/compare.sql new file mode 100644 index 0000000..85740f2 --- /dev/null +++ b/src/ore_cllw_var_8/compare.sql @@ -0,0 +1,54 @@ +-- REQUIRE: src/schema.sql +-- REQUIRE: src/ore_cllw_u64_8/types.sql +-- REQUIRE: src/ore_cllw_u64_8/functions.sql + + +CREATE FUNCTION eql_v2.compare_ore_cllw_var_8(a eql_v2_encrypted, b eql_v2_encrypted) + RETURNS integer + IMMUTABLE STRICT PARALLEL SAFE +AS $$ + DECLARE + a_term eql_v2.ore_cllw_var_8; + b_term eql_v2.ore_cllw_var_8; + BEGIN + + -- PERFORM eql_v2.log('eql_v2.compare_ore_cllw_var_8'); + -- PERFORM eql_v2.log('a', a::text); + -- PERFORM eql_v2.log('b', b::text); + + IF a IS NULL AND b IS NULL THEN + RETURN 0; + END IF; + + IF a IS NULL THEN + RETURN -1; + END IF; + + IF b IS NULL THEN + RETURN 1; + END IF; + + IF eql_v2.has_ore_cllw_var_8(a) THEN + a_term := eql_v2.ore_cllw_var_8(a); + END IF; + + IF eql_v2.has_ore_cllw_var_8(a) THEN + b_term := eql_v2.ore_cllw_var_8(b); + END IF; + + IF a_term IS NULL AND b_term IS NULL THEN + RETURN 0; + END IF; + + IF a_term IS NULL THEN + RETURN -1; + END IF; + + IF b_term IS NULL THEN + RETURN 1; + END IF; + + RETURN eql_v2.compare_ore_cllw_var_8_term(a_term, b_term); + END; +$$ LANGUAGE plpgsql; + diff --git a/src/ore_cllw_var_8/compare_test.sql b/src/ore_cllw_var_8/compare_test.sql new file mode 100644 index 0000000..fa9af42 --- /dev/null +++ b/src/ore_cllw_var_8/compare_test.sql @@ -0,0 +1,29 @@ +\set ON_ERROR_STOP on + +DO $$ + DECLARE + a eql_v2_encrypted; + b eql_v2_encrypted; + c eql_v2_encrypted; + BEGIN + + -- {"hello": "world{N}"} + -- $.hello: d90b97b5207d30fe867ca816ed0fe4a7 + a := eql_v2.jsonb_path_query(create_encrypted_ste_vec_json(1), 'd90b97b5207d30fe867ca816ed0fe4a7'); + b := eql_v2.jsonb_path_query(create_encrypted_ste_vec_json(2), 'd90b97b5207d30fe867ca816ed0fe4a7'); + c := eql_v2.jsonb_path_query(create_encrypted_ste_vec_json(3), 'd90b97b5207d30fe867ca816ed0fe4a7'); + + ASSERT eql_v2.compare_ore_cllw_var_8(a, a) = 0; + ASSERT eql_v2.compare_ore_cllw_var_8(a, b) = -1; + ASSERT eql_v2.compare_ore_cllw_var_8(a, c) = -1; + + ASSERT eql_v2.compare_ore_cllw_var_8(b, b) = 0; + ASSERT eql_v2.compare_ore_cllw_var_8(b, a) = 1; + ASSERT eql_v2.compare_ore_cllw_var_8(b, c) = -1; + + ASSERT eql_v2.compare_ore_cllw_var_8(c, c) = 0; + ASSERT eql_v2.compare_ore_cllw_var_8(c, b) = 1; + ASSERT eql_v2.compare_ore_cllw_var_8(c, a) = 1; + END; +$$ LANGUAGE plpgsql; + diff --git a/src/ore_cllw_var_8/functions.sql b/src/ore_cllw_var_8/functions.sql index 8e33f87..483d7c9 100644 --- a/src/ore_cllw_var_8/functions.sql +++ b/src/ore_cllw_var_8/functions.sql @@ -62,7 +62,7 @@ AS $$ $$ LANGUAGE plpgsql; -CREATE FUNCTION eql_v2.compare_ore_cllw_var_8(a eql_v2.ore_cllw_var_8, b eql_v2.ore_cllw_var_8) +CREATE FUNCTION eql_v2.compare_ore_cllw_var_8_term(a eql_v2.ore_cllw_var_8, b eql_v2.ore_cllw_var_8) RETURNS int AS $$ DECLARE len_a INT; @@ -95,8 +95,8 @@ BEGIN common_len := len_b; END IF; - -- Use the compare_bytea function to compare byte by byte - cmp_result := eql_v2.compare_ore_cllw( + -- Use the compare_ore_cllw_term function to compare byte by byte + cmp_result := eql_v2.compare_ore_cllw_term_bytes( SUBSTRING(a.bytes FROM 1 FOR common_len), SUBSTRING(b.bytes FROM 1 FOR common_len) ); diff --git a/src/ore_cllw_var_8/operator_class.sql b/src/ore_cllw_var_8/operator_class.sql.skip similarity index 65% rename from src/ore_cllw_var_8/operator_class.sql rename to src/ore_cllw_var_8/operator_class.sql.skip index c6db0f1..050d1fe 100644 --- a/src/ore_cllw_var_8/operator_class.sql +++ b/src/ore_cllw_var_8/operator_class.sql.skip @@ -1,8 +1,10 @@ --- REQUIRE: src/schema.sql --- REQUIRE: src/ore_cllw_var_8/types.sql --- REQUIRE: src/ore_cllw_var_8/functions.sql --- REQUIRE: src/ore_cllw_var_8/operators.sql +-- NOTE FILE IS DISABLED +-- REPLACE `!REQUIRE` with `REQUIRE` to enable in the build +-- !REQUIRE: src/schema.sql +-- !REQUIRE: src/ore_cllw_var_8/types.sql +-- !REQUIRE: src/ore_cllw_var_8/functions.sql +-- !REQUIRE: src/ore_cllw_var_8/operators.sql CREATE OPERATOR FAMILY eql_v2.ore_cllw_var_8_variable_btree_ops USING btree; diff --git a/src/ore_cllw_var_8/operators.sql b/src/ore_cllw_var_8/operators.sql.skip similarity index 93% rename from src/ore_cllw_var_8/operators.sql rename to src/ore_cllw_var_8/operators.sql.skip index 697fdc2..0e5e3bc 100644 --- a/src/ore_cllw_var_8/operators.sql +++ b/src/ore_cllw_var_8/operators.sql.skip @@ -1,10 +1,10 @@ --- REQUIRE: src/ore_cllw_var_8/types.sql --- REQUIRE: src/ore_cllw_var_8/functions.sql +-- NOTE FILE IS DISABLED +-- REPLACE `!REQUIRE` with `REQUIRE` to enable in the build +-- !REQUIRE: src/ore_cllw_var_8/types.sql +-- !REQUIRE: src/ore_cllw_var_8/functions.sql --- Lexical comparison operators - CREATE OR REPLACE FUNCTION eql_v2.ore_cllw_var_8_eq(a eql_v2.ore_cllw_var_8, b eql_v2.ore_cllw_var_8) RETURNS boolean AS $$ SELECT eql_v2.bytea_eq(a.bytes, b.bytes) diff --git a/src/ore_cllw_var_8/operators_test.sql b/src/ore_cllw_var_8/operators_test_skip.sql.skip similarity index 100% rename from src/ore_cllw_var_8/operators_test.sql rename to src/ore_cllw_var_8/operators_test_skip.sql.skip diff --git a/tasks/test.sh b/tasks/test.sh index eb68300..1db94ac 100755 --- a/tasks/test.sh +++ b/tasks/test.sh @@ -38,22 +38,28 @@ fail_if_postgres_not_running mise run build --force mise run reset --force --postgres ${POSTGRES_VERSION} +echo +echo '###############################################' +echo '# Installing release/cipherstash-encrypt.sql' +echo '###############################################' +echo # Install -# cat release/cipherstash-encrypt.sql | docker exec -i ${container_name} psql ${connection_url} -f- -if cat release/cipherstash-encrypt.sql | docker exec -i ${container_name} psql ${connection_url} -f- | grep -q "ERROR"; then - echo - echo '******************************************************' - echo '* ❌ ERROR installing release/cipherstash-encrypt.sql' - echo '******************************************************' - echo +cat release/cipherstash-encrypt.sql | docker exec -i ${container_name} psql ${connection_url} -f- +# if cat release/cipherstash-encrypt.sql | docker exec -i ${container_name} psql ${connection_url} -f- | grep -q "ERROR"; then +# echo +# echo '******************************************************' +# echo '* ❌ ERROR installing release/cipherstash-encrypt.sql' +# echo '******************************************************' +# echo - exit 1 -fi +# exit 1 +# fi cat tests/test_helpers.sql | docker exec -i ${container_name} psql ${connection_url} -f- cat tests/ore.sql | docker exec -i ${container_name} psql ${connection_url} -f- +cat tests/ste_vec.sql | docker exec -i ${container_name} psql ${connection_url} -f- if [ $usage_test = "false" ]; then find src -type f -path "*_test.sql" | while read -r sql_file; do diff --git a/tests/ste_vec.sql b/tests/ste_vec.sql new file mode 100644 index 0000000..ea9feec --- /dev/null +++ b/tests/ste_vec.sql @@ -0,0 +1,43 @@ +DROP TABLE IF EXISTS ste_vec; +CREATE TABLE ste_vec +( + id bigint, + e eql_v2_encrypted, + PRIMARY KEY(id) +); + +-- Data generated as +-- +-- for x in 1..=10 { +-- let encrypted_jsonb = serde_json::json!({ +-- "hello": format!("world {}", x), +-- "number": x, +-- "nested": { +-- "number": random_id(), +-- "hello": format!("world {}", x), +-- } +-- }); +-- } + +-- SELECTORS +-- $.hello: d90b97b5207d30fe867ca816ed0fe4a7 +-- $.number: fa6f99753674e2e0db242dd805eacac8 + + +INSERT INTO ste_vec(id, e) VALUES (1, '{"c": "mBbL@V^%dN?0W$;g)1-JP*cmqX%JhW0ZKZ^G?lNn$CfXJH|W!V*=irNa@z{OfN`tJKpjgX(7ToG`HWORpeL^$zO*^J`x7KRuY0gW#{2OV?F-Z2rNIo9CWCgDOt!Fg2d-I_cW7ljFiM641$Ej6!A<1h!E%%1I5$YIE}thw=uucU|IEwG+k8(puh", "i": {"c": "encrypted_jsonb", "t": "encrypted"}, "v": 2, "sv": [{"a": false, "c": "mBbL@V^%dN?0W$;g)1-JP*cmqX%JhW0ZKZ^G?lNn$CfXJH|W!V*=irNa@z{OfN`tJKpjgX(7ToG`HWORpeL^$zO*^J`x7KRuY0gW#{2OV?F-Z2rNIo9CWCgDOt!Fg2d-I_cW7ljFiM641$Ej6!A<1h!E%%1I5$YIE}thw=uucU|IEwG+k8(puh", "s": "9493d6010fe7845d52149b697729c745", "b3": "8067db44a848ab32c3056a3dbe4edf16"}, {"a": false, "c": "mBbL@V^%dN?0W$;g)1-JP*cmq8w1tsgI>{D^0s{k=Kwcv$GK=wXj973J#%Qi#2^fUgv1o_OazD!=oJIS)7m(VzEQU^ztUh?^@=oIRR^HJ", "s": "d90b97b5207d30fe867ca816ed0fe4a7", "ocv": "fbc7a11fc81f2a321553bc06a91f240bb7d8f3a9c6aec445a5ba6793159989698eadf64ab9b3ab45c5366d027b2a5476a635ce6cad9eda1b"}, {"a": false, "c": "mBbL@V^%dN?0W$;g)1-JP*cmqK@;r|K5qT&!~f=;IrFg2#bT?wQ2^uT?MQ1vb$M{qdKJ&)IM{5qYVEjR-wUOWau*19aKGAhNSrAja?iC`)BMCB41$Ej6!A<1h!E%%1I5$YIE}thw=uucU|IEwG+k8(puh", "s": "3a9a5d5601369d00a92e851b5490d2d1", "b3": "6ab75dbd78d2b77f8675161ad8fddbe7"}, {"a": false, "c": "mBbL@V^%dN?0W$;g)1-JP*cmq8w1tsgI>{D^0s{k=Kwcv$GK=wXj973J#%Qi#2^fUgv1o_OazD!=oJIS)7m(VzEQU^ztUh?^@=oIRR^HJ", "s": "f3b937817818610f955b6bbbc337aa2b", "ocv": "fbc7a11fc81f2a321553bc06a91f240bb7d8f3a9c6aec445a5ba6793159989698eadf64ab9b3ab45c5366d027b2a5476a635ce6cad9eda1b"}, {"a": false, "c": "mBbL@V^%dN?0W$;g)1-JP*cmqBor4+`y>b|qoX{uNXP2XSf9UacD`690sM|6wY5xR^!82|E5slSf`r5r@k|7W5a<;H#nak2jlNO0F~8DaS@nuET~!C5zy", "s": "fa6f99753674e2e0db242dd805eacac8", "ocf": "fc6a9c6533b34219a300d82916e71a4955a48b208969eaf4dec0b88477b753fce8e31613f296a3ebc3dc428912fffa10ad58ef698631b5a3a8ec0a53593fbae5"}, {"a": false, "c": "mBbL@V^%dN?0W$;g)1-JP*cmq6X0HB3o?jM)H&5-v7zt=j&nB7f>vGiA$|Xx3CMyn3~nC&!m2n|FsTD7A$Vznv5KN&ZD;2AYnEe)S~DtWX{85Bby<_1V+JAQ#4iCfmE5R8de-4qZ}xLQgnq2A0{V^??Z>lfCrxAE3Y", "i": {"c": "encrypted_jsonb", "t": "encrypted"}, "v": 2, "sv": [{"a": false, "c": "mBbKA;2~_|&h787#WXU&=nqH4YPl!<%e}R}?ZZ86dK=XLlHmD4+@YpqE*k$Nnhnq|L3yhQ@WgNE0P94mCuT5Y>=j&nB7f>vGiA$|Xx3CMyn3~nC&!m2n|FsTD7A$Vznv5KN&ZD;2AYnEe)S~DtWX{85Bby<_1V+JAQ#4iCfmE5R8de-4qZ}xLQgnq2A0{V^??Z>lfCrxAE3Y", "s": "9493d6010fe7845d52149b697729c745", "b3": "8067db44a848ab32c3056a3dbe4edf16"}, {"a": false, "c": "mBbKA;2~_|&h787#WXU&=nqH48zV_I^FE9E$Tx^Bh>*L$Z3UaiidiIG8f6-J#2^>OgC^U%oK#UzQ4U>FeL_z-Y6h0ssP%yfAd|iH^dF$W", "s": "d90b97b5207d30fe867ca816ed0fe4a7", "ocv": "fbc7a11fc81f2a321553bc06a91f240bb7d8f3a9c6aec445a5ba6793159989698eadf64ab9b3ab45c5366d027b2a5476a635ce6cad9edbca"}, {"a": false, "c": "mBbKA;2~_|&h787#WXU&=nqH4LKI%yI#+SZ>%7r@cMkI#>B`Y@g%m&?_;qLaZhOY{yIKN|aPs2dC}n9ugdf8Jtw6L@OO2~2$4fWO5Ld;)=aR3)AQ#4iCfmE5R8de-4qZ}xLQgnq2A0{V^??Z>lfCrxAE3Y", "s": "3a9a5d5601369d00a92e851b5490d2d1", "b3": "6ab75dbd78d2b77f8675161ad8fddbe7"}, {"a": false, "c": "mBbKA;2~_|&h787#WXU&=nqH48zV_I^FE9E$Tx^Bh>*L$Z3UaiidiIG8f6-J#2^>OgC^U%oK#UzQ4U>FeL_z-Y6h0ssP%yfAd|iH^dF$W", "s": "f3b937817818610f955b6bbbc337aa2b", "ocv": "fbc7a11fc81f2a321553bc06a91f240bb7d8f3a9c6aec445a5ba6793159989698eadf64ab9b3ab45c5366d027b2a5476a635ce6cad9edbca"}, {"a": false, "c": "mBbKA;2~_|&h787#WXU&=nqH4C6`I)f|7H0_iUN!sI%p|PD^%)I3u@>Lo)l>D^FTEHMX_T`5(j}7si7o+q;}pQBYA1T~d8QPdI7@mf5KFfe9d!z4Y`Spuh", "s": "fa6f99753674e2e0db242dd805eacac8", "ocf": "fc6a9c6533b34219a3018e1c9ce9330c0e754864cd7341d488ae3fc464cdd85f73b1e9aabab2d18c8de2de82052d5ec9e8c906ef5d082a34b5a4e63234a2f831"}, {"a": false, "c": "mBbKA;2~_|&h787#WXU&=nqH46KPW9$J3a=|Jqzg_kinIG(B$L#2^>OgC^U%oK#UzQ4U>FeL_z-Y6h0ssP%yfAd|iH^dF$W", "s": "3dba004f4d7823446e7cb71f6681b344", "ocf": "fc6a9c6533b341a3bbe1d7eefbfe3457e74c9c4dcde2c1d40fafa6fe7bfe1cf225871f30f428f65a348062433db703d77583587a42443a1808d112f0514f0262"}]}'::jsonb::eql_v2_encrypted); +INSERT INTO ste_vec(id, e) VALUES (3, '{"c": "mBbJ&V+<+WNnWTGaHg#Y!CMH#YUj70Cz_B24U3#W#b#KGw1<@cS7(S0Ce|x{!!At-Epo5#C-8ZJATrn?7A$@`(u>=$?2X*e=$?2X*e1UcJ`#2{On(Eq~PZP7^Gu{SL7X*)sN#Y!JpxT_uu4UfmrWp|*!", "s": "d90b97b5207d30fe867ca816ed0fe4a7", "ocv": "fbc7a11fc81f2a321553bc06a91f240bb7d8f3a9c6aec445a5ba6793159989698eadf64ab9b3ab45c5366d027b2a5476a635ce6cad9edbcb"}, {"a": false, "c": "mBbJ&V+<+WNnWTGaHg#Y!CMH#Li)6dAJoLZZs|CbiZstYT&vn}P=yVCm1M9YnMJisIv8CoL6Tzth(-874C)8j_qYuX4Fv>J<<09@x_=DyfRUxdAX}Tz|H9gB(Ma8~H!SgKJ3-sUN*`Ics~!stkH^qucc8!", "s": "3a9a5d5601369d00a92e851b5490d2d1", "b3": "6ab75dbd78d2b77f8675161ad8fddbe7"}, {"a": false, "c": "mBbJ&V+<+WNnWTGaHg#Y!CMH#8-dM231ayoGQIzTv|n<6^Uo7QSi`z>1UcJ`#2{On(Eq~PZP7^Gu{SL7X*)sN#Y!JpxT_uu4UfmrWp|*!", "s": "f3b937817818610f955b6bbbc337aa2b", "ocv": "fbc7a11fc81f2a321553bc06a91f240bb7d8f3a9c6aec445a5ba6793159989698eadf64ab9b3ab45c5366d027b2a5476a635ce6cad9edbcb"}, {"a": false, "c": "mBbJ&V+<+WNnWTGaHg#Y!CMH#B}MUqDEGI9$OIF8zdRu#08c>I+EsdWf96+dkZC%<3u9$EKb~W)de42&14s2=>FoXlMb%ApcgZX1WmCNxJ>3Blt#*(|HBaC%<3u9$EKb~W)de42&14s2=>FoXlMb%ApcgZX1WmCNxJ>3Blt#*(|HBayw2*id#80AgNqT0K#327xtY*3p+DW?ot0VYEjnjDr(d5XNQ4npH3R?^aEq$QC", "s": "d90b97b5207d30fe867ca816ed0fe4a7", "ocv": "fbc7a11fc81f2a321553bc06a91f240bb7d8f3a9c6aec445a5ba6793159989698eadf64ab9b3ab45c5366d027b2a5476a635ce6cad9f41f8"}, {"a": false, "c": "mBbM9-awLU6awLQJTS5Buj8R|QNY+p4aeSYRGzixBKRP(>$YGm-@6u=+OF_wtB8QA|boP=&$^#B;c1>9aoy)SsApcgZX1WmCNxJ>3Blt#*(|HBayw2*id#80AgNqT0K#327xtY*3p+DW?ot0VYEjnjDr(d5XNQ4npH3R?^aEq$QC", "s": "f3b937817818610f955b6bbbc337aa2b", "ocv": "fbc7a11fc81f2a321553bc06a91f240bb7d8f3a9c6aec445a5ba6793159989698eadf64ab9b3ab45c5366d027b2a5476a635ce6cad9f41f8"}, {"a": false, "c": "mBbM9-awLU6ac?Hqr$d^$NZI=pL3Kt4RJ*8LO2XQqL+Pqd_9s0vN<&V}uKTbz)(?Kb4+xpBxMa;Y2+`wxSdOU}4O~cKwn`(-AcBj{+j{1przTWjt<01cd^h(Fa;pBD=0k9``h@8OPcTs5t(bz$Ve*;3X1KV6FnhAWrE)*M{J-nozAcDun97I9)DC61}WC4g$Z=r!U$ho1nk", "i": {"c": "encrypted_jsonb", "t": "encrypted"}, "v": 2, "sv": [{"a": false, "c": "mBbJZA|9c2`{Osnrra?Hj)cv`YFJ>Kt4RJ*8LO2XQqL+Pqd_9s0vN<&V}uKTbz)(?Kb4+xpBxMa;Y2+`wxSdOU}4O~cKwn`(-AcBj{+j{1przTWjt<01cd^h(Fa;pBD=0k9``h@8OPcTs5t(bz$Ve*;3X1KV6FnhAWrE)*M{J-nozAcDun97I9)DC61}WC4g$Z=r!U$ho1nk", "s": "9493d6010fe7845d52149b697729c745", "b3": "8067db44a848ab32c3056a3dbe4edf16"}, {"a": false, "c": "mBbJZA|9c2`{Osnrra?Hj)cv`8vu0{XK}SSyw%$>)p?C8#My;w6W3&4h>M!|#2`-TLDz=hvYJq>I4Xqd!Z=+nND{rQIt~KA&!;ciB%7eX", "s": "d90b97b5207d30fe867ca816ed0fe4a7", "ocv": "fbc7a11fc81f2a321553bc06a91f240bb7d8f3a9c6aec445a5ba6793159989698eadf64ab9b3ab45c5366d027b2a5476a635ce6cad9f41f9"}, {"a": false, "c": "mBbJZA|9c2`{Osnrra?Hj)cv`LjQ)X$p_~llv&x~<)hiIe5|*>Hc1Zkglk(`D>cnLbBrE07YBC9SR?ZTg}77_!tjaq#%1r4K6AOUpGDKT5L`OMAWrE)*M{J-nozAcDun97I9)DC61}WC4g$Z=r!U$ho1nk", "s": "3a9a5d5601369d00a92e851b5490d2d1", "b3": "6ab75dbd78d2b77f8675161ad8fddbe7"}, {"a": false, "c": "mBbJZA|9c2`{Osnrra?Hj)cv`8vu0{XK}SSyw%$>)p?C8#My;w6W3&4h>M!|#2`-TLDz=hvYJq>I4Xqd!Z=+nND{rQIt~KA&!;ciB%7eX", "s": "f3b937817818610f955b6bbbc337aa2b", "ocv": "fbc7a11fc81f2a321553bc06a91f240bb7d8f3a9c6aec445a5ba6793159989698eadf64ab9b3ab45c5366d027b2a5476a635ce6cad9f41f9"}, {"a": false, "c": "mBbJZA|9c2`{Osnrra?Hj)cv`C06PttDegliI%ijveChO?CCfOY;nXOPU%6{hTyWAP^~yBgzCaLT`ouxy{tM80>96vFWMxVpuh", "s": "fa6f99753674e2e0db242dd805eacac8", "ocf": "fc6a9c6533b34219a3018e1d533343a282b879ce470722cfe6ae36688b2de8d685a395d6c555b720db3eed0042fdaa8ee6403fc3ba8c3f7d423f8821a1228fd7"}, {"a": false, "c": "mBbJZA|9c2`{Osnrra?Hj)cv`6LBDt#>7UH2q|VZbg%~lyV4vB#2`-TLDz=hvYJq>I4Xqd!Z=+nND{rQIt~KA&!;ciB%7eX", "s": "3dba004f4d7823446e7cb71f6681b344", "ocf": "fc6a9c6533b341a3bbe1d7ef077cf858f5582688ede7a88e44522be9ea2a62f87707519a1c76b54b5da3193f77db9531dc887dcedafebc8135ccf8028cf38614"}]}'::jsonb::eql_v2_encrypted); +INSERT INTO ste_vec(id, e) VALUES (6, '{"c": "mBbKU&X2H2TUi~T2sQBASNTOjoiQuI`BLc){G*FRsQBASNTOjoiQuI`BLc){G*FR;1W;<^)-g>TjwP+P;@y+w6)=8kCzp#2_Xku8rKl4La~V6xNI)iB_+`Tn8b$&_I`G&=n39;1W;<^)-g>TjwP+P;@y+w6)=8kCzp#2_Xku8rKl4La~V6xNI)iB_+puh", "s": "fa6f99753674e2e0db242dd805eacac8", "ocf": "fc6a9c6533b34219a3018e1c9ce932bd1929ff8bed603031286d87dd98008307deac134ba0759bedd4b72bdb6c469b0c9bba850f0b9d6de69f941801d901593b"}, {"a": false, "c": "mBbKU&X2H2TUi~T2?knzEr&IQ4C}9_BKS`w@y=ZxMI61!?)?c%KqJ9^_Qhgfj$2Nd3!8skzc`58ed?&hAZ_oqHcY^@#&Q*hTu^_7Of|hoElmzGI;5NP!2kG~rl7z", "i": {"c": "encrypted_jsonb", "t": "encrypted"}, "v": 2, "sv": [{"a": false, "c": "mBbLWIPx0`a~GhoFvD#SK|+DVYWwCvQRgCtCmpM_Je~#b*?be!Od7*jT0qMGN)z(Xa`9*-nQ)h#h>?knzEr&IQ4C}9_BKS`w@y=ZxMI61!?)?c%KqJ9^_Qhgfj$2Nd3!8skzc`58ed?&hAZ_oqHcY^@#&Q*hTu^_7Of|hoElmzGI;5NP!2kG~rl7z", "s": "9493d6010fe7845d52149b697729c745", "b3": "8067db44a848ab32c3056a3dbe4edf16"}, {"a": false, "c": "mBbLWIPx0`a~GhoFvD#SK|+DV8)c(L(X9VOZ->csIkThDI`VV6a}NV%eDmLo#2{_&wl++_w8nB3hg?v9g-kWQNG(kcGCHK2^T7Z3nx>$@", "s": "d90b97b5207d30fe867ca816ed0fe4a7", "ocv": "fbc7a11fc81f2a321553bc06a91f240bb7d8f3a9c6aec445a5ba6793159989698eadf64ab9b3ab45c5366d027b2a5476a635ce6cad9f42bb"}, {"a": false, "c": "mBbLWIPx0`a~GhoFvD#SK|+DVLVlEEd!}1mw5-+>Q)|48N1ODPT`={zO||cAxQ=}b+yt(ANAX*$QWW-pHFGi-2HP^n=gIYsiH{C*(7KhBGYnV6AZ_oqHcY^@#&Q*hTu^_7Of|hoElmzGI;5NP!2kG~rl7z", "s": "3a9a5d5601369d00a92e851b5490d2d1", "b3": "6ab75dbd78d2b77f8675161ad8fddbe7"}, {"a": false, "c": "mBbLWIPx0`a~GhoFvD#SK|+DV8)c(L(X9VOZ->csIkThDI`VV6a}NV%eDmLo#2{_&wl++_w8nB3hg?v9g-kWQNG(kcGCHK2^T7Z3nx>$@", "s": "f3b937817818610f955b6bbbc337aa2b", "ocv": "fbc7a11fc81f2a321553bc06a91f240bb7d8f3a9c6aec445a5ba6793159989698eadf64ab9b3ab45c5366d027b2a5476a635ce6cad9f42bb"}, {"a": false, "c": "mBbLWIPx0`a~GhoFvD#SK|+DVCCe8R*C3LA0=X>OcfeqR8^WMRfsewr$X@D%aU(5LdkQQ9)o{chZSS@=Ou)3pautVMP=AF?HN8kJO%5_Tq?_}=|M;4wpuh", "s": "fa6f99753674e2e0db242dd805eacac8", "ocf": "fc6a9c6533b34219a3018e1d524d118ab347ae240e626857d0111d7f917bb3cd5339df72bafa18d30abbb947a81ad55fd0bd2482e24cb814470c42c13e06c5e8"}, {"a": false, "c": "mBbLWIPx0`a~GhoFvD#SK|+DV6UNb%E^11oJovsVsxVKcuBCqS#2{_&wl++_w8nB3hg?v9g-kWQNG(kcGCHK2^T7Z3nx>$@", "s": "3dba004f4d7823446e7cb71f6681b344", "ocf": "fc6a9c6533b341a3bbe1d7ef08cc248ae8d903e2c5b3872108e910e5e1abfd12b864110cf8c3f96068c2e22a91bd4a31fd576d914ab6f592b510a5d09303a113"}]}'::jsonb::eql_v2_encrypted); +INSERT INTO ste_vec(id, e) VALUES (8, '{"c": "mBbLU1c41)W9q|644h(&;v|K{Y9^G7d5DAJM-UtmtvJFD-rpm|!bIFbJ_38g6>L4JxCAzZqg;J~zXCHw&~>@%Qg;jo1i6*=>!NvDVAeB%BPNh0)fUgx(>_IJTLdje%|Tm3t350kkPVz)R1@HjcJH#rF5b0<0458>AfMQ%t`tCz*iE%8Q=~zakT$5-;E$Vz8_*^me1YEm>!82", "i": {"c": "encrypted_jsonb", "t": "encrypted"}, "v": 2, "sv": [{"a": false, "c": "mBbLU1c41)W9q|644h(&;v|K{Y9^G7d5DAJM-UtmtvJFD-rpm|!bIFbJ_38g6>L4JxCAzZqg;J~zXCHw&~>@%Qg;jo1i6*=>!NvDVAeB%BPNh0)fUgx(>_IJTLdje%|Tm3t350kkPVz)R1@HjcJH#rF5b0<0458>AfMQ%t`tCz*iE%8Q=~zakT$5-;E$Vz8_*^me1YEm>!82", "s": "9493d6010fe7845d52149b697729c745", "b3": "8067db44a848ab32c3056a3dbe4edf16"}, {"a": false, "c": "mBbLU1c41)W9q|644h(&;v|K{8(5Xe9m`5OZ4)XL??yheX-WGqH8&DwuvUEG#2}y8sIC-1kJwGMEK{UGm5?^5*Wizvh8xf(9(;k`{p+B>", "s": "d90b97b5207d30fe867ca816ed0fe4a7", "ocv": "fbc7a11fc81f2a321553bc06a91f240bb7d8f3a9c6aec445a5ba6793159989698eadf64ab9b3ab45c5366d027b2a5476a635ce6cae77a9e6"}, {"a": false, "c": "mBbLU1c41)W9q|644h(&;v|K{LTk1A!h2L`pi*@*IAxKZWEp&PvSNIeN9`O-dc<1;`<{tm3Q%w*bvChnGw`dMo9fQ$%6M)m|ANzcy^dAfMQ%t`tCz*iE%8Q=~zakT$5-;E$Vz8_*^me1YEm>!82", "s": "3a9a5d5601369d00a92e851b5490d2d1", "b3": "6ab75dbd78d2b77f8675161ad8fddbe7"}, {"a": false, "c": "mBbLU1c41)W9q|644h(&;v|K{8(5Xe9m`5OZ4)XL??yheX-WGqH8&DwuvUEG#2}y8sIC-1kJwGMEK{UGm5?^5*Wizvh8xf(9(;k`{p+B>", "s": "f3b937817818610f955b6bbbc337aa2b", "ocv": "fbc7a11fc81f2a321553bc06a91f240bb7d8f3a9c6aec445a5ba6793159989698eadf64ab9b3ab45c5366d027b2a5476a635ce6cae77a9e6"}, {"a": false, "c": "mBbLU1c41)W9q|644h(&;v|K{B`tAY7D@4_eh%C5;rHRnV+K)h-PvUiIy1vhxx%(@YHIJ|V0^?NpV+9b6hM#IO|>jjq(POCHmKL&kDG=Y&?X*yf!_V=puh", "s": "fa6f99753674e2e0db242dd805eacac8", "ocf": "fc6a9c6533b34219a3018e1c9dcaac4823035131d63437a90de98995d0a5f44efc2ec0a4768c718c7c76ffbc7cc5c79e3efe6333415f581fc6a9e9467c8bb509"}, {"a": false, "c": "mBbLU1c41)W9q|644h(&;v|K{6BUWiJXM;%", "s": "3dba004f4d7823446e7cb71f6681b344", "ocf": "fc6a9c6533b341a3bbe1d83c495c498ccdb757c8461e519fb5ad2db6ab3d3a7bd2c87b41fd9dcc07fb922e3f1defe81d04c975f73ca873531646f9693340d169"}]}'::jsonb::eql_v2_encrypted); +INSERT INTO ste_vec(id, e) VALUES (9, '{"c": "mBbK%Ks*MeKDAAsr>I~keTZAcYM9b4|8fb~$D>=F@t{DFHgI0-uESoh1vX`JD2W}wLQ{zT)bJN2)s~oVF-)ubVZ$cQL3PHK6aW_Imq>t*L5uP2iiJQ>>yrXQ9$79k+Csetm7#?HK9lde?+IWkkO%6dKy3qG&U^U8AUq1dArOMF>P%C%>Rmq|o~0(Ggse6t_Yr4zuoAT&_@KZ", "i": {"c": "encrypted_jsonb", "t": "encrypted"}, "v": 2, "sv": [{"a": false, "c": "mBbK%Ks*MeKDAAsr>I~keTZAcYM9b4|8fb~$D>=F@t{DFHgI0-uESoh1vX`JD2W}wLQ{zT)bJN2)s~oVF-)ubVZ$cQL3PHK6aW_Imq>t*L5uP2iiJQ>>yrXQ9$79k+Csetm7#?HK9lde?+IWkkO%6dKy3qG&U^U8AUq1dArOMF>P%C%>Rmq|o~0(Ggse6t_Yr4zuoAT&_@KZ", "s": "9493d6010fe7845d52149b697729c745", "b3": "8067db44a848ab32c3056a3dbe4edf16"}, {"a": false, "c": "mBbK%Ks*MeKDAAsr>I~keTZAc8$p9%O%q$urm@mN+n39d89A;-u7l&A-BbZG#2`Ehz#$NVuI~keTZAcLZs-pqE$l0=C-c5Dk)f~Ku%D4tHX*hf84+p-cokD(@z`M>on8TdKv!5a%!P+7AP%C%>Rmq|o~0(Ggse6t_Yr4zuoAT&_@KZ", "s": "3a9a5d5601369d00a92e851b5490d2d1", "b3": "6ab75dbd78d2b77f8675161ad8fddbe7"}, {"a": false, "c": "mBbK%Ks*MeKDAAsr>I~keTZAc8$p9%O%q$urm@mN+n39d89A;-u7l&A-BbZG#2`Ehz#$NVuI~keTZAcCGfIP%Q;QOtEFX-SyMqY)3lx;8sAp`hPTa2z0mDr@O?=HAWOs`JPN=e5Q4DkOjEY%T|Xe6r6#3>tTrY05odR>615-rpuh", "s": "fa6f99753674e2e0db242dd805eacac8", "ocf": "fc6a9c6533b34219a300d82a7272762b196c2cd4b0f0e1ef45ddea7f90879fd920fc926b97be039fdee7d2b633ae2744617d375f677e3d62bfebbec1501e8f55"}, {"a": false, "c": "mBbK%Ks*MeKDAAsr>I~keTZAc6Gz~_22KC1k~e`Y-54&aG;cYK#2`Ehz#$NVuf@e%>;NishD;H2XykHX^>azaF#hKvJ%zy", "i": {"c": "encrypted_jsonb", "t": "encrypted"}, "v": 2, "sv": [{"a": false, "c": "mBbK(pyr$AQACXmOIVmOi}IhuY%De&eY~aps=IX%RsOT!ondLDle#e%BR$Gv&)f@e%>;NishD;H2XykHX^>azaF#hKvJ%zy", "s": "9493d6010fe7845d52149b697729c745", "b3": "8067db44a848ab32c3056a3dbe4edf16"}, {"a": false, "c": "mBbK(pyr$AQACXmOIVmOi}Ihu96ceUg9XV?28@M-tz#Br;^6<3WFOjd2ER8q=fogcYM1<KvJ%zy", "s": "d90b97b5207d30fe867ca816ed0fe4a7", "ocv": "fbc7a11fc81f2a321553bc06a91f240bb7d8f3a9c6aec445a5ba6793159989698eadf64ab9b3ab45c5366d027b2a5476a635ce6cad9eda1be531d84f87aabfa9"}, {"a": false, "c": "mBbK(pyr$AQACXmOIVmOi}IhuLJr=wKvitTn15T2HK9Gf9WP-@uChztE?QZTtZ``BA3^P-GzWm8T=`6b9{?DB2co}A!JgDzI*_|{%^1GO{WxpHAX#dc{GYTtk;F|W6Vz*6{=fXB?_pGy!(2dzD!=L+nV`S", "s": "3a9a5d5601369d00a92e851b5490d2d1", "b3": "6ab75dbd78d2b77f8675161ad8fddbe7"}, {"a": false, "c": "mBbK(pyr$AQACXmOIVmOi}Ihu96ceUg9XV?28@M-tz#Br;^6<3WFOjd2ER8q=fogcYM1<KvJ%zy", "s": "f3b937817818610f955b6bbbc337aa2b", "ocv": "fbc7a11fc81f2a321553bc06a91f240bb7d8f3a9c6aec445a5ba6793159989698eadf64ab9b3ab45c5366d027b2a5476a635ce6cad9eda1be531d84f87aabfa9"}, {"a": false, "c": "mBbK(pyr$AQACXmOIVmOi}IhuBte;>Ow0vKyBL-0I##N^GXA#daWCrO$8*Bk)0K=lmV1F2cf=rBYM1<KvJ%zy", "s": "fa6f99753674e2e0db242dd805eacac8", "ocf": "fc6a9c6533b34219a300d7db65baa7226274d27d53fb941bb5b8884a18e181a5773acc25bb4dce3e38bfc174f4a91c87b5b22f7e0f9f422b3ad17d6b401590db"}, {"a": false, "c": "mBbK(pyr$AQACXmOIVmOi}Ihu6n`j}Ff83O>k4Ho>^0_=jmcM`uf!l(YM1<KvJ%zy", "s": "3dba004f4d7823446e7cb71f6681b344", "ocf": "fc6a9c6533b341a3bbe1d83c495dd234910130aae562de01247783fd038b94cd6af81089bcdc20b296b09b4475b9dad037051408640ec5d07b716141a05044f3"}]}'::jsonb::eql_v2_encrypted); + + + + + + + diff --git a/tests/test_helpers.sql b/tests/test_helpers.sql index c2052ec..e098eb4 100644 --- a/tests/test_helpers.sql +++ b/tests/test_helpers.sql @@ -316,10 +316,9 @@ AS $$ "t": "encrypted", "c": "e" }, - "hm": "unique.%s", + "hm": "hmac.%s", "b3": "blake3.%s", "bf": %s, - "v": 2 }', random_key, @@ -397,6 +396,19 @@ AS $$ $$ LANGUAGE plpgsql; +DROP FUNCTION IF EXISTS create_encrypted_ste_vec_json(val integer); +CREATE FUNCTION create_encrypted_ste_vec_json(val integer) + RETURNS eql_v2_encrypted +AS $$ + DECLARE + e eql_v2_encrypted; + BEGIN + EXECUTE format('SELECT ste_vec.e FROM ste_vec WHERE id = %s', val) INTO e; + RETURN e::eql_v2_encrypted; + END; +$$ LANGUAGE plpgsql; + + DROP FUNCTION IF EXISTS create_encrypted_json(); CREATE FUNCTION create_encrypted_json() RETURNS eql_v2_encrypted