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 1wQFcP-001NzC-27 for pgsql-hackers@arkaria.postgresql.org; Fri, 22 May 2026 02:28:09 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wQFbN-00CC8a-2g for pgsql-hackers@arkaria.postgresql.org; Fri, 22 May 2026 02:27:06 +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 1wQFbN-00CC8S-0x for pgsql-hackers@lists.postgresql.org; Fri, 22 May 2026 02:27:06 +0000 Received: from mail-qt1-x82b.google.com ([2607:f8b0:4864:20::82b]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1wQFbM-00000000CwW-1Y1Q for pgsql-hackers@lists.postgresql.org; Fri, 22 May 2026 02:27:05 +0000 Received: by mail-qt1-x82b.google.com with SMTP id d75a77b69052e-516d15ed2bcso7377191cf.0 for ; Thu, 21 May 2026 19:27:03 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1779416823; cv=none; d=google.com; s=arc-20240605; b=K6ZBjb+F1X4h+Y8dFzoJ7N/MmJrKqYF1UjFVlftnCy34TV/isg6zFHU7W+ardJJvoV oRJennXWt/D26N5i7Dqn9xVOoX5WrQRkzpxGypT99RdQdxPcbn77SdYWCeLl6y4NDbhq SFimedmewPX9PkDsWgPBUTTEhvj0BEkawmDgdIhkDsjZQQUu9hB5eRFFV6L3cGdKyKin Ysut/3u+cjhBOpEFr2T7HSlTySP+oJtL9NrMIeIq4zyj/GHV9YzRNF2ZlcWUgem84ftm CUJQDdAfQVsNZ3S/UzRnRytPOR6Ls9HAZWsR7poXVTwzAg4GeKzPNlUtkNQOxjErchH0 piEQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:dkim-signature; bh=raUlnvY4mgzOfGFnZZFYQrxLmokdQLJ/j4N9l8QzsNE=; fh=2jBNDjHdj4l0PDAKAs4fQ7opZ1fmpk9VWPHV8bVReO4=; b=ATIQkGs1CmmkdYWQ6mFPtojgjc0hERAlIo+iYJuGo4C9ECovCbXBQWJw43xZg31zXS /cOuJillNkOErmJIw1adUP9XTQiZKbHc2u+YAFtBgxyfVBrxv8h/T0/qP/CzYsnKS3DG hs2wbI7tl7z36YJ7FfHMblyL2VwsmVvmtdIww6R0LT8Z3oOLzazpmm6EJ1+yrIRvN+YY /CySuuQt1uFdHJFgziZaMjx7mu9voE88K0GdWF37TP8awIFmhOLbi+GHqtLW2/O2E3A0 1zMjTXQ/V1K0skKdeu8I4aI2f8Rk28KYwNzLRxtj6gBKfxs7te6ymmXIV5GK0rWPEwM4 mt7w==; darn=lists.postgresql.org ARC-Authentication-Results: i=1; mx.google.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1779416823; x=1780021623; darn=lists.postgresql.org; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=raUlnvY4mgzOfGFnZZFYQrxLmokdQLJ/j4N9l8QzsNE=; b=V/sd6/CSixEd7BH27jXXKYL0f3q31XQ2SB2YBvInAO1KfNbs7lYt7egRPBtA5jwM62 pZkEpm3o4bLsKDLQONN09FDJlqzwf+18GNd6oOr83T8B3tdqthsP2VNCv5CmMIZlHWkY 2IQU80jeKI1492YysmSONHmmwOKcLApY148HMXPTTMZk0tHMq4wIlHl1yMSb3lfm5d3B Vkcax1a9AfiADxSiiuxnQ10QbmqDN5S7wlREWTtaFjaIRgkV5nNi1Wc70Ec9p535tr0u uc/WZd4aq1f98dQzXJL2iNRL57XKYbeJnu4pCQCyriv7lcpoZy0rvNghHwkmUqa4uPYA Uq4w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779416823; x=1780021623; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=raUlnvY4mgzOfGFnZZFYQrxLmokdQLJ/j4N9l8QzsNE=; b=TZ1L1cSmGtz5EJ+KK2lmj/Xq+EGsKPHq6LAsKzxZ/GY6DdTlGYUuTQm3EdAcbqIYYt QDuEtMkuG6Cz3DajbfEoXtMc/F1sdl48hU/uDS6LHYaEnHKM42Qyto/WbaLBJNuTIwIS vWd8rfRtiOkvxrSRV3U2MtWEBtgcXEa+PotgznlBnPgfIYy6m8l3L20Ucn+ycSjMVRfk Ex3//foeL7fDv3rSvBnHTjrNlSvqZe1GOo8rN2ukMSEsJwbmAXcZJ/vEXmjqSdizrLjl I0XK9Dw7IfGJ21vFcQCNzQDpwSHX5GW8hZa1GanYGTRLLqE9ShdeRi7+HK1/1fMkGzP/ I5Ow== X-Forwarded-Encrypted: i=1; AFNElJ/HQ6ixxTaRHjkQ8NvHxxTq9juJuR0z6pFBszW1X9iTE9v6R4fPjgeQJITIzPeluVPJ1rhvCFR2X2GWuVsA@lists.postgresql.org X-Gm-Message-State: AOJu0YzFWeTPfFsaj9KiMO1/9exEYaNEWXuqVbOCNLlD93Qi8wsI22+U MeDYzuijqVaHyDbhwYH7ObpxwLztul5m8G1j7/DGNMdXJBETegzHoG/d80d0Y6KcoQ5lQpxRwmC eLwEW/He2FSx13JsO/3IGAx5Q/OP2cts= X-Gm-Gg: Acq92OFooysmQMCsipR3mHyIBb+BysUTucUYZTBuhUg++yVcqiUFf3HfOTDmzaMOOFw xK2afKGQW14zzsFU9Zl9aiYyMFeRgu2pQw+MpariTRak1ja5crB+cuTjC00/EOxWpu8RVEyu5Eu qOO/3ULqgqdsy97btuC5EsebL2+e0wdzYmJCRjZioR1QksRLij/EnhQovN0fjIKyHjbIPJhYo2C M+LY6xB892AnNEYpEi/MFqUvDMAUDN96jDiwdKE582tpBJ/wzPeZYbx/X2YffVwLl6O3lhTbX0G t3imNZs= X-Received: by 2002:a05:622a:9008:b0:50b:4a3c:8917 with SMTP id d75a77b69052e-516c55d2749mr52530811cf.24.1779416822697; Thu, 21 May 2026 19:27:02 -0700 (PDT) MIME-Version: 1.0 References: In-Reply-To: From: Peter Smith Date: Fri, 22 May 2026 12:26:35 +1000 X-Gm-Features: AVHnY4IfcuEDmk9eB6G-vqkTLpp6MgjmLammRcrKfnhWFZAJ90x7Sz1GBB1vhv0 Message-ID: Subject: Re: Support EXCEPT for TABLES IN SCHEMA publications To: Nisha Moond Cc: shveta malik , Amit Kapila , PostgreSQL Hackers Content-Type: text/plain; charset="UTF-8" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk Hi Nisha. Here are some review comments for patch v6-0001. ====== src/backend/catalog/pg_publication.c GetTopMostAncestorInPublication: 1. +GetTopMostAncestorInPublication(Oid puboid, List *ancestors, + int *ancestor_level, List *except_pubids) I am having dificulty understanding this function. There needs to be a description what does the input parameter 'except_pubids' mean. The param name doesn't tell me anything much -- just that it is a list of pubids that "something" (what?) is excluded from. And how does that relate to the 'ancestors'? ~~~ 2. { aschemaPubids = GetSchemaPublications(get_rel_namespace(ancestor)); - if (list_member_oid(aschemaPubids, puboid)) + if (list_member_oid(aschemaPubids, puboid) && + !list_member_oid(except_pubids, puboid)) Is this new code in the right place? I'm not 100% sure of the 'except_pubids' details, but shouldn't it be checked sooner? e.g. if we know already that this pubid is no good (!list_member_oid(except_pubids, puboid)) then what is the point to even assign/check aschemaPubids? ~~~ 3. + if (is_except) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("table \"%s\" cannot be added because it is excluded from publication \"%s\"", + RelationGetQualifiedRelationName(targetrel), + pub->name))); + else + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("relation \"%s\" is already member of publication \"%s\"", + RelationGetRelationName(targetrel), pub->name))); Fully qualified 'targetrel' in the first error, but not in the second? Is it OK? ~~~ GetAllSchemaPublicationRelations: 4. + List *exceptlist = NIL; The varname is a bit vague; it is a list of "what"? Maybe say 'except_relids' or similar. ====== src/backend/replication/pgoutput/pgoutput.c get_rel_sync_entry: 5. + /* + * For the schema EXCEPT check, we must look up the top-most ancestor + * rather than the relation itself. check_publication_add_relation() + * prevents individual partitions from appearing in the EXCEPT clause, + * so only a root (non-partition) table can have prexcept = true. + * Using the partition's own OID would always return NIL and miss the + * exclusion. + */ + Oid root_relid = am_partition ? + llast_oid(get_partition_ancestors(relid)) : relid; + + schemaExceptPubids = GetRelationExcludedPublications(root_relid); 5a. The varname 'schemaExceptPubids' seems ambiguous. It sounds like it is pubids that have EXCEPT SCHEMA. In the future the ALL TABLES may introduce "EXCEPT SCHEMA", but currently there is no such thing. Meanwhile, here I think it means "EXCEPT TABLE", so IMO that varname needs to indicate the meaning better. ~ 5b. Actually, this is becoming a GENERAL comment. There too many ways that these EXCEPT tables are getting named, and it is causing confusion: - except_pubids - exceptlist - exceptrelations - exceptrels - except_relid - except_tables - schemaExceptPubids Can we standardize on some common names, to make all the code more consistent? ~ 5c. Previously, the result of 'get_partition_ancestors' was being freed, but now it is not. I'm not sure how importatnt that is, because I found other examples in PG source code also not freeing... ====== src/bin/psql/tab-complete.in.c 6. + else if (Matches("CREATE", "PUBLICATION", MatchAny, "FOR", "TABLES", "IN", "SCHEMA", MatchAny, "EXCEPT", "(", "TABLE", MatchAnyN) && ends_with(prev_wd, ',')) + COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables); I'm not sure if this is working as intended. When testing for multiple except tables I get results like: ---- test_pub=# create publication pub1 for tables IN SCHEMA myschema EXCEPT ( TABLE WITH ( test_pub=# create publication pub1 for tables IN SCHEMA myschema except ( table test_pub=# create publication pub1 for tables IN SCHEMA myschema except ( table myschema.t myschema.t1 myschema.t2 myschema.t3 test_pub=# create publication pub1 for tables IN SCHEMA myschema except ( table myschema.t1, information_schema. myschema. public. t1 t2 t3 ---- Note: it is offering suggstions for schema names outside of the "myschema". Should this code be calling Query_for_list_of_tables_in_schema instead of Query_for_list_of_tables? ====== src/test/regress/sql/publication.sql 7. ---- Tests for publications with SEQUENCES +--------------------------------------------- +-- EXCEPT tests for TABLES IN SCHEMA +--------------------------------------------- +SET client_min_messages = 'ERROR'; It looks like a previous comment for the SEQUENCES tests has been accidentally removed. I should be put back, and made more prominent like the other big comments. e.g. --------------------------------------------- -- Tests for publications with SEQUENCES --------------------------------------------- ~~~ 8. +RESET client_min_messages; +DROP TABLE pub_test.testpub_tbl_s1, pub_test.testpub_tbl_s2; +DROP TABLE pub_test.testpub_parted_s CASCADE; +DROP TABLE testpub_nopk, testpub_tbl_s1; +DROP PUBLICATION testpub_schema_except1, testpub_schema_except2, testpub_schema_except_multi; + Add a "Cleanup" comment. ====== Kind Regards, Peter Smith. Fujitsu Australia.