Skip to content

Commit 9f0895b

Browse files
committed
feat: compare
1 parent 5c853b2 commit 9f0895b

File tree

2 files changed

+261
-0
lines changed

2 files changed

+261
-0
lines changed

src/operators/compare.sql

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
-- REQUIRE: src/schema.sql
2+
-- REQUIRE: src/encrypted/types.sql
3+
-- REQUIRE: src/encrypted/functions.sql
4+
5+
-- REQUIRE: src/blake3/types.sql
6+
-- REQUIRE: src/blake3/functions.sql
7+
8+
-- REQUIRE: src/hmac_256/types.sql
9+
-- REQUIRE: src/hmac_256/functions.sql
10+
11+
-- REQUIRE: src/ore_block_u64_8_256/types.sql
12+
-- REQUIRE: src/ore_block_u64_8_256/functions.sql
13+
14+
-- REQUIRE: src/ore_cllw_u64_8/types.sql
15+
-- REQUIRE: src/ore_cllw_u64_8/functions.sql
16+
17+
-- REQUIRE: src/ore_cllw_var_8/types.sql
18+
-- REQUIRE: src/ore_cllw_var_8/functions.sql
19+
20+
21+
--
22+
-- Compare two eql_v2_encrypted values
23+
--
24+
-- Function is used to implement all operators required for btree indexing"
25+
-- - `<`
26+
-- - `<=`
27+
-- - `=`
28+
-- - `>=`
29+
-- - `>`
30+
--
31+
--
32+
-- Index terms are checked in the following order:
33+
-- - `ore_block_u64_8_256`
34+
-- - `ore_cllw_u64_8`
35+
-- - `ore_cllw_var_8`
36+
-- - `hmac_256`
37+
-- - `blake3`
38+
--
39+
-- The first index term present for both values is used for comparsion.
40+
--
41+
-- If no index terms are found, the encrypted data is compared as a jsonb literal.
42+
-- Btree index must have a consistent ordering for a given state, without this text fallback, database errors with "lock BufferContent is not held"
43+
--
44+
CREATE FUNCTION eql_v2.compare(a eql_v2_encrypted, b eql_v2_encrypted)
45+
RETURNS integer
46+
IMMUTABLE STRICT PARALLEL SAFE
47+
AS $$
48+
BEGIN
49+
50+
-- PERFORM eql_v2.log('eql_v2.compare');
51+
-- PERFORM eql_v2.log('a', a::text);
52+
-- PERFORM eql_v2.log('b', b::text);
53+
54+
IF a IS NULL AND b IS NULL THEN
55+
RETURN 0;
56+
END IF;
57+
58+
IF a IS NULL THEN
59+
RETURN -1;
60+
END IF;
61+
62+
IF b IS NULL THEN
63+
RETURN 1;
64+
END IF;
65+
66+
-- Use ORE if both parameters have ore index
67+
IF eql_v2.has_ore_block_u64_8_256(a) AND eql_v2.has_ore_block_u64_8_256(b) THEN
68+
RETURN eql_v2.compare_ore_block_u64_8_256(a, b);
69+
END IF;
70+
71+
IF eql_v2.has_ore_cllw_u64_8(a) AND eql_v2.has_ore_cllw_u64_8(b) THEN
72+
RETURN eql_v2.compare_ore_cllw_u64_8(a, b);
73+
END IF;
74+
75+
IF eql_v2.has_ore_cllw_var_8(a) AND eql_v2.has_ore_cllw_var_8(b) THEN
76+
RETURN eql_v2.compare_ore_cllw_var_8(a, b);
77+
END IF;
78+
79+
-- Fallback to hmac if both parameters have hmac index
80+
IF eql_v2.has_hmac_256(a) AND eql_v2.has_hmac_256(b) THEN
81+
RETURN eql_v2.compare_hmac_256(a, b);
82+
END IF;
83+
84+
IF eql_v2.has_blake3(a) AND eql_v2.has_blake3(b) THEN
85+
RETURN eql_v2.compare_blake3(a, b);
86+
END IF;
87+
88+
89+
-- Fallback to literal comparison of the encrypted data
90+
-- Compare must have consistent ordering for a given state
91+
-- Without this text fallback, database errors with "lock BufferContent is not held"
92+
RETURN eql_v2.compare_literal(a, b);
93+
94+
END;
95+
$$ LANGUAGE plpgsql;

