Skip to content

Commit 19bca58

Browse files
committed
Encrypted JSONB operators and functions
1 parent 71c86bb commit 19bca58

Some content is hidden

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

57 files changed

+3963
-1603
lines changed

diagrams/overview-insert.drawio.svg

-457
This file was deleted.

diagrams/overview-select.drawio.svg

-552
This file was deleted.

src/blake3/functions.sql

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
-- REQUIRE: src/schema.sql
2+
-- REQUIRE: src/mac/types.sql
3+
4+
5+
-- extracts ste_vec index from a jsonb value
6+
DROP FUNCTION IF EXISTS eql_v1.blake3(val jsonb);
7+
8+
-- extracts blake3 index from a jsonb value
9+
DROP FUNCTION IF EXISTS eql_v1.blake3(val jsonb);
10+
11+
CREATE FUNCTION eql_v1.blake3(val jsonb)
12+
RETURNS eql_v1.blake3
13+
IMMUTABLE STRICT PARALLEL SAFE
14+
AS $$
15+
BEGIN
16+
17+
IF NOT (val ? 'b') NULL THEN
18+
RAISE 'Expected a blake3 index (b) value in json: %', val;
19+
END IF;
20+
21+
IF val->>'b' IS NULL THEN
22+
RETURN NULL;
23+
END IF;
24+
25+
RETURN val->>'b';
26+
END;
27+
$$ LANGUAGE plpgsql;
28+
29+
30+
-- extracts blake3 index from an eql_v1_encrypted value
31+
DROP FUNCTION IF EXISTS eql_v1.blake3(val eql_v1_encrypted);
32+
33+
CREATE FUNCTION eql_v1.blake3(val eql_v1_encrypted)
34+
RETURNS eql_v1.blake3
35+
IMMUTABLE STRICT PARALLEL SAFE
36+
AS $$
37+
BEGIN
38+
RETURN (SELECT eql_v1.blake3(val.data));
39+
END;
40+
$$ LANGUAGE plpgsql;

src/blake3/types.sql

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-- REQUIRE: src/schema.sql
2+
3+
DROP DOMAIN IF EXISTS eql_v1.blake3;
4+
CREATE DOMAIN eql_v1.blake3 AS text;

src/common.sql

+48
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,54 @@
22
-- REQUIRE: src/schema.sql
33

44

5+
-- Constant time comparison of 2 bytea values
6+
DROP FUNCTION IF EXISTS eql_v1.bytea_eq(a bytea, b bytea);
7+
8+
CREATE FUNCTION eql_v1.bytea_eq(a bytea, b bytea) RETURNS boolean AS $$
9+
DECLARE
10+
result boolean;
11+
differing bytea;
12+
BEGIN
13+
14+
-- Check if the bytea values are the same length
15+
IF LENGTH(a) != LENGTH(b) THEN
16+
RETURN false;
17+
END IF;
18+
19+
-- Compare each byte in the bytea values
20+
result := true;
21+
FOR i IN 1..LENGTH(a) LOOP
22+
IF SUBSTRING(a FROM i FOR 1) != SUBSTRING(b FROM i FOR 1) THEN
23+
result := result AND false;
24+
END IF;
25+
END LOOP;
26+
27+
RETURN result;
28+
END;
29+
$$ LANGUAGE plpgsql;
30+
31+
32+
DROP FUNCTION IF EXISTS eql_v1.jsonb_array_to_bytea_array(val jsonb);
33+
34+
-- Casts a jsonb array of hex-encoded strings to an array of bytea.
35+
CREATE FUNCTION eql_v1.jsonb_array_to_bytea_array(val jsonb)
36+
RETURNS bytea[] AS $$
37+
DECLARE
38+
terms_arr bytea[];
39+
BEGIN
40+
IF jsonb_typeof(val) = 'null' THEN
41+
RETURN NULL;
42+
END IF;
43+
44+
SELECT array_agg(decode(value::text, 'hex')::bytea)
45+
INTO terms_arr
46+
FROM jsonb_array_elements_text(val) AS value;
47+
48+
RETURN terms_arr;
49+
END;
50+
$$ LANGUAGE plpgsql;
51+
52+
553

654
--
755
-- Convenience function to log a message

src/encrypted/functions.sql

+12
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,18 @@ AS $$
1818
END;
1919
$$ LANGUAGE plpgsql;
2020

