aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/proclang.c83
-rw-r--r--src/backend/nodes/copyfuncs.c3
-rw-r--r--src/backend/nodes/equalfuncs.c3
-rw-r--r--src/backend/parser/gram.y24
-rw-r--r--src/include/nodes/parsenodes.h3
5 files changed, 78 insertions, 38 deletions
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index e51675ee11d..34f33670c3e 100644
--- a/src/backend/commands/proclang.c
+++ b/src/backend/commands/proclang.c
@@ -7,7 +7,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
@@ -17,7 +17,6 @@
#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"
@@ -49,7 +48,7 @@ typedef struct
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);
@@ -73,16 +72,10 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
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.
@@ -232,7 +225,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
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
@@ -306,7 +300,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
valOid = InvalidOid;
/* ok, create it */
- create_proc_lang(languageName, GetUserId(), handlerOid, inlineOid,
+ create_proc_lang(languageName, stmt->replace, GetUserId(),
+ handlerOid, inlineOid,
valOid, stmt->pltrusted);
}
}
@@ -315,7 +310,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
* 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)
{
@@ -323,19 +318,21 @@ create_proc_lang(const char *languageName,
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);
@@ -347,24 +344,62 @@ create_proc_lang(const char *languageName,
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;
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 371d1f245eb..22d24ef21a5 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.462 2010/02/16 22:34:43 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.463 2010/02/23 22:51:42 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -3237,6 +3237,7 @@ _copyCreatePLangStmt(CreatePLangStmt *from)
{
CreatePLangStmt *newnode = makeNode(CreatePLangStmt);
+ COPY_SCALAR_FIELD(replace);
COPY_STRING_FIELD(plname);
COPY_NODE_FIELD(plhandler);
COPY_NODE_FIELD(plinline);
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 7dfc1969f5d..9a05bcc1c0f 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -22,7 +22,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.383 2010/02/16 22:34:43 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.384 2010/02/23 22:51:42 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1710,6 +1710,7 @@ _equalDropPropertyStmt(DropPropertyStmt *a, DropPropertyStmt *b)
static bool
_equalCreatePLangStmt(CreatePLangStmt *a, CreatePLangStmt *b)
{
+ COMPARE_SCALAR_FIELD(replace);
COMPARE_STRING_FIELD(plname);
COMPARE_NODE_FIELD(plhandler);
COMPARE_NODE_FIELD(plinline);
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 94b28bf3d89..368586a95e6 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.710 2010/02/17 04:19:39 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.711 2010/02/23 22:51:42 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -2882,16 +2882,17 @@ NumericOnly:
/*****************************************************************************
*
* QUERIES :
- * CREATE PROCEDURAL LANGUAGE ...
- * DROP PROCEDURAL LANGUAGE ...
+ * CREATE [OR REPLACE] [TRUSTED] [PROCEDURAL] LANGUAGE ...
+ * DROP [PROCEDURAL] LANGUAGE ...
*
*****************************************************************************/
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->plinline = NIL;
@@ -2899,15 +2900,16 @@ CreatePLangStmt:
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_inline_handler opt_validator
{
CreatePLangStmt *n = makeNode(CreatePLangStmt);
- n->plname = $5;
- n->plhandler = $7;
- n->plinline = $8;
- n->plvalidator = $9;
- n->pltrusted = $2;
+ n->replace = $2;
+ n->plname = $6;
+ n->plhandler = $8;
+ n->plinline = $9;
+ n->plvalidator = $10;
+ n->pltrusted = $3;
$$ = (Node *)n;
}
;
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index ca229c8e23d..5a5c040c251 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -13,7 +13,7 @@
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.430 2010/02/16 22:34:57 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.431 2010/02/23 22:51:43 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1623,6 +1623,7 @@ typedef struct CreateTrigStmt
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) */