Header And Logo

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

Functions

pg_type_fn.h File Reference

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

Go to the source code of this file.

Functions

Oid TypeShellMake (const char *typeName, Oid typeNamespace, Oid ownerId)
Oid TypeCreate (Oid newTypeOid, const char *typeName, Oid typeNamespace, Oid relationOid, char relationKind, Oid ownerId, int16 internalSize, char typeType, char typeCategory, bool typePreferred, char typDelim, Oid inputProcedure, Oid outputProcedure, Oid receiveProcedure, Oid sendProcedure, Oid typmodinProcedure, Oid typmodoutProcedure, Oid analyzeProcedure, Oid elementType, bool isImplicitArray, Oid arrayType, Oid baseType, const char *defaultTypeValue, char *defaultTypeBin, bool passedByValue, char alignment, char storage, int32 typeMod, int32 typNDims, bool typeNotNull, Oid typeCollation)
void GenerateTypeDependencies (Oid typeNamespace, Oid typeObjectId, Oid relationOid, char relationKind, Oid owner, Oid inputProcedure, Oid outputProcedure, Oid receiveProcedure, Oid sendProcedure, Oid typmodinProcedure, Oid typmodoutProcedure, Oid analyzeProcedure, Oid elementType, bool isImplicitArray, Oid baseType, Oid typeCollation, Node *defaultExpr, bool rebuild)
void RenameTypeInternal (Oid typeOid, const char *newTypeName, Oid typeNamespace)
char * makeArrayTypeName (const char *typeName, Oid typeNamespace)
bool moveArrayTypeName (Oid typeOid, const char *typeName, Oid typeNamespace)

Function Documentation

void GenerateTypeDependencies ( Oid  typeNamespace,
Oid  typeObjectId,
Oid  relationOid,
char  relationKind,
Oid  owner,
Oid  inputProcedure,
Oid  outputProcedure,
Oid  receiveProcedure,
Oid  sendProcedure,
Oid  typmodinProcedure,
Oid  typmodoutProcedure,
Oid  analyzeProcedure,
Oid  elementType,
bool  isImplicitArray,
Oid  baseType,
Oid  typeCollation,
Node defaultExpr,
bool  rebuild 
)

Definition at line 500 of file pg_type.c.

References ObjectAddress::classId, DEFAULT_COLLATION_OID, deleteDependencyRecordsFor(), deleteSharedDependencyRecordsFor(), DEPENDENCY_INTERNAL, DEPENDENCY_NORMAL, NIL, ObjectAddress::objectId, ObjectAddress::objectSubId, OidIsValid, recordDependencyOn(), recordDependencyOnCurrentExtension(), recordDependencyOnExpr(), recordDependencyOnOwner(), RELKIND_COMPOSITE_TYPE, and TypeRelationId.

Referenced by AlterDomainDefault(), TypeCreate(), and TypeShellMake().

