7
7
* Portions Copyright (c) 1994, Regents of the University of California
8
8
*
9
9
* IDENTIFICATION
10
- * $PostgreSQL: pgsql/src/backend/commands/proclang.c,v 1.89 2010/02/14 18:42:14 rhaas Exp $
10
+ * $PostgreSQL: pgsql/src/backend/commands/proclang.c,v 1.90 2010/02/23 22:51:42 tgl Exp $
11
11
*
12
12
*-------------------------------------------------------------------------
13
13
*/
17
17
#include "access/heapam.h"
18
18
#include "catalog/dependency.h"
19
19
#include "catalog/indexing.h"
20
- #include "catalog/pg_authid.h"
21
20
#include "catalog/pg_language.h"
22
21
#include "catalog/pg_namespace.h"
23
22
#include "catalog/pg_pltemplate.h"
@@ -49,7 +48,7 @@ typedef struct
49
48
char * tmpllibrary ; /* path of shared library */
50
49
} PLTemplate ;
51
50
52
- static void create_proc_lang (const char * languageName ,
51
+ static void create_proc_lang (const char * languageName , bool replace ,
53
52
Oid languageOwner , Oid handlerOid , Oid inlineOid ,
54
53
Oid valOid , bool trusted );
55
54
static PLTemplate * find_language_template (const char * languageName );
@@ -73,16 +72,10 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
73
72
Oid funcargtypes [1 ];
74
73
75
74
/*
76
- * Translate the language name and check that this language doesn't
77
- * already exist
75
+ * Translate the language name to lower case
78
76
*/
79
77
languageName = case_translate_language_name (stmt -> plname );
80
78
81
- if (SearchSysCacheExists1 (LANGNAME , PointerGetDatum (languageName )))
82
- ereport (ERROR ,
83
- (errcode (ERRCODE_DUPLICATE_OBJECT ),
84
- errmsg ("language \"%s\" already exists" , languageName )));
85
-
86
79
/*
87
80
* If we have template information for the language, ignore the supplied
88
81
* parameters (if any) and use the template information.
@@ -232,7 +225,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
232
225
valOid = InvalidOid ;
233
226
234
227
/* ok, create it */
235
- create_proc_lang (languageName , GetUserId (), handlerOid , inlineOid ,
228
+ create_proc_lang (languageName , stmt -> replace , GetUserId (),
229
+ handlerOid , inlineOid ,
236
230
valOid , pltemplate -> tmpltrusted );
237
231
}
238
232
else
@@ -306,7 +300,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
306
300
valOid = InvalidOid ;
307
301
308
302
/* ok, create it */
309
- create_proc_lang (languageName , GetUserId (), handlerOid , inlineOid ,
303
+ create_proc_lang (languageName , stmt -> replace , GetUserId (),
304
+ handlerOid , inlineOid ,
310
305
valOid , stmt -> pltrusted );
311
306
}
312
307
}
@@ -315,27 +310,29 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
315
310
* Guts of language creation.
316
311
*/
317
312
static void
318
- create_proc_lang (const char * languageName ,
313
+ create_proc_lang (const char * languageName , bool replace ,
319
314
Oid languageOwner , Oid handlerOid , Oid inlineOid ,
320
315
Oid valOid , bool trusted )
321
316
{
322
317
Relation rel ;
323
318
TupleDesc tupDesc ;
324
319
Datum values [Natts_pg_language ];
325
320
bool nulls [Natts_pg_language ];
321
+ bool replaces [Natts_pg_language ];
326
322
NameData langname ;
323
+ HeapTuple oldtup ;
327
324
HeapTuple tup ;
325
+ bool is_update ;
328
326
ObjectAddress myself ,
329
327
referenced ;
330
328
331
- /*
332
- * Insert the new language into pg_language
333
- */
334
329
rel = heap_open (LanguageRelationId , RowExclusiveLock );
335
- tupDesc = rel -> rd_att ;
330
+ tupDesc = RelationGetDescr ( rel ) ;
336
331
332
+ /* Prepare data to be inserted */
337
333
memset (values , 0 , sizeof (values ));
338
334
memset (nulls , false, sizeof (nulls ));
335
+ memset (replaces , true, sizeof (replaces ));
339
336
340
337
namestrcpy (& langname , languageName );
341
338
values [Anum_pg_language_lanname - 1 ] = NameGetDatum (& langname );
@@ -347,24 +344,62 @@ create_proc_lang(const char *languageName,
347
344
values [Anum_pg_language_lanvalidator - 1 ] = ObjectIdGetDatum (valOid );
348
345
nulls [Anum_pg_language_lanacl - 1 ] = true;
349
346
350
- tup = heap_form_tuple (tupDesc , values , nulls );
347
+ /* Check for pre-existing definition */
348
+ oldtup = SearchSysCache1 (LANGNAME , PointerGetDatum (languageName ));
351
349
352
- simple_heap_insert (rel , tup );
350
+ if (HeapTupleIsValid (oldtup ))
351
+ {
352
+ /* There is one; okay to replace it? */
353
+ if (!replace )
354
+ ereport (ERROR ,
355
+ (errcode (ERRCODE_DUPLICATE_OBJECT ),
356
+ errmsg ("language \"%s\" already exists" , languageName )));
357
+ if (!pg_language_ownercheck (HeapTupleGetOid (oldtup ), languageOwner ))
358
+ aclcheck_error (ACLCHECK_NOT_OWNER , ACL_KIND_LANGUAGE ,
359
+ languageName );
353
360
361
+ /*
362
+ * Do not change existing ownership or permissions. Note
363
+ * dependency-update code below has to agree with this decision.
364
+ */
365
+ replaces [Anum_pg_language_lanowner - 1 ] = false;
366
+ replaces [Anum_pg_language_lanacl - 1 ] = false;
367
+
368
+ /* Okay, do it... */
369
+ tup = heap_modify_tuple (oldtup , tupDesc , values , nulls , replaces );
370
+ simple_heap_update (rel , & tup -> t_self , tup );
371
+
372
+ ReleaseSysCache (oldtup );
373
+ is_update = true;
374
+ }
375
+ else
376
+ {
377
+ /* Creating a new language */
378
+ tup = heap_form_tuple (tupDesc , values , nulls );
379
+ simple_heap_insert (rel , tup );
380
+ is_update = false;
381
+ }
382
+
383
+ /* Need to update indexes for either the insert or update case */
354
384
CatalogUpdateIndexes (rel , tup );
355
385
356
386
/*
357
- * Create dependencies for language
387
+ * Create dependencies for the new language. If we are updating an
388
+ * existing language, first delete any existing pg_depend entries.
389
+ * (However, since we are not changing ownership or permissions, the
390
+ * shared dependencies do *not* need to change, and we leave them alone.)
358
391
*/
359
392
myself .classId = LanguageRelationId ;
360
393
myself .objectId = HeapTupleGetOid (tup );
361
394
myself .objectSubId = 0 ;
362
395
396
+ if (is_update )
397
+ deleteDependencyRecordsFor (myself .classId , myself .objectId );
398
+
363
399
/* dependency on owner of language */
364
- referenced .classId = AuthIdRelationId ;
365
- referenced .objectId = languageOwner ;
366
- referenced .objectSubId = 0 ;
367
- recordSharedDependencyOn (& myself , & referenced , SHARED_DEPENDENCY_OWNER );
400
+ if (!is_update )
401
+ recordDependencyOnOwner (myself .classId , myself .objectId ,
402
+ languageOwner );
368
403
369
404
/* dependency on the PL handler function */
370
405
referenced .classId = ProcedureRelationId ;
0 commit comments