aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/proclang.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/proclang.c')
-rw-r--r--src/backend/commands/proclang.c422
1 files changed, 65 insertions, 357 deletions
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index cdff43d3ce7..9d72edbfec5 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