Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Functions

proclang.c File Reference

#include "postgres.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "access/htup_details.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_proc_fn.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"
#include "utils/tqual.h"
Include dependency graph for proclang.c:

Go to the source code of this file.

Data Structures

struct  PLTemplate

Functions

static Oid create_proc_lang (const char *languageName, bool replace, Oid languageOwner, Oid handlerOid, Oid inlineOid, Oid valOid, bool trusted)
static PLTemplatefind_language_template (const char *languageName)
Oid CreateProceduralLanguage (CreatePLangStmt *stmt)
bool PLTemplateExists (const char *languageName)
void DropProceduralLanguageById (Oid langOid)
Oid get_language_oid (const char *langname, bool missing_ok)

Function Documentation

static Oid create_proc_lang ( const char *  languageName,
bool  replace,
Oid  languageOwner,
Oid  handlerOid,
Oid  inlineOid,
Oid  valOid,
bool  trusted 
) [static]

Definition at line 313 of file proclang.c.

References ACL_KIND_LANGUAGE, aclcheck_error(), ACLCHECK_NOT_OWNER, Anum_pg_language_lanacl, Anum_pg_language_laninline, Anum_pg_language_lanispl, Anum_pg_language_lanname, Anum_pg_language_lanowner, Anum_pg_language_lanplcallfoid, Anum_pg_language_lanpltrusted, Anum_pg_language_lanvalidator, BoolGetDatum, CatalogUpdateIndexes(), ObjectAddress::classId, deleteDependencyRecordsFor(), DEPENDENCY_NORMAL, ereport, errcode(), errmsg(), ERROR, heap_close, heap_form_tuple(), heap_modify_tuple(), heap_open(), HeapTupleGetOid, HeapTupleIsValid, InvokeObjectPostCreateHook, LANGNAME, LanguageRelationId, NameGetDatum, namestrcpy(), ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, pg_language_ownercheck(), PointerGetDatum, recordDependencyOn(), recordDependencyOnCurrentExtension(), recordDependencyOnOwner(), RelationGetDescr, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1, simple_heap_insert(), simple_heap_update(), HeapTupleData::t_self, and values.

Referenced by CreateProceduralLanguage().

{
    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;
    bool        is_update;
    ObjectAddress myself,
                referenced;

    rel = heap_open(LanguageRelationId, RowExclusiveLock);
    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_lanowner - 1] = ObjectIdGetDatum(languageOwner);
    values[Anum_pg_language_lanispl - 1] = BoolGetDatum(true);
    values[Anum_pg_language_lanpltrusted - 1] = BoolGetDatum(trusted);
    values[Anum_pg_language_lanplcallfoid - 1] = ObjectIdGetDatum(handlerOid);
    values[Anum_pg_language_laninline - 1] = ObjectIdGetDatum(inlineOid);
    values[Anum_pg_language_lanvalidator - 1] = ObjectIdGetDatum(valOid);
    nulls[Anum_pg_language_lanacl - 1] = true;

    /* Check for pre-existing definition */
    oldtup = SearchSysCache1(LANGNAME, PointerGetDatum(languageName));

    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 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, true);

    /* dependency on owner of language */
    if (!is_update)
        recordDependencyOnOwner(myself.classId, myself.objectId,
                                languageOwner);

    /* dependency on extension */
    recordDependencyOnCurrentExtension(&myself, is_update);

    /* dependency on the PL handler function */
    referenced.classId = ProcedureRelationId;
    referenced.objectId = handlerOid;
    referenced.objectSubId = 0;
    recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

    /* dependency on the inline handler function, if any */
    if (OidIsValid(inlineOid))
    {
        referenced.classId = ProcedureRelationId;
        referenced.objectId = inlineOid;
        referenced.objectSubId = 0;
        recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
    }

    /* dependency on the validator function, if any */
    if (OidIsValid(valOid))
    {
        referenced.classId = ProcedureRelationId;
        referenced.objectId = valOid;
        referenced.objectSubId = 0;
        recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
    }

    /* Post creation hook for new procedural language */
    InvokeObjectPostCreateHook(LanguageRelationId, myself.objectId, 0);

    heap_close(rel, RowExclusiveLock);

    return myself.objectId;
}

Oid CreateProceduralLanguage ( CreatePLangStmt stmt  ) 

Definition at line 64 of file proclang.c.

