Skip to content

Commit cb97c93

Browse files
authored
Merge pull request #118 from cipherstash/enable-index-on-hmac_256
Enable indexing on eql_v2_encrypted columns without needing function helpers
2 parents 9164d73 + 7b1f896 commit cb97c93

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1195
-724
lines changed

src/blake3/compare.sql

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
-- REQUIRE: src/schema.sql
2+
-- REQUIRE: src/blake3/types.sql
3+
-- REQUIRE: src/blake3/functions.sql
4+
5+
6+
CREATE FUNCTION eql_v2.compare_blake3(a eql_v2_encrypted, b eql_v2_encrypted)
7+
RETURNS integer
8+
IMMUTABLE STRICT PARALLEL SAFE
9+
AS $$
10+
DECLARE
11+
a_term eql_v2.blake3;
12+
b_term eql_v2.blake3;
13+
BEGIN
14+
15+
IF a IS NULL AND b IS NULL THEN
16+
RETURN 0;
17+
END IF;
18+
19+
IF a IS NULL THEN
20+
RETURN -1;
21+
END IF;
22+
23+
IF b IS NULL THEN
24+
RETURN 1;
25+
END IF;
26+
27+
IF eql_v2.has_blake3(a) THEN
28+
a_term = eql_v2.blake3(a);
29+
END IF;
30+
31+
IF eql_v2.has_blake3(b) THEN
32+
b_term = eql_v2.blake3(b);
33+
END IF;
34+
35+
IF a_term IS NULL AND b_term IS NULL THEN
36+
RETURN 0;
37+
END IF;
38+
39+
IF a_term IS NULL THEN
40+
RETURN -1;
41+
END IF;
42+
43+
IF b_term IS NULL THEN
44+
RETURN 1;
45+
END IF;
46+
47+
-- Using the underlying text type comparison
48+
IF a_term = b_term THEN
49+
RETURN 0;
50+
END IF;
51+
52+
IF a_term < b_term THEN
53+
RETURN -1;
54+
END IF;
55+
56+
IF a_term > b_term THEN
57+
RETURN 1;
58+
END IF;
59+
60+
END;
61+
$$ LANGUAGE plpgsql;

src/blake3/compare_test.sql

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
\set ON_ERROR_STOP on
2+
3+
DO $$
4+
DECLARE
5+
a eql_v2_encrypted;
6+
b eql_v2_encrypted;
7+
c eql_v2_encrypted;
8+
BEGIN
9+
a := create_encrypted_json(1, 'b3');
10+
b := create_encrypted_json(2, 'b3');
11+
c := create_encrypted_json(3, 'b3');
12+
13+
ASSERT eql_v2.compare_blake3(a, a) = 0;
14+
ASSERT eql_v2.compare_blake3(a, b) = -1;
15+
ASSERT eql_v2.compare_blake3(a, c) = -1;
16+
17+
ASSERT eql_v2.compare_blake3(b, b) = 0;
18+
ASSERT eql_v2.compare_blake3(b, a) = 1;
19+
ASSERT eql_v2.compare_blake3(b, c) = -1;
20+
21+
ASSERT eql_v2.compare_blake3(c, c) = 0;
22+
ASSERT eql_v2.compare_blake3(c, b) = 1;
23+
ASSERT eql_v2.compare_blake3(c, a) = 1;
24+
END;
25+
$$ LANGUAGE plpgsql;
26+

