On Sat, 10 May 2008 09:36:26 +0200 Andreas 'ads' Scherbaum wrote:

> On Sat, 3 May 2008 21:12:51 +0200 Andreas 'ads' Scherbaum wrote:
> > On Sat, 03 May 2008 13:34:05 -0400 Tom Lane wrote:
> > 
> > > So maybe the right thing is that CREATE OR REPLACE LANGUAGE can change
> > > "inessential" properties of an existing language, but not the core
> > > properties --- which might only be the handler function, though you
> > > could make a case for the validator and the trusted flag as well.
> > 
> > Already thought about that: exchanging the handler function or the
> > libbrary might only be useful in a developing environment, i don't see
> > other use cases here. The same is true for the validator (but a missing
> > validator could be added afterwards) and in my opinion i would prefer
> > not to change the trust flag - some functions may depend on this.
> > 
> > The name cannot be changed at all so only the owner and maybe the
> > validator is left ...
> 
> Even the owner does not make sense, because it seems it is not possible
> that the owner will changed through the SQL interface. ALTER LANGUAGE
> already exists for this purpose and CREATE LANGUAGE has no option for
> the language owner.

Attached is another version of the patch (still missing documentation),
which changes the language owner on update (the owner can still be
changed in pg_pltemplate).


> So do we want to replace any data (in my opinion only the validator is
> left) at all or just skip any error message?

Anyone has an opinion here?


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-15 12:18:39.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,26 @@
 	 */
 	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)
+		{
+			/* if the language exist but "OR REPLACE" is given, we just remember
+			 * the fact here */
+			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 +146,7 @@
 		{
 			handlerOid = ProcedureCreate(pltemplate->tmplhandler,
 										 PG_CATALOG_NAMESPACE,
-										 false, /* replace */
+										 stmt->replace, /* replace */
 										 false, /* returnsSet */
 										 LANGUAGE_HANDLEROID,
 										 ClanguageId,
@@ -164,7 +179,7 @@
 			{
 				valOid = ProcedureCreate(pltemplate->tmplvalidator,
 										 PG_CATALOG_NAMESPACE,
-										 false, /* replace */
+										 stmt->replace, /* replace */
 										 false, /* returnsSet */
 										 VOIDOID,
 										 ClanguageId,
@@ -189,7 +204,7 @@
 
 		/* ok, create it */
 		create_proc_lang(languageName, GetUserId(), handlerOid, valOid,
-						 pltemplate->tmpltrusted);
+						 pltemplate->tmpltrusted, replace);
 	}
 	else
 	{
@@ -253,7 +268,7 @@
 
 		/* ok, create it */
 		create_proc_lang(languageName, GetUserId(), handlerOid, valOid,
-						 stmt->pltrusted);
+						 stmt->pltrusted, replace);
 	}
 }
 
@@ -262,7 +277,7 @@
  */
 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;
@@ -273,56 +288,83 @@
 	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
+		 */
+
+		AlterLanguageOwner(languageName, languageOwner);
+
+	}
 
-	/* dependency on the validator function, if any */
-	if (OidIsValid(valOid))
+	CatalogUpdateIndexes(rel, tup);
+
+	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
+	{
+
+		/* update dependencies */
+
+		/* the language owner is already updated */
+
+
 	}
 
 	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