Обсуждение: Proposal: Conflict log history table for Logical Replication
Currently we log conflicts to the server's log file and updates, this approach has limitations, 1) Difficult to query and analyze, parsing plain text log files for conflict details is inefficient. 2) Lack of structured data, key conflict attributes (table, operation, old/new data, LSN, etc.) are not readily available in a structured, queryable format. 3) Difficult for external monitoring tools or custom resolution scripts to consume conflict data directly. This proposal aims to address these limitations by introducing a conflict log history table, providing a structured, and queryable record of all logical replication conflicts. This should be a configurable option whether to log into the conflict log history table, server logs or both. This proposal has two main design questions: =================================== 1. How do we store conflicting tuples from different tables? Using a JSON column to store the row data seems like the most flexible solution, as it can accommodate different table schemas. 2. Should this be a system table or a user table? a) System Table: Storing this in a system catalog is simple, but catalogs aren't designed for ever-growing data. While pg_large_object is an exception, this is not what we generally do IMHO. b) User Table: This offers more flexibility. We could allow a user to specify the table name during CREATE SUBSCRIPTION. Then we choose to either create the table internally or let the user create the table with a predefined schema. A potential drawback is that a user might drop or alter the table. However, we could mitigate this risk by simply logging a WARNING if the table is configured but an insertion fails. I am currently working on a POC patch for the same, but will post that once we have some thoughts on design choices. Schema for the conflict log history table may look like this, although there is a room for discussion on this. Note: I think these fields are self explanatory so I haven't explained them here. conflict_log_table ( logid SERIAL PRIMARY KEY, subid OID, schema_id OID, table_id OID, conflict_type TEXT NOT NULL, operation_type TEXT NOT NULL, replication_origin TEXT, remote_commit_ts TIMESTAMPTZ, local_commit_ts TIMESTAMPTZ, ri_key JSON, remote_tuple JSON, local_tuple JSON, ); Credit: Thanks to Amit Kapila for discussing this offlist and providing some valuable suggestions. -- Regards, Dilip Kumar Google
On Tue, Aug 5, 2025 at 5:54 PM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > Currently we log conflicts to the server's log file and updates, this > approach has limitations, 1) Difficult to query and analyze, parsing > plain text log files for conflict details is inefficient. 2) Lack of > structured data, key conflict attributes (table, operation, old/new > data, LSN, etc.) are not readily available in a structured, queryable > format. 3) Difficult for external monitoring tools or custom > resolution scripts to consume conflict data directly. > > This proposal aims to address these limitations by introducing a > conflict log history table, providing a structured, and queryable > record of all logical replication conflicts. This should be a > configurable option whether to log into the conflict log history > table, server logs or both. > +1 for the idea. > This proposal has two main design questions: > =================================== > > 1. How do we store conflicting tuples from different tables? > Using a JSON column to store the row data seems like the most flexible > solution, as it can accommodate different table schemas. Yes, that is one option. I have not looked into details myself, but you can also explore 'anyarray' used in pg_statistics to store 'Column data values of the appropriate kind'. > 2. Should this be a system table or a user table? > a) System Table: Storing this in a system catalog is simple, but > catalogs aren't designed for ever-growing data. While pg_large_object > is an exception, this is not what we generally do IMHO. > b) User Table: This offers more flexibility. We could allow a user to > specify the table name during CREATE SUBSCRIPTION. Then we choose to > either create the table internally or let the user create the table > with a predefined schema. > > A potential drawback is that a user might drop or alter the table. > However, we could mitigate this risk by simply logging a WARNING if > the table is configured but an insertion fails. I believe it makes more sense for this to be a catalog table rather than a user table. I wanted to check if we already have a large catalog table of this kind, and I think pg_statistic could be an example of a sizable catalog table. To get a rough idea of how size scales with data, I ran a quick experiment: I created 1000 tables, each with 2 JSON columns, 1 text column, and 2 integer columns. Then, I inserted 1000 rows into each table and ran ANALYZE to collect statistics. Here’s what I observed on a fresh database before and after: Before: pg_statistic row count: 412 Table size: ~256 kB After: pg_statistic row count: 6,412 Table size: ~5.3 MB Although it isn’t an exact comparison, this gives us some insight into how the statistics catalog table size grows with the number of rows. It doesn’t seem excessively large with 6k rows, given the fact that pg_statistic itself is a complex table having many 'anyarray'-type columns. That said, irrespective of what we decide, it would be ideal to offer users an option for automatic purging, perhaps via a retention period parameter like conflict_stats_retention_period (say default to 30 days), or a manual purge API such as purge_conflict_stats('older than date'). I wasn’t able to find any such purge mechanism for PostgreSQL stats tables, but Oracle does provide such purging options for some of their statistics tables (not related to conflicts), see [1], [2]. And to manage it better, it could be range partitioned on timestamp. > I am currently working on a POC patch for the same, but will post that > once we have some thoughts on design choices. > > Schema for the conflict log history table may look like this, although > there is a room for discussion on this. > > Note: I think these fields are self explanatory so I haven't > explained them here. > > conflict_log_table ( > logid SERIAL PRIMARY KEY, > subid OID, > schema_id OID, > table_id OID, > conflict_type TEXT NOT NULL, > operation_type TEXT NOT NULL, I feel operation_type is not needed when we already have conflict_type. The name of 'conflict_type' is enough to give us info on operation-type. > replication_origin TEXT, > remote_commit_ts TIMESTAMPTZ, > local_commit_ts TIMESTAMPTZ, > ri_key JSON, > remote_tuple JSON, > local_tuple JSON, > ); > > Credit: Thanks to Amit Kapila for discussing this offlist and > providing some valuable suggestions. > [1] https://docs.oracle.com/en/database/oracle/oracle-database/21/arpls/DBMS_STATS.html#GUID-8E6413D5-F827-4F57-9FAD-7EC56362A98C [2] https://docs.oracle.com/en/database/oracle/oracle-database/21/arpls/DBMS_STATS.html#GUID-A04AE1C0-5DE1-4AFC-91F8-D35D41DF98A2 thanks Shveta
On Thu, Aug 7, 2025 at 12:25 PM shveta malik <shveta.malik@gmail.com> wrote: > > On Tue, Aug 5, 2025 at 5:54 PM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > > > Currently we log conflicts to the server's log file and updates, this > > approach has limitations, 1) Difficult to query and analyze, parsing > > plain text log files for conflict details is inefficient. 2) Lack of > > structured data, key conflict attributes (table, operation, old/new > > data, LSN, etc.) are not readily available in a structured, queryable > > format. 3) Difficult for external monitoring tools or custom > > resolution scripts to consume conflict data directly. > > > > This proposal aims to address these limitations by introducing a > > conflict log history table, providing a structured, and queryable > > record of all logical replication conflicts. This should be a > > configurable option whether to log into the conflict log history > > table, server logs or both. > > > > +1 for the idea. > > > This proposal has two main design questions: > > =================================== > > > > 1. How do we store conflicting tuples from different tables? > > Using a JSON column to store the row data seems like the most flexible > > solution, as it can accommodate different table schemas. > > Yes, that is one option. I have not looked into details myself, but > you can also explore 'anyarray' used in pg_statistics to store 'Column > data values of the appropriate kind'. > > > 2. Should this be a system table or a user table? > > a) System Table: Storing this in a system catalog is simple, but > > catalogs aren't designed for ever-growing data. While pg_large_object > > is an exception, this is not what we generally do IMHO. > > b) User Table: This offers more flexibility. We could allow a user to > > specify the table name during CREATE SUBSCRIPTION. Then we choose to > > either create the table internally or let the user create the table > > with a predefined schema. > > > > A potential drawback is that a user might drop or alter the table. > > However, we could mitigate this risk by simply logging a WARNING if > > the table is configured but an insertion fails. > > I believe it makes more sense for this to be a catalog table rather > than a user table. I wanted to check if we already have a large > catalog table of this kind, and I think pg_statistic could be an > example of a sizable catalog table. To get a rough idea of how size > scales with data, I ran a quick experiment: I created 1000 tables, > each with 2 JSON columns, 1 text column, and 2 integer columns. Then, > I inserted 1000 rows into each table and ran ANALYZE to collect > statistics. Here’s what I observed on a fresh database before and > after: > > Before: > pg_statistic row count: 412 > Table size: ~256 kB > > After: > pg_statistic row count: 6,412 > Table size: ~5.3 MB > > Although it isn’t an exact comparison, this gives us some insight into > how the statistics catalog table size grows with the number of rows. > It doesn’t seem excessively large with 6k rows, given the fact that > pg_statistic itself is a complex table having many 'anyarray'-type > columns. > > That said, irrespective of what we decide, it would be ideal to offer > users an option for automatic purging, perhaps via a retention period > parameter like conflict_stats_retention_period (say default to 30 > days), or a manual purge API such as purge_conflict_stats('older than > date'). I wasn’t able to find any such purge mechanism for PostgreSQL > stats tables, but Oracle does provide such purging options for some of > their statistics tables (not related to conflicts), see [1], [2]. > And to manage it better, it could be range partitioned on timestamp. > It seems BDR also has one such conflict-log table which is a catalog table and is also partitioned on time. It has a default retention period of 30 days. See 'bdr.conflict_history' mentioned under 'catalogs' in [1] [1]: https://www.enterprisedb.com/docs/pgd/latest/reference/tables-views-functions/#user-visible-catalogs-and-views thanks Shveta
On Thu, Aug 7, 2025 at 1:43 PM shveta malik <shveta.malik@gmail.com> wrote: > > On Thu, Aug 7, 2025 at 12:25 PM shveta malik <shveta.malik@gmail.com> wrote: Thanks Shveta for your opinion on the design. > > On Tue, Aug 5, 2025 at 5:54 PM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > > > > > This proposal aims to address these limitations by introducing a > > > conflict log history table, providing a structured, and queryable > > > record of all logical replication conflicts. This should be a > > > configurable option whether to log into the conflict log history > > > table, server logs or both. > > > > > > > +1 for the idea. Thanks > > > > > This proposal has two main design questions: > > > =================================== > > > > > > 1. How do we store conflicting tuples from different tables? > > > Using a JSON column to store the row data seems like the most flexible > > > solution, as it can accommodate different table schemas. > > > > Yes, that is one option. I have not looked into details myself, but > > you can also explore 'anyarray' used in pg_statistics to store 'Column > > data values of the appropriate kind'. I think conversion from row to json and json to row is convenient and also other extensions like pgactive/bdr also provide as JSON. But we can explore this alternative options as well, thanks > > > 2. Should this be a system table or a user table? > > > a) System Table: Storing this in a system catalog is simple, but > > > catalogs aren't designed for ever-growing data. While pg_large_object > > > is an exception, this is not what we generally do IMHO. > > > b) User Table: This offers more flexibility. We could allow a user to > > > specify the table name during CREATE SUBSCRIPTION. Then we choose to > > > either create the table internally or let the user create the table > > > with a predefined schema. > > > > > > A potential drawback is that a user might drop or alter the table. > > > However, we could mitigate this risk by simply logging a WARNING if > > > the table is configured but an insertion fails. > > > > I believe it makes more sense for this to be a catalog table rather > > than a user table. I wanted to check if we already have a large > > catalog table of this kind, and I think pg_statistic could be an > > example of a sizable catalog table. To get a rough idea of how size > > scales with data, I ran a quick experiment: I created 1000 tables, > > each with 2 JSON columns, 1 text column, and 2 integer columns. Then, > > I inserted 1000 rows into each table and ran ANALYZE to collect > > statistics. Here’s what I observed on a fresh database before and > > after: > > > > Before: > > pg_statistic row count: 412 > > Table size: ~256 kB > > > > After: > > pg_statistic row count: 6,412 > > Table size: ~5.3 MB > > > > Although it isn’t an exact comparison, this gives us some insight into > > how the statistics catalog table size grows with the number of rows. > > It doesn’t seem excessively large with 6k rows, given the fact that > > pg_statistic itself is a complex table having many 'anyarray'-type > > columns. Yeah that's good analysis, apart from this pg_largeobject is also a catalog which grows with each large object and growth rate for that will be very high because it stores large object data in catalog. > > > > That said, irrespective of what we decide, it would be ideal to offer > > users an option for automatic purging, perhaps via a retention period > > parameter like conflict_stats_retention_period (say default to 30 > > days), or a manual purge API such as purge_conflict_stats('older than > > date'). I wasn’t able to find any such purge mechanism for PostgreSQL > > stats tables, but Oracle does provide such purging options for some of > > their statistics tables (not related to conflicts), see [1], [2]. > > And to manage it better, it could be range partitioned on timestamp. Yeah that's an interesting suggestion to timestamp based partitioning it for purging. > It seems BDR also has one such conflict-log table which is a catalog > table and is also partitioned on time. It has a default retention > period of 30 days. See 'bdr.conflict_history' mentioned under > 'catalogs' in [1] > > [1]: https://www.enterprisedb.com/docs/pgd/latest/reference/tables-views-functions/#user-visible-catalogs-and-views Actually bdr is an extension and this table is under extension namespace (bdr.conflict_history) so this is not really a catalog but its a extension managed table. So logically for PostgreSQL its an user table but yeah this is created and managed by the extension. -- Regards, Dilip Kumar Google
On Thu, Aug 7, 2025 at 3:08 PM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > On Thu, Aug 7, 2025 at 1:43 PM shveta malik <shveta.malik@gmail.com> wrote: > > > > On Thu, Aug 7, 2025 at 12:25 PM shveta malik <shveta.malik@gmail.com> wrote: > > Thanks Shveta for your opinion on the design. > > > > On Tue, Aug 5, 2025 at 5:54 PM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > > > > > > > > This proposal aims to address these limitations by introducing a > > > > conflict log history table, providing a structured, and queryable > > > > record of all logical replication conflicts. This should be a > > > > configurable option whether to log into the conflict log history > > > > table, server logs or both. > > > > > > > > > > +1 for the idea. > > Thanks > > > > > > > > This proposal has two main design questions: > > > > =================================== > > > > > > > > 1. How do we store conflicting tuples from different tables? > > > > Using a JSON column to store the row data seems like the most flexible > > > > solution, as it can accommodate different table schemas. > > > > > > Yes, that is one option. I have not looked into details myself, but > > > you can also explore 'anyarray' used in pg_statistics to store 'Column > > > data values of the appropriate kind'. > > I think conversion from row to json and json to row is convenient and > also other extensions like pgactive/bdr also provide as JSON. Okay. Agreed. > But we > can explore this alternative options as well, thanks > > > > > 2. Should this be a system table or a user table? > > > > a) System Table: Storing this in a system catalog is simple, but > > > > catalogs aren't designed for ever-growing data. While pg_large_object > > > > is an exception, this is not what we generally do IMHO. > > > > b) User Table: This offers more flexibility. We could allow a user to > > > > specify the table name during CREATE SUBSCRIPTION. Then we choose to > > > > either create the table internally or let the user create the table > > > > with a predefined schema. > > > > > > > > A potential drawback is that a user might drop or alter the table. > > > > However, we could mitigate this risk by simply logging a WARNING if > > > > the table is configured but an insertion fails. > > > > > > I believe it makes more sense for this to be a catalog table rather > > > than a user table. I wanted to check if we already have a large > > > catalog table of this kind, and I think pg_statistic could be an > > > example of a sizable catalog table. To get a rough idea of how size > > > scales with data, I ran a quick experiment: I created 1000 tables, > > > each with 2 JSON columns, 1 text column, and 2 integer columns. Then, > > > I inserted 1000 rows into each table and ran ANALYZE to collect > > > statistics. Here’s what I observed on a fresh database before and > > > after: > > > > > > Before: > > > pg_statistic row count: 412 > > > Table size: ~256 kB > > > > > > After: > > > pg_statistic row count: 6,412 > > > Table size: ~5.3 MB > > > > > > Although it isn’t an exact comparison, this gives us some insight into > > > how the statistics catalog table size grows with the number of rows. > > > It doesn’t seem excessively large with 6k rows, given the fact that > > > pg_statistic itself is a complex table having many 'anyarray'-type > > > columns. > > Yeah that's good analysis, apart from this pg_largeobject is also a > catalog which grows with each large object and growth rate for that > will be very high because it stores large object data in catalog. > > > > > > > That said, irrespective of what we decide, it would be ideal to offer > > > users an option for automatic purging, perhaps via a retention period > > > parameter like conflict_stats_retention_period (say default to 30 > > > days), or a manual purge API such as purge_conflict_stats('older than > > > date'). I wasn’t able to find any such purge mechanism for PostgreSQL > > > stats tables, but Oracle does provide such purging options for some of > > > their statistics tables (not related to conflicts), see [1], [2]. > > > And to manage it better, it could be range partitioned on timestamp. > > Yeah that's an interesting suggestion to timestamp based partitioning > it for purging. > > > It seems BDR also has one such conflict-log table which is a catalog > > table and is also partitioned on time. It has a default retention > > period of 30 days. See 'bdr.conflict_history' mentioned under > > 'catalogs' in [1] > > > > [1]: https://www.enterprisedb.com/docs/pgd/latest/reference/tables-views-functions/#user-visible-catalogs-and-views > > Actually bdr is an extension and this table is under extension > namespace (bdr.conflict_history) so this is not really a catalog but > its a extension managed table. Yes, right. Sorry for confusion. > So logically for PostgreSQL its an > user table but yeah this is created and managed by the extension. > Any idea if the user can alter/drop or perform any DML on it? I could not find any details on this part. > -- > Regards, > Dilip Kumar > Google
On Fri, Aug 8, 2025 at 8:58 AM shveta malik <shveta.malik@gmail.com> wrote: > > On Thu, Aug 7, 2025 at 3:08 PM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > > > So logically for PostgreSQL its an > > user table but yeah this is created and managed by the extension. > > > > Any idea if the user can alter/drop or perform any DML on it? I could > not find any details on this part. In my experience, for such extension managed tables where we want them to behave like catalog, generally users are just granted with SELECT permission. So although it is not a catalog but for accessibility wise for non admin users it is like a catalog. IMHO, even if we choose to create a user table for conflict log history we can also control the permissions similarly. What's your opinion on this? -- Regards, Dilip Kumar Google
On Fri, Aug 8, 2025 at 10:01 AM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > On Fri, Aug 8, 2025 at 8:58 AM shveta malik <shveta.malik@gmail.com> wrote: > > > > On Thu, Aug 7, 2025 at 3:08 PM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > > > > > So logically for PostgreSQL its an > > > user table but yeah this is created and managed by the extension. > > > > > > > Any idea if the user can alter/drop or perform any DML on it? I could > > not find any details on this part. > > In my experience, for such extension managed tables where we want them > to behave like catalog, generally users are just granted with SELECT > permission. So although it is not a catalog but for accessibility > wise for non admin users it is like a catalog. IMHO, even if we > choose to create a user table for conflict log history we can also > control the permissions similarly. > Yes, it can be done. Technically there is nothing preventing us from doing it. But in my experience, I have never seen any system-maintained statistics tables to be a user table rather than catalog table. Extensions are a different case; they typically manage their own tables, which are not part of the system catalog. But if any such stats related functionality is part of the core database, it generally makes more sense to implement it as a catalog table (provided there are no major obstacles to doing so). But I am curious to know what others think here. thanks Shveta
On Fri, Aug 8, 2025 at 10:01 AM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > On Fri, Aug 8, 2025 at 8:58 AM shveta malik <shveta.malik@gmail.com> wrote: > > > > On Thu, Aug 7, 2025 at 3:08 PM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > > > > > So logically for PostgreSQL its an > > > user table but yeah this is created and managed by the extension. > > > > > > > Any idea if the user can alter/drop or perform any DML on it? I could > > not find any details on this part. > > In my experience, for such extension managed tables where we want them > to behave like catalog, generally users are just granted with SELECT > permission. So although it is not a catalog but for accessibility > wise for non admin users it is like a catalog. IMHO, even if we > choose to create a user table for conflict log history we can also > control the permissions similarly. What's your opinion on this? > Yes, I think it is important to control permissions on this table even if it is a user table. How about giving SELECT, DELETE, TRUNCATE permissions to subscription owner assuming we create one such table per subscription? It should be a user table due to following reasons (a) It is an ever growing table by definition and we need some level of user control to manage it (like remove the old data); (b) We may want some sort of partitioning streategy to manage it, even though, we decide to do it ourselves now but in future, we should allow user to also specify it; (c) We may also want user to specify what exact information she wants to get stored considering in future we want resolutions to also be stored in it. See a somewhat similar proposal to store errors during copy by Tom [1]; (d) In a near-by thread, we are discussing storing errors during copy in user table [2] and we have some similarity with that proposal as well. If we agree on this then the next thing to consider is whether we allow users to create such a table or do it ourselves. In the long term, we may want both but for simplicity, we can auto-create ourselves during CREATE SUBSCRIPTION with some option. BTW, if we decide to let user create it then we can consider the idea of TYPED tables as discussed in emails [3][4]. For user tables, we need to consider how to avoid replicating these tables for publications that use FOR ALL TABLES specifier. One idea is to use EXCLUDE table functionality as being discussed in thread [5] but that would also be a bit tricky especially if we decide to create such a table automatically. One naive idea is that internally we skip sending changes from this table for "FOR ALL TABLES" publication, and we shouldn't allow creating publication for this table. OTOH, if we allow the user to create and specify this table, we can ask her to specify with EXCLUDE syntax in publication. This needs more thoughts. [1] - https://www.postgresql.org/message-id/flat/752672.1699474336%40sss.pgh.pa.us#b8450be5645c4252d7d02cf7aca1fc7b [2] - https://www.postgresql.org/message-id/CACJufxH_OJpVra%3D0c4ow8fbxHj7heMcVaTNEPa5vAurSeNA-6Q%40mail.gmail.com [3] - https://www.postgresql.org/message-id/28c420cf-f25d-44f1-89fd-04ef0b2dd3db%40dunslane.net [4] - https://www.postgresql.org/message-id/CADrsxdYG%2B%2BK%3DiKjRm35u03q-Nb0tQPJaqjxnA2mGt5O%3DDht7sw%40mail.gmail.com [5] - https://www.postgresql.org/message-id/CANhcyEW%2BuJB_bvQLEaZCgoRTc1%3Di%2BQnrPPHxZ2%3D0SBSCyj9pkg%40mail.gmail.com -- With Regards, Amit Kapila.
On Wed, 13 Aug 2025 at 11:09, Amit Kapila <amit.kapila16@gmail.com> wrote:
On Fri, Aug 8, 2025 at 10:01 AM Dilip Kumar <dilipbalaut@gmail.com> wrote:
>
> On Fri, Aug 8, 2025 at 8:58 AM shveta malik <shveta.malik@gmail.com> wrote:
> >
> > On Thu, Aug 7, 2025 at 3:08 PM Dilip Kumar <dilipbalaut@gmail.com> wrote:
> > >
> > > So logically for PostgreSQL its an
> > > user table but yeah this is created and managed by the extension.
> > >
> >
> > Any idea if the user can alter/drop or perform any DML on it? I could
> > not find any details on this part.
>
> In my experience, for such extension managed tables where we want them
> to behave like catalog, generally users are just granted with SELECT
> permission. So although it is not a catalog but for accessibility
> wise for non admin users it is like a catalog. IMHO, even if we
> choose to create a user table for conflict log history we can also
> control the permissions similarly. What's your opinion on this?
>
Yes, I think it is important to control permissions on this table even
if it is a user table. How about giving SELECT, DELETE, TRUNCATE
permissions to subscription owner assuming we create one such table
per subscription?
It should be a user table due to following reasons (a) It is an ever
growing table by definition and we need some level of user control to
manage it (like remove the old data); (b) We may want some sort of
partitioning streategy to manage it, even though, we decide to do it
ourselves now but in future, we should allow user to also specify it;
(c) We may also want user to specify what exact information she wants
to get stored considering in future we want resolutions to also be
stored in it. See a somewhat similar proposal to store errors during
copy by Tom [1]; (d) In a near-by thread, we are discussing storing
errors during copy in user table [2] and we have some similarity with
that proposal as well.
If we agree on this then the next thing to consider is whether we
allow users to create such a table or do it ourselves. In the long
term, we may want both but for simplicity, we can auto-create
ourselves during CREATE SUBSCRIPTION with some option. BTW, if we
decide to let user create it then we can consider the idea of TYPED
tables as discussed in emails [3][4].
Having it be a user table, and specifying the table per subscription sounds good. This is very similar to how the load error tables for CloudBerry behave, for instance. To have both options for table creation, CREATE ... IF NOT EXISTS semantics work well - if the option on CREATE SUBSCRIPTION specifies an existing table of the right type use it, or create one with the name supplied. This would also give the user control over whether to have one table per subscription, one central table or anything in between. Rather than constraining permissions on the table, the CREATE SUBSCRIPTION command could create a dependency relationship between the table and the subscription.This would prevent removal of the table, even by a superuser.
For user tables, we need to consider how to avoid replicating these
tables for publications that use FOR ALL TABLES specifier. One idea is
to use EXCLUDE table functionality as being discussed in thread [5]
but that would also be a bit tricky especially if we decide to create
such a table automatically. One naive idea is that internally we skip
sending changes from this table for "FOR ALL TABLES" publication, and
we shouldn't allow creating publication for this table. OTOH, if we
allow the user to create and specify this table, we can ask her to
specify with EXCLUDE syntax in publication. This needs more thoughts.
If a dependency relationship is established between the error table and the subscription, could this be used as a basis for filtering the error tables from FOR ALL TABLES subscriptions?
Regards
Alastair
On Thu, Aug 14, 2025 at 4:26 PM Alastair Turner <minion@decodable.me> wrote: > > On Wed, 13 Aug 2025 at 11:09, Amit Kapila <amit.kapila16@gmail.com> wrote: >> >> On Fri, Aug 8, 2025 at 10:01 AM Dilip Kumar <dilipbalaut@gmail.com> wrote: >> > >> > On Fri, Aug 8, 2025 at 8:58 AM shveta malik <shveta.malik@gmail.com> wrote: >> > > >> > > On Thu, Aug 7, 2025 at 3:08 PM Dilip Kumar <dilipbalaut@gmail.com> wrote: >> > > > >> > > > So logically for PostgreSQL its an >> > > > user table but yeah this is created and managed by the extension. >> > > > >> > > >> > > Any idea if the user can alter/drop or perform any DML on it? I could >> > > not find any details on this part. >> > >> > In my experience, for such extension managed tables where we want them >> > to behave like catalog, generally users are just granted with SELECT >> > permission. So although it is not a catalog but for accessibility >> > wise for non admin users it is like a catalog. IMHO, even if we >> > choose to create a user table for conflict log history we can also >> > control the permissions similarly. What's your opinion on this? >> > >> >> Yes, I think it is important to control permissions on this table even >> if it is a user table. How about giving SELECT, DELETE, TRUNCATE >> permissions to subscription owner assuming we create one such table >> per subscription? >> >> It should be a user table due to following reasons (a) It is an ever >> growing table by definition and we need some level of user control to >> manage it (like remove the old data); (b) We may want some sort of >> partitioning streategy to manage it, even though, we decide to do it >> ourselves now but in future, we should allow user to also specify it; >> (c) We may also want user to specify what exact information she wants >> to get stored considering in future we want resolutions to also be >> stored in it. See a somewhat similar proposal to store errors during >> copy by Tom [1]; (d) In a near-by thread, we are discussing storing >> errors during copy in user table [2] and we have some similarity with >> that proposal as well. >> >> If we agree on this then the next thing to consider is whether we >> allow users to create such a table or do it ourselves. In the long >> term, we may want both but for simplicity, we can auto-create >> ourselves during CREATE SUBSCRIPTION with some option. BTW, if we >> decide to let user create it then we can consider the idea of TYPED >> tables as discussed in emails [3][4]. > > > Having it be a user table, and specifying the table per subscription sounds good. This is very similar to how the loaderror tables for CloudBerry behave, for instance. To have both options for table creation, CREATE ... IF NOT EXISTS semanticswork well - if the option on CREATE SUBSCRIPTION specifies an existing table of the right type use it, or createone with the name supplied. This would also give the user control over whether to have one table per subscription,one central table or anything in between. > Sounds reasonable. I think the first version we can let such a table be created automatically with some option(s) with subscription. Then, in subsequent versions, we can extend the functionality to allow existing tables. > > Rather than constraining permissions on the table, the CREATE SUBSCRIPTION command could create a dependency relationshipbetween the table and the subscription.This would prevent removal of the table, even by a superuser. > Okay, that makes sense. But, we still probably want to disallow users from inserting or updating rows in the conflict table. >> >> For user tables, we need to consider how to avoid replicating these >> tables for publications that use FOR ALL TABLES specifier. One idea is >> to use EXCLUDE table functionality as being discussed in thread [5] >> but that would also be a bit tricky especially if we decide to create >> such a table automatically. One naive idea is that internally we skip >> sending changes from this table for "FOR ALL TABLES" publication, and >> we shouldn't allow creating publication for this table. OTOH, if we >> allow the user to create and specify this table, we can ask her to >> specify with EXCLUDE syntax in publication. This needs more thoughts. > > > If a dependency relationship is established between the error table and the subscription, could this be used as a basisfor filtering the error tables from FOR ALL TABLES subscriptions? > Yeah, that is worth considering. -- With Regards, Amit Kapila.
On Wed, Aug 13, 2025 at 3:39 PM Amit Kapila <amit.kapila16@gmail.com> wrote: > > On Fri, Aug 8, 2025 at 10:01 AM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > > > On Fri, Aug 8, 2025 at 8:58 AM shveta malik <shveta.malik@gmail.com> wrote: > > > > > > On Thu, Aug 7, 2025 at 3:08 PM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > > > > > > > So logically for PostgreSQL its an > > > > user table but yeah this is created and managed by the extension. > > > > > > > > > > Any idea if the user can alter/drop or perform any DML on it? I could > > > not find any details on this part. > > > > In my experience, for such extension managed tables where we want them > > to behave like catalog, generally users are just granted with SELECT > > permission. So although it is not a catalog but for accessibility > > wise for non admin users it is like a catalog. IMHO, even if we > > choose to create a user table for conflict log history we can also > > control the permissions similarly. What's your opinion on this? > > > > Yes, I think it is important to control permissions on this table even > if it is a user table. How about giving SELECT, DELETE, TRUNCATE > permissions to subscription owner assuming we create one such table > per subscription? Right, we need to control the permission. I am not sure whether we want a per subscription table or a common one. Earlier I was thinking of a single table, but I think per subscription is not a bad idea especially for managing the permissions. And there can not be a really huge number of subscriptions that we need to worry about creating many conflict log history tables and that too we will only create such tables when users pass that subscription option. > It should be a user table due to following reasons (a) It is an ever > growing table by definition and we need some level of user control to > manage it (like remove the old data); (b) We may want some sort of > partitioning streategy to manage it, even though, we decide to do it > ourselves now but in future, we should allow user to also specify it; Maybe we can partition by range on date (when entry is inserted) . That way it would be easy to get rid of older partitions for users. > (c) We may also want user to specify what exact information she wants > to get stored considering in future we want resolutions to also be > stored in it. See a somewhat similar proposal to store errors during > copy by Tom [1]; (d) In a near-by thread, we are discussing storing > errors during copy in user table [2] and we have some similarity with > that proposal as well. Right, we may consider that as well. > If we agree on this then the next thing to consider is whether we > allow users to create such a table or do it ourselves. In the long > term, we may want both but for simplicity, we can auto-create > ourselves during CREATE SUBSCRIPTION with some option. BTW, if we > decide to let user create it then we can consider the idea of TYPED > tables as discussed in emails [3][4]. Yeah that's an interesting option. > > For user tables, we need to consider how to avoid replicating these > tables for publications that use FOR ALL TABLES specifier. One idea is > to use EXCLUDE table functionality as being discussed in thread [5] > but that would also be a bit tricky especially if we decide to create > such a table automatically. One naive idea is that internally we skip > sending changes from this table for "FOR ALL TABLES" publication, and > we shouldn't allow creating publication for this table. OTOH, if we > allow the user to create and specify this table, we can ask her to > specify with EXCLUDE syntax in publication. This needs more thoughts. Yes this needs more thought, I will think more on this point and respond. Yet another question is about table names, whether we keep some standard name like conflict_log_history_$subid or let users pass the name. -- Regards, Dilip Kumar Google
On Fri, Aug 15, 2025 at 2:31 PM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > Yet another question is about table names, whether we keep some > standard name like conflict_log_history_$subid or let users pass the > name. > It would be good if we can let the user specify the table_name and if she didn't specify then use an internally generated name. I think it will be somewhat similar to slot_name. However, in this case, there is one challenge which is how can we decide whether the schema of the user provided table_name is correct or not? Do we compare it with the standard schema we are planning to use? One idea to keep things simple for the first version is that we allow users to specify the table_name for storing conflicts but the table should be created internally and if the same name table already exists, we can give an ERROR. Then we can later extend the functionality to even allow storing conflicts in pre-created tables with more checks about its schema. -- With Regards, Amit Kapila.
On Mon, Aug 18, 2025 at 12:25 PM Amit Kapila <amit.kapila16@gmail.com> wrote: > > On Fri, Aug 15, 2025 at 2:31 PM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > > > Yet another question is about table names, whether we keep some > > standard name like conflict_log_history_$subid or let users pass the > > name. > > > > It would be good if we can let the user specify the table_name and if > she didn't specify then use an internally generated name. I think it > will be somewhat similar to slot_name. However, in this case, there is > one challenge which is how can we decide whether the schema of the > user provided table_name is correct or not? Do we compare it with the > standard schema we are planning to use? Ideally we can do that, if you see in this thread [1] there is a patch [2] which first try to validate the table schema and if it doesn't exist it creates it on its own. And it seems fine to me. > One idea to keep things simple for the first version is that we allow > users to specify the table_name for storing conflicts but the table > should be created internally and if the same name table already > exists, we can give an ERROR. Then we can later extend the > functionality to even allow storing conflicts in pre-created tables > with more checks about its schema. That's fair too. I am wondering what namespace we should create this user table in. If we are creating internally, I assume the user should provide a schema qualified name right? [1] https://www.postgresql.org/message-id/flat/752672.1699474336%40sss.pgh.pa.us#b8450be5645c4252d7d02cf7aca1fc7b [2] https://www.postgresql.org/message-id/attachment/152792/v8-0001-Add-a-new-COPY-option-SAVE_ERROR.patch -- Regards, Dilip Kumar Google
On Wed, Aug 20, 2025 at 11:47 AM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > On Mon, Aug 18, 2025 at 12:25 PM Amit Kapila <amit.kapila16@gmail.com> wrote: > > > > > One idea to keep things simple for the first version is that we allow > > users to specify the table_name for storing conflicts but the table > > should be created internally and if the same name table already > > exists, we can give an ERROR. Then we can later extend the > > functionality to even allow storing conflicts in pre-created tables > > with more checks about its schema. > > That's fair too. I am wondering what namespace we should create this > user table in. If we are creating internally, I assume the user should > provide a schema qualified name right? > Yeah, but if not provided then we should create it based on search_path similar to what we do when user created the table from psql. -- With Regards, Amit Kapila.
On Wed, Aug 20, 2025 at 5:46 PM Amit Kapila <amit.kapila16@gmail.com> wrote: > > On Wed, Aug 20, 2025 at 11:47 AM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > > > On Mon, Aug 18, 2025 at 12:25 PM Amit Kapila <amit.kapila16@gmail.com> wrote: > > > > > > > > One idea to keep things simple for the first version is that we allow > > > users to specify the table_name for storing conflicts but the table > > > should be created internally and if the same name table already > > > exists, we can give an ERROR. Then we can later extend the > > > functionality to even allow storing conflicts in pre-created tables > > > with more checks about its schema. > > > > That's fair too. I am wondering what namespace we should create this > > user table in. If we are creating internally, I assume the user should > > provide a schema qualified name right? > > > > Yeah, but if not provided then we should create it based on > search_path similar to what we do when user created the table from > psql. Yeah that makes sense. -- Regards, Dilip Kumar Google
On Thu, Aug 21, 2025 at 9:17 AM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > On Wed, Aug 20, 2025 at 5:46 PM Amit Kapila <amit.kapila16@gmail.com> wrote: > > > > On Wed, Aug 20, 2025 at 11:47 AM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > > > > > On Mon, Aug 18, 2025 at 12:25 PM Amit Kapila <amit.kapila16@gmail.com> wrote: > > > > > > > > > > > One idea to keep things simple for the first version is that we allow > > > > users to specify the table_name for storing conflicts but the table > > > > should be created internally and if the same name table already > > > > exists, we can give an ERROR. Then we can later extend the > > > > functionality to even allow storing conflicts in pre-created tables > > > > with more checks about its schema. > > > > > > That's fair too. I am wondering what namespace we should create this > > > user table in. If we are creating internally, I assume the user should > > > provide a schema qualified name right? > > > > > > > Yeah, but if not provided then we should create it based on > > search_path similar to what we do when user created the table from > > psql. While working on the patch, I see there are some open questions 1. We decided to pass the conflict history table name during subscription creation. And it makes sense to create this table when the CREATE SUBSCRIPTION command is executed. A potential concern is that the subscription owner will also own this table, having full control over it, including the ability to drop or alter its schema. This might not be an issue. If an INSERT into the conflict table fails, we can check the table's existence and schema. If they are not as expected, the conflict log history option can be disabled and re-enabled later via ALTER SUBSCRIPTION. 2. A further challenge is how to exclude these tables from publishing changes. If we support a subscription-level log history table and the user publishes ALL TABLES, the output plugin uses is_publishable_relation() to check if a table is publishable. However, applying the same logic here would require checking each subscription on the node to see if the table is designated as a conflict log history table for any subscription, which could be costly. 3. And one last thing is about should we consider dropping this table when we drop the subscription, I think this makes sense as we are internally creating it while creating the subscription. -- Regards, Dilip Kumar Google
Hi Dilip
Thanks for working on this, I think it will make conflict detection a lot more useful.
On Sat, 6 Sept 2025, 10:38 Dilip Kumar, <dilipbalaut@gmail.com> wrote:
While working on the patch, I see there are some open questions
1. We decided to pass the conflict history table name during
subscription creation. And it makes sense to create this table when
the CREATE SUBSCRIPTION command is executed. A potential concern is
that the subscription owner will also own this table, having full
control over it, including the ability to drop or alter its schema.
...
Typed tables and the dependency framework can address this concern. The schema of a typed table cannot be changed. If the subscription is marked as a dependency of the log table, the table cannot be dropped while the subscription exists.
2. A further challenge is how to exclude these tables from publishing
changes. If we support a subscription-level log history table and the
user publishes ALL TABLES, the output plugin uses
is_publishable_relation() to check if a table is publishable. However,
applying the same logic here would require checking each subscription
on the node to see if the table is designated as a conflict log
history table for any subscription, which could be costly.
Checking the type of a table and/or whether a subscription object depends on it in a certain way would be a far less costly operation to add to is_publishable_relation()
3. And one last thing is about should we consider dropping this table
when we drop the subscription, I think this makes sense as we are
internally creating it while creating the subscription.
Having to clean up the log table explicitly is likely to annoy users far less than having the conflict data destroyed as a side effect of another operation. I would strongly suggest leaving the table in place when the subscription is dropped.
Regards
Alastair
On Sun, Sep 7, 2025 at 1:42 PM Alastair Turner <minion@decodable.me> wrote: > > Hi Dilip > > Thanks for working on this, I think it will make conflict detection a lot more useful. Thanks for the suggestions, please find my reply inline. > On Sat, 6 Sept 2025, 10:38 Dilip Kumar, <dilipbalaut@gmail.com> wrote: >> >> While working on the patch, I see there are some open questions >> >> 1. We decided to pass the conflict history table name during >> subscription creation. And it makes sense to create this table when >> the CREATE SUBSCRIPTION command is executed. A potential concern is >> that the subscription owner will also own this table, having full >> control over it, including the ability to drop or alter its schema. > > Typed tables and the dependency framework can address this concern. The schema of a typed table cannot be changed. If thesubscription is marked as a dependency of the log table, the table cannot be dropped while the subscription exists. Yeah type table can be useful here, but only concern is when do we create this type. One option is whenever we can create a catalog relation say "conflict_log_history" that will create a type and then for each subscription if we need to create the conflict history table we can create it as "conflict_log_history" type, but this might not be a best option as we are creating catalog just for using this type. Second option is to create a type while creating a table itself but then again the problem remains the same as subscription owners get control over altering the schema of the type itself. So the goal is we want this type to be created such that it can not be altered so IMHO option1 is more suitable i.e. creating conflict_log_history as catalog and per subscription table can be created as this type. >> >> 2. A further challenge is how to exclude these tables from publishing >> changes. If we support a subscription-level log history table and the >> user publishes ALL TABLES, the output plugin uses >> is_publishable_relation() to check if a table is publishable. However, >> applying the same logic here would require checking each subscription >> on the node to see if the table is designated as a conflict log >> history table for any subscription, which could be costly. > > > Checking the type of a table and/or whether a subscription object depends on it in a certain way would be a far less costlyoperation to add to is_publishable_relation() +1 > >> >> 3. And one last thing is about should we consider dropping this table >> when we drop the subscription, I think this makes sense as we are >> internally creating it while creating the subscription. > > > Having to clean up the log table explicitly is likely to annoy users far less than having the conflict data destroyed asa side effect of another operation. I would strongly suggest leaving the table in place when the subscription is dropped. Thanks for the input, I would like to hear opinions from others as well here. I agree that implicitly getting rid of the conflict history might be problematic but we also need to consider that we are considering dropping this when the whole subscription is dropped. Not sure even after subscription drop users will be interested in conflict history, if yes then they need to be aware of preserving that isn't it. -- Regards, Dilip Kumar Google
On Mon, Sep 8, 2025 at 12:01 PM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > On Sun, Sep 7, 2025 at 1:42 PM Alastair Turner <minion@decodable.me> wrote: > > > > Hi Dilip > > > > Thanks for working on this, I think it will make conflict detection a lot more useful. > > Thanks for the suggestions, please find my reply inline. > > > On Sat, 6 Sept 2025, 10:38 Dilip Kumar, <dilipbalaut@gmail.com> wrote: > >> > >> While working on the patch, I see there are some open questions > >> > >> 1. We decided to pass the conflict history table name during > >> subscription creation. And it makes sense to create this table when > >> the CREATE SUBSCRIPTION command is executed. A potential concern is > >> that the subscription owner will also own this table, having full > >> control over it, including the ability to drop or alter its schema. > > > > > Typed tables and the dependency framework can address this concern. The schema of a typed table cannot be changed. Ifthe subscription is marked as a dependency of the log table, the table cannot be dropped while the subscription exists. > > Yeah type table can be useful here, but only concern is when do we > create this type. > How about having this as a built-in type? > One option is whenever we can create a catalog > relation say "conflict_log_history" that will create a type and then > for each subscription if we need to create the conflict history table > we can create it as "conflict_log_history" type, but this might not be > a best option as we are creating catalog just for using this type. > Second option is to create a type while creating a table itself but > then again the problem remains the same as subscription owners get > control over altering the schema of the type itself. So the goal is > we want this type to be created such that it can not be altered so > IMHO option1 is more suitable i.e. creating conflict_log_history as > catalog and per subscription table can be created as this type. > I think having it as a catalog table has drawbacks like who will clean this ever growing table. The one thing is not clear from Alastair's response is that he said to make subscription as a dependency of table, if we do so, then won't it be difficult to even drop subscription and also doesn't that sound reverse of what we want. > >> > >> 2. A further challenge is how to exclude these tables from publishing > >> changes. If we support a subscription-level log history table and the > >> user publishes ALL TABLES, the output plugin uses > >> is_publishable_relation() to check if a table is publishable. However, > >> applying the same logic here would require checking each subscription > >> on the node to see if the table is designated as a conflict log > >> history table for any subscription, which could be costly. > > > > > > Checking the type of a table and/or whether a subscription object depends on it in a certain way would be a far lesscostly operation to add to is_publishable_relation() > +1 > > > > >> > >> 3. And one last thing is about should we consider dropping this table > >> when we drop the subscription, I think this makes sense as we are > >> internally creating it while creating the subscription. > > > > > > Having to clean up the log table explicitly is likely to annoy users far less than having the conflict data destroyedas a side effect of another operation. I would strongly suggest leaving the table in place when the subscriptionis dropped. > > Thanks for the input, I would like to hear opinions from others as > well here. > But OTOH, there could be users who want such a table to be dropped. One possibility is that if we user provided us a pre-created table then we leave it to user to remove the table, otherwise, we can remove with drop subscription. BTW, did we decide that we want a conflict-table-per-subscription or one table for all subscriptions, if later, then I guess the problem would be that it has to be a shared table across databases. -- With Regards, Amit Kapila.
On Wed, Sep 10, 2025 at 3:25 PM Amit Kapila <amit.kapila16@gmail.com> wrote: > > On Mon, Sep 8, 2025 at 12:01 PM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > > > On Sun, Sep 7, 2025 at 1:42 PM Alastair Turner <minion@decodable.me> wrote: > > > > > > Hi Dilip > > > > > > Thanks for working on this, I think it will make conflict detection a lot more useful. > > > > Thanks for the suggestions, please find my reply inline. > > > > > On Sat, 6 Sept 2025, 10:38 Dilip Kumar, <dilipbalaut@gmail.com> wrote: > > >> > > >> While working on the patch, I see there are some open questions > > >> > > >> 1. We decided to pass the conflict history table name during > > >> subscription creation. And it makes sense to create this table when > > >> the CREATE SUBSCRIPTION command is executed. A potential concern is > > >> that the subscription owner will also own this table, having full > > >> control over it, including the ability to drop or alter its schema. > > > > > > > > Typed tables and the dependency framework can address this concern. The schema of a typed table cannot be changed.If the subscription is marked as a dependency of the log table, the table cannot be dropped while the subscriptionexists. > > > > Yeah type table can be useful here, but only concern is when do we > > create this type. > > > > How about having this as a built-in type? Here we will have to create a built-in type of type table which is I think typcategory => 'C' and if we create this type it should be supplied with the "typrelid" that means there should be a backing catalog table. At least thats what I think. > > One option is whenever we can create a catalog > > relation say "conflict_log_history" that will create a type and then > > for each subscription if we need to create the conflict history table > > we can create it as "conflict_log_history" type, but this might not be > > a best option as we are creating catalog just for using this type. > > Second option is to create a type while creating a table itself but > > then again the problem remains the same as subscription owners get > > control over altering the schema of the type itself. So the goal is > > we want this type to be created such that it can not be altered so > > IMHO option1 is more suitable i.e. creating conflict_log_history as > > catalog and per subscription table can be created as this type. > > > > I think having it as a catalog table has drawbacks like who will clean > this ever growing table. No, I didn't mean an ever growing catalog table, I was giving an option to create a catalog table just to create a built-in type and then we will create an actual log history table of this built-in type for each subscription while creating the subscription. So this catalog table will be there but nothing will be inserted to this table and whenever the user supplies a conflict log history table name while creating a subscription that time we will create an actual table and the type of the table will be as the catalog table type. I agree creating a catalog table for this purpose might not be worth it, but I am not yet able to figure out how to create a built-in type of type table without creating the actual table. The one thing is not clear from Alastair's > response is that he said to make subscription as a dependency of > table, if we do so, then won't it be difficult to even drop > subscription and also doesn't that sound reverse of what we want. I assume he means subscription will be dependent on the log table, that means we can not drop the log table as subscription is dependent on this table. > > >> > > >> 2. A further challenge is how to exclude these tables from publishing > > >> changes. If we support a subscription-level log history table and the > > >> user publishes ALL TABLES, the output plugin uses > > >> is_publishable_relation() to check if a table is publishable. However, > > >> applying the same logic here would require checking each subscription > > >> on the node to see if the table is designated as a conflict log > > >> history table for any subscription, which could be costly. > > > > > > > > > Checking the type of a table and/or whether a subscription object depends on it in a certain way would be a far lesscostly operation to add to is_publishable_relation() > > +1 > > > > > > > >> > > >> 3. And one last thing is about should we consider dropping this table > > >> when we drop the subscription, I think this makes sense as we are > > >> internally creating it while creating the subscription. > > > > > > > > > Having to clean up the log table explicitly is likely to annoy users far less than having the conflict data destroyedas a side effect of another operation. I would strongly suggest leaving the table in place when the subscriptionis dropped. > > > > Thanks for the input, I would like to hear opinions from others as > > well here. > > > > But OTOH, there could be users who want such a table to be dropped. > One possibility is that if we user provided us a pre-created table > then we leave it to user to remove the table, otherwise, we can remove > with drop subscription. Thanks make sense. BTW, did we decide that we want a > conflict-table-per-subscription or one table for all subscriptions, if > later, then I guess the problem would be that it has to be a shared > table across databases. Right and I don't think there is an option to create a user defined shared table. And I don't think there is any issue creating per subscription conflict log history table, except that the subscription owner should have permission to create the table in the database while creating the subscription, but I think this is expected, either user can get the sufficient privilege or disable the option for conflict log history table. -- Regards, Dilip Kumar Google
On Wed, 10 Sept 2025 at 11:15, Dilip Kumar <dilipbalaut@gmail.com> wrote:
On Wed, Sep 10, 2025 at 3:25 PM Amit Kapila <amit.kapila16@gmail.com> wrote:
>
...
>
> How about having this as a built-in type?
Here we will have to create a built-in type of type table which is I
think typcategory => 'C' and if we create this type it should be
supplied with the "typrelid" that means there should be a backing
catalog table. At least thats what I think.
A compound type can be used for building a table, it's not necessary to create a table when creating the type. In user SQL:
CREATE TYPE conflict_log_type AS (
conflictid UUID,
subid OID,
tableid OID,
conflicttype TEXT,
operationtype TEXT,
replication_origin TEXT,
remote_commit_ts TIMESTAMPTZ,
local_commit_ts TIMESTAMPTZ,
ri_key JSON,
remote_tuple JSON,
local_tuple JSON
);
CREATE TABLE my_subscription_conflicts OF conflict_log_type;
conflictid UUID,
subid OID,
tableid OID,
conflicttype TEXT,
operationtype TEXT,
replication_origin TEXT,
remote_commit_ts TIMESTAMPTZ,
local_commit_ts TIMESTAMPTZ,
ri_key JSON,
remote_tuple JSON,
local_tuple JSON
);
CREATE TABLE my_subscription_conflicts OF conflict_log_type;
...
The one thing is not clear from Alastair's
> response is that he said to make subscription as a dependency of
> table, if we do so, then won't it be difficult to even drop
> subscription and also doesn't that sound reverse of what we want.
I assume he means subscription will be dependent on the log table,
that means we can not drop the log table as subscription is dependent
on this table.
Yes, that's what I was proposing.
> > >>
> > >> 2. A further challenge is how to exclude these tables from publishing
> > >> changes. If we support a subscription-level log history table and the
> > >> user publishes ALL TABLES, the output plugin uses
> > >> is_publishable_relation() to check if a table is publishable. However,
> > >> applying the same logic here would require checking each subscription
> > >> on the node to see if the table is designated as a conflict log
> > >> history table for any subscription, which could be costly.
> > >
> > >
> > > Checking the type of a table and/or whether a subscription object depends on it in a certain way would be a far less costly operation to add to is_publishable_relation()
> > +1
> >
> > >
> > >>
> > >> 3. And one last thing is about should we consider dropping this table
> > >> when we drop the subscription, I think this makes sense as we are
> > >> internally creating it while creating the subscription.
> > >
> > >
> > > Having to clean up the log table explicitly is likely to annoy users far less than having the conflict data destroyed as a side effect of another operation. I would strongly suggest leaving the table in place when the subscription is dropped.
> >
> > Thanks for the input, I would like to hear opinions from others as
> > well here.
> >
>
> But OTOH, there could be users who want such a table to be dropped.
> One possibility is that if we user provided us a pre-created table
> then we leave it to user to remove the table, otherwise, we can remove
> with drop subscription.
Thanks make sense.
BTW, did we decide that we want a
> conflict-table-per-subscription or one table for all subscriptions, if
> later, then I guess the problem would be that it has to be a shared
> table across databases.
Right and I don't think there is an option to create a user defined
shared table. And I don't think there is any issue creating per
subscription conflict log history table, except that the subscription
owner should have permission to create the table in the database while
creating the subscription, but I think this is expected, either user
can get the sufficient privilege or disable the option for conflict
log history table.
Since subscriptions are created in a particular database, it seems reasonable that error tables would also be created in a particular database.
On Wed, Sep 10, 2025 at 4:32 PM Alastair Turner <minion@decodable.me> wrote: > >> Here we will have to create a built-in type of type table which is I >> think typcategory => 'C' and if we create this type it should be >> supplied with the "typrelid" that means there should be a backing >> catalog table. At least thats what I think. > > A compound type can be used for building a table, it's not necessary to create a table when creating the type. In userSQL: > > CREATE TYPE conflict_log_type AS ( > conflictid UUID, > subid OID, > tableid OID, > conflicttype TEXT, > operationtype TEXT, > replication_origin TEXT, > remote_commit_ts TIMESTAMPTZ, > local_commit_ts TIMESTAMPTZ, > ri_key JSON, > remote_tuple JSON, > local_tuple JSON > ); > > CREATE TABLE my_subscription_conflicts OF conflict_log_type; Problem is if you CREATE TYPE just before creating the table that means subscription owners get full control over the type as well it means they can alter the type itself. So logically this TYPE should be a built-in type so that subscription owners do not have control to ALTER the type but they have permission to create a table from this type. But the problem is whenever you create a type it needs to have corresponding relid in pg_class in fact you can just create a type as per your example and see[1] it will get corresponding entry in pg_class. So the problem is if you create a user defined type it will be created under the subscription owner and it defeats the purpose of not allowing to alter the type OTOH if we create a built-in type it needs to have a corresponding entry in pg_class. So what's your proposal, create this type while creating a subscription or as a built-in type, or anything else? [1] postgres[1948123]=# CREATE TYPE conflict_log_type AS (conflictid UUID); postgres[1948123]=# select oid, typrelid, typcategory from pg_type where typname='conflict_log_type'; oid | typrelid | typcategory -------+----------+------------- 16386 | 16384 | C (1 row) postgres[1948123]=# select relname from pg_class where oid=16384; relname ------------------- conflict_log_type -- Regards, Dilip Kumar Google
Hi, On Tue, Aug 5, 2025 at 5:24 AM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > Currently we log conflicts to the server's log file and updates, this > approach has limitations, 1) Difficult to query and analyze, parsing > plain text log files for conflict details is inefficient. 2) Lack of > structured data, key conflict attributes (table, operation, old/new > data, LSN, etc.) are not readily available in a structured, queryable > format. 3) Difficult for external monitoring tools or custom > resolution scripts to consume conflict data directly. > > This proposal aims to address these limitations by introducing a > conflict log history table, providing a structured, and queryable > record of all logical replication conflicts. This should be a > configurable option whether to log into the conflict log history > table, server logs or both. +1 for the overall idea. Having an option to separate out the conflicts helps analyze the data correctness issues and understand the behavior of conflicts. Parsing server logs file for analysis and debugging is a typical requirement differently met with tools like log_fdw or capture server logs in CSV format for parsing or do text search and analyze etc. > This proposal has two main design questions: > =================================== > > 1. How do we store conflicting tuples from different tables? > Using a JSON column to store the row data seems like the most flexible > solution, as it can accommodate different table schemas. How good is storing conflicts on the table? Is it okay to generate WAL traffic? Is it okay to physically replicate this log table to all replicas? Is it okay to logically replicate this log table to all subscribers and logical decoding clients? How does this table get truncated? If truncation gets delayed, won't it unnecessarily fill up storage? > 2. Should this be a system table or a user table? > a) System Table: Storing this in a system catalog is simple, but > catalogs aren't designed for ever-growing data. While pg_large_object > is an exception, this is not what we generally do IMHO. > b) User Table: This offers more flexibility. We could allow a user to > specify the table name during CREATE SUBSCRIPTION. Then we choose to > either create the table internally or let the user create the table > with a predefined schema. -1 for the system table for sure. > A potential drawback is that a user might drop or alter the table. > However, we could mitigate this risk by simply logging a WARNING if > the table is configured but an insertion fails. > I am currently working on a POC patch for the same, but will post that > once we have some thoughts on design choices. How about streaming the conflicts in fixed format to a separate log file other than regular postgres server log file? All the rules/settings that apply to regular postgres server log files also apply for conflicts server log files (rotation, GUCs, format CSV/JSON/TEXT etc.). This way there's no additional WAL, and we don't have to worry about drop/alter, truncate, delete, update/insert, permission model, physical replication, logical replication, storage space etc. -- Bharath Rupireddy PostgreSQL Contributors Team RDS Open Source Databases Amazon Web Services: https://aws.amazon.com
On Thu, Sep 11, 2025 at 12:53 AM Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com> wrote: > > On Tue, Aug 5, 2025 at 5:24 AM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > > > Currently we log conflicts to the server's log file and updates, this > > approach has limitations, 1) Difficult to query and analyze, parsing > > plain text log files for conflict details is inefficient. 2) Lack of > > structured data, key conflict attributes (table, operation, old/new > > data, LSN, etc.) are not readily available in a structured, queryable > > format. 3) Difficult for external monitoring tools or custom > > resolution scripts to consume conflict data directly. > > > > This proposal aims to address these limitations by introducing a > > conflict log history table, providing a structured, and queryable > > record of all logical replication conflicts. This should be a > > configurable option whether to log into the conflict log history > > table, server logs or both. > > +1 for the overall idea. Having an option to separate out the > conflicts helps analyze the data correctness issues and understand the > behavior of conflicts. > > Parsing server logs file for analysis and debugging is a typical > requirement differently met with tools like log_fdw or capture server > logs in CSV format for parsing or do text search and analyze etc. > > > This proposal has two main design questions: > > =================================== > > > > 1. How do we store conflicting tuples from different tables? > > Using a JSON column to store the row data seems like the most flexible > > solution, as it can accommodate different table schemas. > > How good is storing conflicts on the table? Is it okay to generate WAL > traffic? > Yesh, I think so. One would like to query conflicts and resolutions for those conflicts at a later point to ensure consistency. BTW, if you are worried about WAL traffic, please note conflicts shouldn't be a very often event, so additional WAL should be okay. OTOH, if the conflicts are frequent, anyway, the performance won't be that great as that means there is a kind of ERROR which we have to deal by having resolution for it. > Is it okay to physically replicate this log table to all > replicas? > Yes, that should be okay as we want the conflict_tables to be present after failover. Is it okay to logically replicate this log table to all > subscribers and logical decoding clients? > I think we should avoid this. > How does this table get > truncated? If truncation gets delayed, won't it unnecessarily fill up > storage? > I think it should be users responsibility to clean this table as they better know when the data in the table is obsolete. Eventually, we can also have some policies via options or some other way to get it truncated. IIRC, we also discussed having these as partition tables so that it is easy to discard data. However, for initial version, we may want something simpler. > > 2. Should this be a system table or a user table? > > a) System Table: Storing this in a system catalog is simple, but > > catalogs aren't designed for ever-growing data. While pg_large_object > > is an exception, this is not what we generally do IMHO. > > b) User Table: This offers more flexibility. We could allow a user to > > specify the table name during CREATE SUBSCRIPTION. Then we choose to > > either create the table internally or let the user create the table > > with a predefined schema. > > -1 for the system table for sure. > > > A potential drawback is that a user might drop or alter the table. > > However, we could mitigate this risk by simply logging a WARNING if > > the table is configured but an insertion fails. > > I am currently working on a POC patch for the same, but will post that > > once we have some thoughts on design choices. > > How about streaming the conflicts in fixed format to a separate log > file other than regular postgres server log file? > I would prefer this info to be stored in tables as it would be easy to query them. If we use separate LOGs then we should provide some views to query the LOG. -- With Regards, Amit Kapila.
On Thu, Sep 11, 2025 at 8:43 AM Amit Kapila <amit.kapila16@gmail.com> wrote: > > On Thu, Sep 11, 2025 at 12:53 AM Bharath Rupireddy > <bharath.rupireddyforpostgres@gmail.com> wrote: > > > > On Tue, Aug 5, 2025 at 5:24 AM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > > > > > Currently we log conflicts to the server's log file and updates, this > > > approach has limitations, 1) Difficult to query and analyze, parsing > > > plain text log files for conflict details is inefficient. 2) Lack of > > > structured data, key conflict attributes (table, operation, old/new > > > data, LSN, etc.) are not readily available in a structured, queryable > > > format. 3) Difficult for external monitoring tools or custom > > > resolution scripts to consume conflict data directly. > > > > > > This proposal aims to address these limitations by introducing a > > > conflict log history table, providing a structured, and queryable > > > record of all logical replication conflicts. This should be a > > > configurable option whether to log into the conflict log history > > > table, server logs or both. > > > > +1 for the overall idea. Having an option to separate out the > > conflicts helps analyze the data correctness issues and understand the > > behavior of conflicts. > > > > Parsing server logs file for analysis and debugging is a typical > > requirement differently met with tools like log_fdw or capture server > > logs in CSV format for parsing or do text search and analyze etc. > > > > > This proposal has two main design questions: > > > =================================== > > > > > > 1. How do we store conflicting tuples from different tables? > > > Using a JSON column to store the row data seems like the most flexible > > > solution, as it can accommodate different table schemas. > > > > How good is storing conflicts on the table? Is it okay to generate WAL > > traffic? > > > > Yesh, I think so. One would like to query conflicts and resolutions > for those conflicts at a later point to ensure consistency. BTW, if > you are worried about WAL traffic, please note conflicts shouldn't be > a very often event, so additional WAL should be okay. OTOH, if the > conflicts are frequent, anyway, the performance won't be that great as > that means there is a kind of ERROR which we have to deal by having > resolution for it. > > > Is it okay to physically replicate this log table to all > > replicas? > > > > Yes, that should be okay as we want the conflict_tables to be present > after failover. > > Is it okay to logically replicate this log table to all > > subscribers and logical decoding clients? > > > > I think we should avoid this. > > > How does this table get > > truncated? If truncation gets delayed, won't it unnecessarily fill up > > storage? > > > > I think it should be users responsibility to clean this table as they > better know when the data in the table is obsolete. Eventually, we can > also have some policies via options or some other way to get it > truncated. IIRC, we also discussed having these as partition tables so > that it is easy to discard data. However, for initial version, we may > want something simpler. > > > > 2. Should this be a system table or a user table? > > > a) System Table: Storing this in a system catalog is simple, but > > > catalogs aren't designed for ever-growing data. While pg_large_object > > > is an exception, this is not what we generally do IMHO. > > > b) User Table: This offers more flexibility. We could allow a user to > > > specify the table name during CREATE SUBSCRIPTION. Then we choose to > > > either create the table internally or let the user create the table > > > with a predefined schema. > > > > -1 for the system table for sure. > > > > > A potential drawback is that a user might drop or alter the table. > > > However, we could mitigate this risk by simply logging a WARNING if > > > the table is configured but an insertion fails. > > > I am currently working on a POC patch for the same, but will post that > > > once we have some thoughts on design choices. > > > > How about streaming the conflicts in fixed format to a separate log > > file other than regular postgres server log file? > > > > I would prefer this info to be stored in tables as it would be easy to > query them. If we use separate LOGs then we should provide some views > to query the LOG. I was looking into another thread where we provide an error table for COPY [1], it requires the user to pre-create the error table. And inside the COPY command we will validate the table, validation in that context is a one-time process checking for: (1) table existence, (2) ability to acquire a sufficient lock, (3) INSERT privileges, and (4) matching column names and data types. This approach avoids concerns about the user's DROP or ALTER permissions. Our requirement for the logical replication conflict log table differs, as we must validate the target table upon every conflict insertion, not just at subscription creation. A more robust alternative is to perform validation and acquire a lock on the conflict table whenever the subscription worker starts. This prevents modifications (like ALTER or DROP) while the worker is active. When the worker gets restarted, we can re-validate the table and automatically disable the conflict logging feature if validation fails. And this can be enabled by ALTER SUBSCRIPTION by setting the option again. And if we want in first version we can expect user to create the table as per the expected schema and supply it, this will avoid the need of handling how to avoid it from publishing as it will be user's responsibility and then in top up patches we can also allow to create the table internally if tables doesn't exist and then we can find out solution to avoid it from being publish when ALL TABLES are published. Thoughts? [1] https://www.postgresql.org/message-id/CACJufxEo-rsH5v__S3guUhDdXjakC7m7N5wj%3DmOB5rPiySBoQg%40mail.gmail.com -- Regards, Dilip Kumar Google
Hi, On Wed, Sep 10, 2025 at 8:13 PM Amit Kapila <amit.kapila16@gmail.com> wrote: > > > How about streaming the conflicts in fixed format to a separate log > > file other than regular postgres server log file? > > I would prefer this info to be stored in tables as it would be easy to > query them. If we use separate LOGs then we should provide some views > to query the LOG. Providing views to query the conflicts LOG is the easiest way than having tables (Probably we must provide both - logging conflicts to tables and separate LOG files). However, wanting the conflicts logs after failovers is something that makes me think the table approach is better. I'm open to more thoughts here. -- Bharath Rupireddy PostgreSQL Contributors Team RDS Open Source Databases Amazon Web Services: https://aws.amazon.com
Hi, On Fri, Sep 12, 2025 at 3:13 AM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > I was looking into another thread where we provide an error table for > COPY [1], it requires the user to pre-create the error table. And > inside the COPY command we will validate the table, validation in that > context is a one-time process checking for: (1) table existence, (2) > ability to acquire a sufficient lock, (3) INSERT privileges, and (4) > matching column names and data types. This approach avoids concerns > about the user's DROP or ALTER permissions. > > Our requirement for the logical replication conflict log table > differs, as we must validate the target table upon every conflict > insertion, not just at subscription creation. A more robust > alternative is to perform validation and acquire a lock on the > conflict table whenever the subscription worker starts. This prevents > modifications (like ALTER or DROP) while the worker is active. When > the worker gets restarted, we can re-validate the table and > automatically disable the conflict logging feature if validation > fails. And this can be enabled by ALTER SUBSCRIPTION by setting the > option again. Having to worry about ALTER/DROP and adding code to protect seems like an overkill. > And if we want in first version we can expect user to create the table > as per the expected schema and supply it, this will avoid the need of > handling how to avoid it from publishing as it will be user's > responsibility and then in top up patches we can also allow to create > the table internally if tables doesn't exist and then we can find out > solution to avoid it from being publish when ALL TABLES are published. This looks much more simple to start with. -- Bharath Rupireddy PostgreSQL Contributors Team RDS Open Source Databases Amazon Web Services: https://aws.amazon.com
On Sat, Sep 13, 2025 at 6:16 AM Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com> wrote: Thanks for the feedback Bharath > On Fri, Sep 12, 2025 at 3:13 AM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > > > I was looking into another thread where we provide an error table for > > COPY [1], it requires the user to pre-create the error table. And > > inside the COPY command we will validate the table, validation in that > > context is a one-time process checking for: (1) table existence, (2) > > ability to acquire a sufficient lock, (3) INSERT privileges, and (4) > > matching column names and data types. This approach avoids concerns > > about the user's DROP or ALTER permissions. > > > > Our requirement for the logical replication conflict log table > > differs, as we must validate the target table upon every conflict > > insertion, not just at subscription creation. A more robust > > alternative is to perform validation and acquire a lock on the > > conflict table whenever the subscription worker starts. This prevents > > modifications (like ALTER or DROP) while the worker is active. When > > the worker gets restarted, we can re-validate the table and > > automatically disable the conflict logging feature if validation > > fails. And this can be enabled by ALTER SUBSCRIPTION by setting the > > option again. > > Having to worry about ALTER/DROP and adding code to protect seems like > an overkill. IMHO eventually if we can control that I feel this is a good goal to have. So that we can avoid failure during conflict insertion. We may argue its user's responsibility to not alter the table and we can just check the validity during create/alter subscription. > > And if we want in first version we can expect user to create the table > > as per the expected schema and supply it, this will avoid the need of > > handling how to avoid it from publishing as it will be user's > > responsibility and then in top up patches we can also allow to create > > the table internally if tables doesn't exist and then we can find out > > solution to avoid it from being publish when ALL TABLES are published. > > This looks much more simple to start with. Right. PFA, attached WIP patches, 0001 allow user created tables to provide as input for conflict history tables and we will validate the table during create/alter subscription. 0002 add an option to internally create the table if it does not exist. TODO: - Still patches are WIP and need more work testing for different failure cases - Need to explore an option to create a built-in type (I will start a separate thread for the same) - Need to add test cases - Need to explore options to avoid getting published, but maybe we only need to avoid this when we internally create the table? Here is some basic test I tried: psql -d postgres -c "CREATE TABLE test(a int, b int, primary key(a));" psql -d postgres -p 5433 -c "CREATE SCHEMA myschema" psql -d postgres -p 5433 -c "CREATE TABLE test(a int, b int, primary key(a));" psql -d postgres -p 5433 -c "GRANT INSERT, UPDATE, SELECT, DELETE ON test TO dk " psql -d postgres -c "CREATE PUBLICATION pub FOR ALL TABLES ;" psql -d postgres -p 5433 -c "CREATE SUBSCRIPTION sub CONNECTION 'dbname=postgres port=5432' PUBLICATION pub WITH(conflict_log_table=myschema.conflict_log_history)"; psql -d postgres -p 5432 -c "INSERT INTO test VALUES(1,2);" psql -d postgres -p 5433 -c "UPDATE test SET b=10 WHERE a=1;" psql -d postgres -p 5432 -c "UPDATE test SET b=20 WHERE a=1;" postgres[1202034]=# select * from myschema.conflict_log_history ; -[ RECORD 1 ]-----+------------------------------ relid | 16385 local_xid | 763 remote_xid | 757 local_lsn | 0/00000000 remote_commit_lsn | 0/0174AB30 local_commit_ts | 2025-09-14 06:45:00.828874+00 remote_commit_ts | 2025-09-14 06:45:05.845614+00 table_schema | public table_name | test conflict_type | update_origin_differs local_origin | remote_origin | pg_16396 key_tuple | {"a":1,"b":20} local_tuple | {"a":1,"b":10} remote_tuple | {"a":1,"b":20} -- Regards, Dilip Kumar Google
Вложения
On Sun, Sep 14, 2025 at 12:23 PM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > On Sat, Sep 13, 2025 at 6:16 AM Bharath Rupireddy > <bharath.rupireddyforpostgres@gmail.com> wrote: > > Thanks for the feedback Bharath > > > On Fri, Sep 12, 2025 at 3:13 AM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > > > > > I was looking into another thread where we provide an error table for > > > COPY [1], it requires the user to pre-create the error table. And > > > inside the COPY command we will validate the table, validation in that > > > context is a one-time process checking for: (1) table existence, (2) > > > ability to acquire a sufficient lock, (3) INSERT privileges, and (4) > > > matching column names and data types. This approach avoids concerns > > > about the user's DROP or ALTER permissions. > > > > > > Our requirement for the logical replication conflict log table > > > differs, as we must validate the target table upon every conflict > > > insertion, not just at subscription creation. A more robust > > > alternative is to perform validation and acquire a lock on the > > > conflict table whenever the subscription worker starts. This prevents > > > modifications (like ALTER or DROP) while the worker is active. When > > > the worker gets restarted, we can re-validate the table and > > > automatically disable the conflict logging feature if validation > > > fails. And this can be enabled by ALTER SUBSCRIPTION by setting the > > > option again. > > > > Having to worry about ALTER/DROP and adding code to protect seems like > > an overkill. > > IMHO eventually if we can control that I feel this is a good goal to > have. So that we can avoid failure during conflict insertion. We may > argue its user's responsibility to not alter the table and we can just > check the validity during create/alter subscription. > If we compare conflict_history_table with the slot that gets created with subscription, one can say the same thing about slots. Users can drop the slots and whole replication will stop. I think this table will be created with the same privileges as the owner of a subscription which can be either a superuser or a user with the privileges of the pg_create_subscription role, so we can rely on such users. -- With Regards, Amit Kapila.
On Thu, Sep 18, 2025 at 2:03 PM Amit Kapila <amit.kapila16@gmail.com> wrote: > > On Sun, Sep 14, 2025 at 12:23 PM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > > > On Sat, Sep 13, 2025 at 6:16 AM Bharath Rupireddy > > <bharath.rupireddyforpostgres@gmail.com> wrote: > > > > Thanks for the feedback Bharath > > > > > On Fri, Sep 12, 2025 at 3:13 AM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > > > > > > > I was looking into another thread where we provide an error table for > > > > COPY [1], it requires the user to pre-create the error table. And > > > > inside the COPY command we will validate the table, validation in that > > > > context is a one-time process checking for: (1) table existence, (2) > > > > ability to acquire a sufficient lock, (3) INSERT privileges, and (4) > > > > matching column names and data types. This approach avoids concerns > > > > about the user's DROP or ALTER permissions. > > > > > > > > Our requirement for the logical replication conflict log table > > > > differs, as we must validate the target table upon every conflict > > > > insertion, not just at subscription creation. A more robust > > > > alternative is to perform validation and acquire a lock on the > > > > conflict table whenever the subscription worker starts. This prevents > > > > modifications (like ALTER or DROP) while the worker is active. When > > > > the worker gets restarted, we can re-validate the table and > > > > automatically disable the conflict logging feature if validation > > > > fails. And this can be enabled by ALTER SUBSCRIPTION by setting the > > > > option again. > > > > > > Having to worry about ALTER/DROP and adding code to protect seems like > > > an overkill. > > > > IMHO eventually if we can control that I feel this is a good goal to > > have. So that we can avoid failure during conflict insertion. We may > > argue its user's responsibility to not alter the table and we can just > > check the validity during create/alter subscription. > > > > If we compare conflict_history_table with the slot that gets created > with subscription, one can say the same thing about slots. Users can > drop the slots and whole replication will stop. I think this table > will be created with the same privileges as the owner of a > subscription which can be either a superuser or a user with the > privileges of the pg_create_subscription role, so we can rely on such > users. Yeah that's a valid point. -- Regards, Dilip Kumar Google
On Thu, Sep 18, 2025 at 1:33 AM Amit Kapila <amit.kapila16@gmail.com> wrote: > > On Sun, Sep 14, 2025 at 12:23 PM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > > > On Sat, Sep 13, 2025 at 6:16 AM Bharath Rupireddy > > <bharath.rupireddyforpostgres@gmail.com> wrote: > > > > Thanks for the feedback Bharath > > > > > On Fri, Sep 12, 2025 at 3:13 AM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > > > > > > > I was looking into another thread where we provide an error table for > > > > COPY [1], it requires the user to pre-create the error table. And > > > > inside the COPY command we will validate the table, validation in that > > > > context is a one-time process checking for: (1) table existence, (2) > > > > ability to acquire a sufficient lock, (3) INSERT privileges, and (4) > > > > matching column names and data types. This approach avoids concerns > > > > about the user's DROP or ALTER permissions. > > > > > > > > Our requirement for the logical replication conflict log table > > > > differs, as we must validate the target table upon every conflict > > > > insertion, not just at subscription creation. A more robust > > > > alternative is to perform validation and acquire a lock on the > > > > conflict table whenever the subscription worker starts. This prevents > > > > modifications (like ALTER or DROP) while the worker is active. When > > > > the worker gets restarted, we can re-validate the table and > > > > automatically disable the conflict logging feature if validation > > > > fails. And this can be enabled by ALTER SUBSCRIPTION by setting the > > > > option again. > > > > > > Having to worry about ALTER/DROP and adding code to protect seems like > > > an overkill. > > > > IMHO eventually if we can control that I feel this is a good goal to > > have. So that we can avoid failure during conflict insertion. We may > > argue its user's responsibility to not alter the table and we can just > > check the validity during create/alter subscription. > > > > If we compare conflict_history_table with the slot that gets created > with subscription, one can say the same thing about slots. Users can > drop the slots and whole replication will stop. I think this table > will be created with the same privileges as the owner of a > subscription which can be either a superuser or a user with the > privileges of the pg_create_subscription role, so we can rely on such > users. We might want to consider which role inserts the conflict info into the history table. For example, if any table created by a user can be used as the history table for a subscription and the conflict info insertion is performed by the subscription owner, we would end up having the same security issue that was addressed by the run_as_owner subscription option. Regards, -- Masahiko Sawada Amazon Web Services: https://aws.amazon.com
On Thu, Sep 18, 2025 at 11:46 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote: > > On Thu, Sep 18, 2025 at 1:33 AM Amit Kapila <amit.kapila16@gmail.com> wrote: > > > > If we compare conflict_history_table with the slot that gets created > > with subscription, one can say the same thing about slots. Users can > > drop the slots and whole replication will stop. I think this table > > will be created with the same privileges as the owner of a > > subscription which can be either a superuser or a user with the > > privileges of the pg_create_subscription role, so we can rely on such > > users. > > We might want to consider which role inserts the conflict info into > the history table. For example, if any table created by a user can be > used as the history table for a subscription and the conflict info > insertion is performed by the subscription owner, we would end up > having the same security issue that was addressed by the run_as_owner > subscription option. > Yeah, I don't think we want to open that door. For user created tables, we should perform actions with table_owner's privilege. In such a case, if one wants to create a subscription with run_as_owner option, she should give DML operation permissions to the subscription owner. OTOH, if we create this table internally (via subscription owner) then irrespective of run_as_owner, we will always insert as subscription_owner. AFAIR, one open point for internally created tables is whether we should skip changes to conflict_history table while replicating changes? The table will be considered under for ALL TABLES publications, if defined? Ideally, these should behave as catalog tables, so one option is to mark them as 'user_catalog_table', or the other option is we have some hard-code checks during replication. The first option has the advantage that it won't write additional WAL for these tables which is otherwise required under wal_level=logical. What other options do we have? -- With Regards, Amit Kapila.
On Sat, Sep 20, 2025 at 4:59 AM Amit Kapila <amit.kapila16@gmail.com> wrote: > > On Thu, Sep 18, 2025 at 11:46 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote: > > > > On Thu, Sep 18, 2025 at 1:33 AM Amit Kapila <amit.kapila16@gmail.com> wrote: > > > > > > If we compare conflict_history_table with the slot that gets created > > > with subscription, one can say the same thing about slots. Users can > > > drop the slots and whole replication will stop. I think this table > > > will be created with the same privileges as the owner of a > > > subscription which can be either a superuser or a user with the > > > privileges of the pg_create_subscription role, so we can rely on such > > > users. > > > > We might want to consider which role inserts the conflict info into > > the history table. For example, if any table created by a user can be > > used as the history table for a subscription and the conflict info > > insertion is performed by the subscription owner, we would end up > > having the same security issue that was addressed by the run_as_owner > > subscription option. > > > > Yeah, I don't think we want to open that door. For user created > tables, we should perform actions with table_owner's privilege. In > such a case, if one wants to create a subscription with run_as_owner > option, she should give DML operation permissions to the subscription > owner. OTOH, if we create this table internally (via subscription > owner) then irrespective of run_as_owner, we will always insert as > subscription_owner. Agreed. > > AFAIR, one open point for internally created tables is whether we > should skip changes to conflict_history table while replicating > changes? The table will be considered under for ALL TABLES > publications, if defined? Ideally, these should behave as catalog > tables, so one option is to mark them as 'user_catalog_table', or the > other option is we have some hard-code checks during replication. The > first option has the advantage that it won't write additional WAL for > these tables which is otherwise required under wal_level=logical. What > other options do we have? I think conflict history information is subscriber local information so doesn't have to be replicated to another subscriber. Also it could be problematic in cross-major-version replication cases if we break the compatibility of history table definition. I would expect that the history table works as a catalog table in terms of logical decoding/replication. It would probably make sense to reuse the user_catalog_table option for that purpose. If we have a history table for each subscription that wants to record the conflict history (I believe so), it would be hard to go with the second option (having hard-code checks). Regards, -- Masahiko Sawada Amazon Web Services: https://aws.amazon.com
On Tue, Sep 23, 2025 at 11:29 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote: > > On Sat, Sep 20, 2025 at 4:59 AM Amit Kapila <amit.kapila16@gmail.com> wrote: > > > > > AFAIR, one open point for internally created tables is whether we > > should skip changes to conflict_history table while replicating > > changes? The table will be considered under for ALL TABLES > > publications, if defined? Ideally, these should behave as catalog > > tables, so one option is to mark them as 'user_catalog_table', or the > > other option is we have some hard-code checks during replication. The > > first option has the advantage that it won't write additional WAL for > > these tables which is otherwise required under wal_level=logical. What > > other options do we have? > > I think conflict history information is subscriber local information > so doesn't have to be replicated to another subscriber. Also it could > be problematic in cross-major-version replication cases if we break > the compatibility of history table definition. > Right, this is another reason not to replicate it. > I would expect that the > history table works as a catalog table in terms of logical > decoding/replication. It would probably make sense to reuse the > user_catalog_table option for that purpose. If we have a history table > for each subscription that wants to record the conflict history (I > believe so), it would be hard to go with the second option (having > hard-code checks). > Agreed. Let's wait and see what Dilip or others have to say on this. -- With Regards, Amit Kapila.
On Tue, Sep 23, 2025 at 11:29 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote: > > On Sat, Sep 20, 2025 at 4:59 AM Amit Kapila <amit.kapila16@gmail.com> wrote: > > > > On Thu, Sep 18, 2025 at 11:46 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote: > > > > > > On Thu, Sep 18, 2025 at 1:33 AM Amit Kapila <amit.kapila16@gmail.com> wrote: > > > > > > > > If we compare conflict_history_table with the slot that gets created > > > > with subscription, one can say the same thing about slots. Users can > > > > drop the slots and whole replication will stop. I think this table > > > > will be created with the same privileges as the owner of a > > > > subscription which can be either a superuser or a user with the > > > > privileges of the pg_create_subscription role, so we can rely on such > > > > users. > > > > > > We might want to consider which role inserts the conflict info into > > > the history table. For example, if any table created by a user can be > > > used as the history table for a subscription and the conflict info > > > insertion is performed by the subscription owner, we would end up > > > having the same security issue that was addressed by the run_as_owner > > > subscription option. > > > > > > > Yeah, I don't think we want to open that door. For user created > > tables, we should perform actions with table_owner's privilege. In > > such a case, if one wants to create a subscription with run_as_owner > > option, she should give DML operation permissions to the subscription > > owner. OTOH, if we create this table internally (via subscription > > owner) then irrespective of run_as_owner, we will always insert as > > subscription_owner. > > Agreed. Yeah that makes sense to me as well. -- Regards, Dilip Kumar Google
On Wed, Sep 24, 2025 at 4:00 PM Amit Kapila <amit.kapila16@gmail.com> wrote: > > On Tue, Sep 23, 2025 at 11:29 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote: > > > > On Sat, Sep 20, 2025 at 4:59 AM Amit Kapila <amit.kapila16@gmail.com> wrote: > > > > > > > > AFAIR, one open point for internally created tables is whether we > > > should skip changes to conflict_history table while replicating > > > changes? The table will be considered under for ALL TABLES > > > publications, if defined? Ideally, these should behave as catalog > > > tables, so one option is to mark them as 'user_catalog_table', or the > > > other option is we have some hard-code checks during replication. The > > > first option has the advantage that it won't write additional WAL for > > > these tables which is otherwise required under wal_level=logical. What > > > other options do we have? > > > > I think conflict history information is subscriber local information > > so doesn't have to be replicated to another subscriber. Also it could > > be problematic in cross-major-version replication cases if we break > > the compatibility of history table definition. > > > > Right, this is another reason not to replicate it. > > > I would expect that the > > history table works as a catalog table in terms of logical > > decoding/replication. It would probably make sense to reuse the > > user_catalog_table option for that purpose. If we have a history table > > for each subscription that wants to record the conflict history (I > > believe so), it would be hard to go with the second option (having > > hard-code checks). > > > > Agreed. Let's wait and see what Dilip or others have to say on this. Yeah I think this makes sense to create as 'user_catalog_table' tables when we internally create them. However, IMHO when a user provides its own table, I believe we should not enforce the restriction for that table to be created as a 'user_catalog_table' table, or do you think we should enforce that property? -- Regards, Dilip Kumar Google
On Wed, Sep 24, 2025 at 4:40 AM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > On Wed, Sep 24, 2025 at 4:00 PM Amit Kapila <amit.kapila16@gmail.com> wrote: > > > > On Tue, Sep 23, 2025 at 11:29 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote: > > > > > > On Sat, Sep 20, 2025 at 4:59 AM Amit Kapila <amit.kapila16@gmail.com> wrote: > > > > > > > > > > > AFAIR, one open point for internally created tables is whether we > > > > should skip changes to conflict_history table while replicating > > > > changes? The table will be considered under for ALL TABLES > > > > publications, if defined? Ideally, these should behave as catalog > > > > tables, so one option is to mark them as 'user_catalog_table', or the > > > > other option is we have some hard-code checks during replication. The > > > > first option has the advantage that it won't write additional WAL for > > > > these tables which is otherwise required under wal_level=logical. What > > > > other options do we have? > > > > > > I think conflict history information is subscriber local information > > > so doesn't have to be replicated to another subscriber. Also it could > > > be problematic in cross-major-version replication cases if we break > > > the compatibility of history table definition. > > > > > > > Right, this is another reason not to replicate it. > > > > > I would expect that the > > > history table works as a catalog table in terms of logical > > > decoding/replication. It would probably make sense to reuse the > > > user_catalog_table option for that purpose. If we have a history table > > > for each subscription that wants to record the conflict history (I > > > believe so), it would be hard to go with the second option (having > > > hard-code checks). > > > > > > > Agreed. Let's wait and see what Dilip or others have to say on this. > > Yeah I think this makes sense to create as 'user_catalog_table' tables > when we internally create them. However, IMHO when a user provides > its own table, I believe we should not enforce the restriction for > that table to be created as a 'user_catalog_table' table, or do you > think we should enforce that property? I find that's a user's responsibility, so I would not enforce that property for user-provided-tables. BTW what is the main use case for supporting the use of user-provided tables for the history table? I think we basically don't want the history table to be updated by any other processes than apply workers, so it would make more sense that such a table is created internally and tied to the subscription. I'm less convinced that it has enough upside to warrant the complexity. Regards, -- Masahiko Sawada Amazon Web Services: https://aws.amazon.com
On Sat, Sep 20, 2025 at 5:29 PM Amit Kapila <amit.kapila16@gmail.com> wrote: > > On Thu, Sep 18, 2025 at 11:46 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote: > > > > On Thu, Sep 18, 2025 at 1:33 AM Amit Kapila <amit.kapila16@gmail.com> wrote: > > > > > > If we compare conflict_history_table with the slot that gets created > > > with subscription, one can say the same thing about slots. Users can > > > drop the slots and whole replication will stop. I think this table > > > will be created with the same privileges as the owner of a > > > subscription which can be either a superuser or a user with the > > > privileges of the pg_create_subscription role, so we can rely on such > > > users. > > > > We might want to consider which role inserts the conflict info into > > the history table. For example, if any table created by a user can be > > used as the history table for a subscription and the conflict info > > insertion is performed by the subscription owner, we would end up > > having the same security issue that was addressed by the run_as_owner > > subscription option. > > > > Yeah, I don't think we want to open that door. For user created > tables, we should perform actions with table_owner's privilege. In > such a case, if one wants to create a subscription with run_as_owner > option, she should give DML operation permissions to the subscription > owner. OTOH, if we create this table internally (via subscription > owner) then irrespective of run_as_owner, we will always insert as > subscription_owner. > > AFAIR, one open point for internally created tables is whether we > should skip changes to conflict_history table while replicating > changes? The table will be considered under for ALL TABLES > publications, if defined? Ideally, these should behave as catalog > tables, so one option is to mark them as 'user_catalog_table', or the > other option is we have some hard-code checks during replication. The > first option has the advantage that it won't write additional WAL for > these tables which is otherwise required under wal_level=logical. What > other options do we have? I was doing more analysis and testing for 'use_catalog_table', so what I found is when a table is marked as 'use_catalog_table', it will log extra information i.e. CID[1] so that these tables can be used for scanning as well during decoding like catalog tables using historical snapshot. And I have checked the code and tested as well 'use_catalog_table' does get streamed with ALL TABLE options. Am I missing something or are we thinking of changing the behavior of use_catalog_table so that they do not get decoded, but I think that will change the existing behaviour so might not be a good option, yet another idea is to invent some other option for which purpose called 'conflict_history_purpose' but maybe that doesn't justify the purpose of the new option IMHO. [1] /* * For logical decode we need combo CIDs to properly decode the * catalog */ if (RelationIsAccessibleInLogicalDecoding(relation)) log_heap_new_cid(relation, &tp); -- Regards, Dilip Kumar Google
On Thu, Sep 25, 2025 at 11:09 AM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > On Sat, Sep 20, 2025 at 5:29 PM Amit Kapila <amit.kapila16@gmail.com> wrote: > > > > On Thu, Sep 18, 2025 at 11:46 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote: > > > > > > On Thu, Sep 18, 2025 at 1:33 AM Amit Kapila <amit.kapila16@gmail.com> wrote: > > > > > > > > If we compare conflict_history_table with the slot that gets created > > > > with subscription, one can say the same thing about slots. Users can > > > > drop the slots and whole replication will stop. I think this table > > > > will be created with the same privileges as the owner of a > > > > subscription which can be either a superuser or a user with the > > > > privileges of the pg_create_subscription role, so we can rely on such > > > > users. > > > > > > We might want to consider which role inserts the conflict info into > > > the history table. For example, if any table created by a user can be > > > used as the history table for a subscription and the conflict info > > > insertion is performed by the subscription owner, we would end up > > > having the same security issue that was addressed by the run_as_owner > > > subscription option. > > > > > > > Yeah, I don't think we want to open that door. For user created > > tables, we should perform actions with table_owner's privilege. In > > such a case, if one wants to create a subscription with run_as_owner > > option, she should give DML operation permissions to the subscription > > owner. OTOH, if we create this table internally (via subscription > > owner) then irrespective of run_as_owner, we will always insert as > > subscription_owner. > > > > AFAIR, one open point for internally created tables is whether we > > should skip changes to conflict_history table while replicating > > changes? The table will be considered under for ALL TABLES > > publications, if defined? Ideally, these should behave as catalog > > tables, so one option is to mark them as 'user_catalog_table', or the > > other option is we have some hard-code checks during replication. The > > first option has the advantage that it won't write additional WAL for > > these tables which is otherwise required under wal_level=logical. What > > other options do we have? > > I was doing more analysis and testing for 'use_catalog_table', so what > I found is when a table is marked as 'use_catalog_table', it will log > extra information i.e. CID[1] so that these tables can be used for > scanning as well during decoding like catalog tables using historical > snapshot. And I have checked the code and tested as well > 'use_catalog_table' does get streamed with ALL TABLE options. Am I > missing something or are we thinking of changing the behavior of > use_catalog_table so that they do not get decoded, but I think that > will change the existing behaviour so might not be a good option, yet > another idea is to invent some other option for which purpose called > 'conflict_history_purpose' but maybe that doesn't justify the purpose > of the new option IMHO. > > [1] > /* > * For logical decode we need combo CIDs to properly decode the > * catalog > */ > if (RelationIsAccessibleInLogicalDecoding(relation)) > log_heap_new_cid(relation, &tp); > Meanwhile I am also exploring the option where we can just CREATE TYPE in initialize_data_directory() during initdb, basically we will create this type in template1 so that it will be available in all the databases, and that would simplify the table creation whether we create internally or we allow user to create it. And while checking is_publishable_class we can check the type and avoid publishing those tables. -- Regards, Dilip Kumar Google
On Thu, Sep 25, 2025 at 11:53 AM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > > [1] > > /* > > * For logical decode we need combo CIDs to properly decode the > > * catalog > > */ > > if (RelationIsAccessibleInLogicalDecoding(relation)) > > log_heap_new_cid(relation, &tp); > > > > Meanwhile I am also exploring the option where we can just CREATE TYPE > in initialize_data_directory() during initdb, basically we will create > this type in template1 so that it will be available in all the > databases, and that would simplify the table creation whether we > create internally or we allow user to create it. And while checking > is_publishable_class we can check the type and avoid publishing those > tables. > Based on my off list discussion with Amit, one option could be to set HEAP_INSERT_NO_LOGICAL option while inserting tuple into conflict history table, for that we can not use SPI interface to insert instead we will have to directly call the heap_insert() to add this option. Since we do not want to create any trigger etc on this table, direct insert should be fine, but if we plan to create this table as partitioned table in future then direct heap insert might not work. -- Regards, Dilip Kumar Google
On Thu, Sep 25, 2025 at 4:19 PM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > On Thu, Sep 25, 2025 at 11:53 AM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > > > > [1] > > > /* > > > * For logical decode we need combo CIDs to properly decode the > > > * catalog > > > */ > > > if (RelationIsAccessibleInLogicalDecoding(relation)) > > > log_heap_new_cid(relation, &tp); > > > > > > > Meanwhile I am also exploring the option where we can just CREATE TYPE > > in initialize_data_directory() during initdb, basically we will create > > this type in template1 so that it will be available in all the > > databases, and that would simplify the table creation whether we > > create internally or we allow user to create it. And while checking > > is_publishable_class we can check the type and avoid publishing those > > tables. > > > > Based on my off list discussion with Amit, one option could be to set > HEAP_INSERT_NO_LOGICAL option while inserting tuple into conflict > history table, for that we can not use SPI interface to insert instead > we will have to directly call the heap_insert() to add this option. > Since we do not want to create any trigger etc on this table, direct > insert should be fine, but if we plan to create this table as > partitioned table in future then direct heap insert might not work. Upon further reflection, I realized that while this approach avoids streaming inserts to the conflict log history table, it still requires that table to exist on the subscriber node upon subscription creation, which isn't ideal. We have two main options to address this: Option1: When calling pg_get_publication_tables(), if the 'alltables' option is used, we can scan all subscriptions and explicitly ignore (filter out) all conflict history tables. This will not be very costly as this will scan the subscriber when pg_get_publication_tables() is called, which is only called during create subscription/alter subscription on the remote node. Option2: Alternatively, we could introduce a table creation option, like a 'non-publishable' flag, to prevent a table from being streamed entirely. I believe this would be a valuable, independent feature for users who want to create certain tables without including them in logical replication. I prefer option2, as I feel this can add value independent of this patch. -- Regards, Dilip Kumar Google
On Fri, Sep 26, 2025 at 4:42 PM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > On Thu, Sep 25, 2025 at 4:19 PM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > > > On Thu, Sep 25, 2025 at 11:53 AM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > > > > > > [1] > > > > /* > > > > * For logical decode we need combo CIDs to properly decode the > > > > * catalog > > > > */ > > > > if (RelationIsAccessibleInLogicalDecoding(relation)) > > > > log_heap_new_cid(relation, &tp); > > > > > > > > > > Meanwhile I am also exploring the option where we can just CREATE TYPE > > > in initialize_data_directory() during initdb, basically we will create > > > this type in template1 so that it will be available in all the > > > databases, and that would simplify the table creation whether we > > > create internally or we allow user to create it. And while checking > > > is_publishable_class we can check the type and avoid publishing those > > > tables. > > > > > > > Based on my off list discussion with Amit, one option could be to set > > HEAP_INSERT_NO_LOGICAL option while inserting tuple into conflict > > history table, for that we can not use SPI interface to insert instead > > we will have to directly call the heap_insert() to add this option. > > Since we do not want to create any trigger etc on this table, direct > > insert should be fine, but if we plan to create this table as > > partitioned table in future then direct heap insert might not work. > > Upon further reflection, I realized that while this approach avoids > streaming inserts to the conflict log history table, it still requires > that table to exist on the subscriber node upon subscription creation, > which isn't ideal. > I am not able to understand what exact problem you are seeing here. I was thinking that during the CREATE SUBSCRIPTION command, a new table with user provided name will be created similar to how we create a slot. The difference would be that we create a slot on the remote/publisher node but this table will be created locally. -- With Regards, Amit Kapila.
On Sat, Sep 27, 2025 at 8:53 PM Amit Kapila <amit.kapila16@gmail.com> wrote: > > I am not able to understand what exact problem you are seeing here. I > was thinking that during the CREATE SUBSCRIPTION command, a new table > with user provided name will be created similar to how we create a > slot. The difference would be that we create a slot on the > remote/publisher node but this table will be created locally. > That's not an issue, the problem here we are discussing is the conflict history table which is created on the subscriber node should not be published when this node subscription node create another publisher with ALL TABLE option. So we found a option for inserting into this table with HEAP_INSERT_NO_LOGICAL flag so that those insert will not be decoded, but what about another not subscribing from this publisher, they should have this table because when ALL TABLES are published subscriber node expect all user table to present there even if its changes are not published. Consider below example Node1: CREATE PUBLICATION pub_node1.. Node2: CREATE SUBSCRIPTION sub.. PUBLICATION pub_node1 WITH(conflict_history_table='my_conflict_table'); CREATE PUBLICATION pub_node2 FOR ALL TABLE; Node3: CREATE SUBSCRIPTION sub1.. PUBLICATION pub_node2; --this will expect 'my_conflict_table' to exist here because when it will call pg_get_publication_tables() from Node2 it will also get the 'my_conflict_table' along with other user tables. And as a solution I wanted to avoid this table to be avoided when pg_get_publication_tables() is being called. Option1: We can see if table name is listed as conflict history table in any of the subscribers on Node2 we will ignore this. Option2: Provide a new table option to mark table as non publishable table when ALL TABLE option is provided, I think this option can be useful independently as well. -- Regards, Dilip Kumar Google
On Sat, Sep 27, 2025 at 9:24 PM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > On Sat, Sep 27, 2025 at 8:53 PM Amit Kapila <amit.kapila16@gmail.com> wrote: > > > > I am not able to understand what exact problem you are seeing here. I > > was thinking that during the CREATE SUBSCRIPTION command, a new table > > with user provided name will be created similar to how we create a > > slot. The difference would be that we create a slot on the > > remote/publisher node but this table will be created locally. > > > That's not an issue, the problem here we are discussing is the > conflict history table which is created on the subscriber node should > not be published when this node subscription node create another > publisher with ALL TABLE option. So we found a option for inserting > into this table with HEAP_INSERT_NO_LOGICAL flag so that those insert > will not be decoded, but what about another not subscribing from this > publisher, they should have this table because when ALL TABLES are > published subscriber node expect all user table to present there even > if its changes are not published. Consider below example > > Node1: > CREATE PUBLICATION pub_node1.. > > Node2: > CREATE SUBSCRIPTION sub.. PUBLICATION pub_node1 > WITH(conflict_history_table='my_conflict_table'); > CREATE PUBLICATION pub_node2 FOR ALL TABLE; > > Node3: > CREATE SUBSCRIPTION sub1.. PUBLICATION pub_node2; --this will expect > 'my_conflict_table' to exist here because when it will call > pg_get_publication_tables() from Node2 it will also get the > 'my_conflict_table' along with other user tables. > > And as a solution I wanted to avoid this table to be avoided when > pg_get_publication_tables() is being called. > Option1: We can see if table name is listed as conflict history table > in any of the subscribers on Node2 we will ignore this. > Option2: Provide a new table option to mark table as non publishable > table when ALL TABLE option is provided, I think this option can be > useful independently as well. > I agree that option-2 is useful and IIUC, we are already working on something similar in thread [1]. However, it is better to use option-1 here because we are using non-user specified mechanism to skip changes during replication, so following the same during other times is preferable. Once we have that other feature [1], we can probably optimize this code to use it without taking input from the user. The other reason of not going with the option-2 in the way you are proposing is that it doesn't seem like a good idea to have multiple ways to specify skipping tables from publishing. I find the approach being discussed in thread [1] a generic and better than a new table-level option. [1] - https://www.postgresql.org/message-id/CANhcyEVt2CBnG7MOktaPPV4rYapHR-VHe5%3DqoziTZh1L9SVc6w%40mail.gmail.com -- With Regards, Amit Kapila.
On Sun, Sep 28, 2025 at 2:43 AM Amit Kapila <amit.kapila16@gmail.com> wrote: > > I agree that option-2 is useful and IIUC, we are already working on > something similar in thread [1]. However, it is better to use option-1 > here because we are using non-user specified mechanism to skip changes > during replication, so following the same during other times is > preferable. Once we have that other feature [1], we can probably > optimize this code to use it without taking input from the user. The > other reason of not going with the option-2 in the way you are > proposing is that it doesn't seem like a good idea to have multiple > ways to specify skipping tables from publishing. I find the approach > being discussed in thread [1] a generic and better than a new > table-level option. > > [1] - https://www.postgresql.org/message-id/CANhcyEVt2CBnG7MOktaPPV4rYapHR-VHe5%3DqoziTZh1L9SVc6w%40mail.gmail.com I understand the current discussion revolves around using an EXCEPT clause (for tables/schemas/columns) during publication creation. But what we want is to mark some table which will be excluded permanently from publication, because we can not expect users to explicitly exclude them while creating publication. So, I propose we add a "non-publishable" property to tables themselves. This is a more valuable option for users who are certain that certain tables should never be replicated. By marking a table as non-publishable, we save users the effort of repeatedly listing it in the EXCEPT option for every new publication. Both methods have merit, but the proposed table property addresses the need for a permanent, system-wide exclusion. See below test with a quick hack, what I am referring to. postgres[2730657]=# CREATE TABLE test(a int) WITH (NON_PUBLISHABLE_TABLE = true); CREATE TABLE postgres[2730657]=# CREATE PUBLICATION pub FOR ALL TABLES ; CREATE PUBLICATION postgres[2730657]=# select pg_get_publication_tables('pub'); pg_get_publication_tables --------------------------- (0 rows) But I agree this is an additional table option which might need consensus, so meanwhile we can proceed with option2, I will prepare patches with option-2 and as a add on patch I will propose option-1. And this option-1 patch can be discussed in a separate thread as well. -- Regards, Dilip Kumar Google
Вложения
On Sun, Sep 28, 2025 at 5:15 PM Dilip Kumar <dilipbalaut@gmail.com> wrote: > > On Sun, Sep 28, 2025 at 2:43 AM Amit Kapila <amit.kapila16@gmail.com> wrote: > > > > > I agree that option-2 is useful and IIUC, we are already working on > > something similar in thread [1]. However, it is better to use option-1 > > here because we are using non-user specified mechanism to skip changes > > during replication, so following the same during other times is > > preferable. Once we have that other feature [1], we can probably > > optimize this code to use it without taking input from the user. The > > other reason of not going with the option-2 in the way you are > > proposing is that it doesn't seem like a good idea to have multiple > > ways to specify skipping tables from publishing. I find the approach > > being discussed in thread [1] a generic and better than a new > > table-level option. > > > > [1] - https://www.postgresql.org/message-id/CANhcyEVt2CBnG7MOktaPPV4rYapHR-VHe5%3DqoziTZh1L9SVc6w%40mail.gmail.com > > I understand the current discussion revolves around using an EXCEPT > clause (for tables/schemas/columns) during publication creation. But > what we want is to mark some table which will be excluded permanently > from publication, because we can not expect users to explicitly > exclude them while creating publication. > > So, I propose we add a "non-publishable" property to tables > themselves. This is a more valuable option for users who are certain > that certain tables should never be replicated. > > By marking a table as non-publishable, we save users the effort of > repeatedly listing it in the EXCEPT option for every new publication. > Both methods have merit, but the proposed table property addresses the > need for a permanent, system-wide exclusion. > > See below test with a quick hack, what I am referring to. > > postgres[2730657]=# CREATE TABLE test(a int) WITH > (NON_PUBLISHABLE_TABLE = true); > CREATE TABLE > postgres[2730657]=# CREATE PUBLICATION pub FOR ALL TABLES ; > CREATE PUBLICATION > postgres[2730657]=# select pg_get_publication_tables('pub'); > pg_get_publication_tables > --------------------------- > (0 rows) > > > But I agree this is an additional table option which might need > consensus, so meanwhile we can proceed with option2, I will prepare > patches with option-2 and as a add on patch I will propose option-1. > And this option-1 patch can be discussed in a separate thread as well. So here is the patch set using option-2, with this when alltable option is used and we get pg_get_publication_tables(), this will check the relid against the conflict history tables in the subscribers and those tables will not be added to the list. I will start a separate thread for proposing the patch I sent in previous email. -- Regards, Dilip Kumar Google