{
    ObjectAddress myself,
                referenced;

    /* If rebuild, first flush old dependencies, except extension deps */
    if (rebuild)
    {
        deleteDependencyRecordsFor(TypeRelationId, typeObjectId, true);
        deleteSharedDependencyRecordsFor(TypeRelationId, typeObjectId, 0);
    }

    myself.classId = TypeRelationId;
    myself.objectId = typeObjectId;
    myself.objectSubId = 0;

    /*
     * Make dependencies on namespace, owner, extension.
     *
     * For a relation rowtype (that's not a composite type), we should skip
     * these because we'll depend on them indirectly through the pg_class
     * entry.  Likewise, skip for implicit arrays since we'll depend on them
     * through the element type.
     */
    if ((!OidIsValid(relationOid) || relationKind == RELKIND_COMPOSITE_TYPE) &&
        !isImplicitArray)
    {
        referenced.classId = NamespaceRelationId;
        referenced.objectId = typeNamespace;
        referenced.objectSubId = 0;
        recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

        recordDependencyOnOwner(TypeRelationId, typeObjectId, owner);

        recordDependencyOnCurrentExtension(&myself, rebuild);
    }

    /* Normal dependencies on the I/O functions */
    if (OidIsValid(inputProcedure))
    {
        referenced.classId = ProcedureRelationId;
        referenced.objectId = inputProcedure;
        referenced.objectSubId = 0;
        recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
    }

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

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

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

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

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

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

    /*
     * If the type is a rowtype for a relation, mark it as internally
     * dependent on the relation, *unless* it is a stand-alone composite type
     * relation. For the latter case, we have to reverse the dependency.
     *
     * In the former case, this allows the type to be auto-dropped when the
     * relation is, and not otherwise. And in the latter, of course we get the
     * opposite effect.
     */
    if (OidIsValid(relationOid))
    {
        referenced.classId = RelationRelationId;
        referenced.objectId = relationOid;
        referenced.objectSubId = 0;

        if (relationKind != RELKIND_COMPOSITE_TYPE)
            recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
        else
            recordDependencyOn(&referenced, &myself, DEPENDENCY_INTERNAL);
    }

    /*
     * If the type is an implicitly-created array type, mark it as internally
     * dependent on the element type.  Otherwise, if it has an element type,
     * the dependency is a normal one.
     */
    if (OidIsValid(elementType))
    {
        referenced.classId = TypeRelationId;
        referenced.objectId = elementType;
        referenced.objectSubId = 0;
        recordDependencyOn(&myself, &referenced,
                  isImplicitArray ? DEPENDENCY_INTERNAL : DEPENDENCY_NORMAL);
    }

    /* Normal dependency from a domain to its base type. */
    if (OidIsValid(baseType))
    {
        referenced.classId = TypeRelationId;
        referenced.objectId = baseType;
        referenced.objectSubId = 0;
        recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
    }

    /* Normal dependency from a domain to its collation. */
    /* We know the default collation is pinned, so don't bother recording it */
    if (OidIsValid(typeCollation) && typeCollation != DEFAULT_COLLATION_OID)
    {
        referenced.classId = CollationRelationId;
        referenced.objectId = typeCollation;
        referenced.objectSubId = 0;
        recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
    }

    /* Normal dependency on the default expression. */
    if (defaultExpr)
        recordDependencyOnExpr(&myself, defaultExpr, NIL, DEPENDENCY_NORMAL);
}

char* makeArrayTypeName ( const char *  typeName,
Oid  typeNamespace 
)

Definition at line 738 of file pg_type.c.

References AccessShareLock, CStringGetDatum, ereport, errcode(), errmsg(), ERROR, heap_close, heap_open(), i, NAMEDATALEN, ObjectIdGetDatum, palloc(), SearchSysCacheExists2, truncate_identifier(), TYPENAMENSP, and TypeRelationId.

Referenced by DefineEnum(), DefineRange(), DefineType(), heap_create_with_catalog(), moveArrayTypeName(), and RenameTypeInternal().

{
    char       *arr = (char *) palloc(NAMEDATALEN);
    int         namelen = strlen(typeName);
    Relation    pg_type_desc;
    int         i;

    /*
     * The idea is to prepend underscores as needed until we make a name that
     * doesn't collide with anything...
     */
    pg_type_desc = heap_open(TypeRelationId, AccessShareLock);

    for (i = 1; i < NAMEDATALEN - 1; i++)
    {
        arr[i - 1] = '_';
        if (i + namelen < NAMEDATALEN)
            strcpy(arr + i, typeName);
        else
        {
            memcpy(arr + i, typeName, NAMEDATALEN - i);
            truncate_identifier(arr, NAMEDATALEN, false);
        }
        if (!SearchSysCacheExists2(TYPENAMENSP,
                                   CStringGetDatum(arr),
                                   ObjectIdGetDatum(typeNamespace)))
            break;
    }

    heap_close(pg_type_desc, AccessShareLock);

    if (i >= NAMEDATALEN - 1)
        ereport(ERROR,
                (errcode(ERRCODE_DUPLICATE_OBJECT),
                 errmsg("could not form array type name for type \"%s\"",
                        typeName)));

    return arr;
}