src/encrypted/compare.sql

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
-- REQUIRE: src/schema.sql
2+
-- REQUIRE: src/encrypted/types.sql
3+
4+
--
5+
-- Compare two eql_v2_encrypted values as literal jsonb values
6+
-- Used as a fallback when no suitable search term is available
7+
--
8+
CREATE FUNCTION eql_v2.compare_literal(a eql_v2_encrypted, b eql_v2_encrypted)
9+
RETURNS integer
10+
IMMUTABLE STRICT PARALLEL SAFE
11+
AS $$
12+
DECLARE
13+
a_data jsonb;
14+
b_data jsonb;
15+
BEGIN
16+
17+
IF a IS NULL AND b IS NULL THEN
18+
RETURN 0;
19+
END IF;
20+
21+
IF a IS NULL THEN
22+
RETURN -1;
23+
END IF;
24+
25+
IF b IS NULL THEN
26+
RETURN 1;
27+
END IF;
28+
29+
a_data := a.data;
30+
b_data := b.data;
31+
32+
IF a_data < b_data THEN
33+
RETURN -1;
34+
END IF;
35+
36+
IF a_data > b_data THEN
37+
RETURN 1;
38+
END IF;
39+
40+
RETURN 0;
41+
END;
42+
$$ LANGUAGE plpgsql;

src/hmac_256/compare.sql

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
-- REQUIRE: src/schema.sql
2+
-- REQUIRE: src/hmac_256/types.sql
3+
-- REQUIRE: src/hmac_256/functions.sql
4+
5+
6+
CREATE FUNCTION eql_v2.compare_hmac_256(a eql_v2_encrypted, b eql_v2_encrypted)
7+
RETURNS integer
8+
IMMUTABLE STRICT PARALLEL SAFE
9+
AS $$
10+
DECLARE
11+
a_term eql_v2.hmac_256;
12+
b_term eql_v2.hmac_256;
13+
BEGIN
14+
15+
IF a IS NULL AND b IS NULL THEN
16+
RETURN 0;
17+
END IF;
18+
19+
IF a IS NULL THEN
20+
RETURN -1;
21+
END IF;
22+
23+
IF b IS NULL THEN
24+
RETURN 1;
25+
END IF;
26+
27+
IF eql_v2.has_hmac_256(a) THEN
28+
a_term = eql_v2.hmac_256(a);
29+
END IF;
30+
31+
IF eql_v2.has_hmac_256(b) THEN
32+
b_term = eql_v2.hmac_256(b);
33+
END IF;
34+
35+
IF a_term IS NULL AND b_term IS NULL THEN
36+
RETURN 0;
37+
END IF;
38+
39+
IF a_term IS NULL THEN
40+
RETURN -1;
41+
END IF;
42+
43+
IF b_term IS NULL THEN
44+
RETURN 1;
45+
END IF;
46+
47+
-- Using the underlying text type comparison
48+
IF a_term = b_term THEN
49+
RETURN 0;
50+
END IF;
51+
52+
IF a_term < b_term THEN
53+
RETURN -1;
54+
END IF;
55+
56+
IF a_term > b_term THEN
57+
RETURN 1;
58+
END IF;
59+
60+
END;
61+
$$ LANGUAGE plpgsql;

src/hmac_256/compare_test.sql

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
\set ON_ERROR_STOP on
2+
3+
DO $$
4+
DECLARE
5+
a eql_v2_encrypted;
6+
b eql_v2_encrypted;
7+
c eql_v2_encrypted;
8+
BEGIN
9+
a := create_encrypted_json(1, 'hm');
10+
b := create_encrypted_json(2, 'hm');
11+
c := create_encrypted_json(3, 'hm');
12+
13+
ASSERT eql_v2.compare_hmac_256(a, a) = 0;
14+
ASSERT eql_v2.compare_hmac_256(a, b) = -1;
15+
ASSERT eql_v2.compare_hmac_256(a, c) = -1;
16+
17+
ASSERT eql_v2.compare_hmac_256(b, b) = 0;
18+
ASSERT eql_v2.compare_hmac_256(b, a) = 1;
19+
ASSERT eql_v2.compare_hmac_256(b, c) = -1;
20+
21+
ASSERT eql_v2.compare_hmac_256(c, c) = 0;
22+
ASSERT eql_v2.compare_hmac_256(c, b) = 1;
23+
ASSERT eql_v2.compare_hmac_256(c, a) = 1;
24+
END;
25+
$$ LANGUAGE plpgsql;
26+

