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

Reply via email to