bool moveArrayTypeName ( Oid  typeOid,
const char *  typeName,
Oid  typeNamespace 
)

Definition at line 804 of file pg_type.c.

References CommandCounterIncrement(), get_array_type(), get_element_type(), get_typisdefined(), makeArrayTypeName(), OidIsValid, pfree(), and RenameTypeInternal().

Referenced by DefineCompositeType(), DefineDomain(), DefineEnum(), DefineRange(), DefineType(), and heap_create_with_catalog().

{
    Oid         elemOid;
    char       *newname;

    /* We need do nothing if it's a shell type. */
    if (!get_typisdefined(typeOid))
        return true;

    /* Can't change it if it's not an autogenerated array type. */
    elemOid = get_element_type(typeOid);
    if (!OidIsValid(elemOid) ||
        get_array_type(elemOid) != typeOid)
        return false;

    /*
     * OK, use makeArrayTypeName to pick an unused modification of the name.
     * Note that since makeArrayTypeName is an iterative process, this will
     * produce a name that it might have produced the first time, had the
     * conflicting type we are about to create already existed.
     */
    newname = makeArrayTypeName(typeName, typeNamespace);

    /* Apply the rename */
    RenameTypeInternal(typeOid, newname, typeNamespace);

    /*
     * We must bump the command counter so that any subsequent use of
     * makeArrayTypeName sees what we just did and doesn't pick the same name.
     */
    CommandCounterIncrement();

    pfree(newname);

    return true;
}

void RenameTypeInternal ( Oid  typeOid,
const char *  newTypeName,
Oid  typeNamespace 
)

Definition at line 680 of file pg_type.c.

References Assert, CatalogUpdateIndexes(), CStringGetDatum, elog, ereport, errcode(), errmsg(), ERROR, GETSTRUCT, heap_close, heap_freetuple(), heap_open(), HeapTupleIsValid, InvokeObjectPostAlterHook, makeArrayTypeName(), namestrcpy(), ObjectIdGetDatum, OidIsValid, pfree(), RenameTypeInternal(), RowExclusiveLock, SearchSysCacheCopy1, SearchSysCacheExists2, simple_heap_update(), HeapTupleData::t_self, TYPENAMENSP, TYPEOID, and TypeRelationId.

Referenced by moveArrayTypeName(), RenameRelationInternal(), RenameType(), and RenameTypeInternal().

{
    Relation    pg_type_desc;
    HeapTuple   tuple;
    Form_pg_type typ;
    Oid         arrayOid;

    pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);

    tuple = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid));
    if (!HeapTupleIsValid(tuple))
        elog(ERROR, "cache lookup failed for type %u", typeOid);
    typ = (Form_pg_type) GETSTRUCT(tuple);

    /* We are not supposed to be changing schemas here */
    Assert(typeNamespace == typ->typnamespace);

    arrayOid = typ->typarray;

    /* Just to give a more friendly error than unique-index violation */
    if (SearchSysCacheExists2(TYPENAMENSP,
                              CStringGetDatum(newTypeName),
                              ObjectIdGetDatum(typeNamespace)))
        ereport(ERROR,
                (errcode(ERRCODE_DUPLICATE_OBJECT),
                 errmsg("type \"%s\" already exists", newTypeName)));

    /* OK, do the rename --- tuple is a copy, so OK to scribble on it */
    namestrcpy(&(typ->typname), newTypeName);

    simple_heap_update(pg_type_desc, &tuple->t_self, tuple);

    /* update the system catalog indexes */
    CatalogUpdateIndexes(pg_type_desc, tuple);

    InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);

    heap_freetuple(tuple);
    heap_close(pg_type_desc, RowExclusiveLock);

    /* If the type has an array type, recurse to handle that */
    if (OidIsValid(arrayOid))
    {
        char       *arrname = makeArrayTypeName(newTypeName, typeNamespace);

        RenameTypeInternal(arrayOid, arrname, typeNamespace);
        pfree(arrname);
    }
}

