Header And Logo

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

Functions

defrem.h File Reference

#include "nodes/parsenodes.h"
Include dependency graph for defrem.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

void RemoveObjects (DropStmt *stmt)
Oid DefineIndex (IndexStmt *stmt, Oid indexRelationId, bool is_alter_table, bool check_rights, bool skip_build, bool quiet)
Oid ReindexIndex (RangeVar *indexRelation)
Oid ReindexTable (RangeVar *relation)
Oid ReindexDatabase (const char *databaseName, bool do_system, bool do_user)
char * makeObjectName (const char *name1, const char *name2, const char *label)
char * ChooseRelationName (const char *name1, const char *name2, const char *label, Oid namespaceid)
bool CheckIndexCompatible (Oid oldId, RangeVar *heapRelation, char *accessMethodName, List *attributeList, List *exclusionOpNames)
Oid GetDefaultOpClass (Oid type_id, Oid am_id)
Oid CreateFunction (CreateFunctionStmt *stmt, const char *queryString)
void RemoveFunctionById (Oid funcOid)
void SetFunctionReturnType (Oid funcOid, Oid newRetType)
void SetFunctionArgType (Oid funcOid, int argIndex, Oid newArgType)
Oid AlterFunction (AlterFunctionStmt *stmt)
Oid CreateCast (CreateCastStmt *stmt)
void DropCastById (Oid castOid)
void IsThereFunctionInNamespace (const char *proname, int pronargs, oidvector proargtypes, Oid nspOid)
void ExecuteDoStmt (DoStmt *stmt)
Oid get_cast_oid (Oid sourcetypeid, Oid targettypeid, bool missing_ok)
Oid DefineOperator (List *names, List *parameters)
void RemoveOperatorById (Oid operOid)
Oid DefineAggregate (List *name, List *args, bool oldstyle, List *parameters)
Oid DefineOpClass (CreateOpClassStmt *stmt)
Oid DefineOpFamily (CreateOpFamilyStmt *stmt)
Oid AlterOpFamily (AlterOpFamilyStmt *stmt)
void RemoveOpClassById (Oid opclassOid)
void RemoveOpFamilyById (Oid opfamilyOid)
void RemoveAmOpEntryById (Oid entryOid)
void RemoveAmProcEntryById (Oid entryOid)
void IsThereOpClassInNamespace (const char *opcname, Oid opcmethod, Oid opcnamespace)
void IsThereOpFamilyInNamespace (const char *opfname, Oid opfmethod, Oid opfnamespace)
Oid get_am_oid (const char *amname, bool missing_ok)
Oid get_opclass_oid (Oid amID, List *opclassname, bool missing_ok)
Oid get_opfamily_oid (Oid amID, List *opfamilyname, bool missing_ok)
Oid DefineTSParser (List *names, List *parameters)
void RemoveTSParserById (Oid prsId)
Oid DefineTSDictionary (List *names, List *parameters)
void RemoveTSDictionaryById (Oid dictId)
Oid AlterTSDictionary (AlterTSDictionaryStmt *stmt)
Oid DefineTSTemplate (List *names, List *parameters)
void RemoveTSTemplateById (Oid tmplId)
Oid DefineTSConfiguration (List *names, List *parameters)
void RemoveTSConfigurationById (Oid cfgId)
Oid AlterTSConfiguration (AlterTSConfigurationStmt *stmt)
textserialize_deflist (List *deflist)
Listdeserialize_deflist (Datum txt)
Oid AlterForeignServerOwner (const char *name, Oid newOwnerId)
void AlterForeignServerOwner_oid (Oid, Oid newOwnerId)
Oid AlterForeignDataWrapperOwner (const char *name, Oid newOwnerId)
void AlterForeignDataWrapperOwner_oid (Oid fwdId, Oid newOwnerId)
Oid CreateForeignDataWrapper (CreateFdwStmt *stmt)
Oid AlterForeignDataWrapper (AlterFdwStmt *stmt)
void RemoveForeignDataWrapperById (Oid fdwId)
Oid CreateForeignServer (CreateForeignServerStmt *stmt)
Oid AlterForeignServer (AlterForeignServerStmt *stmt)
void RemoveForeignServerById (Oid srvId)
Oid CreateUserMapping (CreateUserMappingStmt *stmt)
Oid AlterUserMapping (AlterUserMappingStmt *stmt)
Oid RemoveUserMapping (DropUserMappingStmt *stmt)
void RemoveUserMappingById (Oid umId)
void CreateForeignTable (CreateForeignTableStmt *stmt, Oid relid)
Datum transformGenericOptions (Oid catalogId, Datum oldOptions, List *options, Oid fdwvalidator)
char * defGetString (DefElem *def)
double defGetNumeric (DefElem *def)
bool defGetBoolean (DefElem *def)
int64 defGetInt64 (DefElem *def)
ListdefGetQualifiedName (DefElem *def)
TypeNamedefGetTypeName (DefElem *def)
int defGetTypeLength (DefElem *def)
DefElemdefWithOids (bool value)

Function Documentation

Oid AlterForeignDataWrapper ( AlterFdwStmt stmt  ) 

Definition at line 620 of file foreigncmds.c.

References Anum_pg_foreign_data_wrapper_fdwhandler, Anum_pg_foreign_data_wrapper_fdwoptions, Anum_pg_foreign_data_wrapper_fdwvalidator, CatalogUpdateIndexes(), ObjectAddress::classId, CStringGetDatum, DatumGetPointer, deleteDependencyRecordsForClass(), DEPENDENCY_NORMAL, ereport, errcode(), errhint(), errmsg(), ERROR, AlterFdwStmt::fdwname, FOREIGNDATAWRAPPERNAME, FOREIGNDATAWRAPPEROID, ForeignDataWrapperRelationId, AlterFdwStmt::func_options, GETSTRUCT, heap_close, heap_freetuple(), heap_modify_tuple(), heap_open(), HeapTupleGetOid, HeapTupleIsValid, InvokeObjectPostAlterHook, NULL, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, AlterFdwStmt::options, parse_func_options(), PointerGetDatum, PointerIsValid, ProcedureRelationId, recordDependencyOn(), RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, simple_heap_update(), superuser(), SysCacheGetAttr(), HeapTupleData::t_self, transformGenericOptions(), and WARNING.

Referenced by ProcessUtilitySlow().

{
    Relation    rel;
    HeapTuple   tp;
    Form_pg_foreign_data_wrapper fdwForm;
    Datum       repl_val[Natts_pg_foreign_data_wrapper];
    bool        repl_null[Natts_pg_foreign_data_wrapper];
    bool        repl_repl[Natts_pg_foreign_data_wrapper];
    Oid         fdwId;
    bool        isnull;
    Datum       datum;
    bool        handler_given;
    bool        validator_given;
    Oid         fdwhandler;
    Oid         fdwvalidator;

    rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);

    /* Must be super user */
    if (!superuser())
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
             errmsg("permission denied to alter foreign-data wrapper \"%s\"",
                    stmt->fdwname),
             errhint("Must be superuser to alter a foreign-data wrapper.")));

    tp = SearchSysCacheCopy1(FOREIGNDATAWRAPPERNAME,
                             CStringGetDatum(stmt->fdwname));

    if (!HeapTupleIsValid(tp))
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_OBJECT),
        errmsg("foreign-data wrapper \"%s\" does not exist", stmt->fdwname)));

    fdwForm = (Form_pg_foreign_data_wrapper) GETSTRUCT(tp);
    fdwId = HeapTupleGetOid(tp);

    memset(repl_val, 0, sizeof(repl_val));
    memset(repl_null, false, sizeof(repl_null));
    memset(repl_repl, false, sizeof(repl_repl));

    parse_func_options(stmt->func_options,
                       &handler_given, &fdwhandler,
                       &validator_given, &fdwvalidator);

    if (handler_given)
    {
        repl_val[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = ObjectIdGetDatum(fdwhandler);
        repl_repl[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = true;

        /*
         * It could be that the behavior of accessing foreign table changes
         * with the new handler.  Warn about this.
         */
        ereport(WARNING,
                (errmsg("changing the foreign-data wrapper handler can change behavior of existing foreign tables")));
    }

    if (validator_given)
    {
        repl_val[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = ObjectIdGetDatum(fdwvalidator);
        repl_repl[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = true;

        /*
         * It could be that the options for the FDW, SERVER and USER MAPPING
         * are no longer valid with the new validator.  Warn about this.
         */
        if (OidIsValid(fdwvalidator))
            ereport(WARNING,
             (errmsg("changing the foreign-data wrapper validator can cause "
                     "the options for dependent objects to become invalid")));
    }
    else
    {
        /*
         * Validator is not changed, but we need it for validating options.
         */
        fdwvalidator = fdwForm->fdwvalidator;
    }

    /*
     * If options specified, validate and update.
     */
    if (stmt->options)
    {
        /* Extract the current options */
        datum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID,
                                tp,
                                Anum_pg_foreign_data_wrapper_fdwoptions,
                                &isnull);
        if (isnull)
            datum = PointerGetDatum(NULL);

        /* Transform the options */
        datum = transformGenericOptions(ForeignDataWrapperRelationId,
                                        datum,
                                        stmt->options,
                                        fdwvalidator);

        if (PointerIsValid(DatumGetPointer(datum)))
            repl_val[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = datum;
        else
            repl_null[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true;

        repl_repl[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true;
    }

    /* Everything looks good - update the tuple */
    tp = heap_modify_tuple(tp, RelationGetDescr(rel),
                           repl_val, repl_null, repl_repl);

    simple_heap_update(rel, &tp->t_self, tp);
    CatalogUpdateIndexes(rel, tp);

    heap_freetuple(tp);

    /* Update function dependencies if we changed them */
    if (handler_given || validator_given)
    {
        ObjectAddress myself;
        ObjectAddress referenced;

        /*
         * Flush all existing dependency records of this FDW on functions; we
         * assume there can be none other than the ones we are fixing.
         */
        deleteDependencyRecordsForClass(ForeignDataWrapperRelationId,
                                        fdwId,
                                        ProcedureRelationId,
                                        DEPENDENCY_NORMAL);

        /* And build new ones. */
        myself.classId = ForeignDataWrapperRelationId;
        myself.objectId = fdwId;
        myself.objectSubId = 0;

        if (OidIsValid(fdwhandler))
        {
            referenced.classId = ProcedureRelationId;
            referenced.objectId = fdwhandler;
            referenced.objectSubId = 0;
            recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
        }

        if (OidIsValid(fdwvalidator))
        {
            referenced.classId = ProcedureRelationId;
            referenced.objectId = fdwvalidator;
            referenced.objectSubId = 0;
            recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
        }
    }

    InvokeObjectPostAlterHook(ForeignDataWrapperRelationId, fdwId, 0);

    heap_close(rel, RowExclusiveLock);

    return fdwId;
}

Oid AlterForeignDataWrapperOwner ( const char *  name,
Oid  newOwnerId 
)
void AlterForeignDataWrapperOwner_oid ( Oid  fwdId,
Oid  newOwnerId 
)
Oid AlterForeignServer ( AlterForeignServerStmt stmt  ) 

Definition at line 922 of file foreigncmds.c.

References ACL_KIND_FOREIGN_SERVER, aclcheck_error(), ACLCHECK_NOT_OWNER, Anum_pg_foreign_server_srvoptions, Anum_pg_foreign_server_srvversion, CatalogUpdateIndexes(), CStringGetDatum, CStringGetTextDatum, DatumGetPointer, ereport, errcode(), errmsg(), ERROR, ForeignDataWrapper::fdwvalidator, FOREIGNSERVERNAME, FOREIGNSERVEROID, ForeignServerRelationId, GetForeignDataWrapper(), GETSTRUCT, GetUserId(), AlterForeignServerStmt::has_version, heap_close, heap_freetuple(), heap_modify_tuple(), heap_open(), HeapTupleGetOid, HeapTupleIsValid, InvokeObjectPostAlterHook, NULL, AlterForeignServerStmt::options, pg_foreign_server_ownercheck(), PointerGetDatum, PointerIsValid, RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, AlterForeignServerStmt::servername, simple_heap_update(), SysCacheGetAttr(), HeapTupleData::t_self, transformGenericOptions(), and AlterForeignServerStmt::version.

Referenced by ProcessUtilitySlow().

{
    Relation    rel;
    HeapTuple   tp;
    Datum       repl_val[Natts_pg_foreign_server];
    bool        repl_null[Natts_pg_foreign_server];
    bool        repl_repl[Natts_pg_foreign_server];
    Oid         srvId;
    Form_pg_foreign_server srvForm;

    rel = heap_open(ForeignServerRelationId, RowExclusiveLock);

    tp = SearchSysCacheCopy1(FOREIGNSERVERNAME,
                             CStringGetDatum(stmt->servername));

    if (!HeapTupleIsValid(tp))
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_OBJECT),
                 errmsg("server \"%s\" does not exist", stmt->servername)));

    srvId = HeapTupleGetOid(tp);
    srvForm = (Form_pg_foreign_server) GETSTRUCT(tp);

    /*
     * Only owner or a superuser can ALTER a SERVER.
     */
    if (!pg_foreign_server_ownercheck(srvId, GetUserId()))
        aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
                       stmt->servername);

    memset(repl_val, 0, sizeof(repl_val));
    memset(repl_null, false, sizeof(repl_null));
    memset(repl_repl, false, sizeof(repl_repl));

    if (stmt->has_version)
    {
        /*
         * Change the server VERSION string.
         */
        if (stmt->version)
            repl_val[Anum_pg_foreign_server_srvversion - 1] =
                CStringGetTextDatum(stmt->version);
        else
            repl_null[Anum_pg_foreign_server_srvversion - 1] = true;

        repl_repl[Anum_pg_foreign_server_srvversion - 1] = true;
    }

    if (stmt->options)
    {
        ForeignDataWrapper *fdw = GetForeignDataWrapper(srvForm->srvfdw);
        Datum       datum;
        bool        isnull;

        /* Extract the current srvoptions */
        datum = SysCacheGetAttr(FOREIGNSERVEROID,
                                tp,
                                Anum_pg_foreign_server_srvoptions,
                                &isnull);
        if (isnull)
            datum = PointerGetDatum(NULL);

        /* Prepare the options array */
        datum = transformGenericOptions(ForeignServerRelationId,
                                        datum,
                                        stmt->options,
                                        fdw->fdwvalidator);

        if (PointerIsValid(DatumGetPointer(datum)))
            repl_val[Anum_pg_foreign_server_srvoptions - 1] = datum;
        else
            repl_null[Anum_pg_foreign_server_srvoptions - 1] = true;

        repl_repl[Anum_pg_foreign_server_srvoptions - 1] = true;
    }

    /* Everything looks good - update the tuple */
    tp = heap_modify_tuple(tp, RelationGetDescr(rel),
                           repl_val, repl_null, repl_repl);

    simple_heap_update(rel, &tp->t_self, tp);
    CatalogUpdateIndexes(rel, tp);

    InvokeObjectPostAlterHook(ForeignServerRelationId, srvId, 0);

    heap_freetuple(tp);

    heap_close(rel, RowExclusiveLock);

    return srvId;
}

Oid AlterForeignServerOwner ( const char *  name,
Oid  newOwnerId 
)
void AlterForeignServerOwner_oid ( Oid  ,
Oid  newOwnerId 
)
Oid AlterFunction ( AlterFunctionStmt stmt  ) 

Definition at line 1045 of file functioncmds.c.

References ACL_KIND_PROC, aclcheck_error(), ACLCHECK_NOT_OWNER, AlterFunctionStmt::actions, Anum_pg_proc_proconfig, DefElem::arg, CatalogUpdateIndexes(), compute_common_attribute(), DatumGetArrayTypeP, defGetNumeric(), DefElem::defname, elog, ereport, errcode(), errmsg(), ERROR, AlterFunctionStmt::func, FuncWithArgs::funcargs, FuncWithArgs::funcname, GETSTRUCT, GetUserId(), heap_close, heap_freetuple(), heap_modify_tuple(), heap_open(), HeapTupleIsValid, interpret_func_volatility(), intVal, InvokeObjectPostAlterHook, lfirst, LookupFuncNameTypeNames(), NameListToString(), NoLock, NULL, ObjectIdGetDatum, pg_proc_ownercheck(), PointerGetDatum, ProcedureRelationId, PROCOID, RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, simple_heap_update(), superuser(), SysCacheGetAttr(), HeapTupleData::t_self, and update_proconfig_value().

Referenced by ProcessUtilitySlow().

{
    HeapTuple   tup;
    Oid         funcOid;
    Form_pg_proc procForm;
    Relation    rel;
    ListCell   *l;
    DefElem    *volatility_item = NULL;
    DefElem    *strict_item = NULL;
    DefElem    *security_def_item = NULL;
    DefElem    *leakproof_item = NULL;
    List       *set_items = NIL;
    DefElem    *cost_item = NULL;
    DefElem    *rows_item = NULL;

    rel = heap_open(ProcedureRelationId, RowExclusiveLock);

    funcOid = LookupFuncNameTypeNames(stmt->func->funcname,
                                      stmt->func->funcargs,
                                      false);

    tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(funcOid));
    if (!HeapTupleIsValid(tup)) /* should not happen */
        elog(ERROR, "cache lookup failed for function %u", funcOid);

    procForm = (Form_pg_proc) GETSTRUCT(tup);

    /* Permission check: must own function */
    if (!pg_proc_ownercheck(funcOid, GetUserId()))
        aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
                       NameListToString(stmt->func->funcname));

    if (procForm->proisagg)
        ereport(ERROR,
                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                 errmsg("\"%s\" is an aggregate function",
                        NameListToString(stmt->func->funcname))));

    /* Examine requested actions. */
    foreach(l, stmt->actions)
    {
        DefElem    *defel = (DefElem *) lfirst(l);

        if (compute_common_attribute(defel,
                                     &volatility_item,
                                     &strict_item,
                                     &security_def_item,
                                     &leakproof_item,
                                     &set_items,
                                     &cost_item,
                                     &rows_item) == false)
            elog(ERROR, "option \"%s\" not recognized", defel->defname);
    }

    if (volatility_item)
        procForm->provolatile = interpret_func_volatility(volatility_item);
    if (strict_item)
        procForm->proisstrict = intVal(strict_item->arg);
    if (security_def_item)
        procForm->prosecdef = intVal(security_def_item->arg);
    if (leakproof_item)
    {
        if (intVal(leakproof_item->arg) && !superuser())
            ereport(ERROR,
                    (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                  errmsg("only superuser can define a leakproof function")));
        procForm->proleakproof = intVal(leakproof_item->arg);
    }
    if (cost_item)
    {
        procForm->procost = defGetNumeric(cost_item);
        if (procForm->procost <= 0)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                     errmsg("COST must be positive")));
    }
    if (rows_item)
    {
        procForm->prorows = defGetNumeric(rows_item);
        if (procForm->prorows <= 0)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                     errmsg("ROWS must be positive")));
        if (!procForm->proretset)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                     errmsg("ROWS is not applicable when function does not return a set")));
    }
    if (set_items)
    {
        Datum       datum;
        bool        isnull;
        ArrayType  *a;
        Datum       repl_val[Natts_pg_proc];
        bool        repl_null[Natts_pg_proc];
        bool        repl_repl[Natts_pg_proc];

        /* extract existing proconfig setting */
        datum = SysCacheGetAttr(PROCOID, tup, Anum_pg_proc_proconfig, &isnull);
        a = isnull ? NULL : DatumGetArrayTypeP(datum);

        /* update according to each SET or RESET item, left to right */
        a = update_proconfig_value(a, set_items);

        /* update the tuple */
        memset(repl_repl, false, sizeof(repl_repl));
        repl_repl[Anum_pg_proc_proconfig - 1] = true;

        if (a == NULL)
        {
            repl_val[Anum_pg_proc_proconfig - 1] = (Datum) 0;
            repl_null[Anum_pg_proc_proconfig - 1] = true;
        }
        else
        {
            repl_val[Anum_pg_proc_proconfig - 1] = PointerGetDatum(a);
            repl_null[Anum_pg_proc_proconfig - 1] = false;
        }

        tup = heap_modify_tuple(tup, RelationGetDescr(rel),
                                repl_val, repl_null, repl_repl);
    }

    /* Do the update */
    simple_heap_update(rel, &tup->t_self, tup);
    CatalogUpdateIndexes(rel, tup);

    InvokeObjectPostAlterHook(ProcedureRelationId, funcOid, 0);

    heap_close(rel, NoLock);
    heap_freetuple(tup);

    return funcOid;
}

Oid AlterOpFamily ( AlterOpFamilyStmt stmt  ) 

Definition at line 770 of file opclasscmds.c.

References AlterOpFamilyAdd(), AlterOpFamilyDrop(), AlterOpFamilyStmt::amname, AMNAME, CStringGetDatum, ereport, errcode(), errmsg(), ERROR, get_opfamily_oid(), GETSTRUCT, HeapTupleGetOid, HeapTupleIsValid, AlterOpFamilyStmt::isDrop, AlterOpFamilyStmt::items, AlterOpFamilyStmt::opfamilyname, ReleaseSysCache(), SearchSysCache1, and superuser().

Referenced by ProcessUtilitySlow().

{
    Oid         amoid,          /* our AM's oid */
                opfamilyoid;    /* oid of opfamily */
    int         maxOpNumber,    /* amstrategies value */
                maxProcNumber;  /* amsupport value */
    HeapTuple   tup;
    Form_pg_am  pg_am;

    /* Get necessary info about access method */
    tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
    if (!HeapTupleIsValid(tup))
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_OBJECT),
                 errmsg("access method \"%s\" does not exist",
                        stmt->amname)));

    amoid = HeapTupleGetOid(tup);
    pg_am = (Form_pg_am) GETSTRUCT(tup);
    maxOpNumber = pg_am->amstrategies;
    /* if amstrategies is zero, just enforce that op numbers fit in int16 */
    if (maxOpNumber <= 0)
        maxOpNumber = SHRT_MAX;
    maxProcNumber = pg_am->amsupport;

    /* XXX Should we make any privilege check against the AM? */

    ReleaseSysCache(tup);

    /* Look up the opfamily */
    opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);

    /*
     * Currently, we require superuser privileges to alter an opfamily.
     *
     * XXX re-enable NOT_USED code sections below if you remove this test.
     */
    if (!superuser())
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 errmsg("must be superuser to alter an operator family")));

    /*
     * ADD and DROP cases need separate code from here on down.
     */
    if (stmt->isDrop)
        AlterOpFamilyDrop(stmt->opfamilyname, amoid, opfamilyoid,
                          maxOpNumber, maxProcNumber,
                          stmt->items);
    else
        AlterOpFamilyAdd(stmt->opfamilyname, amoid, opfamilyoid,
                         maxOpNumber, maxProcNumber,
                         stmt->items);

    return opfamilyoid;
}

Oid AlterTSConfiguration ( AlterTSConfigurationStmt stmt  ) 

Definition at line 1157 of file tsearchcmds.c.

References ACL_KIND_TSCONFIGURATION, aclcheck_error(), ACLCHECK_NOT_OWNER, AlterTSConfigurationStmt::cfgname, AlterTSConfigurationStmt::dicts, DropConfigurationMapping(), ereport, errcode(), errmsg(), ERROR, GetTSConfigTuple(), GetUserId(), heap_close, heap_open(), HeapTupleGetOid, HeapTupleIsValid, InvokeObjectPostAlterHook, makeConfigurationDependencies(), MakeConfigurationMapping(), NameListToString(), pg_ts_config_ownercheck(), ReleaseSysCache(), RowExclusiveLock, AlterTSConfigurationStmt::tokentype, and TSConfigMapRelationId.

Referenced by ProcessUtilitySlow().

{
    HeapTuple   tup;
    Oid         cfgId;
    Relation    relMap;

    /* Find the configuration */
    tup = GetTSConfigTuple(stmt->cfgname);
    if (!HeapTupleIsValid(tup))
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_OBJECT),
                 errmsg("text search configuration \"%s\" does not exist",
                        NameListToString(stmt->cfgname))));

    cfgId = HeapTupleGetOid(tup);

    /* must be owner */
    if (!pg_ts_config_ownercheck(HeapTupleGetOid(tup), GetUserId()))
        aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSCONFIGURATION,
                       NameListToString(stmt->cfgname));

    relMap = heap_open(TSConfigMapRelationId, RowExclusiveLock);

    /* Add or drop mappings */
    if (stmt->dicts)
        MakeConfigurationMapping(stmt, tup, relMap);
    else if (stmt->tokentype)
        DropConfigurationMapping(stmt, tup, relMap);

    /* Update dependencies */
    makeConfigurationDependencies(tup, true, relMap);

    InvokeObjectPostAlterHook(TSConfigMapRelationId,
                              HeapTupleGetOid(tup), 0);

    heap_close(relMap, RowExclusiveLock);

    ReleaseSysCache(tup);

    return cfgId;
}

Oid AlterTSDictionary ( AlterTSDictionaryStmt stmt  ) 

Definition at line 518 of file tsearchcmds.c.

References ACL_KIND_TSDICTIONARY, aclcheck_error(), ACLCHECK_NOT_OWNER, Anum_pg_ts_dict_dictinitoption, DefElem::arg, CatalogUpdateIndexes(), DefElem::defname, deserialize_deflist(), AlterTSDictionaryStmt::dictname, elog, ERROR, get_ts_dict_oid(), GETSTRUCT, GetUserId(), heap_close, heap_freetuple(), heap_modify_tuple(), heap_open(), HeapTupleIsValid, InvokeObjectPostAlterHook, lappend(), lfirst, list_delete_cell(), list_head(), lnext, NameListToString(), ObjectIdGetDatum, AlterTSDictionaryStmt::options, pg_strcasecmp(), pg_ts_dict_ownercheck(), PointerGetDatum, RelationGetDescr, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1, serialize_deflist(), simple_heap_update(), SysCacheGetAttr(), HeapTupleData::t_self, TSDictionaryRelationId, TSDICTOID, and verify_dictoptions().

