@@ -662,7 +662,8 @@ impl PgReplicationClient {
662
662
when 0 then true
663
663
else (a.attnum in (select * from pub_attrs))
664
664
end
665
- )" ,
665
+ )"
666
+ . to_string ( ) ,
666
667
)
667
668
} else {
668
669
// No column-level filtering, check if table is in publication
@@ -677,20 +678,90 @@ impl PgReplicationClient {
677
678
)" ,
678
679
publication = quote_literal( publication) ,
679
680
) ,
680
- "and (select count(*) from pub_table) > 0" ,
681
+ format ! (
682
+ "and ((select count(*) from pub_table) > 0 or exists(
683
+ -- Also allow if parent table is in publication (for partitioned tables)
684
+ select 1 from pg_inherits i
685
+ join pg_publication_rel r on r.prrelid = i.inhparent
686
+ join pg_publication p on p.oid = r.prpubid
687
+ where i.inhrelid = {table_id} and p.pubname = {publication}
688
+ ))" ,
689
+ publication = quote_literal( publication) ,
690
+ ) ,
681
691
)
682
692
}
683
693
} else {
684
- ( "" . into ( ) , "" )
694
+ ( "" . to_string ( ) , "" . to_string ( ) )
695
+ } ;
696
+
697
+ let has_pub_cte = !pub_cte. is_empty ( ) ;
698
+
699
+ let cte_prefix = if has_pub_cte {
700
+ // If there's already a pub_cte WITH clause, add our CTEs to it with a comma
701
+ format ! ( "{pub_cte}," )
702
+ } else {
703
+ // If no pub_cte, start our own WITH clause (no need for RECURSIVE)
704
+ "with " . to_string ( )
685
705
} ;
686
706
687
707
let column_info_query = format ! (
688
- "{pub_cte}
689
- select a.attname,
708
+ "{cte_prefix}
709
+ -- Find direct parent of current table (if it's a partition)
710
+ direct_parent as (
711
+ select i.inhparent as parent_oid
712
+ from pg_inherits i
713
+ where i.inhrelid = {table_id}::oid
714
+ limit 1
715
+ ),
716
+ -- Get parent table's primary key columns
717
+ parent_pk_cols as (
718
+ select array_agg(a.attname order by x.n) as pk_column_names
719
+ from pg_constraint con
720
+ join unnest(con.conkey) with ordinality as x(attnum, n) on true
721
+ join pg_attribute a on a.attrelid = con.conrelid and a.attnum = x.attnum
722
+ join direct_parent dp on con.conrelid = dp.parent_oid
723
+ where con.contype = 'p'
724
+ group by con.conname
725
+ ),
726
+ -- Check if current table has a unique index on the parent PK columns
727
+ partition_has_pk_index as (
728
+ select case
729
+ when exists (select 1 from direct_parent)
730
+ and exists (select 1 from parent_pk_cols)
731
+ and exists (
732
+ -- Check if there's a unique, valid index on the parent PK columns
733
+ select 1
734
+ from pg_index ix
735
+ cross join parent_pk_cols pk
736
+ where ix.indrelid = {table_id}::oid
737
+ and ix.indisunique = true
738
+ and ix.indisvalid = true
739
+ and array(
740
+ select a.attname
741
+ from unnest(ix.indkey) with ordinality k(attnum, ord)
742
+ join pg_attribute a on a.attrelid = ix.indrelid and a.attnum = k.attnum
743
+ where ord <= ix.indnkeyatts -- exclude INCLUDE columns
744
+ order by ord
745
+ ) = pk.pk_column_names
746
+ ) then true
747
+ else false
748
+ end as has_inherited_pk
749
+ )
750
+ SELECT a.attname,
690
751
a.atttypid,
691
752
a.atttypmod,
692
753
a.attnotnull,
693
- coalesce(i.indisprimary, false) as primary
754
+ case
755
+ -- First check for direct primary key
756
+ when coalesce(i.indisprimary, false) = true then true
757
+ -- Then check for inherited primary key from partitioned table parent
758
+ when (select has_inherited_pk from partition_has_pk_index) = true
759
+ and exists (
760
+ select 1 from parent_pk_cols pk
761
+ where a.attname = any(pk.pk_column_names)
762
+ ) then true
763
+ else false
764
+ end as primary
694
765
from pg_attribute a
695
766
left join pg_index i
696
767
on a.attrelid = i.indrelid
0 commit comments