Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vWFJo-00Ftey-0z for pgsql-hackers@arkaria.postgresql.org; Thu, 18 Dec 2025 14:49:29 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vWFJm-002bPs-38 for pgsql-hackers@arkaria.postgresql.org; Thu, 18 Dec 2025 14:49:27 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vWFJm-002bPk-0a for pgsql-hackers@lists.postgresql.org; Thu, 18 Dec 2025 14:49:27 +0000 Received: from fout-b3-smtp.messagingengine.com ([202.12.124.146]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vWFJl-001LRF-0j for pgsql-hackers@lists.postgresql.org; Thu, 18 Dec 2025 14:49:26 +0000 Received: from phl-compute-06.internal (phl-compute-06.internal [10.202.2.46]) by mailfout.stl.internal (Postfix) with ESMTP id A1D3E1D0005A; Thu, 18 Dec 2025 09:49:23 -0500 (EST) Received: from phl-imap-05 ([10.202.2.95]) by phl-compute-06.internal (MEProxy); Thu, 18 Dec 2025 09:49:23 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=eulerto.com; h= cc:cc:content-transfer-encoding:content-type:content-type:date :date:from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to; s=fm2; t=1766069363; x=1766155763; bh=V8Q468vCSk/FEeoQzEoMsJsvMfxqRIMDGvAbZsu2fj8=; b= XVM9C14PhGT865ePE5fA9cyUeXGpbMRO/SQUl/P1O+7VWX5uFa1WTT2fxXPsOqGP 4rR9/++3uFhUh0e6DQcCHhT9w2nIxmTGFOHLf2h64obaqMINqEDXRTXKJjg6ld7Z mvGpe8rl8u78Id3ANhrYkO2fWoJC5FH1nYT6tigeq24hYNiBb0s45OQhufu6WJVM bsUl3ew9X23c0aIy7h5gRl5/2Tm3M88dy8kusFsbYny0ShlQmn7uHO351hkjsitp d/nO56OicUck2vgIOpEv2U3d1BIVZ0dK7OEqXdoIJuA24S9q3+6fMVKuKIswVJRc 8lOziAlm0Z3kOLAQDoiNhQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm1; t=1766069363; x= 1766155763; bh=V8Q468vCSk/FEeoQzEoMsJsvMfxqRIMDGvAbZsu2fj8=; b=i zAS4bcxjR1e1Ig+/DLbKaoCE4ieE9YcMkHI7KSb8F6+Kvf5b+MeGMcPUVfCNU6ly VG7R4eY3n3gpg+cJ5il1vwPDij2vaFFwqTkc3S2yrB0qPWVyf1hXdEpylj4E8CP+ 2mKthYQv7MRF59TOnKM1gPAXkzuBnlZ53K3uGWfdnStDz66erK0BGigeXAVl1LbV lLQv2j7RM1pmIeVRmxnfN8eGJ7I1wo/l4zxefqAIHiOEWtDApDUAjdeYzL5Eqb/x /UVNr9jVKvqK9OFmyz6+pOH12Gz9+lrvwsPpoA8zXsbQt5QYoflZAXcV1cZvnHlX cn2ExX+Y3YSEpOm8UqynA== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefgedrtddtgdegheejtdcutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpuffrtefokffrpgfnqfghnecuuegr ihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenucfjug hrpefoggffhffvvefkjghfufgtgfesthhqredtredtjeenucfhrhhomhepfdfguhhlvghr ucfvrghvvghirhgrfdcuoegvuhhlvghrsegvuhhlvghrthhordgtohhmqeenucggtffrrg htthgvrhhnpeefkeeujeegveetffeugefffffgfeehtdegudffjeeludeuvdfhfeelgfej geefleenucffohhmrghinhepvghnthgvrhhprhhishgvuggsrdgtohhmnecuvehluhhsth gvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepvghulhgvrhesvghulhgv rhhtohdrtghomhdpnhgspghrtghpthhtohepiedpmhhouggvpehsmhhtphhouhhtpdhrtg hpthhtohephhhouhiijhdrfhhnshhtsehfuhhjihhtshhurdgtohhmpdhrtghpthhtohep rghmihhtrdhkrghpihhlrgduieesghhmrghilhdrtghomhdprhgtphhtthhopeguihhlih hpsggrlhgruhhtsehgmhgrihhlrdgtohhmpdhrtghpthhtohepghhrrghnthiihhhouhes ghhmrghilhdrtghomhdprhgtphhtthhopehlihdrvghvrghnrdgthhgrohesghhmrghilh drtghomhdprhgtphhtthhopehpghhsqhhlqdhhrggtkhgvrhhssehlihhsthhsrdhpohhs thhgrhgvshhqlhdrohhrgh X-ME-Proxy: Feedback-ID: i0c21471d:Fastmail Received: by mailuser.phl.internal (Postfix, from userid 501) id 500241820054; Thu, 18 Dec 2025 09:49:23 -0500 (EST) X-Mailer: MessagingEngine.com Webmail Interface MIME-Version: 1.0 X-ThreadId: ASirQp6p08EV Date: Thu, 18 Dec 2025 11:49:02 -0300 From: "Euler Taveira" To: "GRANT ZHOU" Cc: "houzj.fnst@fujitsu.com" , "Chao Li" , "Amit Kapila" , "Dilip Kumar" , "Postgres hackers" Message-Id: <19dac243-1f46-4720-bdec-bf0f851d03b9@app.fastmail.com> In-Reply-To: References: <5ABD7727-CD22-4112-A186-0E788EE78109@gmail.com> <23A24BFF-18A7-4FE9-AAFA-13E1AA207DD0@gmail.com> Subject: Re: Improve logical replication usability when tables lack primary keys Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On Wed, Dec 17, 2025, at 6:43 PM, GRANT ZHOU wrote: > On Wed, Dec 17, 2025 at 12:50=E2=80=AFPM Euler Taveira wrote: >> Each table needs to say what's its row identifier. The user created a= table >> without primary key. Well, create a primary key. There are dozens of = thousands >> of objects. Use a script. > However, I=E2=80=99d like to share a user perspective regarding the "u= se a=20 > script" approach. The main value of `FOR TABLES IN SCHEMA` is=20 > *in-database automation*. If users still need to maintain external=20 > scripts to monitor and `ALTER` new tables to prevent replication=20 > errors, it significantly diminishes the value of that automation. > As I tried to explain in the previous email, the problem with FOR ALL TA= BLES and FOR TABLES IN SCHEMA syntax is that the is no catalog information ab= out the relations; the list of relations is collected at runtime. When I suggested "use a script" I was referring to fix the logical repli= cation setup regarding the lack of primary key. There is no need to have an aut= omation outside the database, use an event trigger. If your lazy user doesn't cr= eate the primary key, assign REPLICA IDENTITY FULL. Something like -- This example is far from being a complete solution for fixing the lac= k of -- primary key in a logical replication scenario. -- ALTER TABLE should be supported too CREATE OR REPLACE FUNCTION event_trigger_for_replica_identity() RETURNS event_trigger LANGUAGE plpgsql AS $$ DECLARE obj record; rec record; ricnt integer :=3D 0; BEGIN FOR obj IN SELECT * FROM pg_event_trigger_ddl_commands() LOOP IF obj.command_tag =3D 'CREATE TABLE' THEN SELECT COUNT(*) INTO ricnt FROM pg_index WHERE indrelid =3D = obj.objid AND indisprimary; RAISE NOTICE 'ricnt: %', ricnt; IF ricnt =3D 0 THEN EXECUTE 'ALTER TABLE ' || obj.object_identity || ' REPLI= CA IDENTITY FULL'; END IF; END IF; END LOOP; END; $$; CREATE EVENT TRIGGER event_trigger_for_replica_identity ON ddl_command_end EXECUTE FUNCTION event_trigger_for_replica_identity(); CREATE TABLE event_trigger_test_1 (a int); \d+ event_trigger_test_1 CREATE TABLE event_trigger_test_2 (a int primary key); \d+ event_trigger_test_2 CREATE TABLE event_trigger_test_3 (a int, b text not null, primary key(b= )); \d+ event_trigger_test_3 --ALTER TABLE event_trigger_test_3 DROP CONSTRAINT event_trigger_test_3_= pkey; --\d+ event_trigger_test_3 DROP EVENT TRIGGER event_trigger_for_replica_identity; DROP FUNCTION event_trigger_for_replica_identity; DROP TABLE event_trigger_test_1, event_trigger_test_2, event_trigger_tes= t_3; 8<----------------------------------------------------------------------= ------8< > Additionally, tables without Primary Keys are valid SQL and extremely=20 > common in enterprise environments (e.g., audit logs, data warehousing)= .=20 > In large-scale deployments, enforcing PKs on every single table isn't=20 > always practical.=20 > I'm not saying users shouldn't create tables without a primary key. I'm = arguing that this decision should take into account what adjustments need to be = made to use these tables in logical replication. > > I think the goal of this proposal is not to change the underlying tabl= e=20 > property design, but rather to seek a mechanism (like a Publication=20 > option) to ensure this automation functions safely without external=20 > intervention. It is simply about allowing the database to handle these=20 > valid, common scenarios gracefully when automation is enabled. > You didn't get it. You already have one property to handle it and you are proposing to add a second property to handle it. I think you are pursuing the wrong solution. IMO we need a solution to e= nforce that the logical replication contract is valid. If you create or modify = a table that is part of a publication, there is no validation that that table co= mplies with the publication properties (update and delete properties should req= uire an appropriate replica identity). We should close the gaps in both publicat= ion and table. --=20 Euler Taveira EDB https://www.enterprisedb.com/