Referenced by ProcessUtilitySlow().

{
    HeapTuple   tup,
                newtup;
    Relation    rel;
    Oid         dictId;
    ListCell   *pl;
    List       *dictoptions;
    Datum       opt;
    bool        isnull;
    Datum       repl_val[Natts_pg_ts_dict];
    bool        repl_null[Natts_pg_ts_dict];
    bool        repl_repl[Natts_pg_ts_dict];

    dictId = get_ts_dict_oid(stmt->dictname, false);

    rel = heap_open(TSDictionaryRelationId, RowExclusiveLock);

    tup = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictId));

    if (!HeapTupleIsValid(tup))
        elog(ERROR, "cache lookup failed for text search dictionary %u",
             dictId);

    /* must be owner */
    if (!pg_ts_dict_ownercheck(dictId, GetUserId()))
        aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSDICTIONARY,
                       NameListToString(stmt->dictname));

    /* deserialize the existing set of options */
    opt = SysCacheGetAttr(TSDICTOID, tup,
                          Anum_pg_ts_dict_dictinitoption,
                          &isnull);
    if (isnull)
        dictoptions = NIL;
    else
        dictoptions = deserialize_deflist(opt);

    /*
     * Modify the options list as per specified changes
     */
    foreach(pl, stmt->options)
    {
        DefElem    *defel = (DefElem *) lfirst(pl);
        ListCell   *cell;
        ListCell   *prev;
        ListCell   *next;

        /*
         * Remove any matches ...
         */
        prev = NULL;
        for (cell = list_head(dictoptions); cell; cell = next)
        {
            DefElem    *oldel = (DefElem *) lfirst(cell);

            next = lnext(cell);
            if (pg_strcasecmp(oldel->defname, defel->defname) == 0)
                dictoptions = list_delete_cell(dictoptions, cell, prev);
            else
                prev = cell;
        }

        /*
         * and add new value if it's got one
         */
        if (defel->arg)
            dictoptions = lappend(dictoptions, defel);
    }

    /*
     * Validate
     */
    verify_dictoptions(((Form_pg_ts_dict) GETSTRUCT(tup))->dicttemplate,
                       dictoptions);

    /*
     * Looks good, update
     */
    memset(repl_val, 0, sizeof(repl_val));
    memset(repl_null, false, sizeof(repl_null));
    memset(repl_repl, false, sizeof(repl_repl));

    if (dictoptions)
        repl_val[Anum_pg_ts_dict_dictinitoption - 1] =
            PointerGetDatum(serialize_deflist(dictoptions));
    else
        repl_null[Anum_pg_ts_dict_dictinitoption - 1] = true;
    repl_repl[Anum_pg_ts_dict_dictinitoption - 1] = true;

    newtup = heap_modify_tuple(tup, RelationGetDescr(rel),
                               repl_val, repl_null, repl_repl);

    simple_heap_update(rel, &newtup->t_self, newtup);

    CatalogUpdateIndexes(rel, newtup);

    InvokeObjectPostAlterHook(TSDictionaryRelationId, dictId, 0);

    /*
     * NOTE: because we only support altering the options, not the template,
     * there is no need to update dependencies.  This might have to change if
     * the options ever reference inside-the-database objects.
     */

    heap_freetuple(newtup);
    ReleaseSysCache(tup);

    heap_close(rel, RowExclusiveLock);

    return dictId;
}

Oid AlterUserMapping ( AlterUserMappingStmt stmt  ) 

Definition at line 1168 of file foreigncmds.c.

References Anum_pg_user_mapping_umoptions, CatalogUpdateIndexes(), DatumGetPointer, elog, ereport, errcode(), errmsg(), ERROR, ForeignServer::fdwid, ForeignDataWrapper::fdwvalidator, GetForeignDataWrapper(), GetForeignServerByName(), GetSysCacheOid2, GetUserOidFromMapping(), heap_close, heap_freetuple(), heap_modify_tuple(), heap_open(), HeapTupleIsValid, MappingUserName, NULL, ObjectIdGetDatum, OidIsValid, AlterUserMappingStmt::options, PointerGetDatum, PointerIsValid, RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, ForeignServer::serverid, AlterUserMappingStmt::servername, simple_heap_update(), SysCacheGetAttr(), HeapTupleData::t_self, transformGenericOptions(), user_mapping_ddl_aclcheck(), USERMAPPINGOID, UserMappingRelationId, USERMAPPINGUSERSERVER, and AlterUserMappingStmt::username.

Referenced by ProcessUtilitySlow().

{
    Relation    rel;
    HeapTuple   tp;
    Datum       repl_val[Natts_pg_user_mapping];
    bool        repl_null[Natts_pg_user_mapping];
    bool        repl_repl[Natts_pg_user_mapping];
    Oid         useId;
    Oid         umId;
    ForeignServer *srv;

    rel = heap_open(UserMappingRelationId, RowExclusiveLock);

    useId = GetUserOidFromMapping(stmt->username, false);
    srv = GetForeignServerByName(stmt->servername, false);

    umId = GetSysCacheOid2(USERMAPPINGUSERSERVER,
                           ObjectIdGetDatum(useId),
                           ObjectIdGetDatum(srv->serverid));
    if (!OidIsValid(umId))
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_OBJECT),
                 errmsg("user mapping \"%s\" does not exist for the server",
                        MappingUserName(useId))));

    user_mapping_ddl_aclcheck(useId, srv->serverid, stmt->servername);

    tp = SearchSysCacheCopy1(USERMAPPINGOID, ObjectIdGetDatum(umId));

    if (!HeapTupleIsValid(tp))
        elog(ERROR, "cache lookup failed for user mapping %u", umId);

    memset(repl_val, 0, sizeof(repl_val));
    memset(repl_null, false, sizeof(repl_null));
    memset(repl_repl, false, sizeof(repl_repl));

    if (stmt->options)
    {
        ForeignDataWrapper *fdw;
        Datum       datum;
        bool        isnull;

        /*
         * Process the options.
         */

        fdw = GetForeignDataWrapper(srv->fdwid);

        datum = SysCacheGetAttr(USERMAPPINGUSERSERVER,
                                tp,
                                Anum_pg_user_mapping_umoptions,
                                &isnull);
        if (isnull)
            datum = PointerGetDatum(NULL);

        /* Prepare the options array */
        datum = transformGenericOptions(UserMappingRelationId,
                                        datum,
                                        stmt->options,
                                        fdw->fdwvalidator);

        if (PointerIsValid(DatumGetPointer(datum)))
            repl_val[Anum_pg_user_mapping_umoptions - 1] = datum;
        else
            repl_null[Anum_pg_user_mapping_umoptions - 1] = true;

        repl_repl[Anum_pg_user_mapping_umoptions - 1] = true;
    }

    /* Everything looks good - update the tuple */
    tp = heap_modify_tuple(tp, RelationGetDescr(rel),
                           repl_val, repl_null, repl_repl);

    simple_heap_update(rel, &tp->t_self, tp);
    CatalogUpdateIndexes(rel, tp);

    heap_freetuple(tp);

    heap_close(rel, RowExclusiveLock);

    return umId;
}

bool CheckIndexCompatible ( Oid  oldId,
RangeVar heapRelation,
char *  accessMethodName,
List attributeList,
List exclusionOpNames 
)

Definition at line 114 of file indexcmds.c.

References AccessShareLock, AMNAME, Anum_pg_index_indclass, Anum_pg_index_indcollation, Anum_pg_index_indexprs, Anum_pg_index_indpred, Assert, tupleDesc::attrs, ComputeIndexAttrs(), DatumGetPointer, elog, ereport, errcode(), errmsg(), ERROR, get_opclass_input_type(), GETSTRUCT, heap_attisnull(), HeapTupleGetOid, HeapTupleIsValid, i, IndexInfo::ii_ExclusionOps, IndexInfo::ii_ExclusionProcs, IndexInfo::ii_ExclusionStrats, IndexInfo::ii_Expressions, IndexInfo::ii_ExpressionsState, IndexInfo::ii_PredicateState, index_close(), INDEX_MAX_KEYS, index_open(), IndexIsValid, INDEXRELID, IsPolymorphicType, list_length(), makeNode, memcmp(), NoLock, NULL, ObjectIdGetDatum, op_input_types(), palloc(), PointerGetDatum, RangeVarGetRelid, RelationData::rd_att, RelationGetExclusionInfo(), ReleaseSysCache(), SearchSysCache1, SysCacheGetAttr(), and oidvector::values.

Referenced by TryReuseIndex().

{
    bool        isconstraint;
    Oid        *typeObjectId;
    Oid        *collationObjectId;
    Oid        *classObjectId;
    Oid         accessMethodId;
    Oid         relationId;
    HeapTuple   tuple;
    Form_pg_index indexForm;
    Form_pg_am  accessMethodForm;
    bool        amcanorder;
    int16      *coloptions;
    IndexInfo  *indexInfo;
    int         numberOfAttributes;
    int         old_natts;
    bool        isnull;
    bool        ret = true;
    oidvector  *old_indclass;
    oidvector  *old_indcollation;
    Relation    irel;
    int         i;
    Datum       d;

    /* Caller should already have the relation locked in some way. */
    relationId = RangeVarGetRelid(heapRelation, NoLock, false);

    /*
     * We can pretend isconstraint = false unconditionally.  It only serves to
     * decide the text of an error message that should never happen for us.
     */
    isconstraint = false;

    numberOfAttributes = list_length(attributeList);
    Assert(numberOfAttributes > 0);
    Assert(numberOfAttributes <= INDEX_MAX_KEYS);

    /* look up the access method */
    tuple = SearchSysCache1(AMNAME, PointerGetDatum(accessMethodName));
    if (!HeapTupleIsValid(tuple))
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_OBJECT),
                 errmsg("access method \"%s\" does not exist",
                        accessMethodName)));
    accessMethodId = HeapTupleGetOid(tuple);
    accessMethodForm = (Form_pg_am) GETSTRUCT(tuple);
    amcanorder = accessMethodForm->amcanorder;
    ReleaseSysCache(tuple);

    /*
     * Compute the operator classes, collations, and exclusion operators for
     * the new index, so we can test whether it's compatible with the existing
     * one.  Note that ComputeIndexAttrs might fail here, but that's OK:
     * DefineIndex would have called this function with the same arguments
     * later on, and it would have failed then anyway.
     */
    indexInfo = makeNode(IndexInfo);
    indexInfo->ii_Expressions = NIL;
    indexInfo->ii_ExpressionsState = NIL;
    indexInfo->ii_PredicateState = NIL;
    indexInfo->ii_ExclusionOps = NULL;
    indexInfo->ii_ExclusionProcs = NULL;
    indexInfo->ii_ExclusionStrats = NULL;
    typeObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
    collationObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
    classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
    coloptions = (int16 *) palloc(numberOfAttributes * sizeof(int16));
    ComputeIndexAttrs(indexInfo,
                      typeObjectId, collationObjectId, classObjectId,
                      coloptions, attributeList,
                      exclusionOpNames, relationId,
                      accessMethodName, accessMethodId,
                      amcanorder, isconstraint);


    /* Get the soon-obsolete pg_index tuple. */
    tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(oldId));
    if (!HeapTupleIsValid(tuple))
        elog(ERROR, "cache lookup failed for index %u", oldId);
    indexForm = (Form_pg_index) GETSTRUCT(tuple);

    /*
     * We don't assess expressions or predicates; assume incompatibility.
     * Also, if the index is invalid for any reason, treat it as incompatible.
     */
    if (!(heap_attisnull(tuple, Anum_pg_index_indpred) &&
          heap_attisnull(tuple, Anum_pg_index_indexprs) &&
          IndexIsValid(indexForm)))
    {
        ReleaseSysCache(tuple);
        return false;
    }

    /* Any change in operator class or collation breaks compatibility. */
    old_natts = indexForm->indnatts;
    Assert(old_natts == numberOfAttributes);

    d = SysCacheGetAttr(INDEXRELID, tuple, Anum_pg_index_indcollation, &isnull);
    Assert(!isnull);
    old_indcollation = (oidvector *) DatumGetPointer(d);

    d = SysCacheGetAttr(INDEXRELID, tuple, Anum_pg_index_indclass, &isnull);
    Assert(!isnull);
    old_indclass = (oidvector *) DatumGetPointer(d);

    ret = (memcmp(old_indclass->values, classObjectId,
                  old_natts * sizeof(Oid)) == 0 &&
           memcmp(old_indcollation->values, collationObjectId,
                  old_natts * sizeof(Oid)) == 0);

    ReleaseSysCache(tuple);

    if (!ret)
        return false;

    /* For polymorphic opcintype, column type changes break compatibility. */
    irel = index_open(oldId, AccessShareLock);  /* caller probably has a lock */
    for (i = 0; i < old_natts; i++)
    {
        if (IsPolymorphicType(get_opclass_input_type(classObjectId[i])) &&
            irel->rd_att->attrs[i]->atttypid != typeObjectId[i])
        {
            ret = false;
            break;
        }
    }

    /* Any change in exclusion operator selections breaks compatibility. */
    if (ret && indexInfo->ii_ExclusionOps != NULL)
    {
        Oid        *old_operators,
                   *old_procs;
        uint16     *old_strats;

        RelationGetExclusionInfo(irel, &old_operators, &old_procs, &old_strats);
        ret = memcmp(old_operators, indexInfo->ii_ExclusionOps,
                     old_natts * sizeof(Oid)) == 0;

        /* Require an exact input type match for polymorphic operators. */
        if (ret)
        {
            for (i = 0; i < old_natts && ret; i++)
            {
                Oid         left,
                            right;

                op_input_types(indexInfo->ii_ExclusionOps[i], &left, &right);
                if ((IsPolymorphicType(left) || IsPolymorphicType(right)) &&
                    irel->rd_att->attrs[i]->atttypid != typeObjectId[i])
                {
                    ret = false;
                    break;
                }
            }
        }
    }

    index_close(irel, NoLock);
    return ret;
}

char* ChooseRelationName ( const char *  name1,
const char *  name2,
const char *  label,
Oid  namespaceid 
)

Definition at line 1512 of file indexcmds.c.

References get_relname_relid(), makeObjectName(), OidIsValid, pfree(), snprintf(), and StrNCpy.

Referenced by ChooseIndexName(), and transformColumnDefinition().

{
    int         pass = 0;
    char       *relname = NULL;
    char        modlabel[NAMEDATALEN];

    /* try the unmodified label first */
    StrNCpy(modlabel, label, sizeof(modlabel));

    for (;;)
    {
        relname = makeObjectName(name1, name2, modlabel);

        if (!OidIsValid(get_relname_relid(relname, namespaceid)))
            break;

        /* found a conflict, so try a new name component */
        pfree(relname);
        snprintf(modlabel, sizeof(modlabel), "%s%d", label, ++pass);
    }

    return relname;
}

Oid CreateCast ( CreateCastStmt stmt  ) 

Definition at line 1256 of file functioncmds.c.

References ACL_USAGE, aclcheck_error_type(), ACLCHECK_OK, Anum_pg_cast_castcontext, Anum_pg_cast_castfunc, Anum_pg_cast_castmethod, Anum_pg_cast_castsource, Anum_pg_cast_casttarget, BOOLOID, CastRelationId, CASTSOURCETARGET, CatalogUpdateIndexes(), CharGetDatum, ObjectAddress::classId, COERCION_ASSIGNMENT, COERCION_EXPLICIT, COERCION_IMPLICIT, COERCION_METHOD_BINARY, COERCION_METHOD_FUNCTION, CreateCastStmt::context, DEPENDENCY_NORMAL, elog, ereport, errcode(), errmsg(), ERROR, format_type_be(), CreateCastStmt::func, FuncWithArgs::funcargs, FuncWithArgs::funcname, get_element_type(), get_typlenbyvalalign(), get_typtype(), GETSTRUCT, GetUserId(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), HeapTupleIsValid, CreateCastStmt::inout, INT4OID, InvokeObjectPostCreateHook, IsBinaryCoercible(), LookupFuncNameTypeNames(), MemSet, NULL, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, pg_type_aclcheck(), pg_type_ownercheck(), PROCOID, PROVOLATILE_VOLATILE, recordDependencyOn(), recordDependencyOnCurrentExtension(), RelationGetDescr, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1, SearchSysCache2, simple_heap_insert(), CreateCastStmt::sourcetype, superuser(), CreateCastStmt::targettype, TypeNameToString(), typenameTypeId(), TYPTYPE_COMPOSITE, TYPTYPE_DOMAIN, TYPTYPE_ENUM, TYPTYPE_PSEUDO, values, and WARNING.

Referenced by ProcessUtilitySlow().

{
    Oid         sourcetypeid;
    Oid         targettypeid;
    char        sourcetyptype;
    char        targettyptype;
    Oid         funcid;
    Oid         castid;
    int         nargs;
    char        castcontext;
    char        castmethod;
    Relation    relation;
    HeapTuple   tuple;
    Datum       values[Natts_pg_cast];
    bool        nulls[Natts_pg_cast];
    ObjectAddress myself,
                referenced;
    AclResult   aclresult;

    sourcetypeid = typenameTypeId(NULL, stmt->sourcetype);
    targettypeid = typenameTypeId(NULL, stmt->targettype);
    sourcetyptype = get_typtype(sourcetypeid);
    targettyptype = get_typtype(targettypeid);

    /* No pseudo-types allowed */
    if (sourcetyptype == TYPTYPE_PSEUDO)
        ereport(ERROR,
                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                 errmsg("source data type %s is a pseudo-type",
                        TypeNameToString(stmt->sourcetype))));

    if (targettyptype == TYPTYPE_PSEUDO)
        ereport(ERROR,
                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                 errmsg("target data type %s is a pseudo-type",
                        TypeNameToString(stmt->targettype))));

    /* Permission check */
    if (!pg_type_ownercheck(sourcetypeid, GetUserId())
        && !pg_type_ownercheck(targettypeid, GetUserId()))
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 errmsg("must be owner of type %s or type %s",
                        format_type_be(sourcetypeid),
                        format_type_be(targettypeid))));

    aclresult = pg_type_aclcheck(sourcetypeid, GetUserId(), ACL_USAGE);
    if (aclresult != ACLCHECK_OK)
        aclcheck_error_type(aclresult, sourcetypeid);

    aclresult = pg_type_aclcheck(targettypeid, GetUserId(), ACL_USAGE);
    if (aclresult != ACLCHECK_OK)
        aclcheck_error_type(aclresult, targettypeid);

    /* Domains are allowed for historical reasons, but we warn */
    if (sourcetyptype == TYPTYPE_DOMAIN)
        ereport(WARNING,
                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                 errmsg("cast will be ignored because the source data type is a domain")));

    else if (targettyptype == TYPTYPE_DOMAIN)
        ereport(WARNING,
                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                 errmsg("cast will be ignored because the target data type is a domain")));

    /* Detemine the cast method */
    if (stmt->func != NULL)
        castmethod = COERCION_METHOD_FUNCTION;
    else if (stmt->inout)
        castmethod = COERCION_METHOD_INOUT;
    else
        castmethod = COERCION_METHOD_BINARY;

    if (castmethod == COERCION_METHOD_FUNCTION)
    {
        Form_pg_proc procstruct;

        funcid = LookupFuncNameTypeNames(stmt->func->funcname,
                                         stmt->func->funcargs,
                                         false);

        tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
        if (!HeapTupleIsValid(tuple))
            elog(ERROR, "cache lookup failed for function %u", funcid);

        procstruct = (Form_pg_proc) GETSTRUCT(tuple);
        nargs = procstruct->pronargs;
        if (nargs < 1 || nargs > 3)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                  errmsg("cast function must take one to three arguments")));
        if (!IsBinaryCoercible(sourcetypeid, procstruct->proargtypes.values[0]))
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                     errmsg("argument of cast function must match or be binary-coercible from source data type")));
        if (nargs > 1 && procstruct->proargtypes.values[1] != INT4OID)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
            errmsg("second argument of cast function must be type integer")));
        if (nargs > 2 && procstruct->proargtypes.values[2] != BOOLOID)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
            errmsg("third argument of cast function must be type boolean")));
        if (!IsBinaryCoercible(procstruct->prorettype, targettypeid))
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                     errmsg("return data type of cast function must match or be binary-coercible to target data type")));

        /*
         * Restricting the volatility of a cast function may or may not be a
         * good idea in the abstract, but it definitely breaks many old
         * user-defined types.  Disable this check --- tgl 2/1/03
         */
#ifdef NOT_USED
        if (procstruct->provolatile == PROVOLATILE_VOLATILE)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                     errmsg("cast function must not be volatile")));
#endif
        if (procstruct->proisagg)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                 errmsg("cast function must not be an aggregate function")));
        if (procstruct->proiswindow)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                     errmsg("cast function must not be a window function")));
        if (procstruct->proretset)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                     errmsg("cast function must not return a set")));

        ReleaseSysCache(tuple);
    }
    else
    {
        funcid = InvalidOid;
        nargs = 0;
    }

    if (castmethod == COERCION_METHOD_BINARY)
    {
        int16       typ1len;
        int16       typ2len;
        bool        typ1byval;
        bool        typ2byval;
        char        typ1align;
        char        typ2align;

        /*
         * Must be superuser to create binary-compatible casts, since
         * erroneous casts can easily crash the backend.
         */
        if (!superuser())
            ereport(ERROR,
                    (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
             errmsg("must be superuser to create a cast WITHOUT FUNCTION")));

        /*
         * Also, insist that the types match as to size, alignment, and
         * pass-by-value attributes; this provides at least a crude check that
         * they have similar representations.  A pair of types that fail this
         * test should certainly not be equated.
         */
        get_typlenbyvalalign(sourcetypeid, &typ1len, &typ1byval, &typ1align);
        get_typlenbyvalalign(targettypeid, &typ2len, &typ2byval, &typ2align);
        if (typ1len != typ2len ||
            typ1byval != typ2byval ||
            typ1align != typ2align)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                     errmsg("source and target data types are not physically compatible")));

        /*
         * We know that composite, enum and array types are never binary-
         * compatible with each other.  They all have OIDs embedded in them.
         *
         * Theoretically you could build a user-defined base type that is
         * binary-compatible with a composite, enum, or array type.  But we
         * disallow that too, as in practice such a cast is surely a mistake.
         * You can always work around that by writing a cast function.
         */
        if (sourcetyptype == TYPTYPE_COMPOSITE ||
            targettyptype == TYPTYPE_COMPOSITE)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                  errmsg("composite data types are not binary-compatible")));

        if (sourcetyptype == TYPTYPE_ENUM ||
            targettyptype == TYPTYPE_ENUM)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                     errmsg("enum data types are not binary-compatible")));

        if (OidIsValid(get_element_type(sourcetypeid)) ||
            OidIsValid(get_element_type(targettypeid)))
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                     errmsg("array data types are not binary-compatible")));

        /*
         * We also disallow creating binary-compatibility casts involving
         * domains.  Casting from a domain to its base type is already
         * allowed, and casting the other way ought to go through domain
         * coercion to permit constraint checking.  Again, if you're intent on
         * having your own semantics for that, create a no-op cast function.
         *
         * NOTE: if we were to relax this, the above checks for composites
         * etc. would have to be modified to look through domains to their
         * base types.
         */
        if (sourcetyptype == TYPTYPE_DOMAIN ||
            targettyptype == TYPTYPE_DOMAIN)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                     errmsg("domain data types must not be marked binary-compatible")));
    }

    /*
     * Allow source and target types to be same only for length coercion
     * functions.  We assume a multi-arg function does length coercion.
     */
    if (sourcetypeid == targettypeid && nargs < 2)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
              errmsg("source data type and target data type are the same")));

    /* convert CoercionContext enum to char value for castcontext */
    switch (stmt->context)
    {
        case COERCION_IMPLICIT:
            castcontext = COERCION_CODE_IMPLICIT;
            break;
        case COERCION_ASSIGNMENT:
            castcontext = COERCION_CODE_ASSIGNMENT;
            break;
        case COERCION_EXPLICIT:
            castcontext = COERCION_CODE_EXPLICIT;
            break;
        default:
            elog(ERROR, "unrecognized CoercionContext: %d", stmt->context);
            castcontext = 0;    /* keep compiler quiet */
            break;
    }

    relation = heap_open(CastRelationId, RowExclusiveLock);

    /*
     * Check for duplicate.  This is just to give a friendly error message,
     * the unique index would catch it anyway (so no need to sweat about race
     * conditions).
     */
    tuple = SearchSysCache2(CASTSOURCETARGET,
                            ObjectIdGetDatum(sourcetypeid),
                            ObjectIdGetDatum(targettypeid));
    if (HeapTupleIsValid(tuple))
        ereport(ERROR,
                (errcode(ERRCODE_DUPLICATE_OBJECT),
                 errmsg("cast from type %s to type %s already exists",
                        format_type_be(sourcetypeid),
                        format_type_be(targettypeid))));

    /* ready to go */
    values[Anum_pg_cast_castsource - 1] = ObjectIdGetDatum(sourcetypeid);
    values[Anum_pg_cast_casttarget - 1] = ObjectIdGetDatum(targettypeid);
    values[Anum_pg_cast_castfunc - 1] = ObjectIdGetDatum(funcid);
    values[Anum_pg_cast_castcontext - 1] = CharGetDatum(castcontext);
    values[Anum_pg_cast_castmethod - 1] = CharGetDatum(castmethod);

    MemSet(nulls, false, sizeof(nulls));

    tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);

    castid = simple_heap_insert(relation, tuple);

    CatalogUpdateIndexes(relation, tuple);

    /* make dependency entries */
    myself.classId = CastRelationId;
    myself.objectId = castid;
    myself.objectSubId = 0;

    /* dependency on source type */
    referenced.classId = TypeRelationId;
    referenced.objectId = sourcetypeid;
    referenced.objectSubId = 0;
    recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

    /* dependency on target type */
    referenced.classId = TypeRelationId;
    referenced.objectId = targettypeid;
    referenced.objectSubId = 0;
    recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

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

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

    /* Post creation hook for new cast */
    InvokeObjectPostCreateHook(CastRelationId, castid, 0);

    heap_freetuple(tuple);

    heap_close(relation, RowExclusiveLock);

    return castid;
}

