<!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/create_language.sgml,v 1.48 2009/12/19 01:49:02 tgl Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/create_language.sgml,v 1.49 2010/02/23 22:51:42 tgl Exp $
PostgreSQL documentation
-->
<refsynopsisdiv>
<synopsis>
-CREATE [ PROCEDURAL ] LANGUAGE <replaceable class="parameter">name</replaceable>
-CREATE [ TRUSTED ] [ PROCEDURAL ] LANGUAGE <replaceable class="parameter">name</replaceable>
+CREATE [ OR REPLACE ] [ PROCEDURAL ] LANGUAGE <replaceable class="parameter">name</replaceable>
+CREATE [ OR REPLACE ] [ TRUSTED ] [ PROCEDURAL ] LANGUAGE <replaceable class="parameter">name</replaceable>
HANDLER <replaceable class="parameter">call_handler</replaceable> [ INLINE <replaceable class="parameter">inline_handler</replaceable> ] [ VALIDATOR <replaceable>valfunction</replaceable> ]
</synopsis>
</refsynopsisdiv>
<title>Description</title>
<para>
- Using <command>CREATE LANGUAGE</command>, a
- <productname>PostgreSQL</productname> user can register a new
+ <command>CREATE LANGUAGE</command> registers a new
procedural language with a <productname>PostgreSQL</productname>
database. Subsequently, functions and trigger procedures can be
defined in this new language.
<para>
<command>CREATE LANGUAGE</command> effectively associates the
- language name with a call handler that is responsible for executing
+ language name with handler function(s) that are responsible for executing
functions written in the language. Refer to <xref linkend="plhandler">
- for more information about language call handlers.
+ for more information about language handlers.
</para>
<para>
The creator of a language becomes its owner and can later
drop it, rename it, or assign it to a new owner.
</para>
+
+ <para>
+ <command>CREATE OR REPLACE LANGUAGE</command> will either create a
+ new language, or replace an existing definition. If the language
+ already exists, its parameters are updated according to the values
+ specified or taken from <structname>pg_pltemplate</structname>,
+ but the language's ownership and permissions settings do not change,
+ and any existing functions written in the language are assumed to still
+ be valid. In addition to the normal privilege requirements for creating
+ a language, the user must be superuser or owner of the existing language.
+ The <literal>REPLACE</> case is mainly meant to be used to
+ ensure that the language exists. If the language has a
+ <structname>pg_pltemplate</structname> entry then <literal>REPLACE</>
+ will not actually change anything about an existing definition, except in
+ the unusual case where the <structname>pg_pltemplate</structname> entry
+ has been modified since the language was created.
+ </para>
</refsect1>
<refsect1 id="sql-createlanguage-parameters">
<listitem>
<para>
- <literal>TRUSTED</literal> specifies that the call handler for
+ <literal>TRUSTED</literal> specifies that
the language is safe, that is, it does not offer an
unprivileged user any functionality to bypass access
restrictions. If this key word is omitted when registering the
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/proclang.c,v 1.89 2010/02/14 18:42:14 rhaas Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/proclang.c,v 1.90 2010/02/23 22:51:42 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#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"
char *tmpllibrary; /* path of shared library */
} PLTemplate;
-static void create_proc_lang(const char *languageName,
+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);
Oid funcargtypes[1];
/*
- * Translate the language name and check that this language doesn't
- * already exist
+ * Translate the language name to lower case
*/
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.
valOid = InvalidOid;
/* ok, create it */
- create_proc_lang(languageName, GetUserId(), handlerOid, inlineOid,
+ create_proc_lang(languageName, stmt->replace, GetUserId(),
+ handlerOid, inlineOid,
valOid, pltemplate->tmpltrusted);
}
else
valOid = InvalidOid;
/* ok, create it */
- create_proc_lang(languageName, GetUserId(), handlerOid, inlineOid,
+ create_proc_lang(languageName, stmt->replace, GetUserId(),
+ handlerOid, inlineOid,
valOid, stmt->pltrusted);
}
}
* Guts of language creation.
*/
static void
-create_proc_lang(const char *languageName,
+create_proc_lang(const char *languageName, bool replace,
Oid languageOwner, Oid handlerOid, Oid inlineOid,
Oid valOid, bool trusted)
{
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;
- /*
- * Insert the new language into pg_language
- */
rel = heap_open(LanguageRelationId, RowExclusiveLock);
- tupDesc = rel->rd_att;
+ 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);
values[Anum_pg_language_lanvalidator - 1] = ObjectIdGetDatum(valOid);
nulls[Anum_pg_language_lanacl - 1] = true;
- tup = heap_form_tuple(tupDesc, values, nulls);
+ /* Check for pre-existing definition */
+ oldtup = SearchSysCache1(LANGNAME, PointerGetDatum(languageName));
- simple_heap_insert(rel, tup);
+ 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 language
+ * 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 */
- referenced.classId = AuthIdRelationId;
- referenced.objectId = languageOwner;
- referenced.objectSubId = 0;
- recordSharedDependencyOn(&myself, &referenced, SHARED_DEPENDENCY_OWNER);
+ if (!is_update)
+ recordDependencyOnOwner(myself.classId, myself.objectId,
+ languageOwner);
/* dependency on the PL handler function */
referenced.classId = ProcedureRelationId;