src/operators/<.sql

Lines changed: 4 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,18 @@
11
-- REQUIRE: src/schema.sql
2-
-- REQUIRE: src/ore_block_u64_8_256/types.sql
3-
-- REQUIRE: src/ore_block_u64_8_256/functions.sql
4-
-- REQUIRE: src/ore_block_u64_8_256/operators.sql
2+
-- REQUIRE: src/encrypted/types.sql
3+
-- REQUIRE: src/operators/compare.sql
54

65

76
-- Operators for < less than comparisons of eql_v2_encrypted types
87
--
9-
-- Support for the following comparisons:
8+
-- Uses `eql_v2.compare` for the actual comparison logic.
109
--
11-
-- eql_v2_encrypted = eql_v2_encrypted
12-
-- eql_v2_encrypted = jsonb
13-
-- jsonb = eql_v2_encrypted
1410
--
15-
-- There are multiple index terms that provide equality comparisons
16-
-- - ore_block_u64_8_256
17-
-- - ore_cllw_8_v2
18-
--
19-
-- We check these index terms in this order and use the first one that exists for both parameters
20-
--
21-
--
22-
23-
2411
CREATE FUNCTION eql_v2.lt(a eql_v2_encrypted, b eql_v2_encrypted)
2512
RETURNS boolean
2613
AS $$
2714
BEGIN
28-
29-
BEGIN
30-
RETURN eql_v2.ore_cllw_u64_8(a) < eql_v2.ore_cllw_u64_8(b);
31-
EXCEPTION WHEN OTHERS THEN
32-
-- PERFORM eql_v2.log('eql_v2.lt no ore_cllw_u64_8 index');
33-
END;
34-
35-
BEGIN
36-
RETURN eql_v2.ore_cllw_var_8(a) < eql_v2.ore_cllw_var_8(b);
37-
EXCEPTION WHEN OTHERS THEN
38-
-- PERFORM eql_v2.log('eql_v2.lt no ore_cllw_var_8 index');
39-
END;
40-
41-
BEGIN
42-
RETURN eql_v2.ore_block_u64_8_256(a) < eql_v2.ore_block_u64_8_256(b);
43-
EXCEPTION WHEN OTHERS THEN
44-
-- PERFORM eql_v2.log('eql_v2.lt no ore_block_u64_8_256 index');
45-
END;
46-
47-
RETURN false;
15+
RETURN eql_v2.compare(a, b) = -1;
4816
END;
4917
$$ LANGUAGE plpgsql;
5018

src/operators/<=.sql

Lines changed: 5 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,18 @@
1+
-- REQUIRE: src/schema.sql
12
-- REQUIRE: src/encrypted/types.sql
2-
-- REQUIRE: src/ore_block_u64_8_256/types.sql
3-
-- REQUIRE: src/ore_block_u64_8_256/functions.sql
4-
-- REQUIRE: src/ore_block_u64_8_256/operators.sql
3+
-- REQUIRE: src/operators/compare.sql
54

65

