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 ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-patches