Oid CreateForeignDataWrapper ( CreateFdwStmt stmt  ) 

Definition at line 506 of file foreigncmds.c.

References Anum_pg_foreign_data_wrapper_fdwacl, Anum_pg_foreign_data_wrapper_fdwhandler, Anum_pg_foreign_data_wrapper_fdwname, Anum_pg_foreign_data_wrapper_fdwoptions, Anum_pg_foreign_data_wrapper_fdwowner, Anum_pg_foreign_data_wrapper_fdwvalidator, CatalogUpdateIndexes(), ObjectAddress::classId, CStringGetDatum, DatumGetPointer, DEPENDENCY_NORMAL, DirectFunctionCall1, ereport, errcode(), errhint(), errmsg(), ERROR, CreateFdwStmt::fdwname, ForeignDataWrapperRelationId, CreateFdwStmt::func_options, GetForeignDataWrapperByName(), GetUserId(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), InvokeObjectPostCreateHook, namein(), NULL, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, CreateFdwStmt::options, parse_func_options(), PointerGetDatum, PointerIsValid, RelationData::rd_att, recordDependencyOn(), recordDependencyOnCurrentExtension(), recordDependencyOnOwner(), RowExclusiveLock, simple_heap_insert(), superuser(), transformGenericOptions(), and values.

Referenced by ProcessUtilitySlow().

{
    Relation    rel;
    Datum       values[Natts_pg_foreign_data_wrapper];
    bool        nulls[Natts_pg_foreign_data_wrapper];
    HeapTuple   tuple;
    Oid         fdwId;
    bool        handler_given;
    bool        validator_given;
    Oid         fdwhandler;
    Oid         fdwvalidator;
    Datum       fdwoptions;
    Oid         ownerId;
    ObjectAddress myself;
    ObjectAddress referenced;

    rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);

    /* Must be super user */
    if (!superuser())
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
            errmsg("permission denied to create foreign-data wrapper \"%s\"",
                   stmt->fdwname),
            errhint("Must be superuser to create a foreign-data wrapper.")));

    /* For now the owner cannot be specified on create. Use effective user ID. */
    ownerId = GetUserId();

    /*
     * Check that there is no other foreign-data wrapper by this name.
     */
    if (GetForeignDataWrapperByName(stmt->fdwname, true) != NULL)
        ereport(ERROR,
                (errcode(ERRCODE_DUPLICATE_OBJECT),
                 errmsg("foreign-data wrapper \"%s\" already exists",
                        stmt->fdwname)));

    /*
     * Insert tuple into pg_foreign_data_wrapper.
     */
    memset(values, 0, sizeof(values));
    memset(nulls, false, sizeof(nulls));

    values[Anum_pg_foreign_data_wrapper_fdwname - 1] =
        DirectFunctionCall1(namein, CStringGetDatum(stmt->fdwname));
    values[Anum_pg_foreign_data_wrapper_fdwowner - 1] = ObjectIdGetDatum(ownerId);

    /* Lookup handler and validator functions, if given */
    parse_func_options(stmt->func_options,
                       &handler_given, &fdwhandler,
                       &validator_given, &fdwvalidator);

    values[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = ObjectIdGetDatum(fdwhandler);
    values[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = ObjectIdGetDatum(fdwvalidator);

    nulls[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true;

    fdwoptions = transformGenericOptions(ForeignDataWrapperRelationId,
                                         PointerGetDatum(NULL),
                                         stmt->options,
                                         fdwvalidator);

    if (PointerIsValid(DatumGetPointer(fdwoptions)))
        values[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = fdwoptions;
    else
        nulls[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true;

    tuple = heap_form_tuple(rel->rd_att, values, nulls);

    fdwId = simple_heap_insert(rel, tuple);
    CatalogUpdateIndexes(rel, tuple);

    heap_freetuple(tuple);

    /* record dependencies */
    myself.classId = ForeignDataWrapperRelationId;
    myself.objectId = fdwId;
    myself.objectSubId = 0;

    if (OidIsValid(fdwhandler))
    {
        referenced.classId = ProcedureRelationId;
        referenced.objectId = fdwhandler;
        referenced.objectSubId = 0;
        recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
    }

    if (OidIsValid(fdwvalidator))
    {
        referenced.classId = ProcedureRelationId;
        referenced.objectId = fdwvalidator;
        referenced.objectSubId = 0;
        recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
    }

    recordDependencyOnOwner(ForeignDataWrapperRelationId, fdwId, ownerId);

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

    /* Post creation hook for new foreign data wrapper */
    InvokeObjectPostCreateHook(ForeignDataWrapperRelationId, fdwId, 0);

    heap_close(rel, RowExclusiveLock);

    return fdwId;
}

Oid CreateForeignServer ( CreateForeignServerStmt stmt  ) 

Definition at line 809 of file foreigncmds.c.

References ACL_KIND_FDW, ACL_USAGE, aclcheck_error(), ACLCHECK_OK, Anum_pg_foreign_server_srvacl, Anum_pg_foreign_server_srvfdw, Anum_pg_foreign_server_srvname, Anum_pg_foreign_server_srvoptions, Anum_pg_foreign_server_srvowner, Anum_pg_foreign_server_srvtype, Anum_pg_foreign_server_srvversion, CatalogUpdateIndexes(), ObjectAddress::classId, CStringGetDatum, CStringGetTextDatum, DatumGetPointer, DEPENDENCY_NORMAL, DirectFunctionCall1, ereport, errcode(), errmsg(), ERROR, ForeignDataWrapper::fdwid, ForeignDataWrapper::fdwname, CreateForeignServerStmt::fdwname, ForeignDataWrapper::fdwvalidator, ForeignServerRelationId, GetForeignDataWrapperByName(), GetForeignServerByName(), GetUserId(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), InvokeObjectPostCreateHook, namein(), NULL, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, CreateForeignServerStmt::options, pg_foreign_data_wrapper_aclcheck(), PointerGetDatum, PointerIsValid, RelationData::rd_att, recordDependencyOn(), recordDependencyOnCurrentExtension(), recordDependencyOnOwner(), RowExclusiveLock, CreateForeignServerStmt::servername, CreateForeignServerStmt::servertype, simple_heap_insert(), transformGenericOptions(), values, and CreateForeignServerStmt::version.

Referenced by ProcessUtilitySlow().

{
    Relation    rel;
    Datum       srvoptions;
    Datum       values[Natts_pg_foreign_server];
    bool        nulls[Natts_pg_foreign_server];
    HeapTuple   tuple;
    Oid         srvId;
    Oid         ownerId;
    AclResult   aclresult;
    ObjectAddress myself;
    ObjectAddress referenced;
    ForeignDataWrapper *fdw;

    rel = heap_open(ForeignServerRelationId, RowExclusiveLock);

    /* For now the owner cannot be specified on create. Use effective user ID. */
    ownerId = GetUserId();

    /*
     * Check that there is no other foreign server by this name.
     */
    if (GetForeignServerByName(stmt->servername, true) != NULL)
        ereport(ERROR,
                (errcode(ERRCODE_DUPLICATE_OBJECT),
                 errmsg("server \"%s\" already exists",
                        stmt->servername)));

    /*
     * Check that the FDW exists and that we have USAGE on it. Also get the
     * actual FDW for option validation etc.
     */
    fdw = GetForeignDataWrapperByName(stmt->fdwname, false);

    aclresult = pg_foreign_data_wrapper_aclcheck(fdw->fdwid, ownerId, ACL_USAGE);
    if (aclresult != ACLCHECK_OK)
        aclcheck_error(aclresult, ACL_KIND_FDW, fdw->fdwname);

    /*
     * Insert tuple into pg_foreign_server.
     */
    memset(values, 0, sizeof(values));
    memset(nulls, false, sizeof(nulls));

    values[Anum_pg_foreign_server_srvname - 1] =
        DirectFunctionCall1(namein, CStringGetDatum(stmt->servername));
    values[Anum_pg_foreign_server_srvowner - 1] = ObjectIdGetDatum(ownerId);
    values[Anum_pg_foreign_server_srvfdw - 1] = ObjectIdGetDatum(fdw->fdwid);

    /* Add server type if supplied */
    if (stmt->servertype)
        values[Anum_pg_foreign_server_srvtype - 1] =
            CStringGetTextDatum(stmt->servertype);
    else
        nulls[Anum_pg_foreign_server_srvtype - 1] = true;

    /* Add server version if supplied */
    if (stmt->version)
        values[Anum_pg_foreign_server_srvversion - 1] =
            CStringGetTextDatum(stmt->version);
    else
        nulls[Anum_pg_foreign_server_srvversion - 1] = true;

    /* Start with a blank acl */
    nulls[Anum_pg_foreign_server_srvacl - 1] = true;

    /* Add server options */
    srvoptions = transformGenericOptions(ForeignServerRelationId,
                                         PointerGetDatum(NULL),
                                         stmt->options,
                                         fdw->fdwvalidator);

    if (PointerIsValid(DatumGetPointer(srvoptions)))
        values[Anum_pg_foreign_server_srvoptions - 1] = srvoptions;
    else
        nulls[Anum_pg_foreign_server_srvoptions - 1] = true;

    tuple = heap_form_tuple(rel->rd_att, values, nulls);

    srvId = simple_heap_insert(rel, tuple);

    CatalogUpdateIndexes(rel, tuple);

    heap_freetuple(tuple);

    /* record dependencies */
    myself.classId = ForeignServerRelationId;
    myself.objectId = srvId;
    myself.objectSubId = 0;

    referenced.classId = ForeignDataWrapperRelationId;
    referenced.objectId = fdw->fdwid;
    referenced.objectSubId = 0;
    recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

    recordDependencyOnOwner(ForeignServerRelationId, srvId, ownerId);

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

    /* Post creation hook for new foreign server */
    InvokeObjectPostCreateHook(ForeignServerRelationId, srvId, 0);

    heap_close(rel, RowExclusiveLock);

    return srvId;
}

void CreateForeignTable ( CreateForeignTableStmt stmt,
Oid  relid 
)

Definition at line 1350 of file foreigncmds.c.

References ACL_KIND_FOREIGN_SERVER, ACL_USAGE, aclcheck_error(), ACLCHECK_OK, Anum_pg_foreign_table_ftoptions, Anum_pg_foreign_table_ftrelid, Anum_pg_foreign_table_ftserver, CatalogUpdateIndexes(), ObjectAddress::classId, CommandCounterIncrement(), DatumGetPointer, DEPENDENCY_NORMAL, ForeignServer::fdwid, ForeignDataWrapper::fdwvalidator, ForeignTableRelationId, GetForeignDataWrapper(), GetForeignServerByName(), GetUserId(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), NULL, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, CreateForeignTableStmt::options, pg_foreign_server_aclcheck(), PointerGetDatum, PointerIsValid, RelationData::rd_att, recordDependencyOn(), RowExclusiveLock, ForeignServer::serverid, ForeignServer::servername, CreateForeignTableStmt::servername, simple_heap_insert(), transformGenericOptions(), and values.

Referenced by ProcessUtilitySlow().

{
    Relation    ftrel;
    Datum       ftoptions;
    Datum       values[Natts_pg_foreign_table];
    bool        nulls[Natts_pg_foreign_table];
    HeapTuple   tuple;
    AclResult   aclresult;
    ObjectAddress myself;
    ObjectAddress referenced;
    Oid         ownerId;
    ForeignDataWrapper *fdw;
    ForeignServer *server;

    /*
     * Advance command counter to ensure the pg_attribute tuple is visible;
     * the tuple might be updated to add constraints in previous step.
     */
    CommandCounterIncrement();

    ftrel = heap_open(ForeignTableRelationId, RowExclusiveLock);

    /*
     * For now the owner cannot be specified on create. Use effective user ID.
     */
    ownerId = GetUserId();

    /*
     * Check that the foreign server exists and that we have USAGE on it. Also
     * get the actual FDW for option validation etc.
     */
    server = GetForeignServerByName(stmt->servername, false);
    aclresult = pg_foreign_server_aclcheck(server->serverid, ownerId, ACL_USAGE);
    if (aclresult != ACLCHECK_OK)
        aclcheck_error(aclresult, ACL_KIND_FOREIGN_SERVER, server->servername);

    fdw = GetForeignDataWrapper(server->fdwid);

    /*
     * Insert tuple into pg_foreign_table.
     */
    memset(values, 0, sizeof(values));
    memset(nulls, false, sizeof(nulls));

    values[Anum_pg_foreign_table_ftrelid - 1] = ObjectIdGetDatum(relid);
    values[Anum_pg_foreign_table_ftserver - 1] = ObjectIdGetDatum(server->serverid);
    /* Add table generic options */
    ftoptions = transformGenericOptions(ForeignTableRelationId,
                                        PointerGetDatum(NULL),
                                        stmt->options,
                                        fdw->fdwvalidator);

    if (PointerIsValid(DatumGetPointer(ftoptions)))
        values[Anum_pg_foreign_table_ftoptions - 1] = ftoptions;
    else
        nulls[Anum_pg_foreign_table_ftoptions - 1] = true;

    tuple = heap_form_tuple(ftrel->rd_att, values, nulls);

    simple_heap_insert(ftrel, tuple);
    CatalogUpdateIndexes(ftrel, tuple);

    heap_freetuple(tuple);

    /* Add pg_class dependency on the server */
    myself.classId = RelationRelationId;
    myself.objectId = relid;
    myself.objectSubId = 0;

    referenced.classId = ForeignServerRelationId;
    referenced.objectId = server->serverid;
    referenced.objectSubId = 0;
    recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

    heap_close(ftrel, RowExclusiveLock);
}

Oid CreateFunction ( CreateFunctionStmt stmt,
const char *  queryString 
)

Definition at line 788 of file functioncmds.c.

References ACL_CREATE, ACL_KIND_LANGUAGE, ACL_KIND_NAMESPACE, ACL_USAGE, aclcheck_error(), ACLCHECK_NO_PRIV, ACLCHECK_OK, ClanguageId, compute_attributes_sql_style(), compute_attributes_with_style(), compute_return_type(), ereport, errcode(), errhint(), errmsg(), ERROR, examine_parameter_list(), format_type_be(), CreateFunctionStmt::funcname, get_namespace_name(), GETSTRUCT, GetUserId(), HeapTupleGetOid, HeapTupleIsValid, INTERNALlanguageId, interpret_AS_clause(), LANGNAME, NameStr, OidIsValid, CreateFunctionStmt::options, CreateFunctionStmt::parameters, pg_language_aclcheck(), pg_namespace_aclcheck(), PLTemplateExists(), PointerGetDatum, ProcedureCreate(), QualifiedNameGetCreationNamespace(), ReleaseSysCache(), CreateFunctionStmt::replace, CreateFunctionStmt::returnType, SearchSysCache1, superuser(), and CreateFunctionStmt::withClause.

Referenced by ProcessUtilitySlow().

{
    char       *probin_str;
    char       *prosrc_str;
    Oid         prorettype;
    bool        returnsSet;
    char       *language;
    Oid         languageOid;
    Oid         languageValidator;
    char       *funcname;
    Oid         namespaceId;
    AclResult   aclresult;
    oidvector  *parameterTypes;
    ArrayType  *allParameterTypes;
    ArrayType  *parameterModes;
    ArrayType  *parameterNames;
    List       *parameterDefaults;
    Oid         requiredResultType;
    bool        isWindowFunc,
                isStrict,
                security,
                isLeakProof;
    char        volatility;
    ArrayType  *proconfig;
    float4      procost;
    float4      prorows;
    HeapTuple   languageTuple;
    Form_pg_language languageStruct;
    List       *as_clause;

    /* Convert list of names to a name and namespace */
    namespaceId = QualifiedNameGetCreationNamespace(stmt->funcname,
                                                    &funcname);

    /* Check we have creation rights in target namespace */
    aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE);
    if (aclresult != ACLCHECK_OK)
        aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
                       get_namespace_name(namespaceId));

    /* default attributes */
    isWindowFunc = false;
    isStrict = false;
    security = false;
    isLeakProof = false;
    volatility = PROVOLATILE_VOLATILE;
    proconfig = NULL;
    procost = -1;               /* indicates not set */
    prorows = -1;               /* indicates not set */

    /* override attributes from explicit list */
    compute_attributes_sql_style(stmt->options,
                                 &as_clause, &language,
                                 &isWindowFunc, &volatility,
                                 &isStrict, &security, &isLeakProof,
                                 &proconfig, &procost, &prorows);

    /* Look up the language and validate permissions */
    languageTuple = SearchSysCache1(LANGNAME, PointerGetDatum(language));
    if (!HeapTupleIsValid(languageTuple))
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_OBJECT),
                 errmsg("language \"%s\" does not exist", language),
                 (PLTemplateExists(language) ?
                  errhint("Use CREATE LANGUAGE to load the language into the database.") : 0)));

    languageOid = HeapTupleGetOid(languageTuple);
    languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);

    if (languageStruct->lanpltrusted)
    {
        /* if trusted language, need USAGE privilege */
        AclResult   aclresult;

        aclresult = pg_language_aclcheck(languageOid, GetUserId(), ACL_USAGE);
        if (aclresult != ACLCHECK_OK)
            aclcheck_error(aclresult, ACL_KIND_LANGUAGE,
                           NameStr(languageStruct->lanname));
    }
    else
    {
        /* if untrusted language, must be superuser */
        if (!superuser())
            aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_LANGUAGE,
                           NameStr(languageStruct->lanname));
    }

    languageValidator = languageStruct->lanvalidator;

    ReleaseSysCache(languageTuple);

    /*
     * Only superuser is allowed to create leakproof functions because it
     * possibly allows unprivileged users to reference invisible tuples to be
     * filtered out using views for row-level security.
     */
    if (isLeakProof && !superuser())
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 errmsg("only superuser can define a leakproof function")));

    /*
     * Convert remaining parameters of CREATE to form wanted by
     * ProcedureCreate.
     */
    examine_parameter_list(stmt->parameters, languageOid, queryString,
                           &parameterTypes,
                           &allParameterTypes,
                           &parameterModes,
                           &parameterNames,
                           &parameterDefaults,
                           &requiredResultType);

    if (stmt->returnType)
    {
        /* explicit RETURNS clause */
        compute_return_type(stmt->returnType, languageOid,
                            &prorettype, &returnsSet);
        if (OidIsValid(requiredResultType) && prorettype != requiredResultType)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
                     errmsg("function result type must be %s because of OUT parameters",
                            format_type_be(requiredResultType))));
    }
    else if (OidIsValid(requiredResultType))
    {
        /* default RETURNS clause from OUT parameters */
        prorettype = requiredResultType;
        returnsSet = false;
    }
    else
    {
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
                 errmsg("function result type must be specified")));
        /* Alternative possibility: default to RETURNS VOID */
        prorettype = VOIDOID;
        returnsSet = false;
    }

    compute_attributes_with_style(stmt->withClause, &isStrict, &volatility);

    interpret_AS_clause(languageOid, language, funcname, as_clause,
                        &prosrc_str, &probin_str);

    /*
     * Set default values for COST and ROWS depending on other parameters;
     * reject ROWS if it's not returnsSet.  NB: pg_dump knows these default
     * values, keep it in sync if you change them.
     */
    if (procost < 0)
    {
        /* SQL and PL-language functions are assumed more expensive */
        if (languageOid == INTERNALlanguageId ||
            languageOid == ClanguageId)
            procost = 1;
        else
            procost = 100;
    }
    if (prorows < 0)
    {
        if (returnsSet)
            prorows = 1000;
        else
            prorows = 0;        /* dummy value if not returnsSet */
    }
    else if (!returnsSet)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("ROWS is not applicable when function does not return a set")));

    /*
     * And now that we have all the parameters, and know we're permitted to do
     * so, go ahead and create the function.
     */
    return ProcedureCreate(funcname,
                           namespaceId,
                           stmt->replace,
                           returnsSet,
                           prorettype,
                           GetUserId(),
                           languageOid,
                           languageValidator,
                           prosrc_str, /* converted to text later */
                           probin_str, /* converted to text later */
                           false,       /* not an aggregate */
                           isWindowFunc,
                           security,
                           isLeakProof,
                           isStrict,
                           volatility,
                           parameterTypes,
                           PointerGetDatum(allParameterTypes),
                           PointerGetDatum(parameterModes),
                           PointerGetDatum(parameterNames),
                           parameterDefaults,
                           PointerGetDatum(proconfig),
                           procost,
                           prorows);
}

Oid CreateUserMapping ( CreateUserMappingStmt stmt  ) 

Definition at line 1070 of file foreigncmds.c.

References Anum_pg_user_mapping_umoptions, Anum_pg_user_mapping_umserver, Anum_pg_user_mapping_umuser, CatalogUpdateIndexes(), ObjectAddress::classId, DatumGetPointer, DEPENDENCY_NORMAL, ereport, errcode(), errmsg(), ERROR, ForeignServer::fdwid, ForeignDataWrapper::fdwvalidator, GetForeignDataWrapper(), GetForeignServerByName(), GetSysCacheOid2, GetUserOidFromMapping(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), InvokeObjectPostCreateHook, MappingUserName, NULL, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, CreateUserMappingStmt::options, PointerGetDatum, PointerIsValid, RelationData::rd_att, recordDependencyOn(), recordDependencyOnCurrentExtension(), recordDependencyOnOwner(), RowExclusiveLock, ForeignServer::serverid, CreateUserMappingStmt::servername, simple_heap_insert(), transformGenericOptions(), user_mapping_ddl_aclcheck(), UserMappingRelationId, USERMAPPINGUSERSERVER, CreateUserMappingStmt::username, and values.

Referenced by ProcessUtilitySlow().

{
    Relation    rel;
    Datum       useoptions;
    Datum       values[Natts_pg_user_mapping];
    bool        nulls[Natts_pg_user_mapping];
    HeapTuple   tuple;
    Oid         useId;
    Oid         umId;
    ObjectAddress myself;
    ObjectAddress referenced;
    ForeignServer *srv;
    ForeignDataWrapper *fdw;

    rel = heap_open(UserMappingRelationId, RowExclusiveLock);

    useId = GetUserOidFromMapping(stmt->username, false);

    /* Check that the server exists. */
    srv = GetForeignServerByName(stmt->servername, false);

    user_mapping_ddl_aclcheck(useId, srv->serverid, stmt->servername);

    /*
     * Check that the user mapping is unique within server.
     */
    umId = GetSysCacheOid2(USERMAPPINGUSERSERVER,
                           ObjectIdGetDatum(useId),
                           ObjectIdGetDatum(srv->serverid));
    if (OidIsValid(umId))
        ereport(ERROR,
                (errcode(ERRCODE_DUPLICATE_OBJECT),
                 errmsg("user mapping \"%s\" already exists for server %s",
                        MappingUserName(useId),
                        stmt->servername)));

    fdw = GetForeignDataWrapper(srv->fdwid);

    /*
     * Insert tuple into pg_user_mapping.
     */
    memset(values, 0, sizeof(values));
    memset(nulls, false, sizeof(nulls));

    values[Anum_pg_user_mapping_umuser - 1] = ObjectIdGetDatum(useId);
    values[Anum_pg_user_mapping_umserver - 1] = ObjectIdGetDatum(srv->serverid);

    /* Add user options */
    useoptions = transformGenericOptions(UserMappingRelationId,
                                         PointerGetDatum(NULL),
                                         stmt->options,
                                         fdw->fdwvalidator);

    if (PointerIsValid(DatumGetPointer(useoptions)))
        values[Anum_pg_user_mapping_umoptions - 1] = useoptions;
    else
        nulls[Anum_pg_user_mapping_umoptions - 1] = true;

    tuple = heap_form_tuple(rel->rd_att, values, nulls);

    umId = simple_heap_insert(rel, tuple);

    CatalogUpdateIndexes(rel, tuple);

    heap_freetuple(tuple);

    /* Add dependency on the server */
    myself.classId = UserMappingRelationId;
    myself.objectId = umId;
    myself.objectSubId = 0;

    referenced.classId = ForeignServerRelationId;
    referenced.objectId = srv->serverid;
    referenced.objectSubId = 0;
    recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

    if (OidIsValid(useId))
    {
        /* Record the mapped user dependency */
        recordDependencyOnOwner(UserMappingRelationId, umId, useId);
    }

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

    /* Post creation hook for new user mapping */
    InvokeObjectPostCreateHook(UserMappingRelationId, umId, 0);

    heap_close(rel, RowExclusiveLock);

    return umId;
}

bool defGetBoolean ( DefElem def  ) 

Definition at line 116 of file define.c.

References DefElem::arg, defGetString(), DefElem::defname, ereport, errcode(), errmsg(), ERROR, intVal, nodeTag, NULL, pg_strcasecmp(), and T_Integer.

Referenced by compute_attributes_with_style(), DefineOperator(), DefineType(), dintdict_init(), dsimple_init(), dsynonym_init(), dxsyn_init(), ExplainQuery(), file_fdw_validator(), get_file_fdw_attribute_options(), GetCommandLogLevel(), interpretOidsOption(), postgres_fdw_validator(), postgresGetForeignRelSize(), and ProcessCopyOptions().

