LOAD 'pg_diffix'; CREATE TABLE test_validation ( id INTEGER PRIMARY KEY, name TEXT, city TEXT, discount REAL, birthday DATE, lunchtime TIME, last_seen TIMESTAMP ); CALL diffix.mark_personal('test_validation', 'id'); CREATE TABLE superclass (x INTEGER); CREATE TABLE subclass (x INTEGER, y INTEGER); INSERT INTO subclass VALUES (1, 2); CALL diffix.mark_personal('superclass', 'x'); CALL diffix.mark_personal('subclass', 'y'); ALTER TABLE subclass INHERIT superclass; -- No-op. Repeated to test the error on conflicting configuration CALL diffix.mark_personal('superclass', 'x'); CALL diffix.mark_personal('subclass', 'y'); SET ROLE diffix_test; ---------------------------------------------------------------- -- Trusted mode query restrictions ---------------------------------------------------------------- SET pg_diffix.session_access_level = 'anonymized_trusted'; SELECT diffix.access_level(); ---------------------------------------------------------------- -- Supported queries ---------------------------------------------------------------- -- Supported functions for defining buckets SELECT COUNT(*) FROM test_validation GROUP BY substring(city, 1, 1); SELECT COUNT(*) FROM test_validation GROUP BY width_bucket(id, 0, 1000, 10), width_bucket(id::float, 0.0, 1000.0, 10); SELECT COUNT(*) FROM test_validation GROUP BY round(id::float, -1), round(id::numeric, -1); SELECT COUNT(*) FROM test_validation GROUP BY round(id::float), ceil(id::float), ceiling(id::float), floor(id::float); SELECT COUNT(*) FROM test_validation GROUP BY round(id::numeric), ceil(id::numeric), ceiling(id::numeric), floor(id::numeric); SELECT diffix.round_by(id::numeric, 5), diffix.round_by(id::double precision, 5), COUNT(*) FROM test_validation GROUP BY 1, 2; SELECT diffix.ceil_by(id::numeric, 5), diffix.ceil_by(id::double precision, 5), COUNT(*) FROM test_validation GROUP BY 1, 2; SELECT diffix.floor_by(id::numeric, 5), diffix.floor_by(id::double precision, 5), COUNT(*) FROM test_validation GROUP BY 1, 2; SELECT substring(cast(last_seen AS text), 1, 3), substring(cast(birthday AS text), 2, 3), substring(cast(lunchtime AS varchar), 1, 4) FROM test_validation GROUP BY 1, 2, 3; -- Allow all functions post-anonymization. SELECT 2 * length(city) FROM test_validation GROUP BY city; -- Allow diffix.is_suppress_bin in non-direct access level. SELECT city, count(*), diffix.is_suppress_bin(*) from test_validation GROUP BY 1; -- Set operations between anonymizing queries. SELECT city FROM test_validation EXCEPT SELECT city FROM test_validation; SELECT city FROM test_validation UNION SELECT city FROM test_validation; -- Anonymizing sublinks are supported. SELECT EXISTS (SELECT city FROM test_validation); SELECT 1 WHERE EXISTS (SELECT city FROM test_validation); -- Anonymizing leaf subqueries are supported. SELECT * FROM ( SELECT COUNT(*) FROM test_validation ) x; SELECT COUNT(city) FROM ( SELECT city FROM test_validation GROUP BY 1 ) x; SELECT COUNT(*), COUNT(x.city), COUNT(DISTINCT x.id) FROM ( SELECT * FROM test_validation ) x; SELECT COUNT(DISTINCT x.modified_id) FROM ( SELECT id AS modified_id FROM test_validation ) x; SELECT COUNT(*), COUNT(x.city), COUNT(DISTINCT x.user_id) FROM ( SELECT y.city as city, y.id as user_id FROM ( SELECT * FROM test_validation ) y ) x; SELECT * FROM (SELECT name FROM test_validation) x, (SELECT city FROM test_validation) y; WITH c AS (SELECT city FROM test_validation) SELECT * FROM c; SELECT (SELECT city FROM test_validation); -- Allow discovery commands \dt empty_test_customers \d empty_test_customers \dt+ empty_test_customers \d+ empty_test_customers -- Settings and labels UDFs work SELECT * FROM diffix.show_settings() LIMIT 2; SELECT * FROM diffix.show_labels() WHERE objname LIKE 'public.test_customers%'; ---------------------------------------------------------------- -- Unsupported queries ---------------------------------------------------------------- -- Get rejected because non SELECT queries are unsupported. INSERT INTO test_validation VALUES (NULL, NULL,NULL); -- Get rejected because WITH is unsupported. WITH c AS (SELECT 1 FROM test_validation) SELECT 1 FROM test_validation; -- Get rejected because GROUPING SETS are unsupported. SELECT city FROM test_validation GROUP BY GROUPING SETS ((city), ()); SELECT city FROM test_validation GROUP BY CUBE ((city)); -- Get rejected because SRF functions are unsupported. SELECT generate_series(1,4) FROM test_validation; -- Get rejected because sublinks are unsupported. SELECT city, (SELECT 1 FROM test_validation) FROM test_validation GROUP BY 1; -- Get rejected because DISTINCT is unsupported. SELECT DISTINCT city FROM test_validation; -- Get rejected because window functions are unsupported. SELECT avg(discount) OVER (PARTITION BY city) FROM test_validation; -- Get rejected because aggregators are unsupported. SELECT SUM(id) FROM test_validation; SELECT MIN(id) + MAX(id) FROM test_validation; SELECT city FROM test_validation GROUP BY 1 ORDER BY AVG(LENGTH(city)); SELECT count(city ORDER BY city) FROM test_validation; SELECT count(*) FILTER (WHERE true) FROM test_validation; SELECT count(distinct id + 5) FROM test_validation; SELECT count(distinct least(id, 5)) FROM test_validation; SELECT count(id + 5) FROM test_validation; SELECT count(least(id, 5)) FROM test_validation; -- Get rejected because only a subset of expressions is supported for defining buckets. SELECT COUNT(*) FROM test_validation GROUP BY LENGTH(city); SELECT COUNT(*) FROM test_validation GROUP BY city || 'xxx'; SELECT LENGTH(city) FROM test_validation; SELECT city, 'aaaa' FROM test_validation GROUP BY 1, 2; SELECT COUNT(*) FROM test_validation GROUP BY round(floor(id)); SELECT COUNT(*) FROM test_validation GROUP BY floor(cast(discount AS integer)); SELECT COUNT(*) FROM test_validation GROUP BY substr(city, 1, id); SELECT COUNT(*) FROM test_validation GROUP BY substr('aaaa', 1, 2); -- Get rejected because expression node type is unsupported. SELECT COALESCE(discount, 20) FROM test_validation; SELECT NULLIF(discount, 20) FROM test_validation; SELECT GREATEST(discount, 20) FROM test_validation; SELECT LEAST(discount, 20) FROM test_validation; -- Get rejected because of JOINs SELECT COUNT(*), COUNT(DISTINCT id), COUNT(DISTINCT cid) FROM test_validation INNER JOIN test_purchases tp ON id = cid; SELECT COUNT(c.city), COUNT(p.name) FROM test_validation c LEFT JOIN test_purchases ON c.id = cid LEFT JOIN test_products p ON pid = p.id; SELECT city, COUNT(price) FROM test_validation, test_products GROUP BY 1; SELECT city, COUNT(price) FROM test_products, test_validation GROUP BY 1; SELECT city, COUNT(price) FROM test_products CROSS JOIN test_validation GROUP BY 1; -- Get rejected because of WHERE SELECT COUNT(*) FROM test_validation WHERE city = 'London'; -- Get rejected because of non-datetime cast to text SELECT cast(id AS text) FROM test_validation GROUP BY 1; SELECT cast(id AS varchar) FROM test_validation GROUP BY 1; SELECT substring(cast(id AS text), 1, 1) FROM test_validation GROUP BY 1; SELECT substring(cast(id AS varchar), 1, 1) FROM test_validation GROUP BY 1; -- Invalid subqueries are rejected. SELECT * FROM (SELECT length(city) FROM test_validation) x; SELECT EXISTS (SELECT length(city) FROM test_validation); SELECT 1 WHERE EXISTS (SELECT length(city) FROM test_validation); SELECT 1 UNION SELECT length(city) FROM test_validation; SELECT * FROM (SELECT 1) t1, (SELECT length(city) FROM test_validation) t2; WITH c AS (SELECT length(city) FROM test_validation) SELECT * FROM c; SELECT (SELECT length(city) FROM test_validation); -- Get rejected because of accessing pg_catalog tables with sensitive stats SELECT * FROM pg_stats LIMIT 10; SELECT * FROM pg_statistic LIMIT 10; SELECT * FROM pg_stat_user_functions LIMIT 10; SELECT * FROM pg_stat_user_indexes LIMIT 10; SELECT * FROM pg_class LIMIT 10; -- Get rejected because of inheritance SELECT x, y FROM subclass; SELECT x FROM superclass; -- Get rejected because attempt to use system columns SELECT ctid FROM test_validation; SELECT tableoid FROM test_validation; SELECT count(ctid) FROM test_validation; SELECT count(tableoid) FROM test_validation; SELECT count(distinct ctid) FROM test_validation; SELECT count(distinct tableoid) FROM test_validation; ---------------------------------------------------------------- -- Untrusted mode query restrictions ---------------------------------------------------------------- SET pg_diffix.session_access_level = 'anonymized_untrusted'; SELECT diffix.access_level(); -- Get accepted SELECT substring(city, 1, 2) from test_validation; SELECT floor(discount) from test_validation; SELECT round(discount) from test_validation; SELECT discount from test_validation; SELECT diffix.floor_by(discount, 2) from test_validation; SELECT diffix.round_by(discount, 2) from test_validation; SELECT diffix.floor_by(discount, 20) from test_validation; SELECT diffix.floor_by(discount, 2.0) from test_validation; SELECT diffix.floor_by(discount, 0.2) from test_validation; SELECT diffix.floor_by(discount, 20.0) from test_validation; SELECT diffix.floor_by(discount, 50.0) from test_validation; -- Get rejected because of invalid generalization parameters SELECT substring(city, 2, 2) from test_validation; SELECT diffix.floor_by(discount, 3) from test_validation; SELECT diffix.floor_by(discount, 3.0) from test_validation; SELECT diffix.floor_by(discount, 5000000000.1) from test_validation; -- Get rejected because of invalid generalizing functions SELECT width_bucket(discount, 2, 200, 5) from test_validation; SELECT ceil(discount) from test_validation; SELECT diffix.ceil_by(discount, 2) from test_validation;