On Sat, 29 Mar 2008 22:35:21 -0400 Tom Lane wrote: > The key argument seems to be that it's quite unclear what the state > following CREATE IF NOT EXISTS (CINE) should be, if the object does > exist but not with the same properties specified in the CINE command. > CREATE OR REPLACE resolves that by making it clear that it's gonna be > what the command says. Perhaps there is a use-case for the alternate > behavior where the pre-existing object doesn't get modified, but I'm > not too sure what it would be.
Attached is a first version for the "CREATE OR REPLACE LANGUAGE" patch. It's still missing some functionality (especially the update part is far away from being complete) and it's also missing documentation. I just want to know if i'm heading in the right direction or if something is totally broken in my basic approach: In case a language is already in pg_pltemplate, the (possibly changed) values from this table are used to update the pg_languages entry. This gives the ability to change the owner, trust status, the language or validator handler. In case the language is not in pg_pltemplate, the values from the commandline are used, just like "create language". Thanks & kind regards -- Andreas 'ads' Scherbaum German PostgreSQL User Group
diff -x CVS -ruN pgsql.orig/src/backend/commands/proclang.c pgsql/src/backend/commands/proclang.c --- pgsql.orig/src/backend/commands/proclang.c 2008-04-29 23:59:02.000000000 +0200 +++ pgsql/src/backend/commands/proclang.c 2008-05-03 18:28:50.000000000 +0200 @@ -48,7 +48,7 @@ } PLTemplate; static void create_proc_lang(const char *languageName, - Oid languageOwner, Oid handlerOid, Oid valOid, bool trusted); + Oid languageOwner, Oid handlerOid, Oid valOid, bool trusted, int replace); static PLTemplate *find_language_template(const char *languageName); static void AlterLanguageOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerId); @@ -67,6 +67,7 @@ valOid; Oid funcrettype; Oid funcargtypes[1]; + int replace; /* store info about replace */ /* * Translate the language name and check that this language doesn't @@ -74,12 +75,24 @@ */ languageName = case_translate_language_name(stmt->plname); + + replace = 0; if (SearchSysCacheExists(LANGNAME, PointerGetDatum(languageName), 0, 0, 0)) - ereport(ERROR, - (errcode(ERRCODE_DUPLICATE_OBJECT), - errmsg("language \"%s\" already exists", languageName))); + { + if (stmt->replace) + { + replace = 1; + } + else + { + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("language \"%s\" already exists", languageName))); + } + } + /* * If we have template information for the language, ignore the supplied @@ -131,7 +144,7 @@ { handlerOid = ProcedureCreate(pltemplate->tmplhandler, PG_CATALOG_NAMESPACE, - false, /* replace */ + stmt->replace, /* replace */ false, /* returnsSet */ LANGUAGE_HANDLEROID, ClanguageId, @@ -164,7 +177,7 @@ { valOid = ProcedureCreate(pltemplate->tmplvalidator, PG_CATALOG_NAMESPACE, - false, /* replace */ + stmt->replace, /* replace */ false, /* returnsSet */ VOIDOID, ClanguageId, @@ -189,7 +202,7 @@ /* ok, create it */ create_proc_lang(languageName, GetUserId(), handlerOid, valOid, - pltemplate->tmpltrusted); + pltemplate->tmpltrusted, replace); } else { @@ -253,7 +266,7 @@ /* ok, create it */ create_proc_lang(languageName, GetUserId(), handlerOid, valOid, - stmt->pltrusted); + stmt->pltrusted, replace); } } @@ -262,67 +275,125 @@ */ static void create_proc_lang(const char *languageName, - Oid languageOwner, Oid handlerOid, Oid valOid, bool trusted) + Oid languageOwner, Oid handlerOid, Oid valOid, bool trusted, int replace) { Relation rel; TupleDesc tupDesc; Datum values[Natts_pg_language]; char nulls[Natts_pg_language]; + char replaces[Natts_pg_language]; NameData langname; HeapTuple tup; ObjectAddress myself, referenced; - /* - * Insert the new language into pg_language - */ - rel = heap_open(LanguageRelationId, RowExclusiveLock); - tupDesc = rel->rd_att; + if (replace == 0) + { + /* + * Insert the new language into pg_language + */ + rel = heap_open(LanguageRelationId, RowExclusiveLock); + tupDesc = rel->rd_att; - memset(values, 0, sizeof(values)); - memset(nulls, ' ', sizeof(nulls)); + memset(values, 0, sizeof(values)); + memset(nulls, ' ', sizeof(nulls)); - namestrcpy(&langname, languageName); - values[Anum_pg_language_lanname - 1] = NameGetDatum(&langname); - values[Anum_pg_language_lanowner - 1] = ObjectIdGetDatum(languageOwner); - values[Anum_pg_language_lanispl - 1] = BoolGetDatum(true); - values[Anum_pg_language_lanpltrusted - 1] = BoolGetDatum(trusted); - values[Anum_pg_language_lanplcallfoid - 1] = ObjectIdGetDatum(handlerOid); - values[Anum_pg_language_lanvalidator - 1] = ObjectIdGetDatum(valOid); - nulls[Anum_pg_language_lanacl - 1] = 'n'; + namestrcpy(&langname, languageName); + values[Anum_pg_language_lanname - 1] = NameGetDatum(&langname); + values[Anum_pg_language_lanowner - 1] = ObjectIdGetDatum(languageOwner); + values[Anum_pg_language_lanispl - 1] = BoolGetDatum(true); + values[Anum_pg_language_lanpltrusted - 1] = BoolGetDatum(trusted); + values[Anum_pg_language_lanplcallfoid - 1] = ObjectIdGetDatum(handlerOid); + values[Anum_pg_language_lanvalidator - 1] = ObjectIdGetDatum(valOid); + nulls[Anum_pg_language_lanacl - 1] = 'n'; - tup = heap_formtuple(tupDesc, values, nulls); + tup = heap_formtuple(tupDesc, values, nulls); - simple_heap_insert(rel, tup); + elog(NOTICE, "going to replace language (%s) ...", languageName); - CatalogUpdateIndexes(rel, tup); + simple_heap_insert(rel, tup); + } + else + { - /* - * Create dependencies for language - */ - myself.classId = LanguageRelationId; - myself.objectId = HeapTupleGetOid(tup); - myself.objectSubId = 0; - - /* dependency on owner of language */ - referenced.classId = AuthIdRelationId; - referenced.objectId = languageOwner; - referenced.objectSubId = 0; - recordSharedDependencyOn(&myself, &referenced, SHARED_DEPENDENCY_OWNER); - - /* dependency on the PL handler function */ - referenced.classId = ProcedureRelationId; - referenced.objectId = handlerOid; - referenced.objectSubId = 0; - recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + /* + * Update language in pg_language + */ + rel = heap_open(LanguageRelationId, RowExclusiveLock); + tupDesc = rel->rd_att; + namestrcpy(&langname, languageName); + + memset(values, 0, sizeof(values)); + memset(nulls, ' ', sizeof(nulls)); + memset(replaces, ' ', sizeof(nulls)); + + namestrcpy(&langname, languageName); + values[Anum_pg_language_lanowner - 1] = ObjectIdGetDatum(languageOwner); + values[Anum_pg_language_lanispl - 1] = BoolGetDatum(true); + values[Anum_pg_language_lanpltrusted - 1] = BoolGetDatum(trusted); + values[Anum_pg_language_lanplcallfoid - 1] = ObjectIdGetDatum(handlerOid); + values[Anum_pg_language_lanvalidator - 1] = ObjectIdGetDatum(valOid); + nulls[Anum_pg_language_lanacl - 1] = 'n'; + + /* replaces[Anum_pg_language_lanname - 1] = NameGetDatum(&langname); */ + replaces[Anum_pg_language_lanowner - 1] = 'r'; + replaces[Anum_pg_language_lanispl - 1] = 'r'; + replaces[Anum_pg_language_lanpltrusted - 1] = 'r'; + replaces[Anum_pg_language_lanplcallfoid - 1] = 'r'; + replaces[Anum_pg_language_lanvalidator - 1] = 'r'; + + tup = SearchSysCacheCopy(LANGNAME, + PointerGetDatum(languageName), + 0, 0, 0); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for language %s", + languageName); + + tup = heap_modifytuple(tup, + tupDesc, + values, + nulls, + replaces); + + simple_heap_update(rel, &tup->t_self, tup); + + } + + CatalogUpdateIndexes(rel, tup); - /* dependency on the validator function, if any */ - if (OidIsValid(valOid)) + if (replace == 0) { + /* + * Create dependencies for language + */ + myself.classId = LanguageRelationId; + myself.objectId = HeapTupleGetOid(tup); + myself.objectSubId = 0; + + /* dependency on owner of language */ + referenced.classId = AuthIdRelationId; + referenced.objectId = languageOwner; + referenced.objectSubId = 0; + recordSharedDependencyOn(&myself, &referenced, SHARED_DEPENDENCY_OWNER); + + /* dependency on the PL handler function */ referenced.classId = ProcedureRelationId; - referenced.objectId = valOid; + referenced.objectId = handlerOid; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + + /* dependency on the validator function, if any */ + if (OidIsValid(valOid)) + { + referenced.classId = ProcedureRelationId; + referenced.objectId = valOid; + referenced.objectSubId = 0; + recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); + } + } + else + { + /* FIXME: still missing updated dependencies */ } heap_close(rel, RowExclusiveLock); diff -x CVS -ruN pgsql.orig/src/backend/parser/gram.y pgsql/src/backend/parser/gram.y --- pgsql.orig/src/backend/parser/gram.y 2008-04-29 23:59:03.000000000 +0200 +++ pgsql/src/backend/parser/gram.y 2008-04-29 23:51:45.000000000 +0200 @@ -2524,24 +2524,26 @@ *****************************************************************************/ CreatePLangStmt: - CREATE opt_trusted opt_procedural LANGUAGE ColId_or_Sconst + CREATE opt_or_replace opt_trusted opt_procedural LANGUAGE ColId_or_Sconst { CreatePLangStmt *n = makeNode(CreatePLangStmt); - n->plname = $5; + n->replace = $2; + n->plname = $6; /* parameters are all to be supplied by system */ n->plhandler = NIL; n->plvalidator = NIL; n->pltrusted = false; $$ = (Node *)n; } - | CREATE opt_trusted opt_procedural LANGUAGE ColId_or_Sconst + | CREATE opt_or_replace opt_trusted opt_procedural LANGUAGE ColId_or_Sconst HANDLER handler_name opt_validator opt_lancompiler { CreatePLangStmt *n = makeNode(CreatePLangStmt); - n->plname = $5; - n->plhandler = $7; - n->plvalidator = $8; - n->pltrusted = $2; + n->replace = $2; + n->plname = $6; + n->plhandler = $8; + n->plvalidator = $9; + n->pltrusted = $3; /* LANCOMPILER is now ignored entirely */ $$ = (Node *)n; } diff -x CVS -ruN pgsql.orig/src/include/nodes/parsenodes.h pgsql/src/include/nodes/parsenodes.h --- pgsql.orig/src/include/nodes/parsenodes.h 2008-04-29 23:59:03.000000000 +0200 +++ pgsql/src/include/nodes/parsenodes.h 2008-04-29 23:51:41.000000000 +0200 @@ -1252,6 +1252,7 @@ { NodeTag type; char *plname; /* PL name */ + bool replace; /* T => replace if already exists */ List *plhandler; /* PL call handler function (qual. name) */ List *plvalidator; /* optional validator function (qual. name) */ bool pltrusted; /* PL is trusted */
-- Sent via pgsql-patches mailing list (pgsql-patches@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-patches