{
    /*
     * If no parameter given, assume "true" is meant.
     */
    if (def->arg == NULL)
        return true;

    /*
     * Allow 0, 1, "true", "false", "on", "off"
     */
    switch (nodeTag(def->arg))
    {
        case T_Integer:
            switch (intVal(def->arg))
            {
                case 0:
                    return false;
                case 1:
                    return true;
                default:
                    /* otherwise, error out below */
                    break;
            }
            break;
        default:
            {
                char       *sval = defGetString(def);

                /*
                 * The set of strings accepted here should match up with the
                 * grammar's opt_boolean production.
                 */
                if (pg_strcasecmp(sval, "true") == 0)
                    return true;
                if (pg_strcasecmp(sval, "false") == 0)
                    return false;
                if (pg_strcasecmp(sval, "on") == 0)
                    return true;
                if (pg_strcasecmp(sval, "off") == 0)
                    return false;
            }
            break;
    }
    ereport(ERROR,
            (errcode(ERRCODE_SYNTAX_ERROR),
             errmsg("%s requires a Boolean value",
                    def->defname)));
    return false;               /* keep compiler quiet */
}

int64 defGetInt64 ( DefElem def  ) 

Definition at line 171 of file define.c.

References DefElem::arg, CStringGetDatum, DatumGetInt64, DefElem::defname, DirectFunctionCall1, ereport, errcode(), errmsg(), ERROR, int8in(), intVal, nodeTag, NULL, strVal, T_Float, and T_Integer.

Referenced by init_params().

{
    if (def->arg == NULL)
        ereport(ERROR,
                (errcode(ERRCODE_SYNTAX_ERROR),
                 errmsg("%s requires a numeric value",
                        def->defname)));
    switch (nodeTag(def->arg))
    {
        case T_Integer:
            return (int64) intVal(def->arg);
        case T_Float:

            /*
             * Values too large for int4 will be represented as Float
             * constants by the lexer.  Accept these if they are valid int8
             * strings.
             */
            return DatumGetInt64(DirectFunctionCall1(int8in,
                                         CStringGetDatum(strVal(def->arg))));
        default:
            ereport(ERROR,
                    (errcode(ERRCODE_SYNTAX_ERROR),
                     errmsg("%s requires a numeric value",
                            def->defname)));
    }
    return 0;                   /* keep compiler quiet */
}

double defGetNumeric ( DefElem def  ) 

Definition at line 90 of file define.c.

References DefElem::arg, DefElem::defname, ereport, errcode(), errmsg(), ERROR, floatVal, intVal, nodeTag, NULL, T_Float, and T_Integer.

Referenced by AlterFunction().

{
    if (def->arg == NULL)
        ereport(ERROR,
                (errcode(ERRCODE_SYNTAX_ERROR),
                 errmsg("%s requires a numeric value",
                        def->defname)));
    switch (nodeTag(def->arg))
    {
        case T_Integer:
            return (double) intVal(def->arg);
        case T_Float:
            return floatVal(def->arg);
        default:
            ereport(ERROR,
                    (errcode(ERRCODE_SYNTAX_ERROR),
                     errmsg("%s requires a numeric value",
                            def->defname)));
    }
    return 0;                   /* keep compiler quiet */
}

List* defGetQualifiedName ( DefElem def  ) 

Definition at line 204 of file define.c.

References DefElem::arg, DefElem::defname, ereport, errcode(), errmsg(), ERROR, list_make1, nodeTag, NULL, T_List, T_String, and T_TypeName.

Referenced by DefineAggregate(), DefineCollation(), DefineOperator(), DefineRange(), DefineTSConfiguration(), DefineTSDictionary(), DefineType(), get_ts_parser_func(), get_ts_template_func(), and init_params().

{
    if (def->arg == NULL)
        ereport(ERROR,
                (errcode(ERRCODE_SYNTAX_ERROR),
                 errmsg("%s requires a parameter",
                        def->defname)));
    switch (nodeTag(def->arg))
    {
        case T_TypeName:
            return ((TypeName *) def->arg)->names;
        case T_List:
            return (List *) def->arg;
        case T_String:
            /* Allow quoted name for backwards compatibility */
            return list_make1(def->arg);
        default:
            ereport(ERROR,
                    (errcode(ERRCODE_SYNTAX_ERROR),
                     errmsg("argument of %s must be a name",
                            def->defname)));
    }
    return NIL;                 /* keep compiler quiet */
}

char* defGetString ( DefElem def  ) 

Definition at line 49 of file define.c.

References DefElem::arg, DefElem::defname, elog, ereport, errcode(), errmsg(), ERROR, intVal, NameListToString(), nodeTag, NULL, palloc(), pstrdup(), snprintf(), strVal, T_A_Star, T_Float, T_Integer, T_List, T_String, T_TypeName, and TypeNameToString().

Referenced by check_selective_binary_conversion(), defGetBoolean(), defGetTypeLength(), DefineAggregate(), DefineCollation(), DefineType(), deparseAnalyzeSql(), deparseColumnRef(), deparseRelation(), dintdict_init(), dispell_init(), dsimple_init(), dsnowball_init(), dsynonym_init(), dxsyn_init(), ExplainQuery(), ExplainResultDesc(), ExtractConnectionOptions(), file_fdw_validator(), fileGetOptions(), optionListToArray(), postgres_fdw_validator(), postgresGetForeignRelSize(), ProcessCopyOptions(), prsd_headline(), serialize_deflist(), thesaurus_init(), transformRelOptions(), and unaccent_init().

{
    if (def->arg == NULL)
        ereport(ERROR,
                (errcode(ERRCODE_SYNTAX_ERROR),
                 errmsg("%s requires a parameter",
                        def->defname)));
    switch (nodeTag(def->arg))
    {
        case T_Integer:
            {
                char       *str = palloc(32);

                snprintf(str, 32, "%ld", (long) intVal(def->arg));
                return str;
            }
        case T_Float:

            /*
             * T_Float values are kept in string form, so this type cheat
             * works (and doesn't risk losing precision)
             */
            return strVal(def->arg);
        case T_String:
            return strVal(def->arg);
        case T_TypeName:
            return TypeNameToString((TypeName *) def->arg);
        case T_List:
            return NameListToString((List *) def->arg);
        case T_A_Star:
            return pstrdup("*");
        default:
            elog(ERROR, "unrecognized node type: %d", (int) nodeTag(def->arg));
    }
    return NULL;                /* keep compiler quiet */
}

int defGetTypeLength ( DefElem def  ) 

Definition at line 264 of file define.c.

References DefElem::arg, defGetString(), DefElem::defname, elog, ereport, errcode(), errmsg(), ERROR, intVal, nodeTag, NULL, pg_strcasecmp(), strVal, T_Float, T_Integer, T_List, T_String, T_TypeName, and TypeNameToString().

Referenced by DefineType().

{
    if (def->arg == NULL)
        ereport(ERROR,
                (errcode(ERRCODE_SYNTAX_ERROR),
                 errmsg("%s requires a parameter",
                        def->defname)));
    switch (nodeTag(def->arg))
    {
        case T_Integer:
            return intVal(def->arg);
        case T_Float:
            ereport(ERROR,
                    (errcode(ERRCODE_SYNTAX_ERROR),
                     errmsg("%s requires an integer value",
                            def->defname)));
            break;
        case T_String:
            if (pg_strcasecmp(strVal(def->arg), "variable") == 0)
                return -1;      /* variable length */
            break;
        case T_TypeName:
            /* cope if grammar chooses to believe "variable" is a typename */
            if (pg_strcasecmp(TypeNameToString((TypeName *) def->arg),
                              "variable") == 0)
                return -1;      /* variable length */
            break;
        case T_List:
            /* must be an operator name */
            break;
        default:
            elog(ERROR, "unrecognized node type: %d", (int) nodeTag(def->arg));
    }
    ereport(ERROR,
            (errcode(ERRCODE_SYNTAX_ERROR),
             errmsg("invalid argument for %s: \"%s\"",
                    def->defname, defGetString(def))));
    return 0;                   /* keep compiler quiet */
}

TypeName* defGetTypeName ( DefElem def  ) 

Definition at line 236 of file define.c.

References DefElem::arg, DefElem::defname, ereport, errcode(), errmsg(), ERROR, list_make1, makeTypeNameFromNameList(), nodeTag, NULL, T_String, and T_TypeName.

Referenced by DefineAggregate(), DefineOperator(), DefineRange(), and DefineType().

{
    if (def->arg == NULL)
        ereport(ERROR,
                (errcode(ERRCODE_SYNTAX_ERROR),
                 errmsg("%s requires a parameter",
                        def->defname)));
    switch (nodeTag(def->arg))
    {
        case T_TypeName:
            return (TypeName *) def->arg;
        case T_String:
            /* Allow quoted typename for backwards compatibility */
            return makeTypeNameFromNameList(list_make1(def->arg));
        default:
            ereport(ERROR,
                    (errcode(ERRCODE_SYNTAX_ERROR),
                     errmsg("argument of %s must be a type name",
                            def->defname)));
    }
    return NULL;                /* keep compiler quiet */
}

Oid DefineAggregate ( List name,
List args,
bool  oldstyle,
List parameters 
)

Definition at line 51 of file aggregatecmds.c.

References ACL_CREATE, ACL_KIND_NAMESPACE, aclcheck_error(), ACLCHECK_OK, AggregateCreate(), defGetQualifiedName(), defGetString(), defGetTypeName(), DefElem::defname, ereport, errcode(), errmsg(), ERROR, format_type_be(), get_namespace_name(), get_typtype(), getTypeInputInfo(), GetUserId(), i, INTERNALOID, IsPolymorphicType, lfirst, list_length(), NIL, NULL, OidInputFunctionCall(), palloc(), pg_namespace_aclcheck(), pg_strcasecmp(), QualifiedNameGetCreationNamespace(), superuser(), TypeNameToString(), typenameTypeId(), TYPTYPE_PSEUDO, and WARNING.

Referenced by ProcessUtilitySlow().

{
    char       *aggName;
    Oid         aggNamespace;
    AclResult   aclresult;
    List       *transfuncName = NIL;
    List       *finalfuncName = NIL;
    List       *sortoperatorName = NIL;
    TypeName   *baseType = NULL;
    TypeName   *transType = NULL;
    char       *initval = NULL;
    Oid        *aggArgTypes;
    int         numArgs;
    Oid         transTypeId;
    char        transTypeType;
    ListCell   *pl;

    /* Convert list of names to a name and namespace */
    aggNamespace = QualifiedNameGetCreationNamespace(name, &aggName);

    /* Check we have creation rights in target namespace */
    aclresult = pg_namespace_aclcheck(aggNamespace, GetUserId(), ACL_CREATE);
    if (aclresult != ACLCHECK_OK)
        aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
                       get_namespace_name(aggNamespace));

    foreach(pl, parameters)
    {
        DefElem    *defel = (DefElem *) lfirst(pl);

        /*
         * sfunc1, stype1, and initcond1 are accepted as obsolete spellings
         * for sfunc, stype, initcond.
         */
        if (pg_strcasecmp(defel->defname, "sfunc") == 0)
            transfuncName = defGetQualifiedName(defel);
        else if (pg_strcasecmp(defel->defname, "sfunc1") == 0)
            transfuncName = defGetQualifiedName(defel);
        else if (pg_strcasecmp(defel->defname, "finalfunc") == 0)
            finalfuncName = defGetQualifiedName(defel);
        else if (pg_strcasecmp(defel->defname, "sortop") == 0)
            sortoperatorName = defGetQualifiedName(defel);
        else if (pg_strcasecmp(defel->defname, "basetype") == 0)
            baseType = defGetTypeName(defel);
        else if (pg_strcasecmp(defel->defname, "stype") == 0)
            transType = defGetTypeName(defel);
        else if (pg_strcasecmp(defel->defname, "stype1") == 0)
            transType = defGetTypeName(defel);
        else if (pg_strcasecmp(defel->defname, "initcond") == 0)
            initval = defGetString(defel);
        else if (pg_strcasecmp(defel->defname, "initcond1") == 0)
            initval = defGetString(defel);
        else
            ereport(WARNING,
                    (errcode(ERRCODE_SYNTAX_ERROR),
                     errmsg("aggregate attribute \"%s\" not recognized",
                            defel->defname)));
    }

    /*
     * make sure we have our required definitions
     */
    if (transType == NULL)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
                 errmsg("aggregate stype must be specified")));
    if (transfuncName == NIL)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
                 errmsg("aggregate sfunc must be specified")));

    /*
     * look up the aggregate's input datatype(s).
     */
    if (oldstyle)
    {
        /*
         * Old style: use basetype parameter.  This supports aggregates of
         * zero or one input, with input type ANY meaning zero inputs.
         *
         * Historically we allowed the command to look like basetype = 'ANY'
         * so we must do a case-insensitive comparison for the name ANY. Ugh.
         */
        if (baseType == NULL)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
                     errmsg("aggregate input type must be specified")));

        if (pg_strcasecmp(TypeNameToString(baseType), "ANY") == 0)
        {
            numArgs = 0;
            aggArgTypes = NULL;
        }
        else
        {
            numArgs = 1;
            aggArgTypes = (Oid *) palloc(sizeof(Oid));
            aggArgTypes[0] = typenameTypeId(NULL, baseType);
        }
    }
    else
    {
        /*
         * New style: args is a list of TypeNames (possibly zero of 'em).
         */
        ListCell   *lc;
        int         i = 0;

        if (baseType != NULL)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
                     errmsg("basetype is redundant with aggregate input type specification")));

        numArgs = list_length(args);
        aggArgTypes = (Oid *) palloc(sizeof(Oid) * numArgs);
        foreach(lc, args)
        {
            TypeName   *curTypeName = (TypeName *) lfirst(lc);

            aggArgTypes[i++] = typenameTypeId(NULL, curTypeName);
        }
    }

    /*
     * look up the aggregate's transtype.
     *
     * transtype can't be a pseudo-type, since we need to be able to store
     * values of the transtype.  However, we can allow polymorphic transtype
     * in some cases (AggregateCreate will check).  Also, we allow "internal"
     * for functions that want to pass pointers to private data structures;
     * but allow that only to superusers, since you could crash the system (or
     * worse) by connecting up incompatible internal-using functions in an
     * aggregate.
     */
    transTypeId = typenameTypeId(NULL, transType);
    transTypeType = get_typtype(transTypeId);
    if (transTypeType == TYPTYPE_PSEUDO &&
        !IsPolymorphicType(transTypeId))
    {
        if (transTypeId == INTERNALOID && superuser())
             /* okay */ ;
        else
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
                     errmsg("aggregate transition data type cannot be %s",
                            format_type_be(transTypeId))));
    }

    /*
     * If we have an initval, and it's not for a pseudotype (particularly a
     * polymorphic type), make sure it's acceptable to the type's input
     * function.  We will store the initval as text, because the input
     * function isn't necessarily immutable (consider "now" for timestamp),
     * and we want to use the runtime not creation-time interpretation of the
     * value.  However, if it's an incorrect value it seems much more
     * user-friendly to complain at CREATE AGGREGATE time.
     */
    if (initval && transTypeType != TYPTYPE_PSEUDO)
    {
        Oid         typinput,
                    typioparam;

        getTypeInputInfo(transTypeId, &typinput, &typioparam);
        (void) OidInputFunctionCall(typinput, initval, typioparam, -1);
    }

    /*
     * Most of the argument-checking is done inside of AggregateCreate
     */
    return AggregateCreate(aggName, /* aggregate name */
                           aggNamespace,        /* namespace */
                           aggArgTypes, /* input data type(s) */
                           numArgs,
                           transfuncName,       /* step function name */
                           finalfuncName,       /* final function name */
                           sortoperatorName,    /* sort operator name */
                           transTypeId, /* transition data type */
                           initval);    /* initial condition */
}

Oid DefineIndex ( IndexStmt stmt,
Oid  indexRelationId,
bool  is_alter_table,
bool  check_rights,
bool  skip_build,
bool  quiet 
)

Definition at line 296 of file indexcmds.c.

References IndexStmt::accessMethod, ACL_CREATE, ACL_KIND_NAMESPACE, ACL_KIND_TABLESPACE, aclcheck_error(), ACLCHECK_OK, allowSystemTableMods, AMNAME, Assert, BuildIndexInfo(), CacheInvalidateRelcacheByRelid(), CheckPredicate(), ChooseIndexColumnNames(), ChooseIndexName(), CommitTransactionCommand(), ComputeIndexAttrs(), IndexStmt::concurrent, CreateComments(), LockRelId::dbId, DEBUG1, IndexStmt::deferrable, elog, ereport, errcode(), errmsg(), ERROR, IndexStmt::excludeOpNames, get_namespace_name(), get_tablespace_name(), get_tablespace_oid(), GetCurrentVirtualXIDs(), GetDefaultTablespace(), GetLockConflicts(), GETSTRUCT, GetTransactionSnapshot(), GetUserId(), GLOBALTABLESPACE_OID, heap_close, heap_openrv(), HeapTupleGetOid, HeapTupleIsValid, i, IndexStmt::idxcomment, IndexStmt::idxname, IndexInfo::ii_BrokenHotChain, IndexInfo::ii_Concurrent, IndexInfo::ii_ExclusionOps, IndexInfo::ii_ExclusionProcs, IndexInfo::ii_ExclusionStrats, IndexInfo::ii_Expressions, IndexInfo::ii_ExpressionsState, IndexInfo::ii_NumIndexAttrs, IndexInfo::ii_Predicate, IndexInfo::ii_PredicateState, IndexInfo::ii_ReadyForInserts, IndexInfo::ii_Unique, index_build(), index_check_primary_key(), index_close(), index_create(), INDEX_CREATE_SET_READY, INDEX_CREATE_SET_VALID, INDEX_MAX_KEYS, index_open(), index_reloptions(), index_set_state_flags(), IndexStmt::indexParams, IndexStmt::initdeferred, IsBootstrapProcessingMode, IndexStmt::isconstraint, list_length(), LockRelationIdForSession(), LockInfoData::lockRelId, make_ands_implicit(), makeNode, MyDatabaseTableSpace, NIL, NoLock, NOTICE, NULL, OidIsValid, IndexStmt::oldNode, IndexStmt::options, palloc(), pfree(), pg_namespace_aclcheck(), pg_tablespace_aclcheck(), PointerGetDatum, PopActiveSnapshot(), IndexStmt::primary, PROC_IN_VACUUM, PROC_IS_AUTOVACUUM, PushActiveSnapshot(), RelationData::rd_lockInfo, RelationData::rd_rel, RegisterSnapshot(), IndexStmt::relation, RELATION_IS_OTHER_TEMP, RelationGetNamespace, RelationGetRelationName, RelationGetRelid, RelationRelationId, ReleaseSysCache(), LockRelId::relId, RELKIND_FOREIGN_TABLE, RELKIND_MATVIEW, RELKIND_RELATION, RowExclusiveLock, SearchSysCache1, SET_LOCKTAG_RELATION, SetInvalidVirtualTransactionId, ShareLock, ShareUpdateExclusiveLock, StartTransactionCommand(), IndexStmt::tableSpace, transformRelOptions(), IndexStmt::unique, UnlockRelationIdForSession(), UnregisterSnapshot(), validate_index(), VirtualTransactionIdEquals, VirtualTransactionIdIsValid, VirtualXactLock(), IndexStmt::whereClause, and SnapshotData::xmin.

Referenced by ATExecAddIndex(), and ProcessUtilitySlow().