Oid TypeCreate ( Oid  newTypeOid,
const char *  typeName,
Oid  typeNamespace,
Oid  relationOid,
char  relationKind,
Oid  ownerId,
int16  internalSize,
char  typeType,
char  typeCategory,
bool  typePreferred,
char  typDelim,
Oid  inputProcedure,
Oid  outputProcedure,
Oid  receiveProcedure,
Oid  sendProcedure,
Oid  typmodinProcedure,
Oid  typmodoutProcedure,
Oid  analyzeProcedure,
Oid  elementType,
bool  isImplicitArray,
Oid  arrayType,
Oid  baseType,
const char *  defaultTypeValue,
char *  defaultTypeBin,
bool  passedByValue,
char  alignment,
char  storage,
int32  typeMod,
int32  typNDims,
bool  typeNotNull,
Oid  typeCollation 
)

Definition at line 188 of file pg_type.c.

References ACL_KIND_TYPE, ACL_OBJECT_TYPE, aclcheck_error(), ACLCHECK_NOT_OWNER, Anum_pg_type_typacl, Anum_pg_type_typalign, Anum_pg_type_typanalyze, Anum_pg_type_typarray, Anum_pg_type_typbasetype, Anum_pg_type_typbyval, Anum_pg_type_typcategory, Anum_pg_type_typcollation, Anum_pg_type_typdefault, Anum_pg_type_typdefaultbin, Anum_pg_type_typdelim, Anum_pg_type_typelem, Anum_pg_type_typinput, Anum_pg_type_typisdefined, Anum_pg_type_typispreferred, Anum_pg_type_typlen, Anum_pg_type_typmodin, Anum_pg_type_typmodout, Anum_pg_type_typname, Anum_pg_type_typnamespace, Anum_pg_type_typndims, Anum_pg_type_typnotnull, Anum_pg_type_typoutput, Anum_pg_type_typowner, Anum_pg_type_typreceive, Anum_pg_type_typrelid, Anum_pg_type_typsend, Anum_pg_type_typstorage, Anum_pg_type_typtype, Anum_pg_type_typtypmod, binary_upgrade_next_pg_type_oid, BoolGetDatum, CatalogUpdateIndexes(), CharGetDatum, CStringGetDatum, CStringGetTextDatum, elog, ereport, errcode(), errmsg(), ERROR, GenerateTypeDependencies(), get_user_default_acl(), GETSTRUCT, heap_close, heap_form_tuple(), heap_modify_tuple(), heap_open(), HeapTupleGetOid, HeapTupleIsValid, HeapTupleSetOid, i, Int16GetDatum, Int32GetDatum, InvokeObjectPostCreateHook, IsBinaryUpgrade, IsBootstrapProcessingMode, name, NameGetDatum, namestrcpy(), NULL, ObjectIdGetDatum, OidIsValid, PointerGetDatum, RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy2, simple_heap_insert(), simple_heap_update(), stringToNode(), HeapTupleData::t_self, TYPENAMENSP, TypeRelationId, and values.

Referenced by AddNewRelationType(), DefineDomain(), DefineEnum(), DefineRange(), DefineType(), and heap_create_with_catalog().

{
    Relation    pg_type_desc;
    Oid         typeObjectId;
    bool        rebuildDeps = false;
    HeapTuple   tup;
    bool        nulls[Natts_pg_type];
    bool        replaces[Natts_pg_type];
    Datum       values[Natts_pg_type];
    NameData    name;
    int         i;
    Acl        *typacl = NULL;

    /*
     * We assume that the caller validated the arguments individually, but did
     * not check for bad combinations.
     *
     * Validate size specifications: either positive (fixed-length) or -1
     * (varlena) or -2 (cstring).
     */
    if (!(internalSize > 0 ||
          internalSize == -1 ||
          internalSize == -2))
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                 errmsg("invalid type internal size %d",
                        internalSize)));

    if (passedByValue)
    {
        /*
         * Pass-by-value types must have a fixed length that is one of the
         * values supported by fetch_att() and store_att_byval(); and the
         * alignment had better agree, too.  All this code must match
         * access/tupmacs.h!
         */
        if (internalSize == (int16) sizeof(char))
        {
            if (alignment != 'c')
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                         errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
                                alignment, internalSize)));
        }
        else if (internalSize == (int16) sizeof(int16))
        {
            if (alignment != 's')
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                         errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
                                alignment, internalSize)));
        }
        else if (internalSize == (int16) sizeof(int32))
        {
            if (alignment != 'i')
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                         errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
                                alignment, internalSize)));
        }
