create-or-replace-lang.patch

text/x-patch

Filename: create-or-replace-lang.patch
Type: text/x-patch
Part: 0
Message: Re: PGXS: REGRESS_OPTS=--load-language=plpgsql

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: context
File+
src/backend/commands/proclang.c 58 23
src/backend/nodes/copyfuncs.c 1 0
src/backend/nodes/equalfuncs.c 1 0
src/backend/parser/gram.y 11 9
src/include/nodes/parsenodes.h 1 0
Index: src/backend/commands/proclang.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/commands/proclang.c,v
retrieving revision 1.89
diff -c -r1.89 proclang.c
*** src/backend/commands/proclang.c	14 Feb 2010 18:42:14 -0000	1.89
--- src/backend/commands/proclang.c	21 Feb 2010 17:08:15 -0000
***************
*** 17,23 ****
  #include "access/heapam.h"
  #include "catalog/dependency.h"
  #include "catalog/indexing.h"
- #include "catalog/pg_authid.h"
  #include "catalog/pg_language.h"
  #include "catalog/pg_namespace.h"
  #include "catalog/pg_pltemplate.h"
--- 17,22 ----
***************
*** 49,55 ****
  	char	   *tmpllibrary;	/* path of shared library */
  } PLTemplate;
  
! static void create_proc_lang(const char *languageName,
  				 Oid languageOwner, Oid handlerOid, Oid inlineOid,
  				 Oid valOid, bool trusted);
  static PLTemplate *find_language_template(const char *languageName);
--- 48,54 ----
  	char	   *tmpllibrary;	/* path of shared library */
  } PLTemplate;
  
! static void create_proc_lang(const char *languageName, bool replace,
  				 Oid languageOwner, Oid handlerOid, Oid inlineOid,
  				 Oid valOid, bool trusted);
  static PLTemplate *find_language_template(const char *languageName);
***************
*** 73,88 ****
  	Oid			funcargtypes[1];
  
  	/*
! 	 * Translate the language name and check that this language doesn't
! 	 * already exist
  	 */
  	languageName = case_translate_language_name(stmt->plname);
  
- 	if (SearchSysCacheExists1(LANGNAME, PointerGetDatum(languageName)))
- 		ereport(ERROR,
- 				(errcode(ERRCODE_DUPLICATE_OBJECT),
- 				 errmsg("language \"%s\" already exists", languageName)));
- 
  	/*
  	 * If we have template information for the language, ignore the supplied
  	 * parameters (if any) and use the template information.
--- 72,81 ----
  	Oid			funcargtypes[1];
  
  	/*
! 	 * Translate the language name to lower case
  	 */
  	languageName = case_translate_language_name(stmt->plname);
  
  	/*
  	 * If we have template information for the language, ignore the supplied
  	 * parameters (if any) and use the template information.
***************
*** 232,238 ****
  			valOid = InvalidOid;
  
  		/* ok, create it */
! 		create_proc_lang(languageName, GetUserId(), handlerOid, inlineOid,
  						 valOid, pltemplate->tmpltrusted);
  	}
  	else
--- 225,232 ----
  			valOid = InvalidOid;
  
  		/* ok, create it */
! 		create_proc_lang(languageName, stmt->replace, GetUserId(),
! 						 handlerOid, inlineOid,
  						 valOid, pltemplate->tmpltrusted);
  	}
  	else
***************
*** 306,312 ****
  			valOid = InvalidOid;
  
  		/* ok, create it */
! 		create_proc_lang(languageName, GetUserId(), handlerOid, inlineOid,
  						 valOid, stmt->pltrusted);
  	}
  }
--- 300,307 ----
  			valOid = InvalidOid;
  
  		/* ok, create it */
! 		create_proc_lang(languageName, stmt->replace, GetUserId(),
! 						 handlerOid, inlineOid,
  						 valOid, stmt->pltrusted);
  	}
  }
***************
*** 315,321 ****
   * Guts of language creation.
   */
  static void
