Skip to content

PG-1504 Make partitions inherit encryption status #253

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions contrib/pg_tde/expected/partition_table.out
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,64 @@ SELECT pg_tde_is_encrypted('partition_q4_2024');
(1 row)

DROP TABLE partitioned_table;
-- Partition inherits encryption status from parent table if default is heap and parent is tde_heap
SET default_table_access_method = "heap";
CREATE TABLE partition_parent (a int) PARTITION BY RANGE (a) USING tde_heap;
CREATE TABLE partition_child PARTITION OF partition_parent FOR VALUES FROM (0) TO (9);
SELECT pg_tde_is_encrypted('partition_child');
pg_tde_is_encrypted
---------------------
t
(1 row)

DROP TABLE partition_parent;
RESET default_table_access_method;
-- Partition inherits encryption status from parent table if default is tde_heap and parent is heap
SET default_table_access_method = "tde_heap";
CREATE TABLE partition_parent (a int) PARTITION BY RANGE (a) USING heap;
CREATE TABLE partition_child PARTITION OF partition_parent FOR VALUES FROM (0) TO (9);
SELECT pg_tde_is_encrypted('partition_child');
pg_tde_is_encrypted
---------------------
f
(1 row)

DROP TABLE partition_parent;
RESET default_table_access_method;
-- Partition uses default access method to determine encryption status if neither parent nor child have an access method set
CREATE TABLE partition_parent (a int) PARTITION BY RANGE (a);
SET default_table_access_method = "tde_heap";
CREATE TABLE partition_child_tde PARTITION OF partition_parent FOR VALUES FROM (0) TO (9);
SELECT pg_tde_is_encrypted('partition_child_tde');
pg_tde_is_encrypted
---------------------
t
(1 row)

SET default_table_access_method = "heap";
CREATE TABLE partition_child_heap PARTITION OF partition_parent FOR VALUES FROM (10) TO (19);
SELECT pg_tde_is_encrypted('partition_child_heap');
pg_tde_is_encrypted
---------------------
f
(1 row)

DROP TABLE partition_parent;
RESET default_table_access_method;
-- Enforce encryption GUC is respected when creating partitions even if parent is plain text
CREATE TABLE partition_parent (a int) PARTITION BY RANGE (a) USING heap;
SET pg_tde.enforce_encryption = on;
CREATE TABLE partition_child_inherit PARTITION OF partition_parent FOR VALUES FROM (0) TO (10);
ERROR: pg_tde.enforce_encryption is ON, only the tde_heap access method is allowed.
CREATE TABLE partition_child_heap PARTITION OF partition_parent FOR VALUES FROM (11) TO (20) USING heap;
ERROR: pg_tde.enforce_encryption is ON, only the tde_heap access method is allowed.
CREATE TABLE partition_child_tde_heap PARTITION OF partition_parent FOR VALUES FROM (11) TO (20) USING tde_heap;
SELECT pg_tde_is_encrypted('partition_child_tde_heap');
pg_tde_is_encrypted
---------------------
t
(1 row)

DROP TABLE partition_parent;
RESET pg_tde.enforce_encryption;
DROP EXTENSION pg_tde;
38 changes: 38 additions & 0 deletions contrib/pg_tde/sql/partition_table.sql
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,42 @@ SELECT pg_tde_is_encrypted('partition_q3_2024');
SELECT pg_tde_is_encrypted('partition_q4_2024');

DROP TABLE partitioned_table;

-- Partition inherits encryption status from parent table if default is heap and parent is tde_heap
SET default_table_access_method = "heap";
CREATE TABLE partition_parent (a int) PARTITION BY RANGE (a) USING tde_heap;
CREATE TABLE partition_child PARTITION OF partition_parent FOR VALUES FROM (0) TO (9);
SELECT pg_tde_is_encrypted('partition_child');
DROP TABLE partition_parent;
RESET default_table_access_method;

