Skip to content

handle out-of-order columns in partitioned table#4035

Merged
jgao54 merged 3 commits intomainfrom
clear-error-on-partitioned-table
Mar 18, 2026
Merged

handle out-of-order columns in partitioned table#4035
jgao54 merged 3 commits intomainfrom
clear-error-on-partitioned-table

Conversation

@jgao54
Copy link
Copy Markdown
Contributor

@jgao54 jgao54 commented Mar 10, 2026

Skip child partition relation messages in CDC stream.

With publish_via_partition_root = true, PostgreSQL emits both a parent and child RelationMessage before each partition's first change event.
Also note that with publish_via_partition_root = true, the insert/update/delete message would always use the parent's relation id, what I didn't realize was that the tuple data would also use the parent's column ordering.

this means the parent's RelationMessage carries the correct column ordering, while the child RelationMessage may have a different column ordering.

Previously, processRelationMessage would remap the parent's relation id to the child's relation message and store it in relationMessageMapping (p.relationMessageMapping[currRel.RelationID] = currRel), overwriting the parent's column ordering. This causes change events to be decoded against the child's column order, and if the child's column ordering has a mismatch with the parent, it would lead to decoding errors.

The fix for publish_via_partition_root = true's case turned out to be quite simple: skip the child's relation message rather than overwriting the relationMessageMapping with it.

Note that inherited tables work a bit differently because only the child table's RelationMessage would be sent, not the parent's. So we need to rely on child's RelationMessage. This does mean that inherited tables where the column order does not match the parent can also cause decoding errors. However this is an existing issue already and is out-of-scope for this PR.

Fixes: #3544

Testing: e2e test without the change fails but should succeeds after.

Follow up with #4045 to fix out-of-order columns in partitioned table when pubviaroot = false.

@jgao54 jgao54 force-pushed the clear-error-on-partitioned-table branch 3 times, most recently from 34df64a to 0c17f17 Compare March 10, 2026 20:29
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 10, 2026

❌ 4 Tests Failed:

Tests completed Failed Passed Skipped
2086 4 2082 180
View the top 3 failed test(s) by shortest run time
github.com/PeerDB-io/peerdb/flow/e2e::TestPeerFlowE2ETestSuiteSF
Stack Traces | 0.01s run time
=== RUN   TestPeerFlowE2ETestSuiteSF
=== PAUSE TestPeerFlowE2ETestSuiteSF
=== CONT  TestPeerFlowE2ETestSuiteSF
--- FAIL: TestPeerFlowE2ETestSuiteSF (0.01s)
github.com/PeerDB-io/peerdb/flow/e2e::TestPeerFlowE2ETestSuiteSF/Test_Column_Exclusion_With_Schema_Changes
Stack Traces | 33.4s run time
=== RUN   TestPeerFlowE2ETestSuiteSF/Test_Column_Exclusion_With_Schema_Changes
=== PAUSE TestPeerFlowE2ETestSuiteSF/Test_Column_Exclusion_With_Schema_Changes
=== CONT  TestPeerFlowE2ETestSuiteSF/Test_Column_Exclusion_With_Schema_Changes
    snowflake_test.go:1210: UNEXPECTED STATUS TIMEOUT STATUS_SETUP
    snowflake.go:114: begin tearing down postgres schema sf_qdw3pno6_20260317224543
--- FAIL: TestPeerFlowE2ETestSuiteSF/Test_Column_Exclusion_With_Schema_Changes (33.35s)
github.com/PeerDB-io/peerdb/flow/e2e::TestPeerFlowE2ETestSuiteSF/Test_Invalid_Numeric
Stack Traces | 33.8s run time
=== RUN   TestPeerFlowE2ETestSuiteSF/Test_Invalid_Numeric
=== PAUSE TestPeerFlowE2ETestSuiteSF/Test_Invalid_Numeric
=== CONT  TestPeerFlowE2ETestSuiteSF/Test_Invalid_Numeric
2026/03/17 22:45:42 INFO fetched schema x-peerdb-additional-metadata={Operation:FLOW_OPERATION_UNKNOWN} table=e2e_test_api_t55vtrgx.t1
    snowflake_test.go:116: UNEXPECTED STATUS TIMEOUT STATUS_SETUP
    snowflake.go:114: begin tearing down postgres schema sf_zaacrmgs_20260317224542
