Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 11b5847

Browse files
committed
Add an OR REPLACE option to CREATE LANGUAGE.
This operates in the same way as other CREATE OR REPLACE commands, ie, it replaces everything but the ownership and ACL lists of an existing entry, and requires the caller to have owner privileges for that entry. While modifying an existing language has some use in development scenarios, in typical usage all the "replaced" values come from pg_pltemplate so there will be no actual change in the language definition. The reason for adding this is mainly to allow programs to ensure that a language exists without triggering an error if it already does exist. This commit just adds and documents the new option. A followon patch will use it to clean up some unpleasant cases in pg_dump and pg_regress.
1 parent c4fc082 commit 11b5847

File tree

6 files changed

+102
-46
lines changed

6 files changed

+102
-46
lines changed

doc/src/sgml/ref/create_language.sgml

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$PostgreSQL: pgsql/doc/src/sgml/ref/create_language.sgml,v 1.48 2009/12/19 01:49:02 tgl Exp $
2+
$PostgreSQL: pgsql/doc/src/sgml/ref/create_language.sgml,v 1.49 2010/02/23 22:51:42 tgl Exp $
33
PostgreSQL documentation
44
-->
55

@@ -21,8 +21,8 @@ PostgreSQL documentation
2121

2222
<refsynopsisdiv>
2323
<synopsis>
24-
CREATE [ PROCEDURAL ] LANGUAGE <replaceable class="parameter">name</replaceable>
25-
CREATE [ TRUSTED ] [ PROCEDURAL ] LANGUAGE <replaceable class="parameter">name</replaceable>
24+
CREATE [ OR REPLACE ] [ PROCEDURAL ] LANGUAGE <replaceable class="parameter">name</replaceable>
25+
CREATE [ OR REPLACE ] [ TRUSTED ] [ PROCEDURAL ] LANGUAGE <replaceable class="parameter">name</replaceable>
2626
HANDLER <replaceable class="parameter">call_handler</replaceable> [ INLINE <replaceable class="parameter">inline_handler</replaceable> ] [ VALIDATOR <replaceable>valfunction</replaceable> ]
2727
</synopsis>
2828
</refsynopsisdiv>
@@ -31,18 +31,17 @@ CREATE [ TRUSTED ] [ PROCEDURAL ] LANGUAGE <replaceable class="parameter">name</
3131
<title>Description</title>
3232

3333
<para>
34-
Using <command>CREATE LANGUAGE</command>, a
35-
<productname>PostgreSQL</productname> user can register a new
34+
<command>CREATE LANGUAGE</command> registers a new
3635
procedural language with a <productname>PostgreSQL</productname>
3736
database. Subsequently, functions and trigger procedures can be
3837
defined in this new language.
3938
</para>
4039

4140
<para>
4241
<command>CREATE LANGUAGE</command> effectively associates the
43-
language name with a call handler that is responsible for executing
42+
language name with handler function(s) that are responsible for executing
4443
functions written in the language. Refer to <xref linkend="plhandler">
45-
for more information about language call handlers.
44+
for more information about language handlers.
4645
</para>
4746

4847
<para>
@@ -77,6 +76,23 @@ CREATE [ TRUSTED ] [ PROCEDURAL ] LANGUAGE <replaceable class="parameter">name</
7776
The creator of a language becomes its owner and can later
7877
drop it, rename it, or assign it to a new owner.
7978
</para>
79+
80+
<para>
81+
<command>CREATE OR REPLACE LANGUAGE</command> will either create a
82+
new language, or replace an existing definition. If the language
83+
already exists, its parameters are updated according to the values
84+
specified or taken from <structname>pg_pltemplate</structname>,
85+
but the language's ownership and permissions settings do not change,
86+
and any existing functions written in the language are assumed to still
87+
be valid. In addition to the normal privilege requirements for creating
88+
a language, the user must be superuser or owner of the existing language.
89+
The <literal>REPLACE</> case is mainly meant to be used to
90+
ensure that the language exists. If the language has a
91+
<structname>pg_pltemplate</structname> entry then <literal>REPLACE</>
92+
will not actually change anything about an existing definition, except in
93+
the unusual case where the <structname>pg_pltemplate</structname> entry
94+
has been modified since the language was created.
95+
</para>
8096
</refsect1>
8197

8298
<refsect1 id="sql-createlanguage-parameters">
@@ -88,7 +104,7 @@ CREATE [ TRUSTED ] [ PROCEDURAL ] LANGUAGE <replaceable class="parameter">name</
88104

89105
<listitem>
90106
<para>
91-
<literal>TRUSTED</literal> specifies that the call handler for
107+
<literal>TRUSTED</literal> specifies that
92108
the language is safe, that is, it does not offer an
93109
unprivileged user any functionality to bypass access
94110
restrictions. If this key word is omitted when registering the