7-
-- Operators for < less than comparisons of eql_v2_encrypted types
6+
-- Operators for <= less than or equal to comparisons of eql_v2_encrypted types
87
--
9-
-- Support for the following comparisons:
8+
-- Uses `eql_v2.compare` for the actual comparison logic.
109
--
11-
-- eql_v2_encrypted = eql_v2_encrypted
12-
-- eql_v2_encrypted = jsonb
13-
-- jsonb = eql_v2_encrypted
1410
--
15-
-- There are multiple index terms that provide equality comparisons
16-
-- - ore_block_u64_8_256
17-
-- - ore_cllw_8_v2
18-
--
19-
-- We check these index terms in this order and use the first one that exists for both parameters
20-
--
21-
--
22-
23-
2411
CREATE FUNCTION eql_v2.lte(a eql_v2_encrypted, b eql_v2_encrypted)
2512
RETURNS boolean
2613
AS $$
2714
BEGIN
28-
29-
BEGIN
30-
RETURN eql_v2.ore_cllw_u64_8(a) <= eql_v2.ore_cllw_u64_8(b);
31-
EXCEPTION WHEN OTHERS THEN
32-
-- PERFORM eql_v2.log('eql_v2.lte no ore_cllw_u64_8 index');
33-
END;
34-
35-
BEGIN
36-
RETURN eql_v2.ore_cllw_var_8(a) <= eql_v2.ore_cllw_var_8(b);
37-
EXCEPTION WHEN OTHERS THEN
38-
-- PERFORM eql_v2.log('eql_v2.lte no ore_cllw_var_8 index');
39-
END;
40-
41-
BEGIN
42-
RETURN eql_v2.ore_block_u64_8_256(a) <= eql_v2.ore_block_u64_8_256(b);
43-
EXCEPTION WHEN OTHERS THEN
44-
-- PERFORM eql_v2.log('eql_v2.lte no ore_block_u64_8_256 index');
45-
END;
46-
47-
RETURN false;
15+
RETURN eql_v2.compare(a, b) <= 0;
4816
END;
4917
$$ LANGUAGE plpgsql;
5018

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
\set ON_ERROR_STOP on
2+
3+
SELECT create_table_with_encrypted();
4+
SELECT seed_encrypted_json();
5+
6+
7+
-- ========================================================================
8+
9+
10+
-- ------------------------------------------------------------------------
11+
-- ------------------------------------------------------------------------
12+
--
13+
-- ore_cllw_u64_8 less than or equal to <=
14+
--
15+
-- Test data is in form '{"hello": "{one | two | three}", "n": {10 | 20 | 30} }'
16+
--
17+
-- Paths
18+
-- $ -> bca213de9ccce676fa849ff9c4807963
19+
-- $.hello -> a7cea93975ed8c01f861ccb6bd082784
20+
-- $.n -> 2517068c0d1f9d4d41d2c666211f785e
21+
--
22+
--
23+
DO $$
24+
DECLARE
25+
sv eql_v2_encrypted;
26+
term eql_v2_encrypted;
27+
BEGIN
28+
29+
-- This extracts the data associated with the field from the test eql_v2_encrypted
30+
-- json n: 10
31+
sv := get_numeric_ste_vec_20()::eql_v2_encrypted;
32+
-- extract the term at $.n returned as eql_v2_encrypted
33+
term := sv->'2517068c0d1f9d4d41d2c666211f785e'::text;
34+
35+
-- -- -- -- $.n
36+
PERFORM assert_result(
37+
format('eql_v2_encrypted <= eql_v2_encrypted with ore_cllw_u64_8 index term'),
38+
format('SELECT e FROM encrypted WHERE (e->''2517068c0d1f9d4d41d2c666211f785e''::text) <= %L::eql_v2_encrypted', term));
39+
40+
PERFORM assert_count(
41+
format('eql_v2_encrypted <= eql_v2_encrypted with ore index term'),
42+
format('SELECT e FROM encrypted WHERE e->''2517068c0d1f9d4d41d2c666211f785e''::text <= %L::eql_v2_encrypted', term),
43+
2);
44+
45+
-- Check the $.hello path
46+
-- Returned encrypted does not have ore_cllw_u64_8
47+
-- Falls back to jsonb literal comparison
48+
PERFORM assert_no_result(
49+
format('eql_v2_encrypted <= eql_v2_encrypted with ore index term'),
50+
format('SELECT e FROM encrypted WHERE e->''a7cea93975ed8c01f861ccb6bd082784''::text <= %L::eql_v2_encrypted', term));
51+
52+
END;
53+
$$ LANGUAGE plpgsql;
54+
55+
56+
57+
SELECT drop_table_with_encrypted();

0 commit comments

Comments
 (0)