{
    char       *indexRelationName;
    char       *accessMethodName;
    Oid        *typeObjectId;
    Oid        *collationObjectId;
    Oid        *classObjectId;
    Oid         accessMethodId;
    Oid         relationId;
    Oid         namespaceId;
    Oid         tablespaceId;
    List       *indexColNames;
    Relation    rel;
    Relation    indexRelation;
    HeapTuple   tuple;
    Form_pg_am  accessMethodForm;
    bool        amcanorder;
    RegProcedure amoptions;
    Datum       reloptions;
    int16      *coloptions;
    IndexInfo  *indexInfo;
    int         numberOfAttributes;
    TransactionId limitXmin;
    VirtualTransactionId *old_lockholders;
    VirtualTransactionId *old_snapshots;
    int         n_old_snapshots;
    LockRelId   heaprelid;
    LOCKTAG     heaplocktag;
    Snapshot    snapshot;
    int         i;

    /*
     * count attributes in index
     */
    numberOfAttributes = list_length(stmt->indexParams);
    if (numberOfAttributes <= 0)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                 errmsg("must specify at least one column")));
    if (numberOfAttributes > INDEX_MAX_KEYS)
        ereport(ERROR,
                (errcode(ERRCODE_TOO_MANY_COLUMNS),
                 errmsg("cannot use more than %d columns in an index",
                        INDEX_MAX_KEYS)));

    /*
     * Open heap relation, acquire a suitable lock on it, remember its OID
     *
     * Only SELECT ... FOR UPDATE/SHARE are allowed while doing a standard
     * index build; but for concurrent builds we allow INSERT/UPDATE/DELETE
     * (but not VACUUM).
     */
    rel = heap_openrv(stmt->relation,
                      (stmt->concurrent ? ShareUpdateExclusiveLock : ShareLock));

    relationId = RelationGetRelid(rel);
    namespaceId = RelationGetNamespace(rel);

    if (rel->rd_rel->relkind != RELKIND_RELATION &&
        rel->rd_rel->relkind != RELKIND_MATVIEW)
    {
        if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)

            /*
             * Custom error message for FOREIGN TABLE since the term is close
             * to a regular table and can confuse the user.
             */
            ereport(ERROR,
                    (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                     errmsg("cannot create index on foreign table \"%s\"",
                            RelationGetRelationName(rel))));
        else
            ereport(ERROR,
                    (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                     errmsg("\"%s\" is not a table",
                            RelationGetRelationName(rel))));
    }

    /*
     * Don't try to CREATE INDEX on temp tables of other backends.
     */
    if (RELATION_IS_OTHER_TEMP(rel))
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("cannot create indexes on temporary tables of other sessions")));

    /*
     * Verify we (still) have CREATE rights in the rel's namespace.
     * (Presumably we did when the rel was created, but maybe not anymore.)
     * Skip check if caller doesn't want it.  Also skip check if
     * bootstrapping, since permissions machinery may not be working yet.
     */
    if (check_rights && !IsBootstrapProcessingMode())
    {
        AclResult   aclresult;

        aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(),
                                          ACL_CREATE);
        if (aclresult != ACLCHECK_OK)
            aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
                           get_namespace_name(namespaceId));
    }

    /*
     * Select tablespace to use.  If not specified, use default tablespace
     * (which may in turn default to database's default).
     */
    if (stmt->tableSpace)
    {
        tablespaceId = get_tablespace_oid(stmt->tableSpace, false);
    }
    else
    {
        tablespaceId = GetDefaultTablespace(rel->rd_rel->relpersistence);
        /* note InvalidOid is OK in this case */
    }

    /* Check permissions except when using database's default */
    if (OidIsValid(tablespaceId) && tablespaceId != MyDatabaseTableSpace)
    {
        AclResult   aclresult;

        aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(),
                                           ACL_CREATE);
        if (aclresult != ACLCHECK_OK)
            aclcheck_error(aclresult, ACL_KIND_TABLESPACE,
                           get_tablespace_name(tablespaceId));
    }

    /*
     * Force shared indexes into the pg_global tablespace.  This is a bit of a
     * hack but seems simpler than marking them in the BKI commands.  On the
     * other hand, if it's not shared, don't allow it to be placed there.
     */
    if (rel->rd_rel->relisshared)
        tablespaceId = GLOBALTABLESPACE_OID;
    else if (tablespaceId == GLOBALTABLESPACE_OID)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("only shared relations can be placed in pg_global tablespace")));

    /*
     * Choose the index column names.
     */
    indexColNames = ChooseIndexColumnNames(stmt->indexParams);

    /*
     * Select name for index if caller didn't specify
     */
    indexRelationName = stmt->idxname;
    if (indexRelationName == NULL)
        indexRelationName = ChooseIndexName(RelationGetRelationName(rel),
                                            namespaceId,
                                            indexColNames,
                                            stmt->excludeOpNames,
                                            stmt->primary,
                                            stmt->isconstraint);

    /*
     * look up the access method, verify it can handle the requested features
     */
    accessMethodName = stmt->accessMethod;
    tuple = SearchSysCache1(AMNAME, PointerGetDatum(accessMethodName));
    if (!HeapTupleIsValid(tuple))
    {
        /*
         * Hack to provide more-or-less-transparent updating of old RTREE
         * indexes to GiST: if RTREE is requested and not found, use GIST.
         */
        if (strcmp(accessMethodName, "rtree") == 0)
        {
            ereport(NOTICE,
                    (errmsg("substituting access method \"gist\" for obsolete method \"rtree\"")));
            accessMethodName = "gist";
            tuple = SearchSysCache1(AMNAME, PointerGetDatum(accessMethodName));
        }

        if (!HeapTupleIsValid(tuple))
            ereport(ERROR,
                    (errcode(ERRCODE_UNDEFINED_OBJECT),
                     errmsg("access method \"%s\" does not exist",
                            accessMethodName)));
    }
    accessMethodId = HeapTupleGetOid(tuple);
    accessMethodForm = (Form_pg_am) GETSTRUCT(tuple);

    if (stmt->unique && !accessMethodForm->amcanunique)
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
               errmsg("access method \"%s\" does not support unique indexes",
                      accessMethodName)));
    if (numberOfAttributes > 1 && !accessMethodForm->amcanmulticol)
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
          errmsg("access method \"%s\" does not support multicolumn indexes",
                 accessMethodName)));
    if (stmt->excludeOpNames && !OidIsValid(accessMethodForm->amgettuple))
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
        errmsg("access method \"%s\" does not support exclusion constraints",
               accessMethodName)));

    amcanorder = accessMethodForm->amcanorder;
    amoptions = accessMethodForm->amoptions;

    ReleaseSysCache(tuple);

    /*
     * Validate predicate, if given
     */
    if (stmt->whereClause)
        CheckPredicate((Expr *) stmt->whereClause);

    /*
     * Parse AM-specific options, convert to text array form, validate.
     */
    reloptions = transformRelOptions((Datum) 0, stmt->options,
                                     NULL, NULL, false, false);

    (void) index_reloptions(amoptions, reloptions, true);

    /*
     * Prepare arguments for index_create, primarily an IndexInfo structure.
     * Note that ii_Predicate must be in implicit-AND format.
     */
    indexInfo = makeNode(IndexInfo);
    indexInfo->ii_NumIndexAttrs = numberOfAttributes;
    indexInfo->ii_Expressions = NIL;    /* for now */
    indexInfo->ii_ExpressionsState = NIL;
    indexInfo->ii_Predicate = make_ands_implicit((Expr *) stmt->whereClause);
    indexInfo->ii_PredicateState = NIL;
    indexInfo->ii_ExclusionOps = NULL;
    indexInfo->ii_ExclusionProcs = NULL;
    indexInfo->ii_ExclusionStrats = NULL;
    indexInfo->ii_Unique = stmt->unique;
    /* In a concurrent build, mark it not-ready-for-inserts */
    indexInfo->ii_ReadyForInserts = !stmt->concurrent;
    indexInfo->ii_Concurrent = stmt->concurrent;
    indexInfo->ii_BrokenHotChain = false;

    typeObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
    collationObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
    classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
    coloptions = (int16 *) palloc(numberOfAttributes * sizeof(int16));
    ComputeIndexAttrs(indexInfo,
                      typeObjectId, collationObjectId, classObjectId,
                      coloptions, stmt->indexParams,
                      stmt->excludeOpNames, relationId,
                      accessMethodName, accessMethodId,
                      amcanorder, stmt->isconstraint);

    /*
     * Extra checks when creating a PRIMARY KEY index.
     */
    if (stmt->primary)
        index_check_primary_key(rel, indexInfo, is_alter_table);

    /*
     * Report index creation if appropriate (delay this till after most of the
     * error checks)
     */
    if (stmt->isconstraint && !quiet)
    {
        const char *constraint_type;

        if (stmt->primary)
            constraint_type = "PRIMARY KEY";
        else if (stmt->unique)
            constraint_type = "UNIQUE";
        else if (stmt->excludeOpNames != NIL)
            constraint_type = "EXCLUDE";
        else
        {
            elog(ERROR, "unknown constraint type");
            constraint_type = NULL;     /* keep compiler quiet */
        }

        ereport(DEBUG1,
          (errmsg("%s %s will create implicit index \"%s\" for table \"%s\"",
                  is_alter_table ? "ALTER TABLE / ADD" : "CREATE TABLE /",
                  constraint_type,
                  indexRelationName, RelationGetRelationName(rel))));
    }

    /*
     * A valid stmt->oldNode implies that we already have a built form of the
     * index.  The caller should also decline any index build.
     */
    Assert(!OidIsValid(stmt->oldNode) || (skip_build && !stmt->concurrent));

    /*
     * Make the catalog entries for the index, including constraints. Then, if
     * not skip_build || concurrent, actually build the index.
     */
    indexRelationId =
        index_create(rel, indexRelationName, indexRelationId, stmt->oldNode,
                     indexInfo, indexColNames,
                     accessMethodId, tablespaceId,
                     collationObjectId, classObjectId,
                     coloptions, reloptions, stmt->primary,
                     stmt->isconstraint, stmt->deferrable, stmt->initdeferred,
                     allowSystemTableMods,
                     skip_build || stmt->concurrent,
                     stmt->concurrent, !check_rights);

    /* Add any requested comment */
    if (stmt->idxcomment != NULL)
        CreateComments(indexRelationId, RelationRelationId, 0,
                       stmt->idxcomment);

    if (!stmt->concurrent)
    {
        /* Close the heap and we're done, in the non-concurrent case */
        heap_close(rel, NoLock);
        return indexRelationId;
    }

    /* save lockrelid and locktag for below, then close rel */
    heaprelid = rel->rd_lockInfo.lockRelId;
    SET_LOCKTAG_RELATION(heaplocktag, heaprelid.dbId, heaprelid.relId);
    heap_close(rel, NoLock);

    /*
     * For a concurrent build, it's important to make the catalog entries
     * visible to other transactions before we start to build the index. That
     * will prevent them from making incompatible HOT updates.  The new index
     * will be marked not indisready and not indisvalid, so that no one else
     * tries to either insert into it or use it for queries.
     *
     * We must commit our current transaction so that the index becomes
     * visible; then start another.  Note that all the data structures we just
     * built are lost in the commit.  The only data we keep past here are the
     * relation IDs.
     *
     * Before committing, get a session-level lock on the table, to ensure
     * that neither it nor the index can be dropped before we finish. This
     * cannot block, even if someone else is waiting for access, because we
     * already have the same lock within our transaction.
     *
     * Note: we don't currently bother with a session lock on the index,
     * because there are no operations that could change its state while we
     * hold lock on the parent table.  This might need to change later.
     */
    LockRelationIdForSession(&heaprelid, ShareUpdateExclusiveLock);

    PopActiveSnapshot();
    CommitTransactionCommand();
    StartTransactionCommand();

    /*
     * Phase 2 of concurrent index build (see comments for validate_index()
     * for an overview of how this works)
     *
     * Now we must wait until no running transaction could have the table open
     * with the old list of indexes.  To do this, inquire which xacts
     * currently would conflict with ShareLock on the table -- ie, which ones
     * have a lock that permits writing the table.  Then wait for each of
     * these xacts to commit or abort.  Note we do not need to worry about
     * xacts that open the table for writing after this point; they will see
     * the new index when they open it.
     *
     * Note: the reason we use actual lock acquisition here, rather than just
     * checking the ProcArray and sleeping, is that deadlock is possible if
     * one of the transactions in question is blocked trying to acquire an
     * exclusive lock on our table.  The lock code will detect deadlock and
     * error out properly.
     *
     * Note: GetLockConflicts() never reports our own xid, hence we need not
     * check for that.  Also, prepared xacts are not reported, which is fine
     * since they certainly aren't going to do anything more.
     */
    old_lockholders = GetLockConflicts(&heaplocktag, ShareLock);

    while (VirtualTransactionIdIsValid(*old_lockholders))
    {
        VirtualXactLock(*old_lockholders, true);
        old_lockholders++;
    }

    /*
     * At this moment we are sure that there are no transactions with the
     * table open for write that don't have this new index in their list of
     * indexes.  We have waited out all the existing transactions and any new
     * transaction will have the new index in its list, but the index is still
     * marked as "not-ready-for-inserts".  The index is consulted while
     * deciding HOT-safety though.  This arrangement ensures that no new HOT
     * chains can be created where the new tuple and the old tuple in the
     * chain have different index keys.
     *
     * We now take a new snapshot, and build the index using all tuples that
     * are visible in this snapshot.  We can be sure that any HOT updates to
     * these tuples will be compatible with the index, since any updates made
     * by transactions that didn't know about the index are now committed or
     * rolled back.  Thus, each visible tuple is either the end of its
     * HOT-chain or the extension of the chain is HOT-safe for this index.
     */

    /* Open and lock the parent heap relation */
    rel = heap_openrv(stmt->relation, ShareUpdateExclusiveLock);

    /* And the target index relation */
    indexRelation = index_open(indexRelationId, RowExclusiveLock);

    /* Set ActiveSnapshot since functions in the indexes may need it */
    PushActiveSnapshot(GetTransactionSnapshot());

    /* We have to re-build the IndexInfo struct, since it was lost in commit */
    indexInfo = BuildIndexInfo(indexRelation);
    Assert(!indexInfo->ii_ReadyForInserts);
    indexInfo->ii_Concurrent = true;
    indexInfo->ii_BrokenHotChain = false;

    /* Now build the index */
    index_build(rel, indexRelation, indexInfo, stmt->primary, false);

    /* Close both the relations, but keep the locks */
    heap_close(rel, NoLock);
    index_close(indexRelation, NoLock);

    /*
     * Update the pg_index row to mark the index as ready for inserts. Once we
     * commit this transaction, any new transactions that open the table must
     * insert new entries into the index for insertions and non-HOT updates.
     */
    index_set_state_flags(indexRelationId, INDEX_CREATE_SET_READY);

    /* we can do away with our snapshot */
    PopActiveSnapshot();

    /*
     * Commit this transaction to make the indisready update visible.
     */
    CommitTransactionCommand();
    StartTransactionCommand();

    /*
     * Phase 3 of concurrent index build
     *
     * We once again wait until no transaction can have the table open with
     * the index marked as read-only for updates.
     */
    old_lockholders = GetLockConflicts(&heaplocktag, ShareLock);

    while (VirtualTransactionIdIsValid(*old_lockholders))
    {
        VirtualXactLock(*old_lockholders, true);
        old_lockholders++;
    }

    /*
     * Now take the "reference snapshot" that will be used by validate_index()
     * to filter candidate tuples.  Beware!  There might still be snapshots in
     * use that treat some transaction as in-progress that our reference
     * snapshot treats as committed.  If such a recently-committed transaction
     * deleted tuples in the table, we will not include them in the index; yet
     * those transactions which see the deleting one as still-in-progress will
     * expect such tuples to be there once we mark the index as valid.
     *
     * We solve this by waiting for all endangered transactions to exit before
     * we mark the index as valid.
     *
     * We also set ActiveSnapshot to this snap, since functions in indexes may
     * need a snapshot.
     */
    snapshot = RegisterSnapshot(GetTransactionSnapshot());
    PushActiveSnapshot(snapshot);

    /*
     * Scan the index and the heap, insert any missing index entries.
     */
    validate_index(relationId, indexRelationId, snapshot);

    /*
     * Drop the reference snapshot.  We must do this before waiting out other
     * snapshot holders, else we will deadlock against other processes also
     * doing CREATE INDEX CONCURRENTLY, which would see our snapshot as one
     * they must wait for.  But first, save the snapshot's xmin to use as
     * limitXmin for GetCurrentVirtualXIDs().
     */
    limitXmin = snapshot->xmin;

    PopActiveSnapshot();
    UnregisterSnapshot(snapshot);

    /*
     * The index is now valid in the sense that it contains all currently
     * interesting tuples.  But since it might not contain tuples deleted just
     * before the reference snap was taken, we have to wait out any
     * transactions that might have older snapshots.  Obtain a list of VXIDs
     * of such transactions, and wait for them individually.
     *
     * We can exclude any running transactions that have xmin > the xmin of
     * our reference snapshot; their oldest snapshot must be newer than ours.
     * We can also exclude any transactions that have xmin = zero, since they
     * evidently have no live snapshot at all (and any one they might be in
     * process of taking is certainly newer than ours).  Transactions in other
     * DBs can be ignored too, since they'll never even be able to see this
     * index.
     *
     * We can also exclude autovacuum processes and processes running manual
     * lazy VACUUMs, because they won't be fazed by missing index entries
     * either.  (Manual ANALYZEs, however, can't be excluded because they
     * might be within transactions that are going to do arbitrary operations
     * later.)
     *
     * Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not
     * check for that.
     *
     * If a process goes idle-in-transaction with xmin zero, we do not need to
     * wait for it anymore, per the above argument.  We do not have the
     * infrastructure right now to stop waiting if that happens, but we can at
     * least avoid the folly of waiting when it is idle at the time we would
     * begin to wait.  We do this by repeatedly rechecking the output of
     * GetCurrentVirtualXIDs.  If, during any iteration, a particular vxid
     * doesn't show up in the output, we know we can forget about it.
     */
    old_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false,
                                          PROC_IS_AUTOVACUUM | PROC_IN_VACUUM,
                                          &n_old_snapshots);

    for (i = 0; i < n_old_snapshots; i++)
    {
        if (!VirtualTransactionIdIsValid(old_snapshots[i]))
            continue;           /* found uninteresting in previous cycle */

        if (i > 0)
        {
            /* see if anything's changed ... */
            VirtualTransactionId *newer_snapshots;
            int         n_newer_snapshots;
            int         j;
            int         k;

            newer_snapshots = GetCurrentVirtualXIDs(limitXmin,
                                                    true, false,
                                         PROC_IS_AUTOVACUUM | PROC_IN_VACUUM,
                                                    &n_newer_snapshots);
            for (j = i; j < n_old_snapshots; j++)
            {
                if (!VirtualTransactionIdIsValid(old_snapshots[j]))
                    continue;   /* found uninteresting in previous cycle */
                for (k = 0; k < n_newer_snapshots; k++)
                {
                    if (VirtualTransactionIdEquals(old_snapshots[j],
                                                   newer_snapshots[k]))
                        break;
                }
                if (k >= n_newer_snapshots)     /* not there anymore */
                    SetInvalidVirtualTransactionId(old_snapshots[j]);
            }
            pfree(newer_snapshots);
        }

        if (VirtualTransactionIdIsValid(old_snapshots[i]))
            VirtualXactLock(old_snapshots[i], true);
    }

    /*
     * Index can now be marked valid -- update its pg_index entry
     */
    index_set_state_flags(indexRelationId, INDEX_CREATE_SET_VALID);

    /*
     * The pg_index update will cause backends (including this one) to update
     * relcache entries for the index itself, but we should also send a
     * relcache inval on the parent table to force replanning of cached plans.
     * Otherwise existing sessions might fail to use the new index where it
     * would be useful.  (Note that our earlier commits did not create reasons
     * to replan; so relcache flush on the index itself was sufficient.)
     */
    CacheInvalidateRelcacheByRelid(heaprelid.relId);

    /*
     * Last thing to do is release the session-level lock on the parent table.
     */
    UnlockRelationIdForSession(&heaprelid, ShareUpdateExclusiveLock);

    return indexRelationId;
}

Oid DefineOpClass ( CreateOpClassStmt stmt  ) 

Definition at line 324 of file opclasscmds.c.

References ACL_CREATE, ACL_KIND_NAMESPACE, ACL_KIND_OPER, ACL_KIND_PROC, aclcheck_error(), aclcheck_error_type(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, addFamilyMember(), CreateOpClassStmt::amname, AMNAME, Anum_pg_opclass_opcdefault, Anum_pg_opclass_opcfamily, Anum_pg_opclass_opcintype, Anum_pg_opclass_opckeytype, Anum_pg_opclass_opcmethod, Anum_pg_opclass_opcname, Anum_pg_opclass_opcnamespace, Anum_pg_opclass_opcowner, CreateOpClassItem::args, Assert, assignOperTypes(), assignProcTypes(), BoolGetDatum, BTEqualStrategyNumber, BTREE_AM_OID, CatalogUpdateIndexes(), CLAAMNAMENSP, CreateOpClassItem::class_args, ObjectAddress::classId, CreateOpFamily(), CStringGetDatum, CreateOpClassStmt::datatype, DEPENDENCY_AUTO, DEPENDENCY_NORMAL, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, get_func_name(), get_namespace_name(), get_opcode(), get_opfamily_oid(), get_opname(), GETSTRUCT, GetUserId(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), HeapTupleGetOid, HeapTupleIsValid, InvokeObjectPostCreateHook, IsA, CreateOpClassStmt::isDefault, CreateOpClassStmt::items, CreateOpClassItem::itemtype, OpFamilyMember::lefttype, lfirst, linitial, LookupFuncNameTypeNames(), LookupOperName(), LookupOperNameTypeNames(), lsecond, CreateOpClassItem::name, NameGetDatum, NameStr, namestrcpy(), NIL, NULL, OpFamilyMember::number, CreateOpClassItem::number, OpFamilyMember::object, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, OPCLASS_ITEM_FUNCTION, OPCLASS_ITEM_OPERATOR, OPCLASS_ITEM_STORAGETYPE, OpclassAmNameNspIndexId, CreateOpClassStmt::opclassname, OperatorClassRelationId, OPFAMILYAMNAMENSP, CreateOpClassStmt::opfamilyname, CreateOpClassItem::order_family, palloc0(), pg_namespace_aclcheck(), pg_oper_ownercheck(), pg_proc_ownercheck(), pg_type_ownercheck(), PointerGetDatum, processTypesSpec(), QualifiedNameGetCreationNamespace(), RelationData::rd_att, recordDependencyOn(), recordDependencyOnCurrentExtension(), recordDependencyOnOwner(), ReleaseSysCache(), OpFamilyMember::righttype, RowExclusiveLock, ScanKeyInit(), SearchSysCache1, SearchSysCache3, SearchSysCacheExists3, simple_heap_insert(), SnapshotNow, OpFamilyMember::sortfamily, CreateOpClassItem::storedtype, storeOperators(), storeProcedures(), superuser(), systable_beginscan(), systable_endscan(), systable_getnext(), TypeNameToString(), typenameTypeId(), and values.

Referenced by ProcessUtilitySlow().

{
    char       *opcname;        /* name of opclass we're creating */
    Oid         amoid,          /* our AM's oid */
                typeoid,        /* indexable datatype oid */
                storageoid,     /* storage datatype oid, if any */
                namespaceoid,   /* namespace to create opclass in */
                opfamilyoid,    /* oid of containing opfamily */
                opclassoid;     /* oid of opclass we create */
    int         maxOpNumber,    /* amstrategies value */
                maxProcNumber;  /* amsupport value */
    bool        amstorage;      /* amstorage flag */
    List       *operators;      /* OpFamilyMember list for operators */
    List       *procedures;     /* OpFamilyMember list for support procs */
    ListCell   *l;
    Relation    rel;
    HeapTuple   tup;
    Form_pg_am  pg_am;
    Datum       values[Natts_pg_opclass];
    bool        nulls[Natts_pg_opclass];
    AclResult   aclresult;
    NameData    opcName;
    ObjectAddress myself,
                referenced;

    /* Convert list of names to a name and namespace */
    namespaceoid = QualifiedNameGetCreationNamespace(stmt->opclassname,
                                                     &opcname);

    /* Check we have creation rights in target namespace */
    aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
    if (aclresult != ACLCHECK_OK)
        aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
                       get_namespace_name(namespaceoid));

    /* Get necessary info about access method */
    tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
    if (!HeapTupleIsValid(tup))
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_OBJECT),
                 errmsg("access method \"%s\" does not exist",
                        stmt->amname)));

    amoid = HeapTupleGetOid(tup);
    pg_am = (Form_pg_am) GETSTRUCT(tup);
    maxOpNumber = pg_am->amstrategies;
    /* if amstrategies is zero, just enforce that op numbers fit in int16 */
    if (maxOpNumber <= 0)
        maxOpNumber = SHRT_MAX;
    maxProcNumber = pg_am->amsupport;
    amstorage = pg_am->amstorage;

    /* XXX Should we make any privilege check against the AM? */

    ReleaseSysCache(tup);

    /*
     * The question of appropriate permissions for CREATE OPERATOR CLASS is
     * interesting.  Creating an opclass is tantamount to granting public
     * execute access on the functions involved, since the index machinery
     * generally does not check access permission before using the functions.
     * A minimum expectation therefore is that the caller have execute
     * privilege with grant option.  Since we don't have a way to make the
     * opclass go away if the grant option is revoked, we choose instead to
     * require ownership of the functions.  It's also not entirely clear what
     * permissions should be required on the datatype, but ownership seems
     * like a safe choice.
     *
     * Currently, we require superuser privileges to create an opclass. This
     * seems necessary because we have no way to validate that the offered set
     * of operators and functions are consistent with the AM's expectations.
     * It would be nice to provide such a check someday, if it can be done
     * without solving the halting problem :-(
     *
     * XXX re-enable NOT_USED code sections below if you remove this test.
     */
    if (!superuser())
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 errmsg("must be superuser to create an operator class")));

    /* Look up the datatype */
    typeoid = typenameTypeId(NULL, stmt->datatype);

#ifdef NOT_USED
    /* XXX this is unnecessary given the superuser check above */
    /* Check we have ownership of the datatype */
    if (!pg_type_ownercheck(typeoid, GetUserId()))
        aclcheck_error_type(ACLCHECK_NOT_OWNER, typeoid);
#endif

    /*
     * Look up the containing operator family, or create one if FAMILY option
     * was omitted and there's not a match already.
     */
    if (stmt->opfamilyname)
    {
        opfamilyoid = get_opfamily_oid(amoid, stmt->opfamilyname, false);
    }
    else
    {
        /* Lookup existing family of same name and namespace */
        tup = SearchSysCache3(OPFAMILYAMNAMENSP,
                              ObjectIdGetDatum(amoid),
                              PointerGetDatum(opcname),
                              ObjectIdGetDatum(namespaceoid));
        if (HeapTupleIsValid(tup))
        {
            opfamilyoid = HeapTupleGetOid(tup);

            /*
             * XXX given the superuser check above, there's no need for an
             * ownership check here
             */
            ReleaseSysCache(tup);
        }
        else
        {
            /*
             * Create it ... again no need for more permissions ...
             */
            opfamilyoid = CreateOpFamily(stmt->amname, opcname,
                                         namespaceoid, amoid);
        }
    }

    operators = NIL;
    procedures = NIL;

    /* Storage datatype is optional */
    storageoid = InvalidOid;

    /*
     * Scan the "items" list to obtain additional info.
     */
    foreach(l, stmt->items)
    {
        CreateOpClassItem *item = lfirst(l);
        Oid         operOid;
        Oid         funcOid;
        Oid         sortfamilyOid;
        OpFamilyMember *member;

        Assert(IsA(item, CreateOpClassItem));
        switch (item->itemtype)
        {
            case OPCLASS_ITEM_OPERATOR:
                if (item->number <= 0 || item->number > maxOpNumber)
                    ereport(ERROR,
                            (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                             errmsg("invalid operator number %d,"
                                    " must be between 1 and %d",
                                    item->number, maxOpNumber)));
                if (item->args != NIL)
                {
                    TypeName   *typeName1 = (TypeName *) linitial(item->args);
                    TypeName   *typeName2 = (TypeName *) lsecond(item->args);

                    operOid = LookupOperNameTypeNames(NULL, item->name,
                                                      typeName1, typeName2,
                                                      false, -1);
                }
                else
                {
                    /* Default to binary op on input datatype */
                    operOid = LookupOperName(NULL, item->name,
                                             typeoid, typeoid,
                                             false, -1);
                }

                if (item->order_family)
                    sortfamilyOid = get_opfamily_oid(BTREE_AM_OID,
                                                     item->order_family,
                                                     false);
                else
                    sortfamilyOid = InvalidOid;

#ifdef NOT_USED
                /* XXX this is unnecessary given the superuser check above */
                /* Caller must own operator and its underlying function */
                if (!pg_oper_ownercheck(operOid, GetUserId()))
                    aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
                                   get_opname(operOid));
                funcOid = get_opcode(operOid);
                if (!pg_proc_ownercheck(funcOid, GetUserId()))
                    aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
                                   get_func_name(funcOid));
#endif

                /* Save the info */
                member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
                member->object = operOid;
                member->number = item->number;
                member->sortfamily = sortfamilyOid;
                assignOperTypes(member, amoid, typeoid);
                addFamilyMember(&operators, member, false);
                break;
            case OPCLASS_ITEM_FUNCTION:
                if (item->number <= 0 || item->number > maxProcNumber)
                    ereport(ERROR,
                            (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                             errmsg("invalid procedure number %d,"
                                    " must be between 1 and %d",
                                    item->number, maxProcNumber)));
                funcOid = LookupFuncNameTypeNames(item->name, item->args,
                                                  false);
#ifdef NOT_USED
                /* XXX this is unnecessary given the superuser check above */
                /* Caller must own function */
                if (!pg_proc_ownercheck(funcOid, GetUserId()))
                    aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
                                   get_func_name(funcOid));
#endif

                /* Save the info */
                member = (OpFamilyMember *) palloc0(sizeof(OpFamilyMember));
                member->object = funcOid;
                member->number = item->number;

                /* allow overriding of the function's actual arg types */
                if (item->class_args)
                    processTypesSpec(item->class_args,
                                     &member->lefttype, &member->righttype);

                assignProcTypes(member, amoid, typeoid);
                addFamilyMember(&procedures, member, true);
                break;
            case OPCLASS_ITEM_STORAGETYPE:
                if (OidIsValid(storageoid))
                    ereport(ERROR,
                            (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                           errmsg("storage type specified more than once")));
                storageoid = typenameTypeId(NULL, item->storedtype);

#ifdef NOT_USED
                /* XXX this is unnecessary given the superuser check above */
                /* Check we have ownership of the datatype */
                if (!pg_type_ownercheck(storageoid, GetUserId()))
                    aclcheck_error_type(ACLCHECK_NOT_OWNER, storageoid);