#if SIZEOF_DATUM == 8
        else if (internalSize == (int16) sizeof(Datum))
        {
            if (alignment != 'd')
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                         errmsg("alignment \"%c\" is invalid for passed-by-value type of size %d",
                                alignment, internalSize)));
        }
#endif
        else
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
               errmsg("internal size %d is invalid for passed-by-value type",
                      internalSize)));
    }
    else
    {
        /* varlena types must have int align or better */
        if (internalSize == -1 && !(alignment == 'i' || alignment == 'd'))
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
               errmsg("alignment \"%c\" is invalid for variable-length type",
                      alignment)));
        /* cstring must have char alignment */
        if (internalSize == -2 && !(alignment == 'c'))
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
               errmsg("alignment \"%c\" is invalid for variable-length type",
                      alignment)));
    }

    /* Only varlena types can be toasted */
    if (storage != 'p' && internalSize != -1)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                 errmsg("fixed-size types must have storage PLAIN")));

    /*
     * initialize arrays needed for heap_form_tuple or heap_modify_tuple
     */
    for (i = 0; i < Natts_pg_type; ++i)
    {
        nulls[i] = false;
        replaces[i] = true;
        values[i] = (Datum) 0;
    }

    /*
     * insert data values
     */
    namestrcpy(&name, typeName);
    values[Anum_pg_type_typname - 1] = NameGetDatum(&name);
    values[Anum_pg_type_typnamespace - 1] = ObjectIdGetDatum(typeNamespace);
    values[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(ownerId);
    values[Anum_pg_type_typlen - 1] = Int16GetDatum(internalSize);
    values[Anum_pg_type_typbyval - 1] = BoolGetDatum(passedByValue);
    values[Anum_pg_type_typtype - 1] = CharGetDatum(typeType);
    values[Anum_pg_type_typcategory - 1] = CharGetDatum(typeCategory);
    values[Anum_pg_type_typispreferred - 1] = BoolGetDatum(typePreferred);
    values[Anum_pg_type_typisdefined - 1] = BoolGetDatum(true);
    values[Anum_pg_type_typdelim - 1] = CharGetDatum(typDelim);
    values[Anum_pg_type_typrelid - 1] = ObjectIdGetDatum(relationOid);
    values[Anum_pg_type_typelem - 1] = ObjectIdGetDatum(elementType);
    values[Anum_pg_type_typarray - 1] = ObjectIdGetDatum(arrayType);
    values[Anum_pg_type_typinput - 1] = ObjectIdGetDatum(inputProcedure);
    values[Anum_pg_type_typoutput - 1] = ObjectIdGetDatum(outputProcedure);
    values[Anum_pg_type_typreceive - 1] = ObjectIdGetDatum(receiveProcedure);
    values[Anum_pg_type_typsend - 1] = ObjectIdGetDatum(sendProcedure);
    values[Anum_pg_type_typmodin - 1] = ObjectIdGetDatum(typmodinProcedure);
    values[Anum_pg_type_typmodout - 1] = ObjectIdGetDatum(typmodoutProcedure);
    values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(analyzeProcedure);
    values[Anum_pg_type_typalign - 1] = CharGetDatum(alignment);
    values[Anum_pg_type_typstorage - 1] = CharGetDatum(storage);
    values[Anum_pg_type_typnotnull - 1] = BoolGetDatum(typeNotNull);
    values[Anum_pg_type_typbasetype - 1] = ObjectIdGetDatum(baseType);
    values[Anum_pg_type_typtypmod - 1] = Int32GetDatum(typeMod);
    values[Anum_pg_type_typndims - 1] = Int32GetDatum(typNDims);
    values[Anum_pg_type_typcollation - 1] = ObjectIdGetDatum(typeCollation);

    /*
     * initialize the default binary value for this type.  Check for nulls of
     * course.
     */
    if (defaultTypeBin)
        values[Anum_pg_type_typdefaultbin - 1] = CStringGetTextDatum(defaultTypeBin);
    else
        nulls[Anum_pg_type_typdefaultbin - 1] = true;

    /*
     * initialize the default value for this type.
     */
    if (defaultTypeValue)
        values[Anum_pg_type_typdefault - 1] = CStringGetTextDatum(defaultTypeValue);
    else
        nulls[Anum_pg_type_typdefault - 1] = true;

    typacl = get_user_default_acl(ACL_OBJECT_TYPE, ownerId,
                                  typeNamespace);
    if (typacl != NULL)
        values[Anum_pg_type_typacl - 1] = PointerGetDatum(typacl);
    else
        nulls[Anum_pg_type_typacl - 1] = true;

    /*
     * open pg_type and prepare to insert or update a row.
     *
     * NOTE: updating will not work correctly in bootstrap mode; but we don't
     * expect to be overwriting any shell types in bootstrap mode.
     */
    pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);

    tup = SearchSysCacheCopy2(TYPENAMENSP,
                              CStringGetDatum(typeName),
                              ObjectIdGetDatum(typeNamespace));
    if (HeapTupleIsValid(tup))
    {
        /*
         * check that the type is not already defined.  It may exist as a
         * shell type, however.
         */
        if (((Form_pg_type) GETSTRUCT(tup))->typisdefined)
            ereport(ERROR,
                    (errcode(ERRCODE_DUPLICATE_OBJECT),
                     errmsg("type \"%s\" already exists", typeName)));

        /*
         * shell type must have been created by same owner
         */
        if (((Form_pg_type) GETSTRUCT(tup))->typowner != ownerId)
            aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE, typeName);

        /* trouble if caller wanted to force the OID */
        if (OidIsValid(newTypeOid))
            elog(ERROR, "cannot assign new OID to existing shell type");

        /*
         * Okay to update existing shell type tuple
         */
        tup = heap_modify_tuple(tup,
                                RelationGetDescr(pg_type_desc),
                                values,
                                nulls,
                                replaces);

        simple_heap_update(pg_type_desc, &tup->t_self, tup);

        typeObjectId = HeapTupleGetOid(tup);

        rebuildDeps = true;     /* get rid of shell type's dependencies */
    }
    else
    {
        tup = heap_form_tuple(RelationGetDescr(pg_type_desc),
                              values,
                              nulls);

        /* Force the OID if requested by caller */
        if (OidIsValid(newTypeOid))
            HeapTupleSetOid(tup, newTypeOid);
        /* Use binary-upgrade override for pg_type.oid, if supplied. */
        else if (IsBinaryUpgrade && OidIsValid(binary_upgrade_next_pg_type_oid))
        {
            HeapTupleSetOid(tup, binary_upgrade_next_pg_type_oid);
            binary_upgrade_next_pg_type_oid = InvalidOid;
        }
        /* else allow system to assign oid */

        typeObjectId = simple_heap_insert(pg_type_desc, tup);
    }

    /* Update indexes */
    CatalogUpdateIndexes(pg_type_desc, tup);

    /*
     * Create dependencies.  We can/must skip this in bootstrap mode.
     */
    if (!IsBootstrapProcessingMode())
        GenerateTypeDependencies(typeNamespace,
                                 typeObjectId,
                                 relationOid,
                                 relationKind,
                                 ownerId,
                                 inputProcedure,
                                 outputProcedure,
                                 receiveProcedure,
                                 sendProcedure,
                                 typmodinProcedure,
                                 typmodoutProcedure,
                                 analyzeProcedure,
                                 elementType,
                                 isImplicitArray,
                                 baseType,
                                 typeCollation,
                                 (defaultTypeBin ?
                                  stringToNode(defaultTypeBin) :
                                  NULL),
                                 rebuildDeps);

    /* Post creation hook for new type */
    InvokeObjectPostCreateHook(TypeRelationId, typeObjectId, 0);

    /*
     * finish up
     */
    heap_close(pg_type_desc, RowExclusiveLock);

    return typeObjectId;
}