src/backend/commands/proclang.c

Lines changed: 59 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
99
* 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 $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -17,7 +17,6 @@
1717
#include "access/heapam.h"
1818
#include "catalog/dependency.h"
1919
#include "catalog/indexing.h"
20-
#include "catalog/pg_authid.h"
2120
#include "catalog/pg_language.h"
2221
#include "catalog/pg_namespace.h"
2322
#include "catalog/pg_pltemplate.h"
@@ -49,7 +48,7 @@ typedef struct
4948
char *tmpllibrary; /* path of shared library */
5049
} PLTemplate;
5150

52-
static void create_proc_lang(const char *languageName,
51+
static void create_proc_lang(const char *languageName, bool replace,
5352
Oid languageOwner, Oid handlerOid, Oid inlineOid,
5453
Oid valOid, bool trusted);
5554
static PLTemplate *find_language_template(const char *languageName);
@@ -73,16 +72,10 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
7372
Oid funcargtypes[1];
7473

7574
/*
76-
* Translate the language name and check that this language doesn't
77-
* already exist
75+
* Translate the language name to lower case
7876
*/
7977
languageName = case_translate_language_name(stmt->plname);
8078

81-
if (SearchSysCacheExists1(LANGNAME, PointerGetDatum(languageName)))
82-
ereport(ERROR,
83-
(errcode(ERRCODE_DUPLICATE_OBJECT),
84-
errmsg("language \"%s\" already exists", languageName)));
85-
8679
/*
8780
* If we have template information for the language, ignore the supplied
8881
* parameters (if any) and use the template information.
@@ -232,7 +225,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
232225
valOid = InvalidOid;
233226

234227
/* ok, create it */
235-
create_proc_lang(languageName, GetUserId(), handlerOid, inlineOid,
228+
create_proc_lang(languageName, stmt->replace, GetUserId(),
229+
handlerOid, inlineOid,
236230
valOid, pltemplate->tmpltrusted);
237231
}
238232
else
@@ -306,7 +300,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
306300
valOid = InvalidOid;
307301

308302
/* ok, create it */
309-
create_proc_lang(languageName, GetUserId(), handlerOid, inlineOid,
303+
create_proc_lang(languageName, stmt->replace, GetUserId(),
304+
handlerOid, inlineOid,
310305
valOid, stmt->pltrusted);
311306
}
312307
}
@@ -315,27 +310,29 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
315310
* Guts of language creation.
316311
*/
317312
static void
318-
create_proc_lang(const char *languageName,
313+
create_proc_lang(const char *languageName, bool replace,
319314
Oid languageOwner, Oid handlerOid, Oid inlineOid,
320315
Oid valOid, bool trusted)
321316
{
322317
Relation rel;
323318
TupleDesc tupDesc;
324319
Datum values[Natts_pg_language];
325320
bool nulls[Natts_pg_language];
321+
bool replaces[Natts_pg_language];
326322
NameData langname;
323+
HeapTuple oldtup;
327324
HeapTuple tup;
325+
bool is_update;
328326
ObjectAddress myself,
329327
referenced;
330328

331-
/*
332-
* Insert the new language into pg_language
333-
*/
334329
rel = heap_open(LanguageRelationId, RowExclusiveLock);
335-
tupDesc = rel->rd_att;
330+
tupDesc = RelationGetDescr(rel);
336331

332+
/* Prepare data to be inserted */
337333
memset(values, 0, sizeof(values));
338334
memset(nulls, false, sizeof(nulls));
335+
memset(replaces, true, sizeof(replaces));
339336

340337
namestrcpy(&langname, languageName);
341338
values[Anum_pg_language_lanname - 1] = NameGetDatum(&langname);
@@ -347,24 +344,62 @@ create_proc_lang(const char *languageName,
347344
values[Anum_pg_language_lanvalidator - 1] = ObjectIdGetDatum(valOid);
348345
nulls[Anum_pg_language_lanacl - 1] = true;
349346

350-
tup = heap_form_tuple(tupDesc, values, nulls);
347+
/* Check for pre-existing definition */
348+
oldtup = SearchSysCache1(LANGNAME, PointerGetDatum(languageName));
351349

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);
353360

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 */
354384
CatalogUpdateIndexes(rel, tup);
355385

356386
/*
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.)
358391
*/
359392
myself.classId = LanguageRelationId;
360393
myself.objectId = HeapTupleGetOid(tup);
361394
myself.objectSubId = 0;
362395

396+
if (is_update)
397+
deleteDependencyRecordsFor(myself.classId, myself.objectId);
398+
363399
/* 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);
368403

369404
/* dependency on the PL handler function */
370405
referenced.classId = ProcedureRelationId;

src/backend/nodes/copyfuncs.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* Portions Copyright (c) 1994, Regents of the University of California
1616
*
1717
* IDENTIFICATION
18-
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.462 2010/02/16 22:34:43 tgl Exp $
18+
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.463 2010/02/23 22:51:42 tgl Exp $
1919
*
2020
*-------------------------------------------------------------------------
2121
*/
@@ -3237,6 +3237,7 @@ _copyCreatePLangStmt(CreatePLangStmt *from)
32373237
{
32383238
CreatePLangStmt *newnode = makeNode(CreatePLangStmt);
32393239

3240+
COPY_SCALAR_FIELD(replace);
32403241
COPY_STRING_FIELD(plname);
32413242
COPY_NODE_FIELD(plhandler);
32423243
COPY_NODE_FIELD(plinline);

src/backend/nodes/equalfuncs.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
* Portions Copyright (c) 1994, Regents of the University of California
2323
*
2424
* IDENTIFICATION
25-
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.383 2010/02/16 22:34:43 tgl Exp $
25+
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.384 2010/02/23 22:51:42 tgl Exp $
2626
*
2727
*-------------------------------------------------------------------------
2828
*/
@@ -1710,6 +1710,7 @@ _equalDropPropertyStmt(DropPropertyStmt *a, DropPropertyStmt *b)
17101710
static bool
17111711
_equalCreatePLangStmt(CreatePLangStmt *a, CreatePLangStmt *b)
17121712
{
1713+
COMPARE_SCALAR_FIELD(replace);
17131714
COMPARE_STRING_FIELD(plname);
17141715
COMPARE_NODE_FIELD(plhandler);
17151716
COMPARE_NODE_FIELD(plinline);

src/backend/parser/gram.y

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*
1212
*
1313
* IDENTIFICATION
14-
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.710 2010/02/17 04:19:39 tgl Exp $
14+
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.711 2010/02/23 22:51:42 tgl Exp $
1515
*
1616
* HISTORY
1717
* AUTHOR DATE MAJOR EVENT
@@ -2882,32 +2882,34 @@ NumericOnly:
28822882
/*****************************************************************************
28832883
*
28842884
* QUERIES :
2885-
* CREATE PROCEDURAL LANGUAGE ...
2886-
* DROP PROCEDURAL LANGUAGE ...
2885+
* CREATE [OR REPLACE] [TRUSTED] [PROCEDURAL] LANGUAGE ...
2886+
* DROP [PROCEDURAL] LANGUAGE ...
28872887
*
28882888
*****************************************************************************/
28892889

28902890
CreatePLangStmt:
2891-
CREATE opt_trusted opt_procedural LANGUAGE ColId_or_Sconst
2891+
CREATE opt_or_replace opt_trusted opt_procedural LANGUAGE ColId_or_Sconst
28922892
{
28932893
CreatePLangStmt *n = makeNode(CreatePLangStmt);
2894-
n->plname = $5;
2894+
n->replace = $2;
2895+
n->plname = $6;
28952896
/* parameters are all to be supplied by system */
28962897
n->plhandler = NIL;
28972898
n->plinline = NIL;
28982899
n->plvalidator = NIL;
28992900
n->pltrusted = false;
29002901
$$ = (Node *)n;
29012902
}
2902-
| CREATE opt_trusted opt_procedural LANGUAGE ColId_or_Sconst
2903+
| CREATE opt_or_replace opt_trusted opt_procedural LANGUAGE ColId_or_Sconst
29032904
HANDLER handler_name opt_inline_handler opt_validator
29042905
{
29052906
CreatePLangStmt *n = makeNode(CreatePLangStmt);
2906-
n->plname = $5;
2907-
n->plhandler = $7;
2908-
n->plinline = $8;
2909-
n->plvalidator = $9;
2910-
n->pltrusted = $2;
2907+
n->replace = $2;
2908+
n->plname = $6;
2909+
n->plhandler = $8;
2910+
n->plinline = $9;
2911+
n->plvalidator = $10;
2912+
n->pltrusted = $3;
29112913
$$ = (Node *)n;
29122914
}
29132915
;

src/include/nodes/parsenodes.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
1414
* Portions Copyright (c) 1994, Regents of the University of California
1515
*
16-
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.430 2010/02/16 22:34:57 tgl Exp $
16+
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.431 2010/02/23 22:51:43 tgl Exp $
1717
*
1818
*-------------------------------------------------------------------------
1919
*/
@@ -1623,6 +1623,7 @@ typedef struct CreateTrigStmt
16231623
typedef struct CreatePLangStmt
16241624
{
16251625
NodeTag type;
1626+
bool replace; /* T => replace if already exists */
16261627
char *plname; /* PL name */
16271628
List *plhandler; /* PL call handler function (qual. name) */
16281629
List *plinline; /* optional inline function (qual. name) */

0 commit comments

Comments
 (0)