#endif
                break;
            default:
                elog(ERROR, "unrecognized item type: %d", item->itemtype);
                break;
        }
    }

    /*
     * If storagetype is specified, make sure it's legal.
     */
    if (OidIsValid(storageoid))
    {
        /* Just drop the spec if same as column datatype */
        if (storageoid == typeoid)
            storageoid = InvalidOid;
        else if (!amstorage)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                     errmsg("storage type cannot be different from data type for access method \"%s\"",
                            stmt->amname)));
    }

    rel = heap_open(OperatorClassRelationId, RowExclusiveLock);

    /*
     * Make sure there is no existing opclass of this name (this is just to
     * give a more friendly error message than "duplicate key").
     */
    if (SearchSysCacheExists3(CLAAMNAMENSP,
                              ObjectIdGetDatum(amoid),
                              CStringGetDatum(opcname),
                              ObjectIdGetDatum(namespaceoid)))
        ereport(ERROR,
                (errcode(ERRCODE_DUPLICATE_OBJECT),
                 errmsg("operator class \"%s\" for access method \"%s\" already exists",
                        opcname, stmt->amname)));

    /*
     * If we are creating a default opclass, check there isn't one already.
     * (Note we do not restrict this test to visible opclasses; this ensures
     * that typcache.c can find unique solutions to its questions.)
     */
    if (stmt->isDefault)
    {
        ScanKeyData skey[1];
        SysScanDesc scan;

        ScanKeyInit(&skey[0],
                    Anum_pg_opclass_opcmethod,
                    BTEqualStrategyNumber, F_OIDEQ,
                    ObjectIdGetDatum(amoid));

        scan = systable_beginscan(rel, OpclassAmNameNspIndexId, true,
                                  SnapshotNow, 1, skey);

        while (HeapTupleIsValid(tup = systable_getnext(scan)))
        {
            Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);

            if (opclass->opcintype == typeoid && opclass->opcdefault)
                ereport(ERROR,
                        (errcode(ERRCODE_DUPLICATE_OBJECT),
                         errmsg("could not make operator class \"%s\" be default for type %s",
                                opcname,
                                TypeNameToString(stmt->datatype)),
                   errdetail("Operator class \"%s\" already is the default.",
                             NameStr(opclass->opcname))));
        }

        systable_endscan(scan);
    }

    /*
     * Okay, let's create the pg_opclass entry.
     */
    memset(values, 0, sizeof(values));
    memset(nulls, false, sizeof(nulls));

    values[Anum_pg_opclass_opcmethod - 1] = ObjectIdGetDatum(amoid);
    namestrcpy(&opcName, opcname);
    values[Anum_pg_opclass_opcname - 1] = NameGetDatum(&opcName);
    values[Anum_pg_opclass_opcnamespace - 1] = ObjectIdGetDatum(namespaceoid);
    values[Anum_pg_opclass_opcowner - 1] = ObjectIdGetDatum(GetUserId());
    values[Anum_pg_opclass_opcfamily - 1] = ObjectIdGetDatum(opfamilyoid);
    values[Anum_pg_opclass_opcintype - 1] = ObjectIdGetDatum(typeoid);
    values[Anum_pg_opclass_opcdefault - 1] = BoolGetDatum(stmt->isDefault);
    values[Anum_pg_opclass_opckeytype - 1] = ObjectIdGetDatum(storageoid);

    tup = heap_form_tuple(rel->rd_att, values, nulls);

    opclassoid = simple_heap_insert(rel, tup);

    CatalogUpdateIndexes(rel, tup);

    heap_freetuple(tup);

    /*
     * Now add tuples to pg_amop and pg_amproc tying in the operators and
     * functions.  Dependencies on them are inserted, too.
     */
    storeOperators(stmt->opfamilyname, amoid, opfamilyoid,
                   opclassoid, operators, false);
    storeProcedures(stmt->opfamilyname, amoid, opfamilyoid,
                    opclassoid, procedures, false);

    /*
     * Create dependencies for the opclass proper.  Note: we do not create a
     * dependency link to the AM, because we don't currently support DROP
     * ACCESS METHOD.
     */
    myself.classId = OperatorClassRelationId;
    myself.objectId = opclassoid;
    myself.objectSubId = 0;

    /* dependency on namespace */
    referenced.classId = NamespaceRelationId;
    referenced.objectId = namespaceoid;
    referenced.objectSubId = 0;
    recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

    /* dependency on opfamily */
    referenced.classId = OperatorFamilyRelationId;
    referenced.objectId = opfamilyoid;
    referenced.objectSubId = 0;
    recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);

    /* dependency on indexed datatype */
    referenced.classId = TypeRelationId;
    referenced.objectId = typeoid;
    referenced.objectSubId = 0;
    recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

    /* dependency on storage datatype */
    if (OidIsValid(storageoid))
    {
        referenced.classId = TypeRelationId;
        referenced.objectId = storageoid;
        referenced.objectSubId = 0;
        recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
    }

    /* dependency on owner */
    recordDependencyOnOwner(OperatorClassRelationId, opclassoid, GetUserId());

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

    /* Post creation hook for new operator class */
    InvokeObjectPostCreateHook(OperatorClassRelationId, opclassoid, 0);

    heap_close(rel, RowExclusiveLock);

    return opclassoid;
}

Oid DefineOperator ( List names,
List parameters 
)

Definition at line 63 of file operatorcmds.c.

References ACL_CREATE, ACL_EXECUTE, ACL_KIND_NAMESPACE, ACL_KIND_PROC, ACL_USAGE, aclcheck_error(), aclcheck_error_type(), ACLCHECK_OK, defGetBoolean(), defGetQualifiedName(), defGetTypeName(), DefElem::defname, ereport, errcode(), errdetail(), errmsg(), ERROR, FLOAT8OID, get_func_rettype(), get_namespace_name(), GetUserId(), lfirst, LookupFuncName(), NameListToString(), NIL, NULL, OidIsValid, OperatorCreate(), pg_namespace_aclcheck(), pg_proc_aclcheck(), pg_strcasecmp(), pg_type_aclcheck(), QualifiedNameGetCreationNamespace(), TypeName::setof, typenameTypeId(), and WARNING.

Referenced by ProcessUtilitySlow().

{
    char       *oprName;
    Oid         oprNamespace;
    AclResult   aclresult;
    bool        canMerge = false;       /* operator merges */
    bool        canHash = false;    /* operator hashes */
    List       *functionName = NIL;     /* function for operator */
    TypeName   *typeName1 = NULL;       /* first type name */
    TypeName   *typeName2 = NULL;       /* second type name */
    Oid         typeId1 = InvalidOid;   /* types converted to OID */
    Oid         typeId2 = InvalidOid;
    Oid         rettype;
    List       *commutatorName = NIL;   /* optional commutator operator name */
    List       *negatorName = NIL;      /* optional negator operator name */
    List       *restrictionName = NIL;  /* optional restrict. sel. procedure */
    List       *joinName = NIL; /* optional join sel. procedure */
    Oid         functionOid;    /* functions converted to OID */
    Oid         restrictionOid;
    Oid         joinOid;
    Oid         typeId[5];      /* only need up to 5 args here */
    int         nargs;
    ListCell   *pl;

    /* Convert list of names to a name and namespace */
    oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName);

    /*
     * The SQL standard committee has decided that => should be used for named
     * parameters; therefore, a future release of PostgreSQL may disallow it
     * as the name of a user-defined operator.
     */
    if (strcmp(oprName, "=>") == 0)
        ereport(WARNING,
                (errmsg("=> is deprecated as an operator name"),
                 errdetail("This name may be disallowed altogether in future versions of PostgreSQL.")));

    /* Check we have creation rights in target namespace */
    aclresult = pg_namespace_aclcheck(oprNamespace, GetUserId(), ACL_CREATE);
    if (aclresult != ACLCHECK_OK)
        aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
                       get_namespace_name(oprNamespace));

    /*
     * loop over the definition list and extract the information we need.
     */
    foreach(pl, parameters)
    {
        DefElem    *defel = (DefElem *) lfirst(pl);

        if (pg_strcasecmp(defel->defname, "leftarg") == 0)
        {
            typeName1 = defGetTypeName(defel);
            if (typeName1->setof)
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
                    errmsg("SETOF type not allowed for operator argument")));
        }
        else if (pg_strcasecmp(defel->defname, "rightarg") == 0)
        {
            typeName2 = defGetTypeName(defel);
            if (typeName2->setof)
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
                    errmsg("SETOF type not allowed for operator argument")));
        }
        else if (pg_strcasecmp(defel->defname, "procedure") == 0)
            functionName = defGetQualifiedName(defel);
        else if (pg_strcasecmp(defel->defname, "commutator") == 0)
            commutatorName = defGetQualifiedName(defel);
        else if (pg_strcasecmp(defel->defname, "negator") == 0)
            negatorName = defGetQualifiedName(defel);
        else if (pg_strcasecmp(defel->defname, "restrict") == 0)
            restrictionName = defGetQualifiedName(defel);
        else if (pg_strcasecmp(defel->defname, "join") == 0)
            joinName = defGetQualifiedName(defel);
        else if (pg_strcasecmp(defel->defname, "hashes") == 0)
            canHash = defGetBoolean(defel);
        else if (pg_strcasecmp(defel->defname, "merges") == 0)
            canMerge = defGetBoolean(defel);
        /* These obsolete options are taken as meaning canMerge */
        else if (pg_strcasecmp(defel->defname, "sort1") == 0)
            canMerge = true;
        else if (pg_strcasecmp(defel->defname, "sort2") == 0)
            canMerge = true;
        else if (pg_strcasecmp(defel->defname, "ltcmp") == 0)
            canMerge = true;
        else if (pg_strcasecmp(defel->defname, "gtcmp") == 0)
            canMerge = true;
        else
            ereport(WARNING,
                    (errcode(ERRCODE_SYNTAX_ERROR),
                     errmsg("operator attribute \"%s\" not recognized",
                            defel->defname)));
    }

    /*
     * make sure we have our required definitions
     */
    if (functionName == NIL)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
                 errmsg("operator procedure must be specified")));

    /* Transform type names to type OIDs */
    if (typeName1)
        typeId1 = typenameTypeId(NULL, typeName1);
    if (typeName2)
        typeId2 = typenameTypeId(NULL, typeName2);

    if (!OidIsValid(typeId1) && !OidIsValid(typeId2))
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
           errmsg("at least one of leftarg or rightarg must be specified")));

    if (typeName1)
    {
        aclresult = pg_type_aclcheck(typeId1, GetUserId(), ACL_USAGE);
        if (aclresult != ACLCHECK_OK)
            aclcheck_error_type(aclresult, typeId1);
    }

    if (typeName2)
    {
        aclresult = pg_type_aclcheck(typeId2, GetUserId(), ACL_USAGE);
        if (aclresult != ACLCHECK_OK)
            aclcheck_error_type(aclresult, typeId2);
    }

    /*
     * Look up the operator's underlying function.
     */
    if (!OidIsValid(typeId1))
    {
        typeId[0] = typeId2;
        nargs = 1;
    }
    else if (!OidIsValid(typeId2))
    {
        typeId[0] = typeId1;
        nargs = 1;
    }
    else
    {
        typeId[0] = typeId1;
        typeId[1] = typeId2;
        nargs = 2;
    }
    functionOid = LookupFuncName(functionName, nargs, typeId, false);

    /*
     * We require EXECUTE rights for the function.  This isn't strictly
     * necessary, since EXECUTE will be checked at any attempted use of the
     * operator, but it seems like a good idea anyway.
     */
    aclresult = pg_proc_aclcheck(functionOid, GetUserId(), ACL_EXECUTE);
    if (aclresult != ACLCHECK_OK)
        aclcheck_error(aclresult, ACL_KIND_PROC,
                       NameListToString(functionName));

    rettype = get_func_rettype(functionOid);
    aclresult = pg_type_aclcheck(rettype, GetUserId(), ACL_USAGE);
    if (aclresult != ACLCHECK_OK)
        aclcheck_error_type(aclresult, rettype);

    /*
     * Look up restriction estimator if specified
     */
    if (restrictionName)
    {
        typeId[0] = INTERNALOID;    /* PlannerInfo */
        typeId[1] = OIDOID;     /* operator OID */
        typeId[2] = INTERNALOID;    /* args list */
        typeId[3] = INT4OID;    /* varRelid */

        restrictionOid = LookupFuncName(restrictionName, 4, typeId, false);

        /* estimators must return float8 */
        if (get_func_rettype(restrictionOid) != FLOAT8OID)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                     errmsg("restriction estimator function %s must return type \"float8\"",
                            NameListToString(restrictionName))));

        /* Require EXECUTE rights for the estimator */
        aclresult = pg_proc_aclcheck(restrictionOid, GetUserId(), ACL_EXECUTE);
        if (aclresult != ACLCHECK_OK)
            aclcheck_error(aclresult, ACL_KIND_PROC,
                           NameListToString(restrictionName));
    }
    else
        restrictionOid = InvalidOid;

    /*
     * Look up join estimator if specified
     */
    if (joinName)
    {
        typeId[0] = INTERNALOID;    /* PlannerInfo */
        typeId[1] = OIDOID;     /* operator OID */
        typeId[2] = INTERNALOID;    /* args list */
        typeId[3] = INT2OID;    /* jointype */
        typeId[4] = INTERNALOID;    /* SpecialJoinInfo */

        /*
         * As of Postgres 8.4, the preferred signature for join estimators has
         * 5 arguments, but we still allow the old 4-argument form. Try the
         * preferred form first.
         */
        joinOid = LookupFuncName(joinName, 5, typeId, true);
        if (!OidIsValid(joinOid))
            joinOid = LookupFuncName(joinName, 4, typeId, true);
        /* If not found, reference the 5-argument signature in error msg */
        if (!OidIsValid(joinOid))
            joinOid = LookupFuncName(joinName, 5, typeId, false);

        /* estimators must return float8 */
        if (get_func_rettype(joinOid) != FLOAT8OID)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
             errmsg("join estimator function %s must return type \"float8\"",
                    NameListToString(joinName))));

        /* Require EXECUTE rights for the estimator */
        aclresult = pg_proc_aclcheck(joinOid, GetUserId(), ACL_EXECUTE);
        if (aclresult != ACLCHECK_OK)
            aclcheck_error(aclresult, ACL_KIND_PROC,
                           NameListToString(joinName));
    }
    else
        joinOid = InvalidOid;

    /*
     * now have OperatorCreate do all the work..
     */
    return
        OperatorCreate(oprName,     /* operator name */
                       oprNamespace,    /* namespace */
                       typeId1,     /* left type id */
                       typeId2,     /* right type id */
                       functionOid, /* function for operator */
                       commutatorName,      /* optional commutator operator name */
                       negatorName, /* optional negator operator name */
                       restrictionOid,      /* optional restrict. sel. procedure */
                       joinOid,     /* optional join sel. procedure name */
                       canMerge,    /* operator merges */
                       canHash);    /* operator hashes */
}

Oid DefineOpFamily ( CreateOpFamilyStmt stmt  ) 

Definition at line 725 of file opclasscmds.c.

References ACL_CREATE, ACL_KIND_NAMESPACE, aclcheck_error(), ACLCHECK_OK, CreateOpFamilyStmt::amname, CreateOpFamily(), ereport, errcode(), errmsg(), ERROR, get_am_oid(), get_namespace_name(), GetUserId(), CreateOpFamilyStmt::opfamilyname, pg_namespace_aclcheck(), QualifiedNameGetCreationNamespace(), and superuser().

Referenced by ProcessUtilitySlow().

{
    char       *opfname;        /* name of opfamily we're creating */
    Oid         amoid,          /* our AM's oid */
                namespaceoid;   /* namespace to create opfamily in */
    AclResult   aclresult;

    /* Convert list of names to a name and namespace */
    namespaceoid = QualifiedNameGetCreationNamespace(stmt->opfamilyname,
                                                     &opfname);

    /* Check we have creation rights in target namespace */
    aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
    if (aclresult != ACLCHECK_OK)
        aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
                       get_namespace_name(namespaceoid));

    /* Get access method OID, throwing an error if it doesn't exist. */
    amoid = get_am_oid(stmt->amname, false);

    /* XXX Should we make any privilege check against the AM? */

    /*
     * Currently, we require superuser privileges to create an opfamily. See
     * comments in DefineOpClass.
     */
    if (!superuser())
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 errmsg("must be superuser to create an operator family")));

    /* Insert pg_opfamily catalog entry */
    return CreateOpFamily(stmt->amname, opfname, namespaceoid, amoid);
}

Oid DefineTSConfiguration ( List names,
List parameters 
)

Definition at line 949 of file tsearchcmds.c.

References ACL_CREATE, ACL_KIND_NAMESPACE, aclcheck_error(), ACLCHECK_OK, Anum_pg_ts_config_cfgname, Anum_pg_ts_config_cfgnamespace, Anum_pg_ts_config_cfgowner, Anum_pg_ts_config_cfgparser, Anum_pg_ts_config_map_mapcfg, Anum_pg_ts_config_map_mapdict, Anum_pg_ts_config_map_mapseqno, Anum_pg_ts_config_map_maptokentype, BTEqualStrategyNumber, CatalogUpdateIndexes(), defGetQualifiedName(), DefElem::defname, elog, ereport, errcode(), errmsg(), ERROR, get_namespace_name(), get_ts_config_oid(), get_ts_parser_oid(), GETSTRUCT, GetUserId(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), HeapTupleIsValid, InvokeObjectPostCreateHook, lfirst, makeConfigurationDependencies(), NameGetDatum, namestrcpy(), ObjectIdGetDatum, OidIsValid, pg_namespace_aclcheck(), pg_strcasecmp(), QualifiedNameGetCreationNamespace(), RelationData::rd_att, ReleaseSysCache(), RowExclusiveLock, ScanKeyInit(), SearchSysCache1, simple_heap_insert(), SnapshotNow, systable_beginscan(), systable_endscan(), systable_getnext(), TSConfigMapIndexId, TSConfigMapRelationId, TSCONFIGOID, TSConfigRelationId, and values.

Referenced by ProcessUtilitySlow().

{
    Relation    cfgRel;
    Relation    mapRel = NULL;
    HeapTuple   tup;
    Datum       values[Natts_pg_ts_config];
    bool        nulls[Natts_pg_ts_config];
    AclResult   aclresult;
    Oid         namespaceoid;
    char       *cfgname;
    NameData    cname;
    Oid         sourceOid = InvalidOid;
    Oid         prsOid = InvalidOid;
    Oid         cfgOid;
    ListCell   *pl;

    /* Convert list of names to a name and namespace */
    namespaceoid = QualifiedNameGetCreationNamespace(names, &cfgname);

    /* Check we have creation rights in target namespace */
    aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
    if (aclresult != ACLCHECK_OK)
        aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
                       get_namespace_name(namespaceoid));

    /*
     * loop over the definition list and extract the information we need.
     */
    foreach(pl, parameters)
    {
        DefElem    *defel = (DefElem *) lfirst(pl);

        if (pg_strcasecmp(defel->defname, "parser") == 0)
            prsOid = get_ts_parser_oid(defGetQualifiedName(defel), false);
        else if (pg_strcasecmp(defel->defname, "copy") == 0)
            sourceOid = get_ts_config_oid(defGetQualifiedName(defel), false);
        else
            ereport(ERROR,
                    (errcode(ERRCODE_SYNTAX_ERROR),
                     errmsg("text search configuration parameter \"%s\" not recognized",
                            defel->defname)));
    }

    if (OidIsValid(sourceOid) && OidIsValid(prsOid))
        ereport(ERROR,
                (errcode(ERRCODE_SYNTAX_ERROR),
                 errmsg("cannot specify both PARSER and COPY options")));

    /*
     * Look up source config if given.
     */
    if (OidIsValid(sourceOid))
    {
        Form_pg_ts_config cfg;

        tup = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(sourceOid));
        if (!HeapTupleIsValid(tup))
            elog(ERROR, "cache lookup failed for text search configuration %u",
                 sourceOid);

        cfg = (Form_pg_ts_config) GETSTRUCT(tup);

        /* use source's parser */
        prsOid = cfg->cfgparser;

        ReleaseSysCache(tup);
    }

    /*
     * Validation
     */
    if (!OidIsValid(prsOid))
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                 errmsg("text search parser is required")));

    /*
     * Looks good, build tuple and insert
     */
    memset(values, 0, sizeof(values));
    memset(nulls, false, sizeof(nulls));

    namestrcpy(&cname, cfgname);
    values[Anum_pg_ts_config_cfgname - 1] = NameGetDatum(&cname);
    values[Anum_pg_ts_config_cfgnamespace - 1] = ObjectIdGetDatum(namespaceoid);
    values[Anum_pg_ts_config_cfgowner - 1] = ObjectIdGetDatum(GetUserId());
    values[Anum_pg_ts_config_cfgparser - 1] = ObjectIdGetDatum(prsOid);

    cfgRel = heap_open(TSConfigRelationId, RowExclusiveLock);

    tup = heap_form_tuple(cfgRel->rd_att, values, nulls);

    cfgOid = simple_heap_insert(cfgRel, tup);

    CatalogUpdateIndexes(cfgRel, tup);

    if (OidIsValid(sourceOid))
    {
        /*
         * Copy token-dicts map from source config
         */
        ScanKeyData skey;
        SysScanDesc scan;
        HeapTuple   maptup;

        mapRel = heap_open(TSConfigMapRelationId, RowExclusiveLock);

        ScanKeyInit(&skey,
                    Anum_pg_ts_config_map_mapcfg,
                    BTEqualStrategyNumber, F_OIDEQ,
                    ObjectIdGetDatum(sourceOid));

        scan = systable_beginscan(mapRel, TSConfigMapIndexId, true,
                                  SnapshotNow, 1, &skey);

        while (HeapTupleIsValid((maptup = systable_getnext(scan))))
        {
            Form_pg_ts_config_map cfgmap = (Form_pg_ts_config_map) GETSTRUCT(maptup);
            HeapTuple   newmaptup;
            Datum       mapvalues[Natts_pg_ts_config_map];
            bool        mapnulls[Natts_pg_ts_config_map];

            memset(mapvalues, 0, sizeof(mapvalues));
            memset(mapnulls, false, sizeof(mapnulls));

            mapvalues[Anum_pg_ts_config_map_mapcfg - 1] = cfgOid;
            mapvalues[Anum_pg_ts_config_map_maptokentype - 1] = cfgmap->maptokentype;
            mapvalues[Anum_pg_ts_config_map_mapseqno - 1] = cfgmap->mapseqno;
            mapvalues[Anum_pg_ts_config_map_mapdict - 1] = cfgmap->mapdict;

            newmaptup = heap_form_tuple(mapRel->rd_att, mapvalues, mapnulls);

            simple_heap_insert(mapRel, newmaptup);

            CatalogUpdateIndexes(mapRel, newmaptup);

            heap_freetuple(newmaptup);
        }

        systable_endscan(scan);
    }

    makeConfigurationDependencies(tup, false, mapRel);

    /* Post creation hook for new text search configuration */
    InvokeObjectPostCreateHook(TSConfigRelationId, cfgOid, 0);

    heap_freetuple(tup);

    if (mapRel)
        heap_close(mapRel, RowExclusiveLock);
    heap_close(cfgRel, RowExclusiveLock);

    return cfgOid;
}

Oid DefineTSDictionary ( List names,
List parameters 
)

Definition at line 401 of file tsearchcmds.c.

References ACL_CREATE, ACL_KIND_NAMESPACE, aclcheck_error(), ACLCHECK_OK, Anum_pg_ts_dict_dictinitoption, Anum_pg_ts_dict_dictname, Anum_pg_ts_dict_dictnamespace, Anum_pg_ts_dict_dictowner, Anum_pg_ts_dict_dicttemplate, CatalogUpdateIndexes(), defGetQualifiedName(), DefElem::defname, ereport, errcode(), errmsg(), ERROR, get_namespace_name(), get_ts_template_oid(), GetUserId(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), InvokeObjectPostCreateHook, lappend(), lfirst, makeDictionaryDependencies(), NameGetDatum, namestrcpy(), ObjectIdGetDatum, OidIsValid, pg_namespace_aclcheck(), pg_strcasecmp(), PointerGetDatum, QualifiedNameGetCreationNamespace(), RelationData::rd_att, RowExclusiveLock, serialize_deflist(), simple_heap_insert(), TSDictionaryRelationId, values, and verify_dictoptions().

Referenced by ProcessUtilitySlow().

{
    ListCell   *pl;
    Relation    dictRel;
    HeapTuple   tup;
    Datum       values[Natts_pg_ts_dict];
    bool        nulls[Natts_pg_ts_dict];
    NameData    dname;
    Oid         templId = InvalidOid;
    List       *dictoptions = NIL;
    Oid         dictOid;
    Oid         namespaceoid;
    AclResult   aclresult;
    char       *dictname;

    /* Convert list of names to a name and namespace */
    namespaceoid = QualifiedNameGetCreationNamespace(names, &dictname);

    /* Check we have creation rights in target namespace */
    aclresult = pg_namespace_aclcheck(namespaceoid, GetUserId(), ACL_CREATE);
    if (aclresult != ACLCHECK_OK)
        aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
                       get_namespace_name(namespaceoid));

    /*
     * loop over the definition list and extract the information we need.
     */
    foreach(pl, parameters)
    {
        DefElem    *defel = (DefElem *) lfirst(pl);

        if (pg_strcasecmp(defel->defname, "template") == 0)
        {
            templId = get_ts_template_oid(defGetQualifiedName(defel), false);
        }
        else
        {
            /* Assume it's an option for the dictionary itself */
            dictoptions = lappend(dictoptions, defel);
        }
    }

    /*
     * Validation
     */
    if (!OidIsValid(templId))
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                 errmsg("text search template is required")));

    verify_dictoptions(templId, dictoptions);

    /*
     * Looks good, insert
     */
    memset(values, 0, sizeof(values));
    memset(nulls, false, sizeof(nulls));

    namestrcpy(&dname, dictname);
    values[Anum_pg_ts_dict_dictname - 1] = NameGetDatum(&dname);
    values[Anum_pg_ts_dict_dictnamespace - 1] = ObjectIdGetDatum(namespaceoid);
    values[Anum_pg_ts_dict_dictowner - 1] = ObjectIdGetDatum(GetUserId());
    values[Anum_pg_ts_dict_dicttemplate - 1] = ObjectIdGetDatum(templId);
    if (dictoptions)
        values[Anum_pg_ts_dict_dictinitoption - 1] =
            PointerGetDatum(serialize_deflist(dictoptions));
    else
        nulls[Anum_pg_ts_dict_dictinitoption - 1] = true;

    dictRel = heap_open(TSDictionaryRelationId, RowExclusiveLock);

    tup = heap_form_tuple(dictRel->rd_att, values, nulls);

    dictOid = simple_heap_insert(dictRel, tup);

    CatalogUpdateIndexes(dictRel, tup);

    makeDictionaryDependencies(tup);

    /* Post creation hook for new text search dictionary */
    InvokeObjectPostCreateHook(TSDictionaryRelationId, dictOid, 0);

    heap_freetuple(tup);

    heap_close(dictRel, RowExclusiveLock);

    return dictOid;
}