--- FAIL: TestPeerFlowE2ETestSuiteSF/Test_Invalid_Numeric (33.80s)
github.com/PeerDB-io/peerdb/flow/e2e::TestPeerFlowE2ETestSuiteSF/Test_Multi_Table_SF
Stack Traces | 33.9s run time
=== RUN   TestPeerFlowE2ETestSuiteSF/Test_Multi_Table_SF
=== PAUSE TestPeerFlowE2ETestSuiteSF/Test_Multi_Table_SF
=== CONT  TestPeerFlowE2ETestSuiteSF/Test_Multi_Table_SF
    snowflake_test.go:575: UNEXPECTED STATUS TIMEOUT STATUS_SETUP
    snowflake.go:114: begin tearing down postgres schema sf_apblgpzz_20260317224534
2026/03/17 22:46:08 INFO Executing and processing query x-peerdb-additional-metadata={Operation:FLOW_OPERATION_UNKNOWN} partitionId=testpart query="SELECT id,t1,t2,k FROM e2e_test_sf_9u9bo2i2_20260317224513.\"test_toast_sf_3\" ORDER BY id"
2026/03/17 22:46:08 INFO Executing and processing query stream x-peerdb-additional-metadata={Operation:FLOW_OPERATION_UNKNOWN} partitionId=testpart query="SELECT id,t1,t2,k FROM e2e_test_sf_9u9bo2i2_20260317224513.\"test_toast_sf_3\" ORDER BY id"
2026/03/17 22:46:08 INFO [pg_query_executor] declared cursor x-peerdb-additional-metadata={Operation:FLOW_OPERATION_UNKNOWN} partitionId=testpart cursorQuery="DECLARE peerdb_cursor_10877024238450863000 CURSOR FOR SELECT id,t1,t2,k FROM e2e_test_sf_9u9bo2i2_20260317224513.\"test_toast_sf_3\" ORDER BY id" args=[]
2026/03/17 22:46:08 INFO [pg_query_executor] fetching rows start x-peerdb-additional-metadata={Operation:FLOW_OPERATION_UNKNOWN} partitionId=testpart query="SELECT id,t1,t2,k FROM e2e_test_sf_9u9bo2i2_20260317224513.\"test_toast_sf_3\" ORDER BY id" channelLen=0
2026/03/17 22:46:08 INFO [pg_query_executor] fetching from cursor x-peerdb-additional-metadata={Operation:FLOW_OPERATION_UNKNOWN} partitionId=testpart cursor=peerdb_cursor_10877024238450863000
2026/03/17 22:46:08 INFO processed row stream x-peerdb-additional-metadata={Operation:FLOW_OPERATION_UNKNOWN} partitionId=testpart cursor=peerdb_cursor_10877024238450863000 records=1 bytes=17705 channelLen=0
2026/03/17 22:46:08 INFO [pg_query_executor] fetched rows x-peerdb-additional-metadata={Operation:FLOW_OPERATION_UNKNOWN} partitionId=testpart query="SELECT id,t1,t2,k FROM e2e_test_sf_9u9bo2i2_20260317224513.\"test_toast_sf_3\" ORDER BY id" rows=1 bytes=17705 channelLen=0
2026/03/17 22:46:08 INFO [pg_query_executor] fetching from cursor x-peerdb-additional-metadata={Operation:FLOW_OPERATION_UNKNOWN} partitionId=testpart cursor=peerdb_cursor_10877024238450863000
2026/03/17 22:46:08 INFO processed row stream x-peerdb-additional-metadata={Operation:FLOW_OPERATION_UNKNOWN} partitionId=testpart cursor=peerdb_cursor_10877024238450863000 records=0 bytes=0 channelLen=0
2026/03/17 22:46:08 INFO [pg_query_executor] fetched rows x-peerdb-additional-metadata={Operation:FLOW_OPERATION_UNKNOWN} partitionId=testpart query="SELECT id,t1,t2,k FROM e2e_test_sf_9u9bo2i2_20260317224513.\"test_toast_sf_3\" ORDER BY id" rows=0 bytes=0 channelLen=0
2026/03/17 22:46:08 INFO [pg_query_executor] committing transaction x-peerdb-additional-metadata={Operation:FLOW_OPERATION_UNKNOWN} partitionId=testpart
2026/03/17 22:46:08 INFO [pg_query_executor] committed transaction for query x-peerdb-additional-metadata={Operation:FLOW_OPERATION_UNKNOWN} partitionId=testpart query="SELECT id,t1,t2,k FROM e2e_test_sf_9u9bo2i2_20260317224513.\"test_toast_sf_3\" ORDER BY id" rows=1 bytes=17705 channelLen=0
--- FAIL: TestPeerFlowE2ETestSuiteSF/Test_Multi_Table_SF (33.89s)
github.com/PeerDB-io/peerdb/flow/e2e::TestPeerFlowE2ETestSuiteSF/Test_Supported_Mixed_Case_Table_SF
Stack Traces | 34.1s run time
=== RUN   TestPeerFlowE2ETestSuiteSF/Test_Supported_Mixed_Case_Table_SF
=== PAUSE TestPeerFlowE2ETestSuiteSF/Test_Supported_Mixed_Case_Table_SF
=== CONT  TestPeerFlowE2ETestSuiteSF/Test_Supported_Mixed_Case_Table_SF
2026/03/17 22:45:14 INFO fetched schema x-peerdb-additional-metadata={Operation:FLOW_OPERATION_UNKNOWN} table=e2e_test_api_aoxxehzp.added
    snowflake_test.go:1150: UNEXPECTED STATUS TIMEOUT STATUS_SETUP
    snowflake.go:114: begin tearing down postgres schema sf_4ov61h1b_20260317224514
