public inbox for [email protected]help / color / mirror / Atom feed
[PATCH 1/2] bootstrap: convert Typ to a List* 2+ messages / 2 participants [nested] [flat]
* [PATCH 1/2] bootstrap: convert Typ to a List* @ 2020-11-20 02:48 Justin Pryzby <[email protected]> 0 siblings, 0 replies; 2+ messages in thread From: Justin Pryzby @ 2020-11-20 02:48 UTC (permalink / raw) --- src/backend/bootstrap/bootstrap.c | 89 ++++++++++++++----------------- 1 file changed, 41 insertions(+), 48 deletions(-) diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c index 6f615e6622..1b940d9d27 100644 --- a/src/backend/bootstrap/bootstrap.c +++ b/src/backend/bootstrap/bootstrap.c @@ -58,7 +58,7 @@ static void BootstrapModeMain(void); static void bootstrap_signals(void); static void ShutdownAuxiliaryProcess(int code, Datum arg); static Form_pg_attribute AllocateAttribute(void); -static void populate_typ_array(void); +static void populate_typ(void); static Oid gettype(char *type); static void cleanup(void); @@ -159,7 +159,7 @@ struct typmap FormData_pg_type am_typ; }; -static struct typmap **Typ = NULL; +static List *Typ = NIL; /* List of struct typmap* */ static struct typmap *Ap = NULL; static Datum values[MAXATTR]; /* current row's attribute values */ @@ -595,10 +595,10 @@ boot_openrel(char *relname) /* * pg_type must be filled before any OPEN command is executed, hence we - * can now populate the Typ array if we haven't yet. + * can now populate Typ if we haven't yet. */ - if (Typ == NULL) - populate_typ_array(); + if (Typ == NIL) + populate_typ(); if (boot_reldesc != NULL) closerel(NULL); @@ -688,7 +688,7 @@ DefineAttr(char *name, char *type, int attnum, int nullness) typeoid = gettype(type); - if (Typ != NULL) + if (Typ != NIL) { attrtypes[attnum]->atttypid = Ap->am_oid; attrtypes[attnum]->attlen = Ap->am_typ.typlen; @@ -866,47 +866,36 @@ cleanup(void) } /* ---------------- - * populate_typ_array + * populate_typ * - * Load the Typ array by reading pg_type. + * Load Typ by reading pg_type. * ---------------- */ static void -populate_typ_array(void) +populate_typ(void) { Relation rel; TableScanDesc scan; HeapTuple tup; - int nalloc; - int i; - - Assert(Typ == NULL); + MemoryContext old; - nalloc = 512; - Typ = (struct typmap **) - MemoryContextAlloc(TopMemoryContext, nalloc * sizeof(struct typmap *)); + Assert(Typ == NIL); rel = table_open(TypeRelationId, NoLock); scan = table_beginscan_catalog(rel, 0, NULL); - i = 0; + old = MemoryContextSwitchTo(TopMemoryContext); while ((tup = heap_getnext(scan, ForwardScanDirection)) != NULL) { Form_pg_type typForm = (Form_pg_type) GETSTRUCT(tup); + struct typmap *newtyp; - /* make sure there will be room for a trailing NULL pointer */ - if (i >= nalloc - 1) - { - nalloc *= 2; - Typ = (struct typmap **) - repalloc(Typ, nalloc * sizeof(struct typmap *)); - } - Typ[i] = (struct typmap *) - MemoryContextAlloc(TopMemoryContext, sizeof(struct typmap)); - Typ[i]->am_oid = typForm->oid; - memcpy(&(Typ[i]->am_typ), typForm, sizeof(Typ[i]->am_typ)); - i++; + newtyp = (struct typmap *) palloc(sizeof(struct typmap)); + Typ = lappend(Typ, newtyp); + + newtyp->am_oid = typForm->oid; + memcpy(&newtyp->am_typ, typForm, sizeof(newtyp->am_typ)); } - Typ[i] = NULL; /* Fill trailing NULL pointer */ + MemoryContextSwitchTo(old); table_endscan(scan); table_close(rel, NoLock); } @@ -916,25 +905,26 @@ populate_typ_array(void) * * NB: this is really ugly; it will return an integer index into TypInfo[], * and not an OID at all, until the first reference to a type not known in - * TypInfo[]. At that point it will read and cache pg_type in the Typ array, + * TypInfo[]. At that point it will read and cache pg_type in Typ, * and subsequently return a real OID (and set the global pointer Ap to * point at the found row in Typ). So caller must check whether Typ is - * still NULL to determine what the return value is! + * still NIL to determine what the return value is! * ---------------- */ static Oid gettype(char *type) { - if (Typ != NULL) + if (Typ != NIL) { - struct typmap **app; + ListCell *lc; - for (app = Typ; *app != NULL; app++) + foreach (lc, Typ) { - if (strncmp(NameStr((*app)->am_typ.typname), type, NAMEDATALEN) == 0) + struct typmap *app = lfirst(lc); + if (strncmp(NameStr(app->am_typ.typname), type, NAMEDATALEN) == 0) { - Ap = *app; - return (*app)->am_oid; + Ap = app; + return app->am_oid; } } } @@ -949,7 +939,7 @@ gettype(char *type) } /* Not in TypInfo, so we'd better be able to read pg_type now */ elog(DEBUG4, "external type: %s", type); - populate_typ_array(); + populate_typ(); return gettype(type); } elog(ERROR, "unrecognized type \"%s\"", type); @@ -977,17 +967,20 @@ boot_get_type_io_data(Oid typid, Oid *typinput, Oid *typoutput) { - if (Typ != NULL) + if (Typ != NIL) { /* We have the boot-time contents of pg_type, so use it */ - struct typmap **app; - struct typmap *ap; - - app = Typ; - while (*app && (*app)->am_oid != typid) - ++app; - ap = *app; - if (ap == NULL) + struct typmap *ap = NULL; + ListCell *lc; + + foreach (lc, Typ) + { + ap = lfirst(lc); + if (ap->am_oid == typid) + break; + } + + if (!ap || ap->am_oid != typid) elog(ERROR, "type OID %u not found in Typ list", typid); *typlen = ap->am_typ.typlen; -- 2.17.0 --yQbNiKLmgenwUfTN Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0002-Allow-composite-types-in-bootstrap.patchx" ^ permalink raw reply [nested|flat] 2+ messages in thread
* Implement IF NOT EXISTS for CREATE PUBLICATION AND CREATE SUBSCRIPTION @ 2023-03-12 14:38 vignesh C <[email protected]> 0 siblings, 0 replies; 2+ messages in thread From: vignesh C @ 2023-03-12 14:38 UTC (permalink / raw) To: PostgreSQL Hackers <[email protected]> Hi, Currently we don't support "IF NOT EXISTS" for Create publication and Create subscription, I felt it would be useful to add this "IF NOT EXISTS" which will create publication/subscription only if the object does not exist. Attached patch for handling the same. Thoughts? Regards, Vignesh Attachments: [text/x-patch] v1-0001-Implement-IF-NOT-EXISTS-for-CREATE-PUBLICATION-AN.patch (11.7K, ../../CALDaNm0AD-y5S4jc_Yi2QyQhH5iK0x80n3gZ6x7=wQW4BEE+ag@mail.gmail.com/2-v1-0001-Implement-IF-NOT-EXISTS-for-CREATE-PUBLICATION-AN.patch) download | inline diff: From 63b53a87253af6e5d08f473cb0d568c2321a2bd3 Mon Sep 17 00:00:00 2001 From: Vignesh C <[email protected]> Date: Fri, 3 Mar 2023 15:54:00 +0530 Subject: [PATCH v1] Implement IF NOT EXISTS for CREATE PUBLICATION AND CREATE SUBSCRIPTION Implement IF NOT EXISTS for CREATE PUBLICATION AND CREATE SUBSCRIPTION --- doc/src/sgml/ref/create_publication.sgml | 14 ++++++- doc/src/sgml/ref/create_subscription.sgml | 14 ++++++- src/backend/commands/publicationcmds.c | 20 ++++++++-- src/backend/commands/subscriptioncmds.c | 18 +++++++-- src/backend/parser/gram.y | 45 ++++++++++++++++++++++ src/include/nodes/parsenodes.h | 2 + src/test/regress/expected/publication.out | 2 + src/test/regress/expected/subscription.out | 2 + src/test/regress/sql/publication.sql | 1 + src/test/regress/sql/subscription.sql | 1 + 10 files changed, 109 insertions(+), 10 deletions(-) diff --git a/doc/src/sgml/ref/create_publication.sgml b/doc/src/sgml/ref/create_publication.sgml index a2946feaa3..b2f17bd7d8 100644 --- a/doc/src/sgml/ref/create_publication.sgml +++ b/doc/src/sgml/ref/create_publication.sgml @@ -21,7 +21,7 @@ PostgreSQL documentation <refsynopsisdiv> <synopsis> -CREATE PUBLICATION <replaceable class="parameter">name</replaceable> +CREATE PUBLICATION [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> [ FOR ALL TABLES | FOR <replaceable class="parameter">publication_object</replaceable> [, ... ] ] [ WITH ( <replaceable class="parameter">publication_parameter</replaceable> [= <replaceable class="parameter">value</replaceable>] [, ... ] ) ] @@ -54,6 +54,18 @@ CREATE PUBLICATION <replaceable class="parameter">name</replaceable> <title>Parameters</title> <variablelist> + <varlistentry> + <term><literal>IF NOT EXISTS</literal></term> + <listitem> + <para> + Do not throw an error if a publication with the same name already exists. + A notice is issued in this case. Note that there is no guarantee that + the existing publication is anything like the one that would have been + created. + </para> + </listitem> + </varlistentry> + <varlistentry> <term><replaceable class="parameter">name</replaceable></term> <listitem> diff --git a/doc/src/sgml/ref/create_subscription.sgml b/doc/src/sgml/ref/create_subscription.sgml index 51c45f17c7..4c7fe5dccd 100644 --- a/doc/src/sgml/ref/create_subscription.sgml +++ b/doc/src/sgml/ref/create_subscription.sgml @@ -21,7 +21,7 @@ PostgreSQL documentation <refsynopsisdiv> <synopsis> -CREATE SUBSCRIPTION <replaceable class="parameter">subscription_name</replaceable> +CREATE SUBSCRIPTION [ IF NOT EXISTS ] <replaceable class="parameter">subscription_name</replaceable> CONNECTION '<replaceable class="parameter">conninfo</replaceable>' PUBLICATION <replaceable class="parameter">publication_name</replaceable> [, ...] [ WITH ( <replaceable class="parameter">subscription_parameter</replaceable> [= <replaceable class="parameter">value</replaceable>] [, ... ] ) ] @@ -61,6 +61,18 @@ CREATE SUBSCRIPTION <replaceable class="parameter">subscription_name</replaceabl <title>Parameters</title> <variablelist> + <varlistentry> + <term><literal>IF NOT EXISTS</literal></term> + <listitem> + <para> + Do not throw an error if a subscription with the same name already + exists. A notice is issued in this case. Note that there is no guarantee + that the existing subscription is anything like the one that would have + been created. + </para> + </listitem> + </varlistentry> + <varlistentry> <term><replaceable class="parameter">subscription_name</replaceable></term> <listitem> diff --git a/src/backend/commands/publicationcmds.c b/src/backend/commands/publicationcmds.c index f4ba572697..41e5f2c3e1 100644 --- a/src/backend/commands/publicationcmds.c +++ b/src/backend/commands/publicationcmds.c @@ -766,10 +766,22 @@ CreatePublication(ParseState *pstate, CreatePublicationStmt *stmt) puboid = GetSysCacheOid1(PUBLICATIONNAME, Anum_pg_publication_oid, CStringGetDatum(stmt->pubname)); if (OidIsValid(puboid)) - ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_OBJECT), - errmsg("publication \"%s\" already exists", - stmt->pubname))); + { + if (stmt->if_not_exists) + { + ereport(NOTICE, + errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("publication \"%s\" already exists, skipping", + stmt->pubname)); + table_close(rel, RowExclusiveLock); + return InvalidObjectAddress; + } + else + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("publication \"%s\" already exists", + stmt->pubname))); + } /* Form a tuple. */ memset(values, 0, sizeof(values)); diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c index 464db6d247..f2dd59244b 100644 --- a/src/backend/commands/subscriptioncmds.c +++ b/src/backend/commands/subscriptioncmds.c @@ -593,10 +593,20 @@ CreateSubscription(ParseState *pstate, CreateSubscriptionStmt *stmt, MyDatabaseId, CStringGetDatum(stmt->subname)); if (OidIsValid(subid)) { - ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_OBJECT), - errmsg("subscription \"%s\" already exists", - stmt->subname))); + if (stmt->if_not_exists) + { + ereport(NOTICE, + errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("subscription \"%s\" already exists, skipping", + stmt->subname)); + table_close(rel, RowExclusiveLock); + return InvalidObjectAddress; + } + else + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("subscription \"%s\" already exists", + stmt->subname))); } if (!IsSet(opts.specified_opts, SUBOPT_SLOT_NAME) && diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index a0138382a1..abfd33914c 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -10371,6 +10371,16 @@ CreatePublicationStmt: n->pubname = $3; n->options = $4; + n->if_not_exists = false; + $$ = (Node *) n; + } + | CREATE PUBLICATION IF_P NOT EXISTS name opt_definition + { + CreatePublicationStmt *n = makeNode(CreatePublicationStmt); + + n->pubname = $6; + n->options = $7; + n->if_not_exists = true; $$ = (Node *) n; } | CREATE PUBLICATION name FOR ALL TABLES opt_definition @@ -10380,6 +10390,17 @@ CreatePublicationStmt: n->pubname = $3; n->options = $7; n->for_all_tables = true; + n->if_not_exists = false; + $$ = (Node *) n; + } + | CREATE PUBLICATION IF_P NOT EXISTS name FOR ALL TABLES opt_definition + { + CreatePublicationStmt *n = makeNode(CreatePublicationStmt); + + n->pubname = $6; + n->options = $10; + n->for_all_tables = true; + n->if_not_exists = true; $$ = (Node *) n; } | CREATE PUBLICATION name FOR pub_obj_list opt_definition @@ -10389,6 +10410,18 @@ CreatePublicationStmt: n->pubname = $3; n->options = $6; n->pubobjects = (List *) $5; + n->if_not_exists = false; + preprocess_pubobj_list(n->pubobjects, yyscanner); + $$ = (Node *) n; + } + | CREATE PUBLICATION IF_P NOT EXISTS name FOR pub_obj_list opt_definition + { + CreatePublicationStmt *n = makeNode(CreatePublicationStmt); + + n->pubname = $6; + n->options = $9; + n->pubobjects = (List *) $8; + n->if_not_exists = true; preprocess_pubobj_list(n->pubobjects, yyscanner); $$ = (Node *) n; } @@ -10564,6 +10597,18 @@ CreateSubscriptionStmt: n->conninfo = $5; n->publication = $7; n->options = $8; + n->if_not_exists = false; + $$ = (Node *) n; + } + | CREATE SUBSCRIPTION IF_P NOT EXISTS name CONNECTION Sconst PUBLICATION name_list opt_definition + { + CreateSubscriptionStmt *n = + makeNode(CreateSubscriptionStmt); + n->subname = $6; + n->conninfo = $8; + n->publication = $10; + n->options = $11; + n->if_not_exists = true; $$ = (Node *) n; } ; diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 371aa0ffc5..c47a8797ef 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -3875,6 +3875,7 @@ typedef struct CreatePublicationStmt List *options; /* List of DefElem nodes */ List *pubobjects; /* Optional list of publication objects */ bool for_all_tables; /* Special publication for all tables in db */ + bool if_not_exists; /* Just do nothing if it already exists? */ } CreatePublicationStmt; typedef enum AlterPublicationAction @@ -3909,6 +3910,7 @@ typedef struct CreateSubscriptionStmt char *conninfo; /* Connection string to publisher */ List *publication; /* One or more publication to subscribe to */ List *options; /* List of DefElem nodes */ + bool if_not_exists; /* Just do nothing if it already exists? */ } CreateSubscriptionStmt; typedef enum AlterSubscriptionType diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out index 427f87ea07..0475dffdcf 100644 --- a/src/test/regress/expected/publication.out +++ b/src/test/regress/expected/publication.out @@ -9,6 +9,8 @@ SET SESSION AUTHORIZATION 'regress_publication_user'; SET client_min_messages = 'ERROR'; CREATE PUBLICATION testpub_default; RESET client_min_messages; +CREATE PUBLICATION IF NOT EXISTS testpub_default; +NOTICE: publication "testpub_default" already exists, skipping COMMENT ON PUBLICATION testpub_default IS 'test publication'; SELECT obj_description(p.oid, 'pg_publication') FROM pg_publication p; obj_description diff --git a/src/test/regress/expected/subscription.out b/src/test/regress/expected/subscription.out index 3f99b14394..77d2c41c43 100644 --- a/src/test/regress/expected/subscription.out +++ b/src/test/regress/expected/subscription.out @@ -31,6 +31,8 @@ ERROR: publication name "foo" used more than once CREATE SUBSCRIPTION regress_testsub CONNECTION 'dbname=regress_doesnotexist' PUBLICATION testpub WITH (connect = false); WARNING: subscription was created, but is not connected HINT: To initiate replication, you must manually create the replication slot, enable the subscription, and refresh the subscription. +CREATE SUBSCRIPTION IF NOT EXISTS regress_testsub CONNECTION 'dbname=regress_doesnotexist' PUBLICATION testpub WITH (connect = false); +NOTICE: subscription "regress_testsub" already exists, skipping COMMENT ON SUBSCRIPTION regress_testsub IS 'test subscription'; SELECT obj_description(s.oid, 'pg_subscription') FROM pg_subscription s; obj_description diff --git a/src/test/regress/sql/publication.sql b/src/test/regress/sql/publication.sql index a47c5939d5..14442ce8b1 100644 --- a/src/test/regress/sql/publication.sql +++ b/src/test/regress/sql/publication.sql @@ -10,6 +10,7 @@ SET SESSION AUTHORIZATION 'regress_publication_user'; SET client_min_messages = 'ERROR'; CREATE PUBLICATION testpub_default; RESET client_min_messages; +CREATE PUBLICATION IF NOT EXISTS testpub_default; COMMENT ON PUBLICATION testpub_default IS 'test publication'; SELECT obj_description(p.oid, 'pg_publication') FROM pg_publication p; diff --git a/src/test/regress/sql/subscription.sql b/src/test/regress/sql/subscription.sql index 7281f5fee2..e9050f09d5 100644 --- a/src/test/regress/sql/subscription.sql +++ b/src/test/regress/sql/subscription.sql @@ -26,6 +26,7 @@ CREATE SUBSCRIPTION regress_testsub CONNECTION 'dbname=regress_doesnotexist' PUB -- ok CREATE SUBSCRIPTION regress_testsub CONNECTION 'dbname=regress_doesnotexist' PUBLICATION testpub WITH (connect = false); +CREATE SUBSCRIPTION IF NOT EXISTS regress_testsub CONNECTION 'dbname=regress_doesnotexist' PUBLICATION testpub WITH (connect = false); COMMENT ON SUBSCRIPTION regress_testsub IS 'test subscription'; SELECT obj_description(s.oid, 'pg_subscription') FROM pg_subscription s; -- 2.34.1 ^ permalink raw reply [nested|flat] 2+ messages in thread
end of thread, other threads:[~2023-03-12 14:38 UTC | newest] Thread overview: 2+ messages (download: mbox mbox.gz follow: Atom feed) -- links below jump to the message on this page -- 2020-11-20 02:48 [PATCH 1/2] bootstrap: convert Typ to a List* Justin Pryzby <[email protected]> 2023-03-12 14:38 Implement IF NOT EXISTS for CREATE PUBLICATION AND CREATE SUBSCRIPTION vignesh C <[email protected]>
This inbox is served by agora; see mirroring instructions for how to clone and mirror all data and code used for this inbox