From 9402c44ddc344cca43ac2f5525917465c5657850 Mon Sep 17 00:00:00 2001 From: Ellen Marie Dash Date: Thu, 6 Aug 2026 10:50:52 -0400 Subject: [PATCH 1/4] Add fingerprint tests involving role names. --- test/fingerprint_tests.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/test/fingerprint_tests.c b/test/fingerprint_tests.c index 8c3cfc98..f5fd30fe 100644 --- a/test/fingerprint_tests.c +++ b/test/fingerprint_tests.c @@ -203,5 +203,32 @@ const char* tests[] = { "1a16559b625d7498", "ALTER TABLE baz.bar ADD COLUMN c int", "2f36adf7ba9689b8", + + // Test normalization of role name during fingerprinting. + "CREATE ROLE a", + "c455633f504f917a", + "CREATE ROLE b", + "31245d940af9bdb9", + "ALTER ROLE some_role RENAME TO some_other_role", + "af64e7bce9daa307", + "ALTER ROLE a RENAME TO b", + "260ce435ef1b5be6", + "DROP ROLE a", + "d8643bfda112eea6", + "DROP ROLE b", + "8219411c1be5fd07", + "DROP ROLE IF EXISTS a", + "5aec416bb0c4f1c2", + "DROP ROLE IF EXISTS b", + "0d3764a091e05317", + "GRANT SELECT ON some_table TO some_role", + "31905c256338fabc", + "GRANT SELECT ON some_table TO some_other_role", + "9d27dd2c45e4095f", + "REASSIGN OWNED BY old_role TO new_role", + "feeba332734ecd26", + "REASSIGN OWNED BY role_a TO role_b", + "e539478225d4b3dc", + NULL // Trailing NULL to tell the test runner we're done. }; From 6a6e4c320b7f8bb53ec178388f37a4cd1aa5f5a5 Mon Sep 17 00:00:00 2001 From: Ellen Marie Dash Date: Thu, 6 Aug 2026 10:56:42 -0400 Subject: [PATCH 2/4] Ignore role field of CreateRoleStmt --- scripts/generate_fingerprint_outfuncs.rb | 1 + src/include/pg_query_fingerprint_defs.c | 5 +---- test/fingerprint_tests.c | 4 ++-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/scripts/generate_fingerprint_outfuncs.rb b/scripts/generate_fingerprint_outfuncs.rb index 733861ac..1bdb9687 100755 --- a/scripts/generate_fingerprint_outfuncs.rb +++ b/scripts/generate_fingerprint_outfuncs.rb @@ -342,6 +342,7 @@ def initialize ['JsonTablePathSpec', 'name_location'] => :skip, ['JsonTablePathSpec', 'location'] => :skip, ['VariableSetStmt', 'jumble_args'] => :skip, # TODO: Should we be smarter about using this flag ourselves? + ['CreateRoleStmt', 'role'] => :skip, } INT_TYPES = ['bits32', 'uint32', 'int', 'int32', 'uint16', 'int16', 'Oid', 'Index', 'AttrNumber', 'SubTransactionId', 'RelFileNumber', 'ParseLoc'] LONG_INT_TYPES = ['long'] diff --git a/src/include/pg_query_fingerprint_defs.c b/src/include/pg_query_fingerprint_defs.c index 72d1284d..630407d0 100644 --- a/src/include/pg_query_fingerprint_defs.c +++ b/src/include/pg_query_fingerprint_defs.c @@ -11828,10 +11828,7 @@ _fingerprintCreateRoleStmt(FingerprintContext *ctx, const CreateRoleStmt *node, } XXH3_freeState(prev); } - if (node->role != NULL) { - _fingerprintString(ctx, "role"); - _fingerprintString(ctx, node->role); - } + // Intentionally ignoring node->role for fingerprinting if (true) { _fingerprintString(ctx, "stmt_type"); diff --git a/test/fingerprint_tests.c b/test/fingerprint_tests.c index f5fd30fe..ef939083 100644 --- a/test/fingerprint_tests.c +++ b/test/fingerprint_tests.c @@ -206,9 +206,9 @@ const char* tests[] = { // Test normalization of role name during fingerprinting. "CREATE ROLE a", - "c455633f504f917a", + "652129c250e27e46", "CREATE ROLE b", - "31245d940af9bdb9", + "652129c250e27e46", "ALTER ROLE some_role RENAME TO some_other_role", "af64e7bce9daa307", "ALTER ROLE a RENAME TO b", From f9697d9c48fd24dfc571d0bb3ef3f04602898834 Mon Sep 17 00:00:00 2001 From: Ellen Marie Dash Date: Thu, 6 Aug 2026 10:59:33 -0400 Subject: [PATCH 3/4] Ignore newname and subname fields of RenameStmt. --- scripts/generate_fingerprint_outfuncs.rb | 2 ++ src/include/pg_query_fingerprint_defs.c | 10 ++-------- test/fingerprint_tests.c | 4 ++-- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/scripts/generate_fingerprint_outfuncs.rb b/scripts/generate_fingerprint_outfuncs.rb index 1bdb9687..6aae25b6 100755 --- a/scripts/generate_fingerprint_outfuncs.rb +++ b/scripts/generate_fingerprint_outfuncs.rb @@ -343,6 +343,8 @@ def initialize ['JsonTablePathSpec', 'location'] => :skip, ['VariableSetStmt', 'jumble_args'] => :skip, # TODO: Should we be smarter about using this flag ourselves? ['CreateRoleStmt', 'role'] => :skip, + ['RenameStmt', 'newname'] => :skip, + ['RenameStmt', 'subname'] => :skip, } INT_TYPES = ['bits32', 'uint32', 'int', 'int32', 'uint16', 'int16', 'Oid', 'Index', 'AttrNumber', 'SubTransactionId', 'RelFileNumber', 'ParseLoc'] LONG_INT_TYPES = ['long'] diff --git a/src/include/pg_query_fingerprint_defs.c b/src/include/pg_query_fingerprint_defs.c index 630407d0..fece25d6 100644 --- a/src/include/pg_query_fingerprint_defs.c +++ b/src/include/pg_query_fingerprint_defs.c @@ -13286,10 +13286,7 @@ _fingerprintRenameStmt(FingerprintContext *ctx, const RenameStmt *node, const vo _fingerprintString(ctx, "true"); } - if (node->newname != NULL) { - _fingerprintString(ctx, "newname"); - _fingerprintString(ctx, node->newname); - } + // Intentionally ignoring node->newname for fingerprinting if (node->object != NULL) { XXH3_state_t* prev = XXH3_createState(); @@ -13335,10 +13332,7 @@ _fingerprintRenameStmt(FingerprintContext *ctx, const RenameStmt *node, const vo _fingerprintString(ctx, _enumToStringObjectType(node->renameType)); } - if (node->subname != NULL) { - _fingerprintString(ctx, "subname"); - _fingerprintString(ctx, node->subname); - } + // Intentionally ignoring node->subname for fingerprinting } diff --git a/test/fingerprint_tests.c b/test/fingerprint_tests.c index ef939083..d5a37e81 100644 --- a/test/fingerprint_tests.c +++ b/test/fingerprint_tests.c @@ -210,9 +210,9 @@ const char* tests[] = { "CREATE ROLE b", "652129c250e27e46", "ALTER ROLE some_role RENAME TO some_other_role", - "af64e7bce9daa307", + "6eea95cb0eaf740c", "ALTER ROLE a RENAME TO b", - "260ce435ef1b5be6", + "6eea95cb0eaf740c", "DROP ROLE a", "d8643bfda112eea6", "DROP ROLE b", From 816accbcdecddf324d93043ed699d78f4de4b5cc Mon Sep 17 00:00:00 2001 From: Ellen Marie Dash Date: Thu, 6 Aug 2026 11:05:24 -0400 Subject: [PATCH 4/4] Have fingerprinting ignore rolename field on RoleSpec struct, which ignores role names in DROP ROLE, GRANT, and REASSIGN OWNED BY statements --- scripts/generate_fingerprint_outfuncs.rb | 1 + src/include/pg_query_fingerprint_defs.c | 5 +---- test/fingerprint_tests.c | 18 +++++++++--------- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/scripts/generate_fingerprint_outfuncs.rb b/scripts/generate_fingerprint_outfuncs.rb index 6aae25b6..bf22542a 100755 --- a/scripts/generate_fingerprint_outfuncs.rb +++ b/scripts/generate_fingerprint_outfuncs.rb @@ -345,6 +345,7 @@ def initialize ['CreateRoleStmt', 'role'] => :skip, ['RenameStmt', 'newname'] => :skip, ['RenameStmt', 'subname'] => :skip, + ['RoleSpec', 'rolename'] => :skip, } INT_TYPES = ['bits32', 'uint32', 'int', 'int32', 'uint16', 'int16', 'Oid', 'Index', 'AttrNumber', 'SubTransactionId', 'RelFileNumber', 'ParseLoc'] LONG_INT_TYPES = ['long'] diff --git a/src/include/pg_query_fingerprint_defs.c b/src/include/pg_query_fingerprint_defs.c index fece25d6..1dc63ef9 100644 --- a/src/include/pg_query_fingerprint_defs.c +++ b/src/include/pg_query_fingerprint_defs.c @@ -4688,10 +4688,7 @@ _fingerprintRoleSpec(FingerprintContext *ctx, const RoleSpec *node, const void * { // Intentionally ignoring node->location for fingerprinting - if (node->rolename != NULL) { - _fingerprintString(ctx, "rolename"); - _fingerprintString(ctx, node->rolename); - } + // Intentionally ignoring node->rolename for fingerprinting if (true) { _fingerprintString(ctx, "roletype"); diff --git a/test/fingerprint_tests.c b/test/fingerprint_tests.c index d5a37e81..38850637 100644 --- a/test/fingerprint_tests.c +++ b/test/fingerprint_tests.c @@ -157,7 +157,7 @@ const char* tests[] = { "MERGE into measurement m USING new_measurement nm ON (m.city_id = nm.city_id and m.logdate=nm.logdate) WHEN MATCHED AND nm.peaktemp IS NULL THEN DELETE WHEN MATCHED THEN UPDATE SET peaktemp = greatest(m.peaktemp, nm.peaktemp), unitsales = m.unitsales + coalesce(nm.unitsales, 0) WHEN NOT MATCHED THEN INSERT (city_id, logdate, peaktemp, unitsales) VALUES (city_id, logdate, peaktemp, unitsales)", "4e3d1136f89c4229", "ALTER TABLE ALL IN TABLESPACE foo OWNED BY bar, quux SET TABLESPACE fred NOWAIT", - "1bcfca993d29bc0f", + "b29772e8207534a5", "CREATE PUBLICATION foo FOR TABLES IN SCHEMA bar", "7dfa0872d08125e6", "COPY vistest FROM stdin FREEZE CSV", @@ -214,21 +214,21 @@ const char* tests[] = { "ALTER ROLE a RENAME TO b", "6eea95cb0eaf740c", "DROP ROLE a", - "d8643bfda112eea6", + "f538c9be30bdfedc", "DROP ROLE b", - "8219411c1be5fd07", + "f538c9be30bdfedc", "DROP ROLE IF EXISTS a", - "5aec416bb0c4f1c2", + "8966c75ff804a16c", "DROP ROLE IF EXISTS b", - "0d3764a091e05317", + "8966c75ff804a16c", "GRANT SELECT ON some_table TO some_role", - "31905c256338fabc", + "b07ebf0c371d057a", "GRANT SELECT ON some_table TO some_other_role", - "9d27dd2c45e4095f", + "b07ebf0c371d057a", "REASSIGN OWNED BY old_role TO new_role", - "feeba332734ecd26", + "30516c6e029e9e94", "REASSIGN OWNED BY role_a TO role_b", - "e539478225d4b3dc", + "30516c6e029e9e94", NULL // Trailing NULL to tell the test runner we're done. };