References ACL_KIND_DATABASE, aclcheck_error(), ACLCHECK_NOT_OWNER, BOOTSTRAP_SUPERUSERID, buildoidvector(), ClanguageId, create_proc_lang(), ereport, errcode(), errhint(), errmsg(), ERROR, find_language_template(), get_database_name(), get_func_rettype(), GetUserId(), LANGUAGE_HANDLEROID, LookupFuncName(), MyDatabaseId, NameListToString(), NIL, NOTICE, NULL, OidIsValid, OPAQUEOID, PG_CATALOG_NAMESPACE, pg_database_ownercheck(), CreatePLangStmt::plhandler, CreatePLangStmt::plinline, CreatePLangStmt::plname, CreatePLangStmt::pltrusted, CreatePLangStmt::plvalidator, PointerGetDatum, ProcedureCreate(), PROVOLATILE_VOLATILE, CreatePLangStmt::replace, SetFunctionReturnType(), superuser(), SystemFuncName(), PLTemplate::tmpldbacreate, PLTemplate::tmplhandler, PLTemplate::tmplinline, PLTemplate::tmpllibrary, PLTemplate::tmpltrusted, PLTemplate::tmplvalidator, VOIDOID, and WARNING.

Referenced by ProcessUtilitySlow().

{
    PLTemplate *pltemplate;
    Oid         handlerOid,
                inlineOid,
                valOid;
    Oid         funcrettype;
    Oid         funcargtypes[1];

    /*
     * If we have template information for the language, ignore the supplied
     * parameters (if any) and use the template information.
     */
    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, ACL_KIND_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, funcargtypes, 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 \"language_handler\"",
                         NameListToString(funcname))));
        }
        else
        {
            handlerOid = ProcedureCreate(pltemplate->tmplhandler,
                                         PG_CATALOG_NAMESPACE,
                                         false, /* replace */
                                         false, /* returnsSet */
                                         LANGUAGE_HANDLEROID,
                                         BOOTSTRAP_SUPERUSERID,
                                         ClanguageId,
                                         F_FMGR_C_VALIDATOR,
                                         pltemplate->tmplhandler,
                                         pltemplate->tmpllibrary,
                                         false, /* isAgg */
                                         false, /* isWindowFunc */
                                         false, /* security_definer */
                                         false, /* isLeakProof */
                                         false, /* isStrict */
                                         PROVOLATILE_VOLATILE,
                                         buildoidvector(funcargtypes, 0),
                                         PointerGetDatum(NULL),
                                         PointerGetDatum(NULL),
                                         PointerGetDatum(NULL),
                                         NIL,
                                         PointerGetDatum(NULL),
                                         1,
                                         0);
        }

        /*
         * 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))
            {
                inlineOid = ProcedureCreate(pltemplate->tmplinline,
                                            PG_CATALOG_NAMESPACE,
                                            false,      /* replace */
                                            false,      /* returnsSet */
                                            VOIDOID,
                                            BOOTSTRAP_SUPERUSERID,
                                            ClanguageId,
                                            F_FMGR_C_VALIDATOR,
                                            pltemplate->tmplinline,
                                            pltemplate->tmpllibrary,
                                            false,      /* isAgg */
                                            false,      /* isWindowFunc */
                                            false,      /* security_definer */
                                            false,      /* isLeakProof */
                                            true,       /* isStrict */
                                            PROVOLATILE_VOLATILE,
                                            buildoidvector(funcargtypes, 1),
                                            PointerGetDatum(NULL),
                                            PointerGetDatum(NULL),
                                            PointerGetDatum(NULL),
                                            NIL,
                                            PointerGetDatum(NULL),
                                            1,
                                            0);
            }
        }
        else
            inlineOid = InvalidOid;

        /*
         * Likewise for the validator, if required; but we don't care about
         * its return type.
         */
        if (pltemplate->tmplvalidator)
        {
            funcname = SystemFuncName(pltemplate->tmplvalidator);
            funcargtypes[0] = OIDOID;
            valOid = LookupFuncName(funcname, 1, funcargtypes, true);
            if (!OidIsValid(valOid))
            {
                valOid = ProcedureCreate(pltemplate->tmplvalidator,
                                         PG_CATALOG_NAMESPACE,
                                         false, /* replace */
                                         false, /* returnsSet */
                                         VOIDOID,
                                         BOOTSTRAP_SUPERUSERID,
                                         ClanguageId,
                                         F_FMGR_C_VALIDATOR,
                                         pltemplate->tmplvalidator,
                                         pltemplate->tmpllibrary,
                                         false, /* isAgg */
                                         false, /* isWindowFunc */
                                         false, /* security_definer */
                                         false, /* isLeakProof */
                                         true,  /* isStrict */
                                         PROVOLATILE_VOLATILE,
                                         buildoidvector(funcargtypes, 1),
                                         PointerGetDatum(NULL),
                                         PointerGetDatum(NULL),
                                         PointerGetDatum(NULL),
                                         NIL,
                                         PointerGetDatum(NULL),
                                         1,
                                         0);
            }
        }
        else
            valOid = InvalidOid;

        /* ok, create it */
        return create_proc_lang(stmt->plname, stmt->replace, GetUserId(),
                                handlerOid, inlineOid,
                                valOid, pltemplate->tmpltrusted);
    }
    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.")));

        /*
         * 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, funcargtypes, 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 \"opaque\" to \"language_handler\"",
                                NameListToString(stmt->plhandler))));
                SetFunctionReturnType(handlerOid, LANGUAGE_HANDLEROID);
            }
            else
                ereport(ERROR,
                        (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                  errmsg("function %s must return type \"language_handler\"",
                         NameListToString(stmt->plhandler))));
        }

        /* 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);
    }
}

void DropProceduralLanguageById ( Oid  langOid  ) 

Definition at line 520 of file proclang.c.

References elog, ERROR, heap_close, heap_open(), HeapTupleIsValid, LANGOID, LanguageRelationId, ObjectIdGetDatum, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1, simple_heap_delete(), and HeapTupleData::t_self.

Referenced by doDeletion().

{
    Relation    rel;
    HeapTuple   langTup;

    rel = heap_open(LanguageRelationId, RowExclusiveLock);

    langTup = SearchSysCache1(LANGOID, ObjectIdGetDatum(langOid));
    if (!HeapTupleIsValid(langTup))     /* should not happen */
        elog(ERROR, "cache lookup failed for language %u", langOid);

    simple_heap_delete(rel, &langTup->t_self);

    ReleaseSysCache(langTup);

    heap_close(rel, RowExclusiveLock);
}