src/operators/compare_test.sql

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
\set ON_ERROR_STOP on
2+
3+
4+
-- Compare compare_ore_cllw_var_8
5+
DO $$
6+
DECLARE
7+
a eql_v2_encrypted;
8+
b eql_v2_encrypted;
9+
c eql_v2_encrypted;
10+
BEGIN
11+
12+
-- {"hello": "world{N}"}
13+
-- $.hello: d90b97b5207d30fe867ca816ed0fe4a7
14+
a := eql_v2.jsonb_path_query(create_encrypted_ste_vec_json(1), 'd90b97b5207d30fe867ca816ed0fe4a7');
15+
b := eql_v2.jsonb_path_query(create_encrypted_ste_vec_json(2), 'd90b97b5207d30fe867ca816ed0fe4a7');
16+
c := eql_v2.jsonb_path_query(create_encrypted_ste_vec_json(3), 'd90b97b5207d30fe867ca816ed0fe4a7');
17+
18+
ASSERT eql_v2.compare(a, a) = 0;
19+
ASSERT eql_v2.compare(a, b) = -1;
20+
ASSERT eql_v2.compare(a, c) = -1;
21+
22+
ASSERT eql_v2.compare(b, b) = 0;
23+
ASSERT eql_v2.compare(b, a) = 1;
24+
ASSERT eql_v2.compare(b, c) = -1;
25+
26+
ASSERT eql_v2.compare(c, c) = 0;
27+
ASSERT eql_v2.compare(c, b) = 1;
28+
ASSERT eql_v2.compare(c, a) = 1;
29+
END;
30+
$$ LANGUAGE plpgsql;
31+
32+
33+
-- Compare compare_ore_cllw_var_8
34+
DO $$
35+
DECLARE
36+
a eql_v2_encrypted;
37+
b eql_v2_encrypted;
38+
c eql_v2_encrypted;
39+
BEGIN
40+
41+
-- {"number": {N}}
42+
-- $.number: 3dba004f4d7823446e7cb71f6681b344
43+
a := eql_v2.jsonb_path_query(create_encrypted_ste_vec_json(1), '3dba004f4d7823446e7cb71f6681b344');
44+
b := eql_v2.jsonb_path_query(create_encrypted_ste_vec_json(5), '3dba004f4d7823446e7cb71f6681b344');
45+
c := eql_v2.jsonb_path_query(create_encrypted_ste_vec_json(10), '3dba004f4d7823446e7cb71f6681b344');
46+
47+
ASSERT eql_v2.compare(a, a) = 0;
48+
ASSERT eql_v2.compare(a, b) = -1;
49+
ASSERT eql_v2.compare(a, c) = -1;
50+
51+
ASSERT eql_v2.compare(b, b) = 0;
52+
ASSERT eql_v2.compare(b, a) = 1;
53+
ASSERT eql_v2.compare(b, c) = -1;
54+
55+
ASSERT eql_v2.compare(c, c) = 0;
56+
ASSERT eql_v2.compare(c, b) = 1;
57+
ASSERT eql_v2.compare(c, a) = 1;
58+
END;
59+
$$ LANGUAGE plpgsql;
60+
61+
62+
-- Compare ore_block_u64_8_256
63+
DO $$
64+
DECLARE
65+
a eql_v2_encrypted;
66+
b eql_v2_encrypted;
67+
c eql_v2_encrypted;
68+
BEGIN
69+
70+
a := create_encrypted_ore_json(1);
71+
b := create_encrypted_ore_json(21);
72+
c := create_encrypted_ore_json(42);
73+
74+
ASSERT eql_v2.compare(a, a) = 0;
75+
ASSERT eql_v2.compare(a, b) = -1;
76+
ASSERT eql_v2.compare(a, c) = -1;
77+
78+
ASSERT eql_v2.compare(b, b) = 0;
79+
ASSERT eql_v2.compare(b, a) = 1;
80+
ASSERT eql_v2.compare(b, c) = -1;
81+
82+
ASSERT eql_v2.compare(c, c) = 0;
83+
ASSERT eql_v2.compare(c, b) = 1;
84+
ASSERT eql_v2.compare(c, a) = 1;
85+
END;
86+
$$ LANGUAGE plpgsql;
87+
88+
89+
-- Compare blake3
90+
DO $$
91+
DECLARE
92+
a eql_v2_encrypted;
93+
b eql_v2_encrypted;
94+
c eql_v2_encrypted;
95+
BEGIN
96+
a := create_encrypted_json(1, 'b3');
97+
b := create_encrypted_json(2, 'b3');
98+
c := create_encrypted_json(3, 'b3');
99+
100+
ASSERT eql_v2.compare(a, a) = 0;
101+
ASSERT eql_v2.compare(a, b) = -1;
102+
ASSERT eql_v2.compare(a, c) = -1;
103+
104+
ASSERT eql_v2.compare(b, b) = 0;
105+
ASSERT eql_v2.compare(b, a) = 1;
106+
ASSERT eql_v2.compare(b, c) = -1;
107+
108+
ASSERT eql_v2.compare(c, c) = 0;
109+
ASSERT eql_v2.compare(c, b) = 1;
110+
ASSERT eql_v2.compare(c, a) = 1;
111+
END;
112+
$$ LANGUAGE plpgsql;
113+
114+
115+
-- Compare hmac_256
116+
DO $$
117+
DECLARE
118+
a eql_v2_encrypted;
119+
b eql_v2_encrypted;
120+
c eql_v2_encrypted;
121+
BEGIN
122+
a := create_encrypted_json(1, 'hm');
123+
b := create_encrypted_json(2, 'hm');
124+
c := create_encrypted_json(3, 'hm');
125+
126+
ASSERT eql_v2.compare(a, a) = 0;
127+
ASSERT eql_v2.compare(a, b) = -1;
128+
ASSERT eql_v2.compare(a, c) = -1;
129+
130+
ASSERT eql_v2.compare(b, b) = 0;
131+
ASSERT eql_v2.compare(b, a) = 1;
132+
ASSERT eql_v2.compare(b, c) = -1;
133+
134+
ASSERT eql_v2.compare(c, c) = 0;
135+
ASSERT eql_v2.compare(c, b) = 1;
136+
ASSERT eql_v2.compare(c, a) = 1;
137+
END;
138+
$$ LANGUAGE plpgsql;
139+
140+
141+
142+
-- Compare with no index terms
143+
-- This is a fallback to literal comparison of the encrypted data
144+
DO $$
145+
DECLARE
146+
a eql_v2_encrypted;
147+
b eql_v2_encrypted;
148+
c eql_v2_encrypted;
149+
BEGIN
150+
a := '{"a": 1}'::jsonb::eql_v2_encrypted;
151+
b := '{"b": 2}'::jsonb::eql_v2_encrypted;
152+
c := '{"c": 3}'::jsonb::eql_v2_encrypted;
153+
154+
ASSERT eql_v2.compare(a, a) = 0;
155+
ASSERT eql_v2.compare(a, b) = -1;
156+
ASSERT eql_v2.compare(a, c) = -1;
157+
158+
ASSERT eql_v2.compare(b, b) = 0;
159+
ASSERT eql_v2.compare(b, a) = 1;
160+
ASSERT eql_v2.compare(b, c) = -1;
161+
162+
ASSERT eql_v2.compare(c, c) = 0;
163+
ASSERT eql_v2.compare(c, b) = 1;
164+
ASSERT eql_v2.compare(c, a) = 1;
165+
END;
166+
$$ LANGUAGE plpgsql;

0 commit comments

Comments
 (0)