Oid TypeShellMake ( const char *  typeName,
Oid  typeNamespace,
Oid  ownerId 
)

Definition at line 55 of file pg_type.c.

References Anum_pg_type_typacl, Anum_pg_type_typalign, Anum_pg_type_typanalyze, Anum_pg_type_typarray, Anum_pg_type_typbasetype, Anum_pg_type_typbyval, Anum_pg_type_typcategory, Anum_pg_type_typcollation, Anum_pg_type_typdefault, Anum_pg_type_typdefaultbin, Anum_pg_type_typdelim, Anum_pg_type_typelem, Anum_pg_type_typinput, Anum_pg_type_typisdefined, Anum_pg_type_typispreferred, Anum_pg_type_typlen, Anum_pg_type_typmodin, Anum_pg_type_typmodout, Anum_pg_type_typname, Anum_pg_type_typnamespace, Anum_pg_type_typndims, Anum_pg_type_typnotnull, Anum_pg_type_typoutput, Anum_pg_type_typowner, Anum_pg_type_typreceive, Anum_pg_type_typrelid, Anum_pg_type_typsend, Anum_pg_type_typstorage, Anum_pg_type_typtype, Anum_pg_type_typtypmod, Assert, binary_upgrade_next_pg_type_oid, BoolGetDatum, CatalogUpdateIndexes(), CharGetDatum, DEFAULT_TYPDELIM, GenerateTypeDependencies(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), HeapTupleSetOid, i, Int16GetDatum, Int32GetDatum, InvalidOid, InvokeObjectPostCreateHook, IsBinaryUpgrade, IsBootstrapProcessingMode, name, NameGetDatum, namestrcpy(), NULL, ObjectIdGetDatum, OidIsValid, PointerIsValid, RelationData::rd_att, RowExclusiveLock, simple_heap_insert(), TYPCATEGORY_PSEUDOTYPE, TypeRelationId, TYPTYPE_PSEUDO, and values.