-- Partition inherits encryption status from parent table if default is tde_heap and parent is heap
SET default_table_access_method = "tde_heap";
CREATE TABLE partition_parent (a int) PARTITION BY RANGE (a) USING heap;
CREATE TABLE partition_child PARTITION OF partition_parent FOR VALUES FROM (0) TO (9);
SELECT pg_tde_is_encrypted('partition_child');
DROP TABLE partition_parent;
RESET default_table_access_method;

-- Partition uses default access method to determine encryption status if neither parent nor child have an access method set
CREATE TABLE partition_parent (a int) PARTITION BY RANGE (a);
SET default_table_access_method = "tde_heap";
CREATE TABLE partition_child_tde PARTITION OF partition_parent FOR VALUES FROM (0) TO (9);
SELECT pg_tde_is_encrypted('partition_child_tde');
SET default_table_access_method = "heap";
CREATE TABLE partition_child_heap PARTITION OF partition_parent FOR VALUES FROM (10) TO (19);
SELECT pg_tde_is_encrypted('partition_child_heap');
DROP TABLE partition_parent;
RESET default_table_access_method;

-- Enforce encryption GUC is respected when creating partitions even if parent is plain text
CREATE TABLE partition_parent (a int) PARTITION BY RANGE (a) USING heap;
SET pg_tde.enforce_encryption = on;
CREATE TABLE partition_child_inherit PARTITION OF partition_parent FOR VALUES FROM (0) TO (10);
CREATE TABLE partition_child_heap PARTITION OF partition_parent FOR VALUES FROM (11) TO (20) USING heap;
CREATE TABLE partition_child_tde_heap PARTITION OF partition_parent FOR VALUES FROM (11) TO (20) USING tde_heap;
SELECT pg_tde_is_encrypted('partition_child_tde_heap');
DROP TABLE partition_parent;
RESET pg_tde.enforce_encryption;

DROP EXTENSION pg_tde;
44 changes: 43 additions & 1 deletion contrib/pg_tde/src/pg_tde_event_capture.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "fmgr.h"
#include "utils/rel.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "catalog/pg_class.h"
#include "commands/defrem.h"
#include "commands/sequence.h"
Expand Down Expand Up @@ -149,12 +150,53 @@ pg_tde_ddl_command_start_capture(PG_FUNCTION_ARGS)
else if (IsA(parsetree, CreateStmt))
{
CreateStmt *stmt = castNode(CreateStmt, parsetree);
bool foundAccessMethod = false;

validateCurrentEventTriggerState(true);
tdeCurrentCreateEvent.tid = GetCurrentFullTransactionId();

if (shouldEncryptTable(stmt->accessMethod))

if (stmt->accessMethod)
{
foundAccessMethod = true;
if (strcmp(stmt->accessMethod, "tde_heap") == 0)
{
tdeCurrentCreateEvent.encryptMode = true;
}
}
else if (stmt->partbound)
{
/*
* If no access method is specified, and this is a partition of a
* parent table, access method can be inherited from the parent
* table if it has one set.
*
* AccessExclusiveLock might seem excessive, but it's what
* DefineRelation() will take on any partitioned parent relation
* in this transaction anyway.
*/
Oid parentOid;
Oid parentAmOid;

Assert(list_length(stmt->inhRelations) == 1);

parentOid = RangeVarGetRelid(linitial(stmt->inhRelations),
AccessExclusiveLock,
false);
parentAmOid = get_rel_relam(parentOid);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could accomplish the same with relation_open_rv() but I am not sure which is cleaner.

foundAccessMethod = parentAmOid != InvalidOid;

if (foundAccessMethod && parentAmOid == get_tde_table_am_oid())
{
tdeCurrentCreateEvent.encryptMode = true;
}
}

if (!foundAccessMethod
&& strcmp(default_table_access_method, "tde_heap") == 0)
{
tdeCurrentCreateEvent.encryptMode = true;
}

checkEncryptionStatus();
}
Expand Down