static PLTemplate * find_language_template ( const char *  languageName  )  [static]

Definition at line 443 of file proclang.c.

References AccessShareLock, Anum_pg_pltemplate_tmplhandler, Anum_pg_pltemplate_tmplinline, Anum_pg_pltemplate_tmpllibrary, Anum_pg_pltemplate_tmplname, Anum_pg_pltemplate_tmplvalidator, BTEqualStrategyNumber, GETSTRUCT, heap_close, heap_getattr, heap_open(), HeapTupleIsValid, NameGetDatum, palloc0(), PLTemplateNameIndexId, PLTemplateRelationId, RelationGetDescr, ScanKeyInit(), SnapshotNow, systable_beginscan(), systable_endscan(), systable_getnext(), TextDatumGetCString, PLTemplate::tmpldbacreate, PLTemplate::tmplhandler, PLTemplate::tmplinline, PLTemplate::tmpllibrary, PLTemplate::tmpltrusted, and PLTemplate::tmplvalidator.

Referenced by CreateProceduralLanguage(), and PLTemplateExists().

{
    PLTemplate *result;
    Relation    rel;
    SysScanDesc scan;
    ScanKeyData key;
    HeapTuple   tup;

    rel = heap_open(PLTemplateRelationId, AccessShareLock);

    ScanKeyInit(&key,
                Anum_pg_pltemplate_tmplname,
                BTEqualStrategyNumber, F_NAMEEQ,
                NameGetDatum(languageName));
    scan = systable_beginscan(rel, PLTemplateNameIndexId, true,
                              SnapshotNow, 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);

    heap_close(rel, AccessShareLock);

    return result;
}

Oid get_language_oid ( const char *  langname,
bool  missing_ok 
)

Definition at line 545 of file proclang.c.

References CStringGetDatum, ereport, errcode(), errmsg(), ERROR, GetSysCacheOid1, LANGNAME, and OidIsValid.

Referenced by convert_language_name(), get_object_address_unqualified(), and objectNamesToOids().

{
    Oid         oid;

    oid = GetSysCacheOid1(LANGNAME, CStringGetDatum(langname));
    if (!OidIsValid(oid) && !missing_ok)
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_OBJECT),
                 errmsg("language \"%s\" does not exist", langname)));
    return oid;
}

bool PLTemplateExists ( const char *  languageName  ) 

Definition at line 511 of file proclang.c.

References find_language_template(), and NULL.

Referenced by CreateFunction(), and ExecuteDoStmt().

{
    return (find_language_template(languageName) != NULL);
}