Referenced by compute_return_type(), DefineRange(), and DefineType().

{
    Relation    pg_type_desc;
    TupleDesc   tupDesc;
    int         i;
    HeapTuple   tup;
    Datum       values[Natts_pg_type];
    bool        nulls[Natts_pg_type];
    Oid         typoid;
    NameData    name;

    Assert(PointerIsValid(typeName));

    /*
     * open pg_type
     */
    pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock);
    tupDesc = pg_type_desc->rd_att;

    /*
     * initialize our *nulls and *values arrays
     */
    for (i = 0; i < Natts_pg_type; ++i)
    {
        nulls[i] = false;
        values[i] = (Datum) NULL;       /* redundant, but safe */
    }

    /*
     * initialize *values with the type name and dummy values
     *
     * The representational details are the same as int4 ... it doesn't really
     * matter what they are so long as they are consistent.  Also note that we
     * give it typtype = TYPTYPE_PSEUDO as extra insurance that it won't be
     * mistaken for a usable type.
     */
    namestrcpy(&name, typeName);
    values[Anum_pg_type_typname - 1] = NameGetDatum(&name);
    values[Anum_pg_type_typnamespace - 1] = ObjectIdGetDatum(typeNamespace);
    values[Anum_pg_type_typowner - 1] = ObjectIdGetDatum(ownerId);
    values[Anum_pg_type_typlen - 1] = Int16GetDatum(sizeof(int32));
    values[Anum_pg_type_typbyval - 1] = BoolGetDatum(true);
    values[Anum_pg_type_typtype - 1] = CharGetDatum(TYPTYPE_PSEUDO);
    values[Anum_pg_type_typcategory - 1] = CharGetDatum(TYPCATEGORY_PSEUDOTYPE);
    values[Anum_pg_type_typispreferred - 1] = BoolGetDatum(false);
    values[Anum_pg_type_typisdefined - 1] = BoolGetDatum(false);
    values[Anum_pg_type_typdelim - 1] = CharGetDatum(DEFAULT_TYPDELIM);
    values[Anum_pg_type_typrelid - 1] = ObjectIdGetDatum(InvalidOid);
    values[Anum_pg_type_typelem - 1] = ObjectIdGetDatum(InvalidOid);
    values[Anum_pg_type_typarray - 1] = ObjectIdGetDatum(InvalidOid);
    values[Anum_pg_type_typinput - 1] = ObjectIdGetDatum(F_SHELL_IN);
    values[Anum_pg_type_typoutput - 1] = ObjectIdGetDatum(F_SHELL_OUT);
    values[Anum_pg_type_typreceive - 1] = ObjectIdGetDatum(InvalidOid);
    values[Anum_pg_type_typsend - 1] = ObjectIdGetDatum(InvalidOid);
    values[Anum_pg_type_typmodin - 1] = ObjectIdGetDatum(InvalidOid);
    values[Anum_pg_type_typmodout - 1] = ObjectIdGetDatum(InvalidOid);
    values[Anum_pg_type_typanalyze - 1] = ObjectIdGetDatum(InvalidOid);
    values[Anum_pg_type_typalign - 1] = CharGetDatum('i');
    values[Anum_pg_type_typstorage - 1] = CharGetDatum('p');
    values[Anum_pg_type_typnotnull - 1] = BoolGetDatum(false);
    values[Anum_pg_type_typbasetype - 1] = ObjectIdGetDatum(InvalidOid);
    values[Anum_pg_type_typtypmod - 1] = Int32GetDatum(-1);
    values[Anum_pg_type_typndims - 1] = Int32GetDatum(0);
    values[Anum_pg_type_typcollation - 1] = ObjectIdGetDatum(InvalidOid);
    nulls[Anum_pg_type_typdefaultbin - 1] = true;
    nulls[Anum_pg_type_typdefault - 1] = true;
    nulls[Anum_pg_type_typacl - 1] = true;

    /*
     * create a new type tuple
     */
    tup = heap_form_tuple(tupDesc, values, nulls);

    /* Use binary-upgrade override for pg_type.oid, if supplied. */
    if (IsBinaryUpgrade && OidIsValid(binary_upgrade_next_pg_type_oid))
    {
        HeapTupleSetOid(tup, binary_upgrade_next_pg_type_oid);
        binary_upgrade_next_pg_type_oid = InvalidOid;
    }

    /*
     * insert the tuple in the relation and get the tuple's oid.
     */
    typoid = simple_heap_insert(pg_type_desc, tup);

    CatalogUpdateIndexes(pg_type_desc, tup);

    /*
     * Create dependencies.  We can/must skip this in bootstrap mode.
     */
    if (!IsBootstrapProcessingMode())
        GenerateTypeDependencies(typeNamespace,
                                 typoid,
                                 InvalidOid,
                                 0,
                                 ownerId,
                                 F_SHELL_IN,
                                 F_SHELL_OUT,
                                 InvalidOid,
                                 InvalidOid,
                                 InvalidOid,
                                 InvalidOid,
                                 InvalidOid,
                                 InvalidOid,
                                 false,
                                 InvalidOid,
                                 InvalidOid,
                                 NULL,
                                 false);

    /* Post creation hook for new shell type */
    InvokeObjectPostCreateHook(TypeRelationId, typoid, 0);

    /*
     * clean up and return the type-oid
     */
    heap_freetuple(tup);
    heap_close(pg_type_desc, RowExclusiveLock);

    return typoid;
}