pg_type.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:15k
- /*-------------------------------------------------------------------------
- *
- * pg_type.c
- * routines to support manipulation of the pg_type relation
- *
- * Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- * $Header: /usr/local/cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.37.2.1 1999/08/02 05:56:55 scrappy Exp $
- *
- *-------------------------------------------------------------------------
- */
- #include "postgres.h"
- #include "access/heapam.h"
- #include "catalog/catname.h"
- #include "catalog/indexing.h"
- #include "catalog/pg_type.h"
- #include "miscadmin.h"
- #include "parser/parse_func.h"
- #include "utils/builtins.h"
- #include "utils/syscache.h"
- static Oid TypeShellMakeWithOpenRelation(Relation pg_type_desc,
- char *typeName);
- /* ----------------------------------------------------------------
- * TypeGetWithOpenRelation
- *
- * preforms a scan on pg_type for a type tuple with the
- * given type name.
- * ----------------------------------------------------------------
- * pg_type_desc -- reldesc for pg_type
- * typeName -- name of type to be fetched
- * defined -- has the type been defined?
- */
- static Oid
- TypeGetWithOpenRelation(Relation pg_type_desc,
- char *typeName,
- bool *defined)
- {
- HeapScanDesc scan;
- HeapTuple tup;
- Oid typoid;
- static ScanKeyData typeKey[1] = {
- {0, Anum_pg_type_typname, F_NAMEEQ}
- };
- /* ----------------
- * initialize the scan key and begin a scan of pg_type
- * ----------------
- */
- fmgr_info(F_NAMEEQ, &typeKey[0].sk_func);
- typeKey[0].sk_nargs = typeKey[0].sk_func.fn_nargs;
- typeKey[0].sk_argument = PointerGetDatum(typeName);
- scan = heap_beginscan(pg_type_desc,
- 0,
- SnapshotSelf, /* cache? */
- 1,
- typeKey);
- /* ----------------
- * get the type tuple, if it exists.
- * ----------------
- */
- tup = heap_getnext(scan, 0);
- /* ----------------
- * if no type tuple exists for the given type name, then
- * end the scan and return appropriate information.
- * ----------------
- */
- if (!HeapTupleIsValid(tup))
- {
- heap_endscan(scan);
- *defined = false;
- return InvalidOid;
- }
- /* ----------------
- * here, the type tuple does exist so we pull information from
- * the typisdefined field of the tuple and return the tuple's
- * oid, which is the oid of the type.
- * ----------------
- */
- *defined = (bool) ((Form_pg_type) GETSTRUCT(tup))->typisdefined;
- typoid = tup->t_data->t_oid;
- heap_endscan(scan);
- return typoid;
- }
- /* ----------------------------------------------------------------
- * TypeGet
- *
- * Finds the ObjectId of a type, even if uncommitted; "defined"
- * is only set if the type has actually been defined, i.e., if
- * the type tuple is not a shell.
- *
- * Note: the meat of this function is now in the function
- * TypeGetWithOpenRelation(). -cim 6/15/90
- *
- * Also called from util/remove.c
- * ----------------------------------------------------------------
- */
- Oid
- TypeGet(char *typeName, /* name of type to be fetched */
- bool *defined) /* has the type been defined? */
- {
- Relation pg_type_desc;
- Oid typeoid;
- /* ----------------
- * open the pg_type relation
- * ----------------
- */
- pg_type_desc = heap_openr(TypeRelationName);
- /* ----------------
- * scan the type relation for the information we want
- * ----------------
- */
- typeoid = TypeGetWithOpenRelation(pg_type_desc,
- typeName,
- defined);
- /* ----------------
- * close the type relation and return the type oid.
- * ----------------
- */
- heap_close(pg_type_desc);
- return typeoid;
- }
- /* ----------------------------------------------------------------
- * TypeShellMakeWithOpenRelation
- *
- * ----------------------------------------------------------------
- */
- static Oid
- TypeShellMakeWithOpenRelation(Relation pg_type_desc, char *typeName)
- {
- int i;
- HeapTuple tup;
- Datum values[Natts_pg_type];
- char nulls[Natts_pg_type];
- Oid typoid;
- NameData name;
- TupleDesc tupDesc;
- /* ----------------
- * initialize our *nulls and *values arrays
- * ----------------
- */
- for (i = 0; i < Natts_pg_type; ++i)
- {
- nulls[i] = ' ';
- values[i] = (Datum) NULL; /* redundant, but safe */
- }
- /* ----------------
- * initialize *values with the type name and
- * ----------------
- */
- i = 0;
- namestrcpy(&name, typeName);
- values[i++] = NameGetDatum(&name); /* 1 */
- values[i++] = (Datum) InvalidOid; /* 2 */
- values[i++] = (Datum) (int16) 0; /* 3 */
- values[i++] = (Datum) (int16) 0; /* 4 */
- values[i++] = (Datum) (bool) 0; /* 5 */
- values[i++] = (Datum) (bool) 0; /* 6 */
- values[i++] = (Datum) (bool) 0; /* 7 */
- values[i++] = (Datum) (bool) 0; /* 8 */
- values[i++] = (Datum) InvalidOid; /* 9 */
- values[i++] = (Datum) InvalidOid; /* 10 */
- values[i++] = (Datum) InvalidOid; /* 11 */
- values[i++] = (Datum) InvalidOid; /* 12 */
- values[i++] = (Datum) InvalidOid; /* 13 */
- values[i++] = (Datum) InvalidOid; /* 14 */
- values[i++] = (Datum) 'i'; /* 15 */
- /*
- * ... and fill typdefault with a bogus value
- */
- values[i++] = (Datum) fmgr(F_TEXTIN, typeName); /* 15 */
- /* ----------------
- * create a new type tuple with FormHeapTuple
- * ----------------
- */
- tupDesc = pg_type_desc->rd_att;
- tup = heap_formtuple(tupDesc, values, nulls);
- /* ----------------
- * insert the tuple in the relation and get the tuple's oid.
- * ----------------
- */
- heap_insert(pg_type_desc, tup);
- typoid = tup->t_data->t_oid;
- if (RelationGetForm(pg_type_desc)->relhasindex)
- {
- Relation idescs[Num_pg_type_indices];
- CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
- CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tup);
- CatalogCloseIndices(Num_pg_type_indices, idescs);
- }
- /* ----------------
- * free the tuple and return the type-oid
- * ----------------
- */
- pfree(tup);
- return typoid;
- }
- /* ----------------------------------------------------------------
- * TypeShellMake
- *
- * This procedure inserts a "shell" tuple into the type
- * relation. The type tuple inserted has invalid values
- * and in particular, the "typisdefined" field is false.
- *
- * This is used so that a tuple exists in the catalogs.
- * The invalid fields should be fixed up sometime after
- * this routine is called, and then the "typeisdefined"
- * field is set to true. -cim 6/15/90
- * ----------------------------------------------------------------
- */
- Oid
- TypeShellMake(char *typeName)
- {
- Relation pg_type_desc;
- Oid typoid;
- Assert(PointerIsValid(typeName));
- /* ----------------
- * open pg_type
- * ----------------
- */
- pg_type_desc = heap_openr(TypeRelationName);
- /* ----------------
- * insert the shell tuple
- * ----------------
- */
- typoid = TypeShellMakeWithOpenRelation(pg_type_desc, typeName);
- /* ----------------
- * close pg_type and return the tuple's oid.
- * ----------------
- */
- heap_close(pg_type_desc);
- return typoid;
- }
- /* ----------------------------------------------------------------
- * TypeCreate
- *
- * This does all the necessary work needed to define a new type.
- * ----------------------------------------------------------------
- */
- Oid
- TypeCreate(char *typeName,
- Oid relationOid, /* only for 'c'atalog typeTypes */
- int16 internalSize,
- int16 externalSize,
- char typeType,
- char typDelim,
- char *inputProcedure,
- char *outputProcedure,
- char *receiveProcedure,
- char *sendProcedure,
- char *elementTypeName,
- char *defaultTypeValue, /* internal rep */
- bool passedByValue,
- char alignment)
- {
- int i,
- j;
- Relation pg_type_desc;
- HeapScanDesc pg_type_scan;
- Oid typeObjectId;
- Oid elementObjectId = InvalidOid;
- HeapTuple tup;
- char nulls[Natts_pg_type];
- char replaces[Natts_pg_type];
- Datum values[Natts_pg_type];
- char *procname;
- char *procs[4];
- bool defined;
- NameData name;
- TupleDesc tupDesc;
- Oid argList[8];
- static ScanKeyData typeKey[1] = {
- {0, Anum_pg_type_typname, F_NAMEEQ}
- };
- fmgr_info(F_NAMEEQ, &typeKey[0].sk_func);
- typeKey[0].sk_nargs = typeKey[0].sk_func.fn_nargs;
- /* ----------------
- * check that the type is not already defined.
- * ----------------
- */
- typeObjectId = TypeGet(typeName, &defined);
- if (OidIsValid(typeObjectId) && defined)
- elog(ERROR, "TypeCreate: type %s already defined", typeName);
- /* ----------------
- * if this type has an associated elementType, then we check that
- * it is defined.
- * ----------------
- */
- if (elementTypeName)
- {
- elementObjectId = TypeGet(elementTypeName, &defined);
- if (!defined)
- elog(ERROR, "TypeCreate: type %s is not defined", elementTypeName);
- }
- /* ----------------
- * XXX comment me
- * ----------------
- */
- if (externalSize == 0)
- externalSize = -1; /* variable length */
- /* ----------------
- * initialize arrays needed by FormHeapTuple
- * ----------------
- */
- for (i = 0; i < Natts_pg_type; ++i)
- {
- nulls[i] = ' ';
- replaces[i] = 'r';
- values[i] = (Datum) NULL; /* redundant, but nice */
- }
- /*
- * XXX
- *
- * Do this so that user-defined types have size -1 instead of zero if
- * they are variable-length - this is so that everything else in the
- * backend works.
- */
- if (internalSize == 0)
- internalSize = -1;
- /* ----------------
- * initialize the *values information
- * ----------------
- */
- i = 0;
- namestrcpy(&name, typeName);
- values[i++] = NameGetDatum(&name); /* 1 */
- values[i++] = (Datum) GetUserId(); /* 2 */
- values[i++] = (Datum) internalSize; /* 3 */
- values[i++] = (Datum) externalSize; /* 4 */
- values[i++] = (Datum) passedByValue; /* 5 */
- values[i++] = (Datum) typeType; /* 6 */
- values[i++] = (Datum) (bool) 1; /* 7 */
- values[i++] = (Datum) typDelim; /* 8 */
- values[i++] = (Datum) (typeType == 'c' ? relationOid : InvalidOid); /* 9 */
- values[i++] = (Datum) elementObjectId; /* 10 */
- procs[0] = inputProcedure;
- procs[1] = outputProcedure;
- procs[2] = (receiveProcedure) ? receiveProcedure : inputProcedure;
- procs[3] = (sendProcedure) ? sendProcedure : outputProcedure;
- for (j = 0; j < 4; ++j)
- {
- procname = procs[j];
- /*
- * First look for a 1-argument func with all argtypes 0. This is
- * valid for all four kinds of procedure.
- */
- MemSet(argList, 0, 8 * sizeof(Oid));
- tup = SearchSysCacheTuple(PRONAME,
- PointerGetDatum(procname),
- Int32GetDatum(1),
- PointerGetDatum(argList),
- 0);
- if (!HeapTupleIsValid(tup))
- {
- /*
- * For array types, the input procedures may take 3 args (data
- * value, element OID, atttypmod); the pg_proc argtype
- * signature is 0,0,INT4OID. The output procedures may take 2
- * args (data value, element OID).
- */
- if (OidIsValid(elementObjectId))
- {
- int nargs;
- if (j % 2)
- {
- /* output proc */
- nargs = 2;
- }
- else
- {
- /* input proc */
- nargs = 3;
- argList[2] = INT4OID;
- }
- tup = SearchSysCacheTuple(PRONAME,
- PointerGetDatum(procname),
- Int32GetDatum(nargs),
- PointerGetDatum(argList),
- 0);
- }
- if (!HeapTupleIsValid(tup))
- func_error("TypeCreate", procname, 1, argList, NULL);
- }
- values[i++] = (Datum) tup->t_data->t_oid; /* 11 - 14 */
- }
- /* ----------------
- * set default alignment
- * ----------------
- */
- values[i++] = (Datum) alignment; /* 15 */
- /* ----------------
- * initialize the default value for this type.
- * ----------------
- */
- values[i] = (Datum) fmgr(F_TEXTIN, /* 16 */
- PointerIsValid(defaultTypeValue)
- ? defaultTypeValue : "-"); /* XXX default
- * typdefault */
- /* ----------------
- * open pg_type and begin a scan for the type name.
- * ----------------
- */
- pg_type_desc = heap_openr(TypeRelationName);
- /* -----------------
- * Set a write lock initially so as not upgrade a read to a write
- * when the heap_insert() or heap_replace() is called.
- * -----------------
- */
- LockRelation(pg_type_desc, AccessExclusiveLock);
- typeKey[0].sk_argument = PointerGetDatum(typeName);
- pg_type_scan = heap_beginscan(pg_type_desc,
- 0,
- SnapshotSelf, /* cache? */
- 1,
- typeKey);
- /* ----------------
- * define the type either by adding a tuple to the type
- * relation, or by updating the fields of the "shell" tuple
- * already there.
- * ----------------
- */
- tup = heap_getnext(pg_type_scan, 0);
- if (HeapTupleIsValid(tup))
- {
- tup = heap_modifytuple(tup,
- pg_type_desc,
- values,
- nulls,
- replaces);
- setheapoverride(true);
- heap_replace(pg_type_desc, &tup->t_self, tup, NULL);
- setheapoverride(false);
- typeObjectId = tup->t_data->t_oid;
- }
- else
- {
- tupDesc = pg_type_desc->rd_att;
- tup = heap_formtuple(tupDesc,
- values,
- nulls);
- heap_insert(pg_type_desc, tup);
- typeObjectId = tup->t_data->t_oid;
- }
- /* ----------------
- * finish up
- * ----------------
- */
- heap_endscan(pg_type_scan);
- if (RelationGetForm(pg_type_desc)->relhasindex)
- {
- Relation idescs[Num_pg_type_indices];
- CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
- CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tup);
- CatalogCloseIndices(Num_pg_type_indices, idescs);
- }
- UnlockRelation(pg_type_desc, AccessExclusiveLock);
- heap_close(pg_type_desc);
- return typeObjectId;
- }
- /* ----------------------------------------------------------------
- * TypeRename
- *
- * This renames a type
- * ----------------------------------------------------------------
- */
- void
- TypeRename(char *oldTypeName, char *newTypeName)
- {
- Relation pg_type_desc;
- Relation idescs[Num_pg_type_indices];
- HeapTuple oldtup,
- newtup;
- pg_type_desc = heap_openr(TypeRelationName);
- oldtup = SearchSysCacheTupleCopy(TYPNAME,
- PointerGetDatum(oldTypeName),
- 0, 0, 0);
- if (!HeapTupleIsValid(oldtup))
- {
- heap_close(pg_type_desc);
- elog(ERROR, "TypeRename: type %s not defined", oldTypeName);
- }
- newtup = SearchSysCacheTuple(TYPNAME,
- PointerGetDatum(newTypeName),
- 0, 0, 0);
- if (HeapTupleIsValid(newtup))
- {
- pfree(oldtup);
- heap_close(pg_type_desc);
- elog(ERROR, "TypeRename: type %s already defined", newTypeName);
- }
- namestrcpy(&(((Form_pg_type) GETSTRUCT(oldtup))->typname), newTypeName);
- setheapoverride(true);
- heap_replace(pg_type_desc, &oldtup->t_self, oldtup, NULL);
- setheapoverride(false);
- /* update the system catalog indices */
- CatalogOpenIndices(Num_pg_type_indices, Name_pg_type_indices, idescs);
- CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, oldtup);
- CatalogCloseIndices(Num_pg_type_indices, idescs);
- pfree(oldtup);
- heap_close(pg_type_desc);
- }
- /*
- * makeArrayTypeName(typeName);
- * - given a base type name, make an array of type name out of it
- *
- * the CALLER is responsible for pfreeing the
- */
- char *
- makeArrayTypeName(char *typeName)
- {
- char *arr;
- if (!typeName)
- return NULL;
- arr = palloc(strlen(typeName) + 2);
- arr[0] = '_';
- strcpy(arr + 1, typeName);
- return arr;
- }