Oid DefineTSParser ( List names,
List parameters 
)

Definition at line 171 of file tsearchcmds.c.

References Anum_pg_ts_parser_prsend, Anum_pg_ts_parser_prsheadline, Anum_pg_ts_parser_prslextype, Anum_pg_ts_parser_prsname, Anum_pg_ts_parser_prsnamespace, Anum_pg_ts_parser_prsstart, Anum_pg_ts_parser_prstoken, CatalogUpdateIndexes(), DatumGetObjectId, DefElem::defname, ereport, errcode(), errmsg(), ERROR, get_ts_parser_func(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), InvokeObjectPostCreateHook, lfirst, makeParserDependencies(), NameGetDatum, namestrcpy(), ObjectIdGetDatum, OidIsValid, pg_strcasecmp(), QualifiedNameGetCreationNamespace(), RelationData::rd_att, RowExclusiveLock, simple_heap_insert(), superuser(), TSParserRelationId, and values.

Referenced by ProcessUtilitySlow().

{
    char       *prsname;
    ListCell   *pl;
    Relation    prsRel;
    HeapTuple   tup;
    Datum       values[Natts_pg_ts_parser];
    bool        nulls[Natts_pg_ts_parser];
    NameData    pname;
    Oid         prsOid;
    Oid         namespaceoid;

    if (!superuser())
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 errmsg("must be superuser to create text search parsers")));

    /* Convert list of names to a name and namespace */
    namespaceoid = QualifiedNameGetCreationNamespace(names, &prsname);

    /* initialize tuple fields with name/namespace */
    memset(values, 0, sizeof(values));
    memset(nulls, false, sizeof(nulls));

    namestrcpy(&pname, prsname);
    values[Anum_pg_ts_parser_prsname - 1] = NameGetDatum(&pname);
    values[Anum_pg_ts_parser_prsnamespace - 1] = ObjectIdGetDatum(namespaceoid);

    /*
     * loop over the definition list and extract the information we need.
     */
    foreach(pl, parameters)
    {
        DefElem    *defel = (DefElem *) lfirst(pl);

        if (pg_strcasecmp(defel->defname, "start") == 0)
        {
            values[Anum_pg_ts_parser_prsstart - 1] =
                get_ts_parser_func(defel, Anum_pg_ts_parser_prsstart);
        }
        else if (pg_strcasecmp(defel->defname, "gettoken") == 0)
        {
            values[Anum_pg_ts_parser_prstoken - 1] =
                get_ts_parser_func(defel, Anum_pg_ts_parser_prstoken);
        }
        else if (pg_strcasecmp(defel->defname, "end") == 0)
        {
            values[Anum_pg_ts_parser_prsend - 1] =
                get_ts_parser_func(defel, Anum_pg_ts_parser_prsend);
        }
        else if (pg_strcasecmp(defel->defname, "headline") == 0)
        {
            values[Anum_pg_ts_parser_prsheadline - 1] =
                get_ts_parser_func(defel, Anum_pg_ts_parser_prsheadline);
        }
        else if (pg_strcasecmp(defel->defname, "lextypes") == 0)
        {
            values[Anum_pg_ts_parser_prslextype - 1] =
                get_ts_parser_func(defel, Anum_pg_ts_parser_prslextype);
        }
        else
            ereport(ERROR,
                    (errcode(ERRCODE_SYNTAX_ERROR),
                 errmsg("text search parser parameter \"%s\" not recognized",
                        defel->defname)));
    }

    /*
     * Validation
     */
    if (!OidIsValid(DatumGetObjectId(values[Anum_pg_ts_parser_prsstart - 1])))
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                 errmsg("text search parser start method is required")));

    if (!OidIsValid(DatumGetObjectId(values[Anum_pg_ts_parser_prstoken - 1])))
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                 errmsg("text search parser gettoken method is required")));

    if (!OidIsValid(DatumGetObjectId(values[Anum_pg_ts_parser_prsend - 1])))
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                 errmsg("text search parser end method is required")));

    if (!OidIsValid(DatumGetObjectId(values[Anum_pg_ts_parser_prslextype - 1])))
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                 errmsg("text search parser lextypes method is required")));

    /*
     * Looks good, insert
     */
    prsRel = heap_open(TSParserRelationId, RowExclusiveLock);

    tup = heap_form_tuple(prsRel->rd_att, values, nulls);

    prsOid = simple_heap_insert(prsRel, tup);

    CatalogUpdateIndexes(prsRel, tup);

    makeParserDependencies(tup);

    /* Post creation hook for new text search parser */
    InvokeObjectPostCreateHook(TSParserRelationId, prsOid, 0);

    heap_freetuple(tup);

    heap_close(prsRel, RowExclusiveLock);

    return prsOid;
}

Oid DefineTSTemplate ( List names,
List parameters 
)

Definition at line 719 of file tsearchcmds.c.

References Anum_pg_ts_template_tmplinit, Anum_pg_ts_template_tmpllexize, Anum_pg_ts_template_tmplname, Anum_pg_ts_template_tmplnamespace, CatalogUpdateIndexes(), DatumGetObjectId, DefElem::defname, ereport, errcode(), errmsg(), ERROR, get_ts_template_func(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), i, InvalidOid, InvokeObjectPostCreateHook, lfirst, makeTSTemplateDependencies(), NameGetDatum, namestrcpy(), ObjectIdGetDatum, OidIsValid, pg_strcasecmp(), QualifiedNameGetCreationNamespace(), RelationData::rd_att, RowExclusiveLock, simple_heap_insert(), superuser(), TSTemplateRelationId, and values.

Referenced by ProcessUtilitySlow().

{
    ListCell   *pl;
    Relation    tmplRel;
    HeapTuple   tup;
    Datum       values[Natts_pg_ts_template];
    bool        nulls[Natts_pg_ts_template];
    NameData    dname;
    int         i;
    Oid         tmplOid;
    Oid         namespaceoid;
    char       *tmplname;

    if (!superuser())
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
               errmsg("must be superuser to create text search templates")));

    /* Convert list of names to a name and namespace */
    namespaceoid = QualifiedNameGetCreationNamespace(names, &tmplname);

    for (i = 0; i < Natts_pg_ts_template; i++)
    {
        nulls[i] = false;
        values[i] = ObjectIdGetDatum(InvalidOid);
    }

    namestrcpy(&dname, tmplname);
    values[Anum_pg_ts_template_tmplname - 1] = NameGetDatum(&dname);
    values[Anum_pg_ts_template_tmplnamespace - 1] = ObjectIdGetDatum(namespaceoid);

    /*
     * loop over the definition list and extract the information we need.
     */
    foreach(pl, parameters)
    {
        DefElem    *defel = (DefElem *) lfirst(pl);

        if (pg_strcasecmp(defel->defname, "init") == 0)
        {
            values[Anum_pg_ts_template_tmplinit - 1] =
                get_ts_template_func(defel, Anum_pg_ts_template_tmplinit);
            nulls[Anum_pg_ts_template_tmplinit - 1] = false;
        }
        else if (pg_strcasecmp(defel->defname, "lexize") == 0)
        {
            values[Anum_pg_ts_template_tmpllexize - 1] =
                get_ts_template_func(defel, Anum_pg_ts_template_tmpllexize);
            nulls[Anum_pg_ts_template_tmpllexize - 1] = false;
        }
        else
            ereport(ERROR,
                    (errcode(ERRCODE_SYNTAX_ERROR),
               errmsg("text search template parameter \"%s\" not recognized",
                      defel->defname)));
    }

    /*
     * Validation
     */
    if (!OidIsValid(DatumGetObjectId(values[Anum_pg_ts_template_tmpllexize - 1])))
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                 errmsg("text search template lexize method is required")));

    /*
     * Looks good, insert
     */

    tmplRel = heap_open(TSTemplateRelationId, RowExclusiveLock);

    tup = heap_form_tuple(tmplRel->rd_att, values, nulls);

    tmplOid = simple_heap_insert(tmplRel, tup);

    CatalogUpdateIndexes(tmplRel, tup);

    makeTSTemplateDependencies(tup);

    /* Post creation hook for new text search template */
    InvokeObjectPostCreateHook(TSTemplateRelationId, tmplOid, 0);

    heap_freetuple(tup);

    heap_close(tmplRel, RowExclusiveLock);

    return tmplOid;
}

DefElem* defWithOids ( bool  value  ) 

Definition at line 308 of file define.c.

References makeDefElem(), and makeInteger().

{
    return makeDefElem("oids", (Node *) makeInteger(value));
}

List* deserialize_deflist ( Datum  txt  ) 

Definition at line 1542 of file tsearchcmds.c.

References DatumGetTextP, elog, ereport, errcode(), errmsg(), ERROR, lappend(), makeDefElem(), makeString(), palloc(), pfree(), pstrdup(), text_to_cstring(), VARDATA, and VARSIZE.

Referenced by AlterTSDictionary(), lookup_ts_dictionary_cache(), and ts_headline_byid_opt().

{
    text       *in = DatumGetTextP(txt);        /* in case it's toasted */
    List       *result = NIL;
    int         len = VARSIZE(in) - VARHDRSZ;
    char       *ptr,
               *endptr,
               *workspace,
               *wsptr = NULL,
               *startvalue = NULL;
    typedef enum
    {
        CS_WAITKEY,
        CS_INKEY,
        CS_INQKEY,
        CS_WAITEQ,
        CS_WAITVALUE,
        CS_INSQVALUE,
        CS_INDQVALUE,
        CS_INWVALUE
    } ds_state;
    ds_state    state = CS_WAITKEY;

    workspace = (char *) palloc(len + 1);       /* certainly enough room */
    ptr = VARDATA(in);
    endptr = ptr + len;
    for (; ptr < endptr; ptr++)
    {
        switch (state)
        {
            case CS_WAITKEY:
                if (isspace((unsigned char) *ptr) || *ptr == ',')
                    continue;
                if (*ptr == '"')
                {
                    wsptr = workspace;
                    state = CS_INQKEY;
                }
                else
                {
                    wsptr = workspace;
                    *wsptr++ = *ptr;
                    state = CS_INKEY;
                }
                break;
            case CS_INKEY:
                if (isspace((unsigned char) *ptr))
                {
                    *wsptr++ = '\0';
                    state = CS_WAITEQ;
                }
                else if (*ptr == '=')
                {
                    *wsptr++ = '\0';
                    state = CS_WAITVALUE;
                }
                else
                {
                    *wsptr++ = *ptr;
                }
                break;
            case CS_INQKEY:
                if (*ptr == '"')
                {
                    if (ptr + 1 < endptr && ptr[1] == '"')
                    {
                        /* copy only one of the two quotes */
                        *wsptr++ = *ptr++;
                    }
                    else
                    {
                        *wsptr++ = '\0';
                        state = CS_WAITEQ;
                    }
                }
                else
                {
                    *wsptr++ = *ptr;
                }
                break;
            case CS_WAITEQ:
                if (*ptr == '=')
                    state = CS_WAITVALUE;
                else if (!isspace((unsigned char) *ptr))
                    ereport(ERROR,
                            (errcode(ERRCODE_SYNTAX_ERROR),
                             errmsg("invalid parameter list format: \"%s\"",
                                    text_to_cstring(in))));
                break;
            case CS_WAITVALUE:
                if (*ptr == '\'')
                {
                    startvalue = wsptr;
                    state = CS_INSQVALUE;
                }
                else if (*ptr == 'E' && ptr + 1 < endptr && ptr[1] == '\'')
                {
                    ptr++;
                    startvalue = wsptr;
                    state = CS_INSQVALUE;
                }
                else if (*ptr == '"')
                {
                    startvalue = wsptr;
                    state = CS_INDQVALUE;
                }
                else if (!isspace((unsigned char) *ptr))
                {
                    startvalue = wsptr;
                    *wsptr++ = *ptr;
                    state = CS_INWVALUE;
                }
                break;
            case CS_INSQVALUE:
                if (*ptr == '\'')
                {
                    if (ptr + 1 < endptr && ptr[1] == '\'')
                    {
                        /* copy only one of the two quotes */
                        *wsptr++ = *ptr++;
                    }
                    else
                    {
                        *wsptr++ = '\0';
                        result = lappend(result,
                                         makeDefElem(pstrdup(workspace),
                                  (Node *) makeString(pstrdup(startvalue))));
                        state = CS_WAITKEY;
                    }
                }
                else if (*ptr == '\\')
                {
                    if (ptr + 1 < endptr && ptr[1] == '\\')
                    {
                        /* copy only one of the two backslashes */
                        *wsptr++ = *ptr++;
                    }
                    else
                        *wsptr++ = *ptr;
                }
                else
                {
                    *wsptr++ = *ptr;
                }
                break;
            case CS_INDQVALUE:
                if (*ptr == '"')
                {
                    if (ptr + 1 < endptr && ptr[1] == '"')
                    {
                        /* copy only one of the two quotes */
                        *wsptr++ = *ptr++;
                    }
                    else
                    {
                        *wsptr++ = '\0';
                        result = lappend(result,
                                         makeDefElem(pstrdup(workspace),
                                  (Node *) makeString(pstrdup(startvalue))));
                        state = CS_WAITKEY;
                    }
                }
                else
                {
                    *wsptr++ = *ptr;
                }
                break;
            case CS_INWVALUE:
                if (*ptr == ',' || isspace((unsigned char) *ptr))
                {
                    *wsptr++ = '\0';
                    result = lappend(result,
                                     makeDefElem(pstrdup(workspace),
                                  (Node *) makeString(pstrdup(startvalue))));
                    state = CS_WAITKEY;
                }
                else
                {
                    *wsptr++ = *ptr;
                }
                break;
            default:
                elog(ERROR, "unrecognized deserialize_deflist state: %d",
                     state);
        }
    }

    if (state == CS_INWVALUE)
    {
        *wsptr++ = '\0';
        result = lappend(result,
                         makeDefElem(pstrdup(workspace),
                                  (Node *) makeString(pstrdup(startvalue))));
    }
    else if (state != CS_WAITKEY)
        ereport(ERROR,
                (errcode(ERRCODE_SYNTAX_ERROR),
                 errmsg("invalid parameter list format: \"%s\"",
                        text_to_cstring(in))));

    pfree(workspace);

    return result;
}

void DropCastById ( Oid  castOid  ) 
void ExecuteDoStmt ( DoStmt stmt  ) 

Definition at line 1649 of file functioncmds.c.

References ACL_KIND_LANGUAGE, ACL_USAGE, aclcheck_error(), ACLCHECK_NO_PRIV, ACLCHECK_OK, DefElem::arg, arg, DoStmt::args, DefElem::defname, elog, ereport, errcode(), errhint(), errmsg(), ERROR, GETSTRUCT, GetUserId(), HeapTupleGetOid, HeapTupleIsValid, InlineCodeBlock::langIsTrusted, LANGNAME, InlineCodeBlock::langOid, lfirst, makeNode, NameStr, OidFunctionCall1, OidIsValid, pg_language_aclcheck(), PLTemplateExists(), PointerGetDatum, ReleaseSysCache(), SearchSysCache1, InlineCodeBlock::source_text, strVal, and superuser().

Referenced by standard_ProcessUtility().

{
    InlineCodeBlock *codeblock = makeNode(InlineCodeBlock);
    ListCell   *arg;
    DefElem    *as_item = NULL;
    DefElem    *language_item = NULL;
    char       *language;
    Oid         laninline;
    HeapTuple   languageTuple;
    Form_pg_language languageStruct;

    /* Process options we got from gram.y */
    foreach(arg, stmt->args)
    {
        DefElem    *defel = (DefElem *) lfirst(arg);

        if (strcmp(defel->defname, "as") == 0)
        {
            if (as_item)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            as_item = defel;
        }
        else if (strcmp(defel->defname, "language") == 0)
        {
            if (language_item)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            language_item = defel;
        }
        else
            elog(ERROR, "option \"%s\" not recognized",
                 defel->defname);
    }

    if (as_item)
        codeblock->source_text = strVal(as_item->arg);
    else
        ereport(ERROR,
                (errcode(ERRCODE_SYNTAX_ERROR),
                 errmsg("no inline code specified")));

    /* if LANGUAGE option wasn't specified, use the default */
    if (language_item)
        language = strVal(language_item->arg);
    else
        language = "plpgsql";

    /* Look up the language and validate permissions */
    languageTuple = SearchSysCache1(LANGNAME, PointerGetDatum(language));
    if (!HeapTupleIsValid(languageTuple))
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_OBJECT),
                 errmsg("language \"%s\" does not exist", language),
                 (PLTemplateExists(language) ?
                  errhint("Use CREATE LANGUAGE to load the language into the database.") : 0)));

    codeblock->langOid = HeapTupleGetOid(languageTuple);
    languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
    codeblock->langIsTrusted = languageStruct->lanpltrusted;

    if (languageStruct->lanpltrusted)
    {
        /* if trusted language, need USAGE privilege */
        AclResult   aclresult;

        aclresult = pg_language_aclcheck(codeblock->langOid, GetUserId(),
                                         ACL_USAGE);
        if (aclresult != ACLCHECK_OK)
            aclcheck_error(aclresult, ACL_KIND_LANGUAGE,
                           NameStr(languageStruct->lanname));
    }
    else
    {
        /* if untrusted language, must be superuser */
        if (!superuser())
            aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_LANGUAGE,
                           NameStr(languageStruct->lanname));
    }

    /* get the handler function's OID */
    laninline = languageStruct->laninline;
    if (!OidIsValid(laninline))
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
             errmsg("language \"%s\" does not support inline code execution",
                    NameStr(languageStruct->lanname))));

    ReleaseSysCache(languageTuple);

    /* execute the inline handler */
    OidFunctionCall1(laninline, PointerGetDatum(codeblock));
}

Oid get_am_oid ( const char *  amname,
bool  missing_ok 
)

Definition at line 1735 of file opclasscmds.c.

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

Referenced by DefineOpFamily(), get_object_address_opcf(), and transformIndexConstraint().

{
    Oid         oid;

    oid = GetSysCacheOid1(AMNAME, CStringGetDatum(amname));
    if (!OidIsValid(oid) && !missing_ok)
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_OBJECT),
                 errmsg("access method \"%s\" does not exist", amname)));
    return oid;
}

Oid get_cast_oid ( Oid  sourcetypeid,
Oid  targettypeid,
bool  missing_ok 
)

Definition at line 1579 of file functioncmds.c.

References CASTSOURCETARGET, ereport, errcode(), errmsg(), ERROR, format_type_be(), GetSysCacheOid2, ObjectIdGetDatum, and OidIsValid.

Referenced by get_object_address().

{
    Oid         oid;

    oid = GetSysCacheOid2(CASTSOURCETARGET,
                          ObjectIdGetDatum(sourcetypeid),
                          ObjectIdGetDatum(targettypeid));
    if (!OidIsValid(oid) && !missing_ok)
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_OBJECT),
                 errmsg("cast from type %s to type %s does not exist",
                        format_type_be(sourcetypeid),
                        format_type_be(targettypeid))));
    return oid;
}

Oid get_opclass_oid ( Oid  amID,
List opclassname,
bool  missing_ok 
)

Definition at line 223 of file opclasscmds.c.

References HeapTupleGetOid, HeapTupleIsValid, OpClassCacheLookup(), and ReleaseSysCache().

Referenced by findRangeSubOpclass(), and get_object_address_opcf().

{
    HeapTuple   htup;
    Oid         opcID;

    htup = OpClassCacheLookup(amID, opclassname, missing_ok);
    if (!HeapTupleIsValid(htup))
        return InvalidOid;
    opcID = HeapTupleGetOid(htup);
    ReleaseSysCache(htup);

    return opcID;
}

Oid get_opfamily_oid ( Oid  amID,
List opfamilyname,
bool  missing_ok 
)

Definition at line 147 of file opclasscmds.c.

References HeapTupleGetOid, HeapTupleIsValid, OpFamilyCacheLookup(), and ReleaseSysCache().

Referenced by AlterOpFamily(), AlterOpFamilyAdd(), DefineOpClass(), and get_object_address_opcf().

{
    HeapTuple   htup;
    Oid         opfID;

    htup = OpFamilyCacheLookup(amID, opfamilyname, missing_ok);
    if (!HeapTupleIsValid(htup))
        return InvalidOid;
    opfID = HeapTupleGetOid(htup);
    ReleaseSysCache(htup);

    return opfID;
}

Oid GetDefaultOpClass ( Oid  type_id,
Oid  am_id 
)

Definition at line 1324 of file indexcmds.c.

References AccessShareLock, Anum_pg_opclass_opcmethod, BTEqualStrategyNumber, ereport, errcode(), errmsg(), ERROR, format_type_be(), getBaseType(), GETSTRUCT, heap_close, heap_open(), HeapTupleGetOid, HeapTupleIsValid, IsBinaryCoercible(), IsPreferredType(), ObjectIdGetDatum, OpclassAmNameNspIndexId, OperatorClassRelationId, ScanKeyInit(), SnapshotNow, systable_beginscan(), systable_endscan(), systable_getnext(), and TypeCategory().

Referenced by findRangeSubOpclass(), get_opclass(), get_opclass_name(), GetIndexOpClass(), lookup_type_cache(), and transformIndexConstraint().

{
    Oid         result = InvalidOid;
    int         nexact = 0;
    int         ncompatible = 0;
    int         ncompatiblepreferred = 0;
    Relation    rel;
    ScanKeyData skey[1];
    SysScanDesc scan;
    HeapTuple   tup;
    TYPCATEGORY tcategory;

    /* If it's a domain, look at the base type instead */
    type_id = getBaseType(type_id);

    tcategory = TypeCategory(type_id);

    /*
     * We scan through all the opclasses available for the access method,
     * looking for one that is marked default and matches the target type
     * (either exactly or binary-compatibly, but prefer an exact match).
     *
     * We could find more than one binary-compatible match.  If just one is
     * for a preferred type, use that one; otherwise we fail, forcing the user
     * to specify which one he wants.  (The preferred-type special case is a
     * kluge for varchar: it's binary-compatible to both text and bpchar, so
     * we need a tiebreaker.)  If we find more than one exact match, then
     * someone put bogus entries in pg_opclass.
     */
    rel = heap_open(OperatorClassRelationId, AccessShareLock);

    ScanKeyInit(&skey[0],
                Anum_pg_opclass_opcmethod,
                BTEqualStrategyNumber, F_OIDEQ,
                ObjectIdGetDatum(am_id));

    scan = systable_beginscan(rel, OpclassAmNameNspIndexId, true,
                              SnapshotNow, 1, skey);

    while (HeapTupleIsValid(tup = systable_getnext(scan)))
    {
        Form_pg_opclass opclass = (Form_pg_opclass) GETSTRUCT(tup);

        /* ignore altogether if not a default opclass */
        if (!opclass->opcdefault)
            continue;
        if (opclass->opcintype == type_id)
        {
            nexact++;
            result = HeapTupleGetOid(tup);
        }
        else if (nexact == 0 &&
                 IsBinaryCoercible(type_id, opclass->opcintype))
        {
            if (IsPreferredType(tcategory, opclass->opcintype))
            {
                ncompatiblepreferred++;
                result = HeapTupleGetOid(tup);
            }
            else if (ncompatiblepreferred == 0)
            {
                ncompatible++;
                result = HeapTupleGetOid(tup);
            }
        }
    }

    systable_endscan(scan);

    heap_close(rel, AccessShareLock);

    /* raise error if pg_opclass contains inconsistent data */
    if (nexact > 1)
        ereport(ERROR,
                (errcode(ERRCODE_DUPLICATE_OBJECT),
        errmsg("there are multiple default operator classes for data type %s",
               format_type_be(type_id))));

    if (nexact == 1 ||
        ncompatiblepreferred == 1 ||
        (ncompatiblepreferred == 0 && ncompatible == 1))
        return result;

    return InvalidOid;
}

void IsThereFunctionInNamespace ( const char *  proname,
int  pronargs,
oidvector  proargtypes,
Oid  nspOid 
)

Definition at line 1628 of file functioncmds.c.

References CStringGetDatum, ereport, errcode(), errmsg(), ERROR, funcname_signature_string(), get_namespace_name(), NIL, ObjectIdGetDatum, PointerGetDatum, PROCNAMEARGSNSP, SearchSysCacheExists3, and oidvector::values.

Referenced by AlterObjectNamespace_internal(), and AlterObjectRename_internal().

{
    /* check for duplicate name (more friendly than unique-index failure) */
    if (SearchSysCacheExists3(PROCNAMEARGSNSP,
                              CStringGetDatum(proname),
                              PointerGetDatum(&proargtypes),
                              ObjectIdGetDatum(nspOid)))
        ereport(ERROR,
                (errcode(ERRCODE_DUPLICATE_FUNCTION),
                 errmsg("function %s already exists in schema \"%s\"",
                        funcname_signature_string(proname, pronargs,
                                                  NIL, proargtypes.values),
                        get_namespace_name(nspOid))));
}

void IsThereOpClassInNamespace ( const char *  opcname,
Oid  opcmethod,
Oid  opcnamespace 
)

Definition at line 1689 of file opclasscmds.c.

References CLAAMNAMENSP, CStringGetDatum, ereport, errcode(), errmsg(), ERROR, get_am_name(), get_namespace_name(), ObjectIdGetDatum, and SearchSysCacheExists3.

Referenced by AlterObjectNamespace_internal(), and AlterObjectRename_internal().