! create_proc_lang(const char *languageName,
  				 Oid languageOwner, Oid handlerOid, Oid inlineOid,
  				 Oid valOid, bool trusted)
  {
--- 310,316 ----
   * Guts of language creation.
   */
  static void
! create_proc_lang(const char *languageName, bool replace,
  				 Oid languageOwner, Oid handlerOid, Oid inlineOid,
  				 Oid valOid, bool trusted)
  {
***************
*** 323,341 ****
  	TupleDesc	tupDesc;
  	Datum		values[Natts_pg_language];
  	bool		nulls[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;
  
  	memset(values, 0, sizeof(values));
  	memset(nulls, false, sizeof(nulls));
  
  	namestrcpy(&langname, languageName);
  	values[Anum_pg_language_lanname - 1] = NameGetDatum(&langname);
--- 318,338 ----
  	TupleDesc	tupDesc;
  	Datum		values[Natts_pg_language];
  	bool		nulls[Natts_pg_language];
+ 	bool		replaces[Natts_pg_language];
  	NameData	langname;
+ 	HeapTuple	oldtup;
  	HeapTuple	tup;
+ 	bool		is_update;
  	ObjectAddress myself,
  				referenced;
  
  	rel = heap_open(LanguageRelationId, RowExclusiveLock);
! 	tupDesc = RelationGetDescr(rel);
  
+ 	/* Prepare data to be inserted */
  	memset(values, 0, sizeof(values));
  	memset(nulls, false, sizeof(nulls));
+ 	memset(replaces, true, sizeof(replaces));
  
  	namestrcpy(&langname, languageName);
  	values[Anum_pg_language_lanname - 1] = NameGetDatum(&langname);
***************
*** 347,370 ****
  	values[Anum_pg_language_lanvalidator - 1] = ObjectIdGetDatum(valOid);
  	nulls[Anum_pg_language_lanacl - 1] = true;
  
! 	tup = heap_form_tuple(tupDesc, values, nulls);
  
! 	simple_heap_insert(rel, tup);
  
  	CatalogUpdateIndexes(rel, tup);
  
  	/*
! 	 * 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;
--- 344,405 ----
  	values[Anum_pg_language_lanvalidator - 1] = ObjectIdGetDatum(valOid);
  	nulls[Anum_pg_language_lanacl - 1] = true;
  
! 	/* Check for pre-existing definition */
! 	oldtup = SearchSysCache1(LANGNAME, PointerGetDatum(languageName));
  
! 	if (HeapTupleIsValid(oldtup))
! 	{
! 		/* There is one; okay to replace it? */
! 		if (!replace)
! 			ereport(ERROR,
! 					(errcode(ERRCODE_DUPLICATE_OBJECT),
! 					 errmsg("language \"%s\" already exists", languageName)));
! 		if (!pg_language_ownercheck(HeapTupleGetOid(oldtup), languageOwner))
! 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE,
! 						   languageName);
  
+ 		/*
+ 		 * Do not change existing ownership or permissions.  Note
+ 		 * dependency-update code below has to agree with this decision.
+ 		 */
+ 		replaces[Anum_pg_language_lanowner - 1] = false;
+ 		replaces[Anum_pg_language_lanacl - 1] = false;
+ 
+ 		/* Okay, do it... */
+ 		tup = heap_modify_tuple(oldtup, tupDesc, values, nulls, replaces);
+ 		simple_heap_update(rel, &tup->t_self, tup);
+ 
+ 		ReleaseSysCache(oldtup);
+ 		is_update = true;
+ 	}
+ 	else
+ 	{
+ 		/* Creating a new language */
+ 		tup = heap_form_tuple(tupDesc, values, nulls);
+ 		simple_heap_insert(rel, tup);
+ 		is_update = false;
+ 	}
+ 
+ 	/* Need to update indexes for either the insert or update case */
  	CatalogUpdateIndexes(rel, tup);
  
  	/*
! 	 * Create dependencies for the new language.  If we are updating an
! 	 * existing language, first delete any existing pg_depend entries.
! 	 * (However, since we are not changing ownership or permissions, the
! 	 * shared dependencies do *not* need to change, and we leave them alone.)
  	 */
  	myself.classId = LanguageRelationId;
  	myself.objectId = HeapTupleGetOid(tup);
  	myself.objectSubId = 0;
  
+ 	if (is_update)
+ 		deleteDependencyRecordsFor(myself.classId, myself.objectId);
+ 
  	/* dependency on owner of language */
! 	if (!is_update)
! 		recordDependencyOnOwner(myself.classId, myself.objectId,
! 								languageOwner);
  
  	/* dependency on the PL handler function */
  	referenced.classId = ProcedureRelationId;
Index: src/backend/nodes/copyfuncs.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v
retrieving revision 1.462
diff -c -r1.462 copyfuncs.c
*** src/backend/nodes/copyfuncs.c	16 Feb 2010 22:34:43 -0000	1.462
--- src/backend/nodes/copyfuncs.c	21 Feb 2010 17:08:15 -0000
***************
*** 3237,3242 ****
--- 3237,3243 ----
  {
  	CreatePLangStmt *newnode = makeNode(CreatePLangStmt);
  
+ 	COPY_SCALAR_FIELD(replace);
  	COPY_STRING_FIELD(plname);
  	COPY_NODE_FIELD(plhandler);
  	COPY_NODE_FIELD(plinline);
Index: src/backend/nodes/equalfuncs.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v
retrieving revision 1.383
diff -c -r1.383 equalfuncs.c
*** src/backend/nodes/equalfuncs.c	16 Feb 2010 22:34:43 -0000	1.383
--- src/backend/nodes/equalfuncs.c	21 Feb 2010 17:08:15 -0000
***************
*** 1710,1715 ****
--- 1710,1716 ----
  static bool
  _equalCreatePLangStmt(CreatePLangStmt *a, CreatePLangStmt *b)
  {
+ 	COMPARE_SCALAR_FIELD(replace);
  	COMPARE_STRING_FIELD(plname);
  	COMPARE_NODE_FIELD(plhandler);
  	COMPARE_NODE_FIELD(plinline);
Index: src/backend/parser/gram.y
===================================================================
RCS file: /cvsroot/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.710
diff -c -r2.710 gram.y
*** src/backend/parser/gram.y	17 Feb 2010 04:19:39 -0000	2.710
--- src/backend/parser/gram.y	21 Feb 2010 17:08:16 -0000
***************
*** 2882,2897 ****
  /*****************************************************************************
   *
   *		QUERIES :
!  *				CREATE PROCEDURAL LANGUAGE ...
   *				DROP PROCEDURAL LANGUAGE ...
   *
   *****************************************************************************/
  
  CreatePLangStmt:
! 			CREATE opt_trusted opt_procedural LANGUAGE ColId_or_Sconst
  			{
  				CreatePLangStmt *n = makeNode(CreatePLangStmt);
! 				n->plname = $5;
  				/* parameters are all to be supplied by system */
  				n->plhandler = NIL;
  				n->plinline = NIL;
--- 2882,2898 ----
  /*****************************************************************************
   *
   *		QUERIES :
!  *				CREATE [OR REPLACE] PROCEDURAL LANGUAGE ...
   *				DROP PROCEDURAL LANGUAGE ...
   *
   *****************************************************************************/
  
  CreatePLangStmt:
! 			CREATE opt_or_replace opt_trusted opt_procedural LANGUAGE ColId_or_Sconst
  			{
  				CreatePLangStmt *n = makeNode(CreatePLangStmt);
! 				n->replace = $2;
! 				n->plname = $6;
  				/* parameters are all to be supplied by system */
  				n->plhandler = NIL;
  				n->plinline = NIL;
***************
*** 2899,2913 ****
  				n->pltrusted = false;
  				$$ = (Node *)n;
  			}
! 			| CREATE opt_trusted opt_procedural LANGUAGE ColId_or_Sconst
  			  HANDLER handler_name opt_inline_handler opt_validator
  			{
  				CreatePLangStmt *n = makeNode(CreatePLangStmt);
! 				n->plname = $5;
! 				n->plhandler = $7;
! 				n->plinline = $8;
! 				n->plvalidator = $9;
! 				n->pltrusted = $2;
  				$$ = (Node *)n;
  			}
  		;
--- 2900,2915 ----
  				n->pltrusted = false;
  				$$ = (Node *)n;
  			}
! 			| CREATE opt_or_replace opt_trusted opt_procedural LANGUAGE ColId_or_Sconst
  			  HANDLER handler_name opt_inline_handler opt_validator
  			{
  				CreatePLangStmt *n = makeNode(CreatePLangStmt);
! 				n->replace = $2;
! 				n->plname = $6;
! 				n->plhandler = $8;
! 				n->plinline = $9;
! 				n->plvalidator = $10;
! 				n->pltrusted = $3;
  				$$ = (Node *)n;
  			}
  		;
Index: src/include/nodes/parsenodes.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/nodes/parsenodes.h,v
retrieving revision 1.430
diff -c -r1.430 parsenodes.h
*** src/include/nodes/parsenodes.h	16 Feb 2010 22:34:57 -0000	1.430
--- src/include/nodes/parsenodes.h	21 Feb 2010 17:08:16 -0000
***************
*** 1623,1628 ****
--- 1623,1629 ----
  typedef struct CreatePLangStmt
  {
  	NodeTag		type;
+ 	bool		replace;		/* T => replace if already exists */
  	char	   *plname;			/* PL name */
  	List	   *plhandler;		/* PL call handler function (qual. name) */
  	List	   *plinline;		/* optional inline function (qual. name) */