2026/03/17 22:45:47 INFO Executing and processing query x-peerdb-additional-metadata={Operation:FLOW_OPERATION_UNKNOWN} partitionId=testpart query="SELECT id,c1,c2,t FROM e2e_test_sf_zjvb2pxp_20260317224450.\"test_simple_cpkey\" ORDER BY id"
2026/03/17 22:45:47 INFO Executing and processing query stream x-peerdb-additional-metadata={Operation:FLOW_OPERATION_UNKNOWN} partitionId=testpart query="SELECT id,c1,c2,t FROM e2e_test_sf_zjvb2pxp_20260317224450.\"test_simple_cpkey\" ORDER BY id"
2026/03/17 22:45:47 INFO [pg_query_executor] declared cursor x-peerdb-additional-metadata={Operation:FLOW_OPERATION_UNKNOWN} partitionId=testpart cursorQuery="DECLARE peerdb_cursor_1683803861288750462 CURSOR FOR SELECT id,c1,c2,t FROM e2e_test_sf_zjvb2pxp_20260317224450.\"test_simple_cpkey\" ORDER BY id" args=[]
2026/03/17 22:45:47 INFO [pg_query_executor] fetching rows start x-peerdb-additional-metadata={Operation:FLOW_OPERATION_UNKNOWN} partitionId=testpart query="SELECT id,c1,c2,t FROM e2e_test_sf_zjvb2pxp_20260317224450.\"test_simple_cpkey\" ORDER BY id" channelLen=0
2026/03/17 22:45:47 INFO [pg_query_executor] fetching from cursor x-peerdb-additional-metadata={Operation:FLOW_OPERATION_UNKNOWN} partitionId=testpart cursor=peerdb_cursor_1683803861288750462
2026/03/17 22:45:47 INFO processed row stream x-peerdb-additional-metadata={Operation:FLOW_OPERATION_UNKNOWN} partitionId=testpart cursor=peerdb_cursor_1683803861288750462 records=5 bytes=120 channelLen=4
2026/03/17 22:45:47 INFO [pg_query_executor] fetched rows x-peerdb-additional-metadata={Operation:FLOW_OPERATION_UNKNOWN} partitionId=testpart query="SELECT id,c1,c2,t FROM e2e_test_sf_zjvb2pxp_20260317224450.\"test_simple_cpkey\" ORDER BY id" rows=5 bytes=120 channelLen=4
2026/03/17 22:45:47 INFO [pg_query_executor] fetching from cursor x-peerdb-additional-metadata={Operation:FLOW_OPERATION_UNKNOWN} partitionId=testpart cursor=peerdb_cursor_1683803861288750462
2026/03/17 22:45:47 INFO processed row stream x-peerdb-additional-metadata={Operation:FLOW_OPERATION_UNKNOWN} partitionId=testpart cursor=peerdb_cursor_1683803861288750462 records=0 bytes=0 channelLen=0
2026/03/17 22:45:47 INFO [pg_query_executor] fetched rows x-peerdb-additional-metadata={Operation:FLOW_OPERATION_UNKNOWN} partitionId=testpart query="SELECT id,c1,c2,t FROM e2e_test_sf_zjvb2pxp_20260317224450.\"test_simple_cpkey\" ORDER BY id" rows=0 bytes=0 channelLen=0
2026/03/17 22:45:47 INFO [pg_query_executor] committing transaction x-peerdb-additional-metadata={Operation:FLOW_OPERATION_UNKNOWN} partitionId=testpart
2026/03/17 22:45:47 INFO [pg_query_executor] committed transaction for query x-peerdb-additional-metadata={Operation:FLOW_OPERATION_UNKNOWN} partitionId=testpart query="SELECT id,c1,c2,t FROM e2e_test_sf_zjvb2pxp_20260317224450.\"test_simple_cpkey\" ORDER BY id" rows=5 bytes=120 channelLen=0
--- FAIL: TestPeerFlowE2ETestSuiteSF/Test_Supported_Mixed_Case_Table_SF (34.07s)

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