{
    /* make sure the new name doesn't exist */
    if (SearchSysCacheExists3(CLAAMNAMENSP,
                              ObjectIdGetDatum(opcmethod),
                              CStringGetDatum(opcname),
                              ObjectIdGetDatum(opcnamespace)))
        ereport(ERROR,
                (errcode(ERRCODE_DUPLICATE_OBJECT),
                 errmsg("operator class \"%s\" for access method \"%s\" already exists in schema \"%s\"",
                        opcname,
                        get_am_name(opcmethod),
                        get_namespace_name(opcnamespace))));
}

void IsThereOpFamilyInNamespace ( const char *  opfname,
Oid  opfmethod,
Oid  opfnamespace 
)

Definition at line 1712 of file opclasscmds.c.

References CStringGetDatum, ereport, errcode(), errmsg(), ERROR, get_am_name(), get_namespace_name(), ObjectIdGetDatum, OPFAMILYAMNAMENSP, and SearchSysCacheExists3.

Referenced by AlterObjectNamespace_internal(), and AlterObjectRename_internal().

{
    /* make sure the new name doesn't exist */
    if (SearchSysCacheExists3(OPFAMILYAMNAMENSP,
                              ObjectIdGetDatum(opfmethod),
                              CStringGetDatum(opfname),
                              ObjectIdGetDatum(opfnamespace)))
        ereport(ERROR,
                (errcode(ERRCODE_DUPLICATE_OBJECT),
                 errmsg("operator family \"%s\" for access method \"%s\" already exists in schema \"%s\"",
                        opfname,
                        get_am_name(opfmethod),
                        get_namespace_name(opfnamespace))));
}

char* makeObjectName ( const char *  name1,
const char *  name2,
const char *  label 
)

Definition at line 1432 of file indexcmds.c.

References Assert, name, NAMEDATALEN, palloc(), and pg_mbcliplen().

Referenced by ChooseConstraintName(), and ChooseRelationName().

{
    char       *name;
    int         overhead = 0;   /* chars needed for label and underscores */
    int         availchars;     /* chars available for name(s) */
    int         name1chars;     /* chars allocated to name1 */
    int         name2chars;     /* chars allocated to name2 */
    int         ndx;

    name1chars = strlen(name1);
    if (name2)
    {
        name2chars = strlen(name2);
        overhead++;             /* allow for separating underscore */
    }
    else
        name2chars = 0;
    if (label)
        overhead += strlen(label) + 1;

    availchars = NAMEDATALEN - 1 - overhead;
    Assert(availchars > 0);     /* else caller chose a bad label */

    /*
     * If we must truncate,  preferentially truncate the longer name. This
     * logic could be expressed without a loop, but it's simple and obvious as
     * a loop.
     */
    while (name1chars + name2chars > availchars)
    {
        if (name1chars > name2chars)
            name1chars--;
        else
            name2chars--;
    }

    name1chars = pg_mbcliplen(name1, name1chars, name1chars);
    if (name2)
        name2chars = pg_mbcliplen(name2, name2chars, name2chars);

    /* Now construct the string using the chosen lengths */
    name = palloc(name1chars + name2chars + overhead + 1);
    memcpy(name, name1, name1chars);
    ndx = name1chars;
    if (name2)
    {
        name[ndx++] = '_';
        memcpy(name + ndx, name2, name2chars);
        ndx += name2chars;
    }
    if (label)
    {
        name[ndx++] = '_';
        strcpy(name + ndx, label);
    }
    else
        name[ndx] = '\0';

    return name;
}

Oid ReindexDatabase ( const char *  databaseName,
bool  do_system,
bool  do_user 
)

Definition at line 1788 of file indexcmds.c.

References AccessShareLock, ACL_KIND_DATABASE, aclcheck_error(), ACLCHECK_NOT_OWNER, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), AssertArg, CommitTransactionCommand(), ereport, errcode(), errmsg(), ERROR, ForwardScanDirection, get_database_name(), get_namespace_name(), get_rel_name(), get_rel_namespace(), GETSTRUCT, GetTransactionSnapshot(), GetUserId(), heap_beginscan(), heap_close, heap_endscan(), heap_getnext(), heap_open(), HeapTupleGetOid, IsSystemClass(), isTempNamespace(), lappend_oid(), lfirst_oid, MemoryContextDelete(), MemoryContextSwitchTo(), MyDatabaseId, NOTICE, NULL, pg_database_ownercheck(), PopActiveSnapshot(), PortalContext, PushActiveSnapshot(), REINDEX_REL_PROCESS_TOAST, reindex_relation(), RelationRelationId, RELKIND_MATVIEW, RELKIND_RELATION, RELPERSISTENCE_TEMP, SnapshotNow, and StartTransactionCommand().

Referenced by standard_ProcessUtility().

{
    Relation    relationRelation;
    HeapScanDesc scan;
    HeapTuple   tuple;
    MemoryContext private_context;
    MemoryContext old;
    List       *relids = NIL;
    ListCell   *l;

    AssertArg(databaseName);

    if (strcmp(databaseName, get_database_name(MyDatabaseId)) != 0)
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("can only reindex the currently open database")));

    if (!pg_database_ownercheck(MyDatabaseId, GetUserId()))
        aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
                       databaseName);

    /*
     * Create a memory context that will survive forced transaction commits we
     * do below.  Since it is a child of PortalContext, it will go away
     * eventually even if we suffer an error; there's no need for special
     * abort cleanup logic.
     */
    private_context = AllocSetContextCreate(PortalContext,
                                            "ReindexDatabase",
                                            ALLOCSET_DEFAULT_MINSIZE,
                                            ALLOCSET_DEFAULT_INITSIZE,
                                            ALLOCSET_DEFAULT_MAXSIZE);

    /*
     * We always want to reindex pg_class first.  This ensures that if there
     * is any corruption in pg_class' indexes, they will be fixed before we
     * process any other tables.  This is critical because reindexing itself
     * will try to update pg_class.
     */
    if (do_system)
    {
        old = MemoryContextSwitchTo(private_context);
        relids = lappend_oid(relids, RelationRelationId);
        MemoryContextSwitchTo(old);
    }

    /*
     * Scan pg_class to build a list of the relations we need to reindex.
     *
     * We only consider plain relations here (toast rels will be processed
     * indirectly by reindex_relation).
     */
    relationRelation = heap_open(RelationRelationId, AccessShareLock);
    scan = heap_beginscan(relationRelation, SnapshotNow, 0, NULL);
    while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
    {
        Form_pg_class classtuple = (Form_pg_class) GETSTRUCT(tuple);

        if (classtuple->relkind != RELKIND_RELATION &&
            classtuple->relkind != RELKIND_MATVIEW)
            continue;

        /* Skip temp tables of other backends; we can't reindex them at all */
        if (classtuple->relpersistence == RELPERSISTENCE_TEMP &&
            !isTempNamespace(classtuple->relnamespace))
            continue;

        /* Check user/system classification, and optionally skip */
        if (IsSystemClass(classtuple))
        {
            if (!do_system)
                continue;
        }
        else
        {
            if (!do_user)
                continue;
        }

        if (HeapTupleGetOid(tuple) == RelationRelationId)
            continue;           /* got it already */

        old = MemoryContextSwitchTo(private_context);
        relids = lappend_oid(relids, HeapTupleGetOid(tuple));
        MemoryContextSwitchTo(old);
    }
    heap_endscan(scan);
    heap_close(relationRelation, AccessShareLock);

    /* Now reindex each rel in a separate transaction */
    PopActiveSnapshot();
    CommitTransactionCommand();
    foreach(l, relids)
    {
        Oid         relid = lfirst_oid(l);

        StartTransactionCommand();
        /* functions in indexes may want a snapshot set */
        PushActiveSnapshot(GetTransactionSnapshot());
        if (reindex_relation(relid, REINDEX_REL_PROCESS_TOAST))
            ereport(NOTICE,
                    (errmsg("table \"%s.%s\" was reindexed",
                            get_namespace_name(get_rel_namespace(relid)),
                            get_rel_name(relid))));
        PopActiveSnapshot();
        CommitTransactionCommand();
    }
    StartTransactionCommand();

    MemoryContextDelete(private_context);

    return MyDatabaseId;
}

Oid ReindexIndex ( RangeVar indexRelation  ) 

Definition at line 1683 of file indexcmds.c.

References AccessExclusiveLock, RangeVarCallbackForReindexIndex(), RangeVarGetRelidExtended(), and reindex_index().

Referenced by standard_ProcessUtility().

{
    Oid         indOid;
    Oid         heapOid = InvalidOid;

    /* lock level used here should match index lock reindex_index() */
    indOid = RangeVarGetRelidExtended(indexRelation, AccessExclusiveLock,
                                      false, false,
                                      RangeVarCallbackForReindexIndex,
                                      (void *) &heapOid);

    reindex_index(indOid, false);

    return indOid;
}

Oid ReindexTable ( RangeVar relation  ) 

Definition at line 1763 of file indexcmds.c.

References ereport, errmsg(), NOTICE, NULL, RangeVarCallbackOwnsTable(), RangeVarGetRelidExtended(), REINDEX_REL_PROCESS_TOAST, reindex_relation(), RangeVar::relname, and ShareLock.

Referenced by standard_ProcessUtility().

{
    Oid         heapOid;

    /* The lock level used here should match reindex_relation(). */
    heapOid = RangeVarGetRelidExtended(relation, ShareLock, false, false,
                                       RangeVarCallbackOwnsTable, NULL);

    if (!reindex_relation(heapOid, REINDEX_REL_PROCESS_TOAST))
        ereport(NOTICE,
                (errmsg("table \"%s\" has no indexes",
                        relation->relname)));

    return heapOid;
}

void RemoveAmOpEntryById ( Oid  entryOid  ) 
void RemoveAmProcEntryById ( Oid  entryOid  ) 
void RemoveForeignDataWrapperById ( Oid  fdwId  ) 
void RemoveForeignServerById ( Oid  srvId  ) 
void RemoveFunctionById ( Oid  funcOid  ) 

Definition at line 997 of file functioncmds.c.

References AGGFNOID, AggregateRelationId, elog, ERROR, GETSTRUCT, heap_close, heap_open(), HeapTupleIsValid, ObjectIdGetDatum, ProcedureRelationId, PROCOID, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1, simple_heap_delete(), and HeapTupleData::t_self.

Referenced by doDeletion().

{
    Relation    relation;
    HeapTuple   tup;
    bool        isagg;

    /*
     * Delete the pg_proc tuple.
     */
    relation = heap_open(ProcedureRelationId, RowExclusiveLock);

    tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcOid));
    if (!HeapTupleIsValid(tup)) /* should not happen */
        elog(ERROR, "cache lookup failed for function %u", funcOid);

    isagg = ((Form_pg_proc) GETSTRUCT(tup))->proisagg;

    simple_heap_delete(relation, &tup->t_self);

    ReleaseSysCache(tup);

    heap_close(relation, RowExclusiveLock);

    /*
     * If there's a pg_aggregate tuple, delete that too.
     */
    if (isagg)
    {
        relation = heap_open(AggregateRelationId, RowExclusiveLock);

        tup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(funcOid));
        if (!HeapTupleIsValid(tup))     /* should not happen */
            elog(ERROR, "cache lookup failed for pg_aggregate tuple for function %u", funcOid);

        simple_heap_delete(relation, &tup->t_self);

        ReleaseSysCache(tup);

        heap_close(relation, RowExclusiveLock);
    }
}

void RemoveObjects ( DropStmt stmt  ) 

Definition at line 47 of file dropcmds.c.

References AccessExclusiveLock, add_exact_object_address(), DropStmt::arguments, DropStmt::behavior, check_object_ownership(), does_not_exist_skipping(), elog, ereport, errcode(), errhint(), errmsg(), ERROR, free_object_addresses(), get_object_address(), get_object_namespace(), GETSTRUCT, GetUserId(), heap_close, HeapTupleIsValid, lfirst, list_head(), lnext, DropStmt::missing_ok, NameListToString(), new_object_addresses(), NoLock, OBJECT_FUNCTION, ObjectAddress::objectId, ObjectIdGetDatum, DropStmt::objects, OidIsValid, performMultipleDeletions(), pg_namespace_ownercheck(), PROCOID, ReleaseSysCache(), DropStmt::removeType, and SearchSysCache1.

Referenced by ExecDropStmt().

{
    ObjectAddresses *objects;
    ListCell   *cell1;
    ListCell   *cell2 = NULL;

    objects = new_object_addresses();

    foreach(cell1, stmt->objects)
    {
        ObjectAddress address;
        List       *objname = lfirst(cell1);
        List       *objargs = NIL;
        Relation    relation = NULL;
        Oid         namespaceId;

        if (stmt->arguments)
        {
            cell2 = (!cell2 ? list_head(stmt->arguments) : lnext(cell2));
            objargs = lfirst(cell2);
        }

        /* Get an ObjectAddress for the object. */
        address = get_object_address(stmt->removeType,
                                     objname, objargs,
                                     &relation,
                                     AccessExclusiveLock,
                                     stmt->missing_ok);

        /* Issue NOTICE if supplied object was not found. */
        if (!OidIsValid(address.objectId))
        {
            does_not_exist_skipping(stmt->removeType, objname, objargs);
            continue;
        }

        /*
         * Although COMMENT ON FUNCTION, SECURITY LABEL ON FUNCTION, etc. are
         * happy to operate on an aggregate as on any other function, we have
         * historically not allowed this for DROP FUNCTION.
         */
        if (stmt->removeType == OBJECT_FUNCTION)
        {
            Oid         funcOid = address.objectId;
            HeapTuple   tup;

            tup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcOid));
            if (!HeapTupleIsValid(tup)) /* should not happen */
                elog(ERROR, "cache lookup failed for function %u", funcOid);

            if (((Form_pg_proc) GETSTRUCT(tup))->proisagg)
                ereport(ERROR,
                        (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                         errmsg("\"%s\" is an aggregate function",
                                NameListToString(objname)),
                errhint("Use DROP AGGREGATE to drop aggregate functions.")));

            ReleaseSysCache(tup);
        }

        /* Check permissions. */
        namespaceId = get_object_namespace(&address);
        if (!OidIsValid(namespaceId) ||
            !pg_namespace_ownercheck(namespaceId, GetUserId()))
            check_object_ownership(GetUserId(), stmt->removeType, address,
                                   objname, objargs, relation);

        /* Release any relcache reference count, but keep lock until commit. */
        if (relation)
            heap_close(relation, NoLock);

        add_exact_object_address(&address, objects);
    }

    /* Here we really delete them. */
    performMultipleDeletions(objects, stmt->behavior, 0);

    free_object_addresses(objects);
}

void RemoveOpClassById ( Oid  opclassOid  ) 
void RemoveOperatorById ( Oid  operOid  ) 

Definition at line 316 of file operatorcmds.c.

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

Referenced by doDeletion().

{
    Relation    relation;
    HeapTuple   tup;

    relation = heap_open(OperatorRelationId, RowExclusiveLock);

    tup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operOid));
    if (!HeapTupleIsValid(tup)) /* should not happen */
        elog(ERROR, "cache lookup failed for operator %u", operOid);

    simple_heap_delete(relation, &tup->t_self);

    ReleaseSysCache(tup);

    heap_close(relation, RowExclusiveLock);
}

void RemoveOpFamilyById ( Oid  opfamilyOid  ) 
void RemoveTSConfigurationById ( Oid  cfgId  ) 
void RemoveTSDictionaryById ( Oid  dictId  ) 
void RemoveTSParserById ( Oid  prsId  ) 
void RemoveTSTemplateById ( Oid  tmplId  ) 
Oid RemoveUserMapping ( DropUserMappingStmt stmt  ) 

Definition at line 1256 of file foreigncmds.c.

References DROP_CASCADE, elog, ereport, errcode(), errmsg(), ERROR, GetForeignServerByName(), GetSysCacheOid2, GetUserOidFromMapping(), MappingUserName, DropUserMappingStmt::missing_ok, NOTICE, ObjectIdGetDatum, OidIsValid, performDeletion(), ForeignServer::serverid, ForeignServer::servername, DropUserMappingStmt::servername, user_mapping_ddl_aclcheck(), USERMAPPINGUSERSERVER, and DropUserMappingStmt::username.

Referenced by ProcessUtilitySlow().

{
    ObjectAddress object;
    Oid         useId;
    Oid         umId;
    ForeignServer *srv;

    useId = GetUserOidFromMapping(stmt->username, stmt->missing_ok);
    srv = GetForeignServerByName(stmt->servername, true);

    if (stmt->username && !OidIsValid(useId))
    {
        /*
         * IF EXISTS specified, role not found and not public. Notice this and
         * leave.
         */
        elog(NOTICE, "role \"%s\" does not exist, skipping", stmt->username);
        return InvalidOid;
    }

    if (!srv)
    {
        if (!stmt->missing_ok)
            ereport(ERROR,
                    (errcode(ERRCODE_UNDEFINED_OBJECT),
                     errmsg("server \"%s\" does not exist",
                            stmt->servername)));
        /* IF EXISTS, just note it */
        ereport(NOTICE, (errmsg("server does not exist, skipping")));
        return InvalidOid;
    }

    umId = GetSysCacheOid2(USERMAPPINGUSERSERVER,
                           ObjectIdGetDatum(useId),
                           ObjectIdGetDatum(srv->serverid));

    if (!OidIsValid(umId))
    {
        if (!stmt->missing_ok)
            ereport(ERROR,
                    (errcode(ERRCODE_UNDEFINED_OBJECT),
                  errmsg("user mapping \"%s\" does not exist for the server",
                         MappingUserName(useId))));

        /* IF EXISTS specified, just note it */
        ereport(NOTICE,
        (errmsg("user mapping \"%s\" does not exist for the server, skipping",
                MappingUserName(useId))));
        return InvalidOid;
    }

    user_mapping_ddl_aclcheck(useId, srv->serverid, srv->servername);

    /*
     * Do the deletion
     */
    object.classId = UserMappingRelationId;
    object.objectId = umId;
    object.objectSubId = 0;

    performDeletion(&object, DROP_CASCADE, 0);

    return umId;
}

void RemoveUserMappingById ( Oid  umId  ) 
text* serialize_deflist ( List deflist  ) 

Definition at line 1497 of file tsearchcmds.c.

References appendStringInfo(), appendStringInfoChar(), buf, cstring_to_text_with_len(), StringInfoData::data, defGetString(), DefElem::defname, ESCAPE_STRING_SYNTAX, initStringInfo(), StringInfoData::len, lfirst, lnext, NULL, pfree(), quote_identifier(), SQL_STR_DOUBLE, and val.

Referenced by AlterTSDictionary(), and DefineTSDictionary().

{
    text       *result;
    StringInfoData buf;
    ListCell   *l;

    initStringInfo(&buf);

    foreach(l, deflist)
    {
        DefElem    *defel = (DefElem *) lfirst(l);
        char       *val = defGetString(defel);

        appendStringInfo(&buf, "%s = ",
                         quote_identifier(defel->defname));
        /* If backslashes appear, force E syntax to determine their handling */
        if (strchr(val, '\\'))
            appendStringInfoChar(&buf, ESCAPE_STRING_SYNTAX);
        appendStringInfoChar(&buf, '\'');
        while (*val)
        {
            char        ch = *val++;

            if (SQL_STR_DOUBLE(ch, true))
                appendStringInfoChar(&buf, ch);
            appendStringInfoChar(&buf, ch);
        }
        appendStringInfoChar(&buf, '\'');
        if (lnext(l) != NULL)
            appendStringInfo(&buf, ", ");
    }

    result = cstring_to_text_with_len(buf.data, buf.len);
    pfree(buf.data);
    return result;
}

void SetFunctionArgType ( Oid  funcOid,
int  argIndex,
Oid  newArgType 
)

Definition at line 1222 of file functioncmds.c.

References CatalogUpdateIndexes(), elog, ERROR, GETSTRUCT, heap_close, heap_open(), HeapTupleIsValid, ObjectIdGetDatum, OPAQUEOID, ProcedureRelationId, PROCOID, RowExclusiveLock, SearchSysCacheCopy1, simple_heap_update(), and HeapTupleData::t_self.

Referenced by findTypeInputFunction(), and findTypeOutputFunction().

{
    Relation    pg_proc_rel;
    HeapTuple   tup;
    Form_pg_proc procForm;

    pg_proc_rel = heap_open(ProcedureRelationId, RowExclusiveLock);

    tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(funcOid));
    if (!HeapTupleIsValid(tup)) /* should not happen */
        elog(ERROR, "cache lookup failed for function %u", funcOid);
    procForm = (Form_pg_proc) GETSTRUCT(tup);

    if (argIndex < 0 || argIndex >= procForm->pronargs ||
        procForm->proargtypes.values[argIndex] != OPAQUEOID)
        elog(ERROR, "function %u doesn't take OPAQUE", funcOid);

    /* okay to overwrite copied tuple */
    procForm->proargtypes.values[argIndex] = newArgType;

    /* update the catalog and its indexes */
    simple_heap_update(pg_proc_rel, &tup->t_self, tup);

    CatalogUpdateIndexes(pg_proc_rel, tup);

    heap_close(pg_proc_rel, RowExclusiveLock);
}

void SetFunctionReturnType ( Oid  funcOid,
Oid  newRetType 
)

Definition at line 1188 of file functioncmds.c.

References CatalogUpdateIndexes(), elog, ERROR, GETSTRUCT, heap_close, heap_open(), HeapTupleIsValid, ObjectIdGetDatum, OPAQUEOID, ProcedureRelationId, PROCOID, RowExclusiveLock, SearchSysCacheCopy1, simple_heap_update(), and HeapTupleData::t_self.

Referenced by CreateProceduralLanguage(), CreateTrigger(), and DefineType().

{
    Relation    pg_proc_rel;
    HeapTuple   tup;
    Form_pg_proc procForm;

    pg_proc_rel = heap_open(ProcedureRelationId, RowExclusiveLock);

    tup = SearchSysCacheCopy1(PROCOID, ObjectIdGetDatum(funcOid));
    if (!HeapTupleIsValid(tup)) /* should not happen */
        elog(ERROR, "cache lookup failed for function %u", funcOid);
    procForm = (Form_pg_proc) GETSTRUCT(tup);

    if (procForm->prorettype != OPAQUEOID)      /* caller messed up */
        elog(ERROR, "function %u doesn't return OPAQUE", funcOid);

    /* okay to overwrite copied tuple */
    procForm->prorettype = newRetType;

    /* update the catalog and its indexes */
    simple_heap_update(pg_proc_rel, &tup->t_self, tup);

    CatalogUpdateIndexes(pg_proc_rel, tup);

    heap_close(pg_proc_rel, RowExclusiveLock);
}

Datum transformGenericOptions ( Oid  catalogId,
Datum  oldOptions,
List options,
Oid  fdwvalidator 
)

Definition at line 94 of file foreigncmds.c.

References construct_empty_array(), DatumGetPointer, DefElem::defaction, DEFELEM_ADD, DEFELEM_DROP, DEFELEM_SET, DEFELEM_UNSPEC, DefElem::defname, elog, ereport, errcode(), errmsg(), ERROR, lappend(), lfirst, list_delete_cell(), NULL, ObjectIdGetDatum, OidFunctionCall2, OidIsValid, optionListToArray(), PointerGetDatum, TEXTOID, and untransformRelOptions().

Referenced by AlterForeignDataWrapper(), AlterForeignServer(), AlterUserMapping(), ATExecAlterColumnGenericOptions(), ATExecGenericOptions(), CreateForeignDataWrapper(), CreateForeignServer(), CreateForeignTable(), and CreateUserMapping().

{
    List       *resultOptions = untransformRelOptions(oldOptions);
    ListCell   *optcell;
    Datum       result;

    foreach(optcell, options)
    {
        DefElem    *od = lfirst(optcell);
        ListCell   *cell;
        ListCell   *prev = NULL;

        /*
         * Find the element in resultOptions.  We need this for validation in
         * all cases.  Also identify the previous element.
         */
        foreach(cell, resultOptions)
        {
            DefElem    *def = lfirst(cell);

            if (strcmp(def->defname, od->defname) == 0)
                break;
            else
                prev = cell;
        }

        /*
         * It is possible to perform multiple SET/DROP actions on the same
         * option.  The standard permits this, as long as the options to be
         * added are unique.  Note that an unspecified action is taken to be
         * ADD.
         */
        switch (od->defaction)
        {
            case DEFELEM_DROP:
                if (!cell)
                    ereport(ERROR,
                            (errcode(ERRCODE_UNDEFINED_OBJECT),
                             errmsg("option \"%s\" not found",
                                    od->defname)));
                resultOptions = list_delete_cell(resultOptions, cell, prev);
                break;

            case DEFELEM_SET:
                if (!cell)
                    ereport(ERROR,
                            (errcode(ERRCODE_UNDEFINED_OBJECT),
                             errmsg("option \"%s\" not found",
                                    od->defname)));
                lfirst(cell) = od;
                break;

            case DEFELEM_ADD:
            case DEFELEM_UNSPEC:
                if (cell)
                    ereport(ERROR,
                            (errcode(ERRCODE_DUPLICATE_OBJECT),
                             errmsg("option \"%s\" provided more than once",
                                    od->defname)));
                resultOptions = lappend(resultOptions, od);
                break;

            default:
                elog(ERROR, "unrecognized action %d on option \"%s\"",
                     (int) od->defaction, od->defname);
                break;
        }
    }

    result = optionListToArray(resultOptions);

    if (OidIsValid(fdwvalidator))
    {
        Datum       valarg = result;

        /*
         * Pass a null options list as an empty array, so that validators
         * don't have to be declared non-strict to handle the case.
         */
        if (DatumGetPointer(valarg) == NULL)
            valarg = PointerGetDatum(construct_empty_array(TEXTOID));
        OidFunctionCall2(fdwvalidator, valarg, ObjectIdGetDatum(catalogId));
    }

    return result;
}