21+
DROP FUNCTION IF EXISTS eql_v1.ciphertext(val eql_v1_encrypted);
22+
23+
CREATE FUNCTION eql_v1.ciphertext(val eql_v1_encrypted)
24+
RETURNS text
25+
IMMUTABLE STRICT PARALLEL SAFE
26+
AS $$
27+
BEGIN
28+
RETURN eql_v1.ciphertext(val.data);
29+
END;
30+
$$ LANGUAGE plpgsql;
31+
32+
2133

2234
DROP FUNCTION IF EXISTS eql_v1.to_jsonb(val eql_v1_encrypted);
2335

src/jsonb/functions.sql

+234
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
-- REQUIRE: src/schema.sql
2+
-- REQUIRE: src/encrypted/types.sql
3+
4+
-- The jsonpath operators @? and @@ suppress the following errors:
5+
-- missing object field or array element,
6+
-- unexpected JSON item type,
7+
-- datetime and numeric errors.
8+
-- The jsonpath-related functions described below can also be told to suppress these types of errors.
9+
-- This behavior might be helpful when searching JSON document collections of varying structure.
10+
11+
12+
13+
--
14+
--
15+
-- Returns the stevec encrypted element matching the selector
16+
--
17+
-- If the
18+
19+
DROP FUNCTION IF EXISTS eql_v1.jsonb_path_query(val jsonb, selector text);
20+
21+
CREATE FUNCTION eql_v1.jsonb_path_query(val jsonb, selector text)
22+
RETURNS SETOF eql_v1_encrypted
23+
IMMUTABLE STRICT PARALLEL SAFE
24+
AS $$
25+
DECLARE
26+
e eql_v1_encrypted;
27+
sv eql_v1_encrypted[];
28+
found eql_v1_encrypted[];
29+
ary boolean;
30+
BEGIN
31+
32+
IF val IS NULL THEN
33+
RETURN NEXT NULL;
34+
END IF;
35+
36+
sv := eql_v1.ste_vec(val);
37+
38+
FOR idx IN 1..array_length(sv, 1) LOOP
39+
e := sv[idx];
40+
41+
IF eql_v1.selector(e) = selector THEN
42+
found := array_append(found, e);
43+
44+
IF eql_v1.is_ste_vec_array(e) THEN
45+
ary := true;
46+
END IF;
47+
48+
END IF;
49+
END LOOP;
50+
51+
IF found IS NOT NULL THEN
52+
53+
IF ary THEN
54+
RETURN NEXT jsonb_build_object(
55+
'sv', found,
56+
'a', 1
57+
)::eql_v1_encrypted;
58+
59+
ELSE
60+
RETURN NEXT found[1];
61+
END IF;
62+
63+
END IF;
64+
65+
RETURN;
66+
END;
67+
$$ LANGUAGE plpgsql;
68+
69+
70+
DROP FUNCTION IF EXISTS eql_v1.jsonb_path_query(val eql_v1_encrypted, selector text);
71+
72+
CREATE FUNCTION eql_v1.jsonb_path_query(val eql_v1_encrypted, selector text)
73+
RETURNS SETOF eql_v1_encrypted
74+
IMMUTABLE STRICT PARALLEL SAFE
75+
AS $$
76+
BEGIN
77+
RETURN QUERY
78+
SELECT * FROM eql_v1.jsonb_path_query(val.data, selector);
79+
END;
80+
$$ LANGUAGE plpgsql;
81+
82+
83+
DROP FUNCTION IF EXISTS eql_v1.jsonb_path_exists(val jsonb, selector text);
84+
85+
CREATE FUNCTION eql_v1.jsonb_path_exists(val jsonb, selector text)
86+
RETURNS boolean
87+
IMMUTABLE STRICT PARALLEL SAFE
88+
AS $$
89+
BEGIN
90+
RETURN EXISTS (
91+
SELECT eql_v1.jsonb_path_query(val, selector)
92+
);
93+
END;
94+
$$ LANGUAGE plpgsql;
95+
96+
97+
DROP FUNCTION IF EXISTS eql_v1.jsonb_path_exists(val eql_v1_encrypted, selector text);
98+
99+
CREATE FUNCTION eql_v1.jsonb_path_exists(val eql_v1_encrypted, selector text)
100+
RETURNS boolean
101+
IMMUTABLE STRICT PARALLEL SAFE
102+
AS $$
103+
BEGIN
104+
RETURN EXISTS (
105+
SELECT eql_v1.jsonb_path_query(val, selector)
106+
);
107+
END;
108+
$$ LANGUAGE plpgsql;
109+
110+
111+
--
112+
--
113+
DROP FUNCTION IF EXISTS eql_v1.jsonb_path_query_first(val jsonb, selector text);
114+
115+
CREATE FUNCTION eql_v1.jsonb_path_query_first(val jsonb, selector text)
116+
RETURNS eql_v1_encrypted
117+
IMMUTABLE STRICT PARALLEL SAFE
118+
AS $$
119+
BEGIN
120+
RETURN (
121+
SELECT (
122+
SELECT e
123+
FROM eql_v1.jsonb_path_query(val.data, selector) AS e
124+
LIMIT 1
125+
)
126+
);
127+
END;
128+
$$ LANGUAGE plpgsql;
129+
130+
131+
DROP FUNCTION IF EXISTS eql_v1.jsonb_path_query_first(val eql_v1_encrypted, selector text);
132+
133+
CREATE FUNCTION eql_v1.jsonb_path_query_first(val eql_v1_encrypted, selector text)
134+
RETURNS eql_v1_encrypted
135+
IMMUTABLE STRICT PARALLEL SAFE
136+
AS $$
137+
BEGIN
138+
RETURN (
139+
SELECT e
140+
FROM eql_v1.jsonb_path_query(val.data, selector) as e
141+
LIMIT 1
142+
);
143+
END;
144+
$$ LANGUAGE plpgsql;
145+
146+
147+
148+
--
149+
150+
151+
-- =====================================================================
152+
153+
154+
DROP FUNCTION IF EXISTS eql_v1.jsonb_array_length(val jsonb);
155+
156+
CREATE FUNCTION eql_v1.jsonb_array_length(val jsonb)
157+
RETURNS integer
158+
IMMUTABLE STRICT PARALLEL SAFE
159+
AS $$
160+
DECLARE
161+
sv eql_v1_encrypted[];
162+
found eql_v1_encrypted[];
163+
BEGIN
164+
165+
-- PERFORM eql_v1.log('eql_v1.jsonb_array_length', val::text);
166+
167+
IF val IS NULL THEN
168+
RETURN NULL;
169+
END IF;
170+
171+
IF eql_v1.is_ste_vec_array(val) THEN
172+
sv := eql_v1.ste_vec(val);
173+
-- PERFORM eql_v1.log('eql_v1.jsonb_array_length', sv::text);
174+
RETURN array_length(sv, 1);
175+
END IF;
176+
177+
RAISE 'cannot get array length of a non-array';
178+
END;
179+
$$ LANGUAGE plpgsql;
180+
181+
182+
DROP FUNCTION IF EXISTS eql_v1.jsonb_array_length(val eql_v1_encrypted);
183+
184+
CREATE FUNCTION eql_v1.jsonb_array_length(val eql_v1_encrypted)
185+
RETURNS integer
186+
IMMUTABLE STRICT PARALLEL SAFE
187+
AS $$
188+
BEGIN
189+
RETURN (
190+
SELECT eql_v1.jsonb_array_length(val.data)
191+
);
192+
END;
193+
$$ LANGUAGE plpgsql;
194+
195+
196+
197+
198+
199+
200+
-- DROP FUNCTION IF EXISTS eql_v1.jsonb_array_elements(val jsonb);
201+
202+
-- CREATE FUNCTION eql_v1.jsonb_array_elements(val jsonb)
203+
-- RETURNS SETOF eql_v1_encrypted
204+
-- IMMUTABLE STRICT PARALLEL SAFE
205+
-- AS $$
206+
-- DECLARE
207+
-- sv eql_v1_encrypted[];
208+
-- found eql_v1_encrypted[];
209+
-- BEGIN
210+
211+
-- IF val IS NULL THEN
212+
-- RETURN NEXT NULL;
213+
-- END IF;
214+
215+
-- sv := eql_v1.ste_vec(val);
216+
217+
-- FOR idx IN 1..array_length(sv, 1) LOOP
218+
-- IF eql_v1.selector(sv[idx]) = selector THEN
219+
-- found := array_append(found, sv[idx]);
220+
-- END IF;
221+
-- END LOOP;
222+
223+
-- IF found IS NOT NULL THEN
224+
-- FOR idx IN 1..array_length(found, 1) LOOP
225+
-- IF found[idx] IS NOT NULL THEN
226+
-- RETURN NEXT found[idx];
227+
-- END IF;
228+
-- END LOOP;
229+
-- END IF;
230+
231+
-- RETURN;
232+
-- END;
233+
-- $$ LANGUAGE plpgsql;
234+

0 commit comments

Comments
 (0)