diff --git a/src/query/anonymization.c b/src/query/anonymization.c index f0fdef3f..b357aa6a 100644 --- a/src/query/anonymization.c +++ b/src/query/anonymization.c @@ -8,10 +8,13 @@ #include "nodes/nodeFuncs.h" #include "optimizer/optimizer.h" #include "optimizer/tlist.h" +#include "parser/parse_coerce.h" #include "parser/parse_oper.h" #include "parser/parsetree.h" +#include "utils/datetime.h" #include "utils/fmgroids.h" #include "utils/fmgrprotos.h" +#include "utils/json.h" #include "utils/lsyscache.h" #include "pg_diffix/aggregation/bucket_scan.h" @@ -626,6 +629,14 @@ static hash_t hash_label(Oid type, Datum value, bool is_null) return hash_string(value_as_string); } + if (TypeCategory(type) == TYPCATEGORY_DATETIME) + { + char value_as_string[MAXDATELEN + 1]; + /* Leveraging `json.h` as a way to get style-stable encoding of various datetime types. */ + JsonEncodeDateTime(value_as_string, value, type, NULL); + return hash_string(value_as_string); + } + /* Handle all other types by casting to text. */ Oid type_output_funcid = InvalidOid; bool is_varlena = false; diff --git a/test/expected/datetime.out b/test/expected/datetime.out new file mode 100644 index 00000000..a25f1dd1 --- /dev/null +++ b/test/expected/datetime.out @@ -0,0 +1,47 @@ +LOAD 'pg_diffix'; +CREATE TABLE test_datetime ( + id INTEGER, + d DATE, + t TIME, + ts TIMESTAMP WITHOUT TIME ZONE, + tz TIMESTAMP WITH TIME ZONE, + i INTERVAL +); +INSERT INTO test_datetime VALUES + (1, '2012-05-14', '14:59', '2012-05-14', '2012-05-14', '1 years'), + (2, '2012-05-14', '14:59', '2012-05-14', '2012-05-14', '1 years'), + (3, '2012-05-14', '14:59', '2012-05-14', '2012-05-14', '1 years'), + (4, '2012-05-14', '14:59', '2012-05-14', '2012-05-14', '1 years'), + (5, '2012-05-14', '14:59', '2012-05-14', '2012-05-14', '1 years'), + (6, '2012-05-14', '14:59', '2012-05-14', '2012-05-14', '1 years'), + (7, '2012-05-14', '14:59', '2012-05-14', '2012-05-14', '1 years'); +CALL diffix.mark_personal('test_datetime', 'id'); +SET ROLE diffix_test; +SET pg_diffix.session_access_level = 'anonymized_trusted'; +---------------------------------------------------------------- +-- Sanity checks +---------------------------------------------------------------- +SELECT diffix.access_level(); + access_level +-------------------- + anonymized_trusted +(1 row) + +---------------------------------------------------------------- +-- Seeding +---------------------------------------------------------------- +-- Datetime values are seeded the same regardless of global `datestyle` setting +SET datestyle = 'SQL'; +SELECT ts, count(*) FROM test_datetime GROUP BY 1; + ts | count +---------------------+------- + 05/14/2012 00:00:00 | 9 +(1 row) + +SET datestyle = 'ISO'; +SELECT ts, count(*) FROM test_datetime GROUP BY 1; + ts | count +---------------------+------- + 2012-05-14 00:00:00 | 9 +(1 row) + diff --git a/test/sql/datetime.sql b/test/sql/datetime.sql new file mode 100755 index 00000000..5e1bf57c --- /dev/null +++ b/test/sql/datetime.sql @@ -0,0 +1,40 @@ +LOAD 'pg_diffix'; + +CREATE TABLE test_datetime ( + id INTEGER, + d DATE, + t TIME, + ts TIMESTAMP WITHOUT TIME ZONE, + tz TIMESTAMP WITH TIME ZONE, + i INTERVAL +); + +INSERT INTO test_datetime VALUES + (1, '2012-05-14', '14:59', '2012-05-14', '2012-05-14', '1 years'), + (2, '2012-05-14', '14:59', '2012-05-14', '2012-05-14', '1 years'), + (3, '2012-05-14', '14:59', '2012-05-14', '2012-05-14', '1 years'), + (4, '2012-05-14', '14:59', '2012-05-14', '2012-05-14', '1 years'), + (5, '2012-05-14', '14:59', '2012-05-14', '2012-05-14', '1 years'), + (6, '2012-05-14', '14:59', '2012-05-14', '2012-05-14', '1 years'), + (7, '2012-05-14', '14:59', '2012-05-14', '2012-05-14', '1 years'); + +CALL diffix.mark_personal('test_datetime', 'id'); + +SET ROLE diffix_test; +SET pg_diffix.session_access_level = 'anonymized_trusted'; + +---------------------------------------------------------------- +-- Sanity checks +---------------------------------------------------------------- + +SELECT diffix.access_level(); + +---------------------------------------------------------------- +-- Seeding +---------------------------------------------------------------- + +-- Datetime values are seeded the same regardless of global `datestyle` setting +SET datestyle = 'SQL'; +SELECT ts, count(*) FROM test_datetime GROUP BY 1; +SET datestyle = 'ISO'; +SELECT ts, count(*) FROM test_datetime GROUP BY 1;