@jgao54 jgao54 force-pushed the clear-error-on-partitioned-table branch 2 times, most recently from b24ac1c to a875037 Compare March 10, 2026 21:23
@jgao54 jgao54 changed the title handle out-of-order partitined table handle out-of-order partitioned table Mar 10, 2026
@jgao54 jgao54 force-pushed the clear-error-on-partitioned-table branch 2 times, most recently from bb1e777 to 622ab85 Compare March 11, 2026 21:18
@jgao54 jgao54 marked this pull request as ready for review March 11, 2026 21:51
@jgao54 jgao54 marked this pull request as draft March 11, 2026 22:00
@jgao54 jgao54 force-pushed the clear-error-on-partitioned-table branch 4 times, most recently from 31b9927 to 544a1b2 Compare March 12, 2026 01:20
@jgao54 jgao54 marked this pull request as ready for review March 12, 2026 01:39
@jgao54 jgao54 changed the title handle out-of-order partitioned table handle out-of-order columns in partitioned table Mar 12, 2026
@jgao54 jgao54 requested review from heavycrystal and ilidemi March 12, 2026 02:16
// followed by a child RelationMessage for each partition. The parent's
// column list matches the tuple data wire format, so skip the child's
// to avoid overwriting with a potentially reordered column definition.
if originalRelID != msg.RelationID && parentRelKind == 'p' && p.publishViaPartitionRoot {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: can store 'p' and other relkinds as a rune type somewhere and reference here so it's more clear what each relkind does

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

makes sense, there's a few other places where detecting relKind is needed, such as introducing ctid for partitioned tables, will consolidate it as a follow-up.

@jgao54 jgao54 force-pushed the clear-error-on-partitioned-table branch from 69ceb98 to 4dbe3ee Compare March 17, 2026 22:41
@github-actions
Copy link
Copy Markdown
Contributor

🔄 Flaky Test Detected

Analysis: All four failing Snowflake e2e tests timed out during the STATUS_SETUP phase with "UNEXPECTED STATUS TIMEOUT STATUS_SETUP", indicating a transient Snowflake connectivity/resource delay rather than a code regression.
Confidence: 0.92

✅ Automatically retrying the workflow

View workflow run

@github-actions
Copy link
Copy Markdown
Contributor

🔄 Flaky Test Detected

Analysis: The e2e test suite timed out after exactly 900 seconds (the configured limit), indicating a slow/overloaded CI environment rather than a code defect.
Confidence: 0.92

✅ Automatically retrying the workflow

View workflow run

@github-actions
Copy link
Copy Markdown
Contributor

🔄 Flaky Test Detected

Analysis: The TestPeerFlowE2ETestSuiteSF/Test_Multi_Table_SF test hit an UNEXPECTED TIMEOUT waiting for Snowflake normalization to complete, which is a timing-dependent e2e test against an external service rather than a code bug.
Confidence: 0.9

✅ Automatically retrying the workflow

View workflow run

@jgao54 jgao54 merged commit fa5064f into main Mar 18, 2026
14 of 18 checks passed
@jgao54 jgao54 deleted the clear-error-on-partitioned-table branch March 18, 2026 01:02
jgao54 added a commit that referenced this pull request Mar 31, 2026
jgao54 added a commit that referenced this pull request Mar 31, 2026
jgao54 added a commit that referenced this pull request Apr 8, 2026
jgao54 added a commit that referenced this pull request Apr 10, 2026
- Bring back #4035, optionally
query for pubviaroot only if pg version >= 13, otherwise default to
false since pubviaroot is not supported anyways
- Add e2e coverage to check that a dynamically added partition with
out-of-order columns works
- Validate that cdc continue to work on pg 12

Fixes: #3544
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ClickPipe Fails When Partition Column Order Differs from Parent (PostgreSQL)

2 participants