0003-interpret-create-lang-as-create-ext-5.patch
text/x-diff
Filename: 0003-interpret-create-lang-as-create-ext-5.patch
Type: text/x-diff
Part: 2
Patch
Format: unified
Series: patch 0003
| File | + | − |
|---|---|---|
| doc/src/sgml/ref/create_language.sgml | 28 | 85 |
| src/backend/commands/extension.c | 58 | 0 |
| src/backend/commands/functioncmds.c | 3 | 2 |
| src/backend/commands/proclang.c | 65 | 357 |
| src/backend/parser/gram.y | 11 | 8 |
| src/include/commands/extension.h | 1 | 0 |
| src/include/commands/proclang.h | 6 | 5 |
diff --git a/doc/src/sgml/ref/create_language.sgml b/doc/src/sgml/ref/create_language.sgml
index 13b28b1..af9d115 100644
--- a/doc/src/sgml/ref/create_language.sgml
+++ b/doc/src/sgml/ref/create_language.sgml
@@ -21,9 +21,9 @@ PostgreSQL documentation
<refsynopsisdiv>
<synopsis>
-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> ]
+CREATE [ OR REPLACE ] [ TRUSTED ] [ PROCEDURAL ] LANGUAGE <replaceable class="parameter">name</replaceable>
</synopsis>
</refsynopsisdiv>
@@ -37,21 +37,6 @@ CREATE [ OR REPLACE ] [ TRUSTED ] [ PROCEDURAL ] LANGUAGE <replaceable class="pa
defined in this new language.
</para>
- <note>
- <para>
- As of <productname>PostgreSQL</productname> 9.1, most procedural
- languages have been made into <quote>extensions</quote>, and should
- therefore be installed with <xref linkend="sql-createextension"/>
- not <command>CREATE LANGUAGE</command>. Direct use of
- <command>CREATE LANGUAGE</command> should now be confined to
- extension installation scripts. If you have a <quote>bare</quote>
- language in your database, perhaps as a result of an upgrade,
- you can convert it to an extension using
- <literal>CREATE EXTENSION <replaceable>langname</replaceable> FROM
- unpackaged</literal>.
- </para>
- </note>
-
<para>
<command>CREATE LANGUAGE</command> effectively associates the
language name with handler function(s) that are responsible for executing
@@ -60,53 +45,32 @@ CREATE [ OR REPLACE ] [ TRUSTED ] [ PROCEDURAL ] LANGUAGE <replaceable class="pa
</para>
<para>
- There are two forms of the <command>CREATE LANGUAGE</command> command.
- In the first form, the user supplies just the name of the desired
- language, and the <productname>PostgreSQL</productname> server consults
- the <link linkend="catalog-pg-pltemplate"><structname>pg_pltemplate</structname></link>
- system catalog to determine the correct parameters. In the second form,
- the user supplies the language parameters along with the language name.
- The second form can be used to create a language that is not defined in
- <structname>pg_pltemplate</structname>, but this approach is considered obsolescent.
- </para>
-
- <para>
- When the server finds an entry in the <structname>pg_pltemplate</structname> catalog
- for the given language name, it will use the catalog data even if the
- command includes language parameters. This behavior simplifies loading of
- old dump files, which are likely to contain out-of-date information
- about language support functions.
+ <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 command,
+ 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.
</para>
<para>
- Ordinarily, the user must have the
+ One must have the
<productname>PostgreSQL</productname> superuser privilege to
- register a new language. However, the owner of a database can register
- a new language within that database if the language is listed in
- the <structname>pg_pltemplate</structname> catalog and is marked
- as allowed to be created by database owners (<structfield>tmpldbacreate</structfield>
- is true). The default is that trusted languages can be created
- by database owners, but this can be adjusted by superusers by modifying
- the contents of <structname>pg_pltemplate</structname>.
- The creator of a language becomes its owner and can later
- drop it, rename it, or assign it to a new owner.
+ register a new language or change an existing language's parameters.
+ However, once the language is created it is valid to assign ownership of
+ it to a non-superuser, who may then drop it, change its permissions,
+ rename it, or assign it to a new owner. (Do not, however, assign
+ ownership of the underlying C functions to a non-superuser; that would
+ create a privilege escalation path for that user.)
</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</literal> 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</literal>
- 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.
+ The form of <command>CREATE LANGUAGE</command> that does not supply
+ any handler function is obsolete. For backwards compatibility with
+ old dump files, it is interpreted as <command>CREATE EXTENSION</command>.
+ That will work if the language has been packaged into an extension of
+ the same name, which is the conventional way to set up procedural
+ languages.
</para>
</refsect1>
@@ -218,12 +182,6 @@ CREATE [ OR REPLACE ] [ TRUSTED ] [ PROCEDURAL ] LANGUAGE <replaceable class="pa
</listitem>
</varlistentry>
</variablelist>
-
- <para>
- The <literal>TRUSTED</literal> option and the support function name(s) are
- ignored if the server has an entry for the specified language
- name in <structname>pg_pltemplate</structname>.
- </para>
</refsect1>
<refsect1 id="sql-createlanguage-notes">
@@ -255,18 +213,6 @@ CREATE [ OR REPLACE ] [ TRUSTED ] [ PROCEDURAL ] LANGUAGE <replaceable class="pa
</para>
<para>
- The call handler function, the inline handler function (if any),
- and the validator function (if any)
- must already exist if the server does not have an entry for the language
- in <structname>pg_pltemplate</structname>. But when there is an entry,
- the functions need not already exist;
- they will be automatically defined if not present in the database.
- (This might result in <command>CREATE LANGUAGE</command> failing, if the
- shared library that implements the language is not available in
- the installation.)
- </para>
-
- <para>
In <productname>PostgreSQL</productname> versions before 7.3, it was
necessary to declare handler functions as returning the placeholder
type <type>opaque</type>, rather than <type>language_handler</type>.
@@ -281,23 +227,20 @@ CREATE [ OR REPLACE ] [ TRUSTED ] [ PROCEDURAL ] LANGUAGE <replaceable class="pa
<title>Examples</title>
<para>
- The preferred way of creating any of the standard procedural languages
- is just:
-<programlisting>
-CREATE LANGUAGE plperl;
-</programlisting>
- </para>
-
- <para>
- For a language not known in the <structname>pg_pltemplate</structname> catalog, a
- sequence such as this is needed:
+ A minimal sequence for creating a new procedural language is:
<programlisting>
CREATE FUNCTION plsample_call_handler() RETURNS language_handler
AS '$libdir/plsample'
LANGUAGE C;
CREATE LANGUAGE plsample
HANDLER plsample_call_handler;
-</programlisting></para>
+</programlisting>
+ Typically that would be written in an extension's creation script,
+ and users would do this to install the extension:
+<programlisting>
+CREATE EXTENSION plsample;
+</programlisting>
+ </para>
</refsect1>
<refsect1 id="sql-createlanguage-compat">
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 01de398..ddd46f4 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -2277,6 +2277,64 @@ get_available_versions_for_extension(ExtensionControlFile *pcontrol,
}
/*
+ * Test whether the given extension exists (not whether it's installed)
+ *
+ * This checks for the existence of a matching control file in the extension
+ * directory. That's not a bulletproof check, since the file might be
+ * invalid, but this is only used for hints so it doesn't have to be 100%
+ * right.
+ */
+bool
+extension_file_exists(const char *extensionName)
+{
+ bool result = false;
+ char *location;
+ DIR *dir;
+ struct dirent *de;
+
+ location = get_extension_control_directory();
+ dir = AllocateDir(location);
+
+ /*
+ * If the control directory doesn't exist, we want to silently return
+ * false. Any other error will be reported by ReadDir.
+ */
+ if (dir == NULL && errno == ENOENT)
+ {
+ /* do nothing */
+ }
+ else
+ {
+ while ((de = ReadDir(dir, location)) != NULL)
+ {
+ char *extname;
+
+ if (!is_extension_control_filename(de->d_name))
+ continue;
+
+ /* extract extension name from 'name.control' filename */
+ extname = pstrdup(de->d_name);
+ *strrchr(extname, '.') = '\0';
+
+ /* ignore it if it's an auxiliary control file */
+ if (strstr(extname, "--"))
+ continue;
+
+ /* done if it matches request */
+ if (strcmp(extname, extensionName) == 0)
+ {
+ result = true;
+ break;
+ }
+ }
+
+ FreeDir(dir);
+ }
+
+ return result;
+}
+
+/*
* Convert a list of extension names to a name[] Datum
*/
static Datum
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index c31c57e..0f40c9e 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -49,6 +49,7 @@
#include "catalog/pg_type.h"
#include "commands/alter.h"
#include "commands/defrem.h"
+#include "commands/extension.h"
#include "commands/proclang.h"
#include "executor/execdesc.h"
#include "executor/executor.h"
@@ -991,7 +992,7 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("language \"%s\" does not exist", language),
- (PLTemplateExists(language) ?
+ (extension_file_exists(language) ?
errhint("Use CREATE EXTENSION to load the language into the database.") : 0)));
languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
@@ -2225,7 +2226,7 @@ ExecuteDoStmt(DoStmt *stmt, bool atomic)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("language \"%s\" does not exist", language),
- (PLTemplateExists(language) ?
+ (extension_file_exists(language) ?
errhint("Use CREATE EXTENSION to load the language into the database.") : 0)));
languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index cdff43d..9d72edb 100644
--- a/src/backend/commands/proclang.c
+++ b/src/backend/commands/proclang.c
@@ -13,329 +13,110 @@
*/
#include "postgres.h"
-#include "access/genam.h"
-#include "access/htup_details.h"
#include "access/table.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/objectaccess.h"
-#include "catalog/pg_authid.h"
#include "catalog/pg_language.h"
#include "catalog/pg_namespace.h"
-#include "catalog/pg_pltemplate.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
-#include "commands/dbcommands.h"
#include "commands/defrem.h"
#include "commands/proclang.h"
#include "miscadmin.h"
#include "parser/parse_func.h"
-#include "parser/parser.h"
-#include "utils/acl.h"
#include "utils/builtins.h"
-#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/syscache.h"
-typedef struct
-{
- bool tmpltrusted; /* trusted? */
- bool tmpldbacreate; /* db owner allowed to create? */
- char *tmplhandler; /* name of handler function */
- char *tmplinline; /* name of anonymous-block handler, or NULL */
- char *tmplvalidator; /* name of validator function, or NULL */
- char *tmpllibrary; /* path of shared library */
-} PLTemplate;
-
-static ObjectAddress 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);
-
/*
* CREATE LANGUAGE
*/
ObjectAddress
CreateProceduralLanguage(CreatePLangStmt *stmt)
{
- PLTemplate *pltemplate;
- ObjectAddress tmpAddr;
+ const char *languageName = stmt->plname;
+ Oid languageOwner = GetUserId();
Oid handlerOid,
inlineOid,
valOid;
Oid funcrettype;
Oid funcargtypes[1];
+ Relation rel;
+ TupleDesc tupDesc;
+ Datum values[Natts_pg_language];
+ bool nulls[Natts_pg_language];
+ bool replaces[Natts_pg_language];
+ NameData langname;
+ HeapTuple oldtup;
+ HeapTuple tup;
+ Oid langoid;
+ bool is_update;
+ ObjectAddress myself,
+ referenced;
/*
- * If we have template information for the language, ignore the supplied
- * parameters (if any) and use the template information.
+ * Check permission
*/
- if ((pltemplate = find_language_template(stmt->plname)) != NULL)
- {
- List *funcname;
-
- /*
- * Give a notice if we are ignoring supplied parameters.
- */
- if (stmt->plhandler)
- ereport(NOTICE,
- (errmsg("using pg_pltemplate information instead of CREATE LANGUAGE parameters")));
-
- /*
- * Check permission
- */
- if (!superuser())
- {
- if (!pltemplate->tmpldbacreate)
- ereport(ERROR,
- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be superuser to create procedural language \"%s\"",
- stmt->plname)));
- if (!pg_database_ownercheck(MyDatabaseId, GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_DATABASE,
- get_database_name(MyDatabaseId));
- }
-
- /*
- * Find or create the handler function, which we force to be in the
- * pg_catalog schema. If already present, it must have the correct
- * return type.
- */
- funcname = SystemFuncName(pltemplate->tmplhandler);
- handlerOid = LookupFuncName(funcname, 0, NULL, true);
- if (OidIsValid(handlerOid))
- {
- funcrettype = get_func_rettype(handlerOid);
- if (funcrettype != LANGUAGE_HANDLEROID)
- ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("function %s must return type %s",
- NameListToString(funcname), "language_handler")));
- }
- else
- {
- tmpAddr = ProcedureCreate(pltemplate->tmplhandler,
- PG_CATALOG_NAMESPACE,
- false, /* replace */
- false, /* returnsSet */
- LANGUAGE_HANDLEROID,
- BOOTSTRAP_SUPERUSERID,
- ClanguageId,
- F_FMGR_C_VALIDATOR,
- pltemplate->tmplhandler,
- pltemplate->tmpllibrary,
- PROKIND_FUNCTION,
- false, /* security_definer */
- false, /* isLeakProof */
- false, /* isStrict */
- PROVOLATILE_VOLATILE,
- PROPARALLEL_UNSAFE,
- buildoidvector(funcargtypes, 0),
- PointerGetDatum(NULL),
- PointerGetDatum(NULL),
- PointerGetDatum(NULL),
- NIL,
- PointerGetDatum(NULL),
- PointerGetDatum(NULL),
- InvalidOid,
- 1,
- 0);
- handlerOid = tmpAddr.objectId;
- }
-
- /*
- * Likewise for the anonymous block handler, if required; but we don't
- * care about its return type.
- */
- if (pltemplate->tmplinline)
- {
- funcname = SystemFuncName(pltemplate->tmplinline);
- funcargtypes[0] = INTERNALOID;
- inlineOid = LookupFuncName(funcname, 1, funcargtypes, true);
- if (!OidIsValid(inlineOid))
- {
- tmpAddr = ProcedureCreate(pltemplate->tmplinline,
- PG_CATALOG_NAMESPACE,
- false, /* replace */
- false, /* returnsSet */
- VOIDOID,
- BOOTSTRAP_SUPERUSERID,
- ClanguageId,
- F_FMGR_C_VALIDATOR,
- pltemplate->tmplinline,
- pltemplate->tmpllibrary,
- PROKIND_FUNCTION,
- false, /* security_definer */
- false, /* isLeakProof */
- true, /* isStrict */
- PROVOLATILE_VOLATILE,
- PROPARALLEL_UNSAFE,
- buildoidvector(funcargtypes, 1),
- PointerGetDatum(NULL),
- PointerGetDatum(NULL),
- PointerGetDatum(NULL),
- NIL,
- PointerGetDatum(NULL),
- PointerGetDatum(NULL),
- InvalidOid,
- 1,
- 0);
- inlineOid = tmpAddr.objectId;
- }
- }
- else
- inlineOid = InvalidOid;
+ if (!superuser())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("must be superuser to create custom procedural language")));
+ /*
+ * Lookup the PL handler function and check that it is of the expected
+ * return type
+ */
+ Assert(stmt->plhandler);
+ handlerOid = LookupFuncName(stmt->plhandler, 0, NULL, false);
+ funcrettype = get_func_rettype(handlerOid);
+ if (funcrettype != LANGUAGE_HANDLEROID)
+ {
/*
- * Likewise for the validator, if required; but we don't care about
- * its return type.
+ * We allow OPAQUE just so we can load old dump files. When we see a
+ * handler function declared OPAQUE, change it to LANGUAGE_HANDLER.
+ * (This is probably obsolete and removable?)
*/
- if (pltemplate->tmplvalidator)
+ if (funcrettype == OPAQUEOID)
{
- funcname = SystemFuncName(pltemplate->tmplvalidator);
- funcargtypes[0] = OIDOID;
- valOid = LookupFuncName(funcname, 1, funcargtypes, true);
- if (!OidIsValid(valOid))
- {
- tmpAddr = ProcedureCreate(pltemplate->tmplvalidator,
- PG_CATALOG_NAMESPACE,
- false, /* replace */
- false, /* returnsSet */
- VOIDOID,
- BOOTSTRAP_SUPERUSERID,
- ClanguageId,
- F_FMGR_C_VALIDATOR,
- pltemplate->tmplvalidator,
- pltemplate->tmpllibrary,
- PROKIND_FUNCTION,
- false, /* security_definer */
- false, /* isLeakProof */
- true, /* isStrict */
- PROVOLATILE_VOLATILE,
- PROPARALLEL_UNSAFE,
- buildoidvector(funcargtypes, 1),
- PointerGetDatum(NULL),
- PointerGetDatum(NULL),
- PointerGetDatum(NULL),
- NIL,
- PointerGetDatum(NULL),
- PointerGetDatum(NULL),
- InvalidOid,
- 1,
- 0);
- valOid = tmpAddr.objectId;
- }
+ ereport(WARNING,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("changing return type of function %s from %s to %s",
+ NameListToString(stmt->plhandler),
+ "opaque", "language_handler")));
+ SetFunctionReturnType(handlerOid, LANGUAGE_HANDLEROID);
}
else
- valOid = InvalidOid;
+ ereport(ERROR,
+ (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ errmsg("function %s must return type %s",
+ NameListToString(stmt->plhandler), "language_handler")));
+ }
- /* ok, create it */
- return create_proc_lang(stmt->plname, stmt->replace, GetUserId(),
- handlerOid, inlineOid,
- valOid, pltemplate->tmpltrusted);
+ /* validate the inline function */
+ if (stmt->plinline)
+ {
+ funcargtypes[0] = INTERNALOID;
+ inlineOid = LookupFuncName(stmt->plinline, 1, funcargtypes, false);
+ /* return value is ignored, so we don't check the type */
}
else
- {
- /*
- * No template, so use the provided information. If there's no
- * handler clause, the user is trying to rely on a template that we
- * don't have, so complain accordingly.
- */
- if (!stmt->plhandler)
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("unsupported language \"%s\"",
- stmt->plname),
- errhint("The supported languages are listed in the pg_pltemplate system catalog.")));
+ inlineOid = InvalidOid;
- /*
- * Check permission
- */
- if (!superuser())
- ereport(ERROR,
- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be superuser to create custom procedural language")));
-
- /*
- * Lookup the PL handler function and check that it is of the expected
- * return type
- */
- handlerOid = LookupFuncName(stmt->plhandler, 0, NULL, false);
- funcrettype = get_func_rettype(handlerOid);
- if (funcrettype != LANGUAGE_HANDLEROID)
- {
- /*
- * We allow OPAQUE just so we can load old dump files. When we
- * see a handler function declared OPAQUE, change it to
- * LANGUAGE_HANDLER. (This is probably obsolete and removable?)
- */
- if (funcrettype == OPAQUEOID)
- {
- ereport(WARNING,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("changing return type of function %s from %s to %s",
- NameListToString(stmt->plhandler),
- "opaque", "language_handler")));
- SetFunctionReturnType(handlerOid, LANGUAGE_HANDLEROID);
- }
- else
- ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("function %s must return type %s",
- NameListToString(stmt->plhandler), "language_handler")));
- }
-
- /* validate the inline function */
- if (stmt->plinline)
- {
- funcargtypes[0] = INTERNALOID;
- inlineOid = LookupFuncName(stmt->plinline, 1, funcargtypes, false);
- /* return value is ignored, so we don't check the type */
- }
- else
- inlineOid = InvalidOid;
-
- /* validate the validator function */
- if (stmt->plvalidator)
- {
- funcargtypes[0] = OIDOID;
- valOid = LookupFuncName(stmt->plvalidator, 1, funcargtypes, false);
- /* return value is ignored, so we don't check the type */
- }
- else
- valOid = InvalidOid;
-
- /* ok, create it */
- return create_proc_lang(stmt->plname, stmt->replace, GetUserId(),
- handlerOid, inlineOid,
- valOid, stmt->pltrusted);
+ /* validate the validator function */
+ if (stmt->plvalidator)
+ {
+ funcargtypes[0] = OIDOID;
+ valOid = LookupFuncName(stmt->plvalidator, 1, funcargtypes, false);
+ /* return value is ignored, so we don't check the type */
}
-}
-
-/*
- * Guts of language creation.
- */
-static ObjectAddress
-create_proc_lang(const char *languageName, bool replace,
- Oid languageOwner, Oid handlerOid, Oid inlineOid,
- Oid valOid, bool trusted)
-{
- Relation rel;
- TupleDesc tupDesc;
- Datum values[Natts_pg_language];
- bool nulls[Natts_pg_language];
- bool replaces[Natts_pg_language];
- NameData langname;
- HeapTuple oldtup;
- HeapTuple tup;
- Oid langoid;
- bool is_update;
- ObjectAddress myself,
- referenced;
+ else
+ valOid = InvalidOid;
+ /* ok to create it */
rel = table_open(LanguageRelationId, RowExclusiveLock);
tupDesc = RelationGetDescr(rel);
@@ -348,7 +129,7 @@ create_proc_lang(const char *languageName, bool replace,
values[Anum_pg_language_lanname - 1] = NameGetDatum(&langname);
values[Anum_pg_language_lanowner - 1] = ObjectIdGetDatum(languageOwner);
values[Anum_pg_language_lanispl - 1] = BoolGetDatum(true);
- values[Anum_pg_language_lanpltrusted - 1] = BoolGetDatum(trusted);
+ values[Anum_pg_language_lanpltrusted - 1] = BoolGetDatum(stmt->pltrusted);
values[Anum_pg_language_lanplcallfoid - 1] = ObjectIdGetDatum(handlerOid);
values[Anum_pg_language_laninline - 1] = ObjectIdGetDatum(inlineOid);
values[Anum_pg_language_lanvalidator - 1] = ObjectIdGetDatum(valOid);
@@ -362,13 +143,17 @@ create_proc_lang(const char *languageName, bool replace,
Form_pg_language oldform = (Form_pg_language) GETSTRUCT(oldtup);
/* There is one; okay to replace it? */
- if (!replace)
+ if (!stmt->replace)
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("language \"%s\" already exists", languageName)));
+
+ /* This is currently pointless, since we already checked superuser */
+#ifdef NOT_USED
if (!pg_language_ownercheck(oldform->oid, languageOwner))
aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_LANGUAGE,
languageName);
+#endif
/*
* Do not change existing oid, ownership or permissions. Note
@@ -451,83 +236,6 @@ create_proc_lang(const char *languageName, bool replace,
}
/*
- * Look to see if we have template information for the given language name.
- */
-static PLTemplate *
-find_language_template(const char *languageName)
-{
- PLTemplate *result;
- Relation rel;
- SysScanDesc scan;
- ScanKeyData key;
- HeapTuple tup;
-
- rel = table_open(PLTemplateRelationId, AccessShareLock);
-
- ScanKeyInit(&key,
- Anum_pg_pltemplate_tmplname,
- BTEqualStrategyNumber, F_NAMEEQ,
- CStringGetDatum(languageName));
- scan = systable_beginscan(rel, PLTemplateNameIndexId, true,
- NULL, 1, &key);
-
- tup = systable_getnext(scan);
- if (HeapTupleIsValid(tup))
- {
- Form_pg_pltemplate tmpl = (Form_pg_pltemplate) GETSTRUCT(tup);
- Datum datum;
- bool isnull;
-
- result = (PLTemplate *) palloc0(sizeof(PLTemplate));
- result->tmpltrusted = tmpl->tmpltrusted;
- result->tmpldbacreate = tmpl->tmpldbacreate;
-
- /* Remaining fields are variable-width so we need heap_getattr */
- datum = heap_getattr(tup, Anum_pg_pltemplate_tmplhandler,
- RelationGetDescr(rel), &isnull);
- if (!isnull)
- result->tmplhandler = TextDatumGetCString(datum);
-
- datum = heap_getattr(tup, Anum_pg_pltemplate_tmplinline,
- RelationGetDescr(rel), &isnull);
- if (!isnull)
- result->tmplinline = TextDatumGetCString(datum);
-
- datum = heap_getattr(tup, Anum_pg_pltemplate_tmplvalidator,
- RelationGetDescr(rel), &isnull);
- if (!isnull)
- result->tmplvalidator = TextDatumGetCString(datum);
-
- datum = heap_getattr(tup, Anum_pg_pltemplate_tmpllibrary,
- RelationGetDescr(rel), &isnull);
- if (!isnull)
- result->tmpllibrary = TextDatumGetCString(datum);
-
- /* Ignore template if handler or library info is missing */
- if (!result->tmplhandler || !result->tmpllibrary)
- result = NULL;
- }
- else
- result = NULL;
-
- systable_endscan(scan);
-
- table_close(rel, AccessShareLock);
-
- return result;
-}
-
-
-/*
- * This just returns true if we have a valid template for a given language
- */
-bool
-PLTemplateExists(const char *languageName)
-{
- return (find_language_template(languageName) != NULL);
-}
-
-/*
* Guts of language dropping.
*/
void
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index ba5916b..1b0edf5 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -4324,14 +4324,17 @@ NumericOnly_list: NumericOnly { $$ = list_make1($1); }
CreatePLangStmt:
CREATE opt_or_replace opt_trusted opt_procedural LANGUAGE NonReservedWord_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;
- n->plvalidator = NIL;
- n->pltrusted = false;
+ /*
+ * We now interpret parameterless CREATE LANGUAGE as
+ * CREATE EXTENSION. "OR REPLACE" is silently translated
+ * to "IF NOT EXISTS", which isn't quite the same, but
+ * seems more useful than throwing an error. We just
+ * ignore TRUSTED, as the previous code would have too.
+ */
+ CreateExtensionStmt *n = makeNode(CreateExtensionStmt);
+ n->if_not_exists = $2;
+ n->extname = $6;
+ n->options = NIL;
$$ = (Node *)n;
}
| CREATE opt_or_replace opt_trusted opt_procedural LANGUAGE NonReservedWord_or_Sconst
diff --git a/src/include/commands/extension.h b/src/include/commands/extension.h
index 6f10707..7923cdc 100644
--- a/src/include/commands/extension.h
+++ b/src/include/commands/extension.h
@@ -47,6 +47,7 @@ extern ObjectAddress ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *
extern Oid get_extension_oid(const char *extname, bool missing_ok);
extern char *get_extension_name(Oid ext_oid);
+extern bool extension_file_exists(const char *extensionName);
extern ObjectAddress AlterExtensionNamespace(const char *extensionName, const char *newschema,
Oid *oldschema);
diff --git a/src/include/commands/proclang.h b/src/include/commands/proclang.h
index 9a4bc75..c70f8ec 100644
--- a/src/include/commands/proclang.h
+++ b/src/include/commands/proclang.h
@@ -1,11 +1,12 @@
-/*
- * src/include/commands/proclang.h
- *
- *-------------------------------------------------------------------------
+/*-------------------------------------------------------------------------
*
* proclang.h
* prototypes for proclang.c.
*
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/commands/proclang.h
*
*-------------------------------------------------------------------------
*/
@@ -17,7 +18,7 @@
extern ObjectAddress CreateProceduralLanguage(CreatePLangStmt *stmt);
extern void DropProceduralLanguageById(Oid langOid);
-extern bool PLTemplateExists(const char *languageName);
+
extern Oid get_language_oid(const char *langname, bool missing_ok);
#endif /* PROCLANG_H */