diff --git a/contrib/pg_tde/expected/partition_table.out b/contrib/pg_tde/expected/partition_table.out index 05cdc5708e66c..22d67a0b2100f 100644 --- a/contrib/pg_tde/expected/partition_table.out +++ b/contrib/pg_tde/expected/partition_table.out @@ -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; diff --git a/contrib/pg_tde/sql/partition_table.sql b/contrib/pg_tde/sql/partition_table.sql index 2651ef71d726f..ddaf30033adab 100644 --- a/contrib/pg_tde/sql/partition_table.sql +++ b/contrib/pg_tde/sql/partition_table.sql @@ -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; diff --git a/contrib/pg_tde/src/pg_tde_event_capture.c b/contrib/pg_tde/src/pg_tde_event_capture.c index d6b7a7ab4bb0b..23bc02a22bd3a 100644 --- a/contrib/pg_tde/src/pg_tde_event_capture.c +++ b/contrib/pg_tde/src/pg_tde_event_capture.c @@ -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" @@ -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); + 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(); }