1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* pg_type.c--
|
1997-09-07 07:04:48 +02:00
|
|
|
* routines to support manipulation of the pg_type relation
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
1998-08-19 04:04:17 +02:00
|
|
|
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.27 1998/08/19 02:01:38 momjian Exp $
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
1998-04-27 06:08:07 +02:00
|
|
|
#include "postgres.h"
|
|
|
|
|
|
|
|
#include "access/heapam.h"
|
|
|
|
#include "access/relscan.h"
|
|
|
|
#include "catalog/catname.h"
|
|
|
|
#include "catalog/indexing.h"
|
|
|
|
#include "catalog/pg_type.h"
|
|
|
|
#include "fmgr.h"
|
|
|
|
#include "miscadmin.h"
|
|
|
|
#include "parser/parse_func.h"
|
1998-08-19 04:04:17 +02:00
|
|
|
#include "storage/bufmgr.h"
|
1998-04-27 06:08:07 +02:00
|
|
|
#include "storage/lmgr.h"
|
|
|
|
#include "utils/builtins.h"
|
|
|
|
#include "utils/syscache.h"
|
|
|
|
#include "utils/tqual.h"
|
|
|
|
|
1996-11-06 08:31:26 +01:00
|
|
|
#ifndef HAVE_MEMMOVE
|
1997-09-07 07:04:48 +02:00
|
|
|
#include <regex/utils.h>
|
1996-11-06 08:31:26 +01:00
|
|
|
#else
|
1997-09-07 07:04:48 +02:00
|
|
|
#include <string.h>
|
1996-11-06 08:31:26 +01:00
|
|
|
#endif
|
1996-11-04 00:27:08 +01:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
static Oid
|
|
|
|
TypeShellMakeWithOpenRelation(Relation pg_type_desc,
|
|
|
|
char *typeName);
|
1997-08-19 23:40:56 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* TypeGetWithOpenRelation
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* preforms a scan on pg_type for a type tuple with the
|
|
|
|
* given type name.
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* pg_type_desc -- reldesc for pg_type
|
|
|
|
* typeName -- name of type to be fetched
|
|
|
|
* defined -- has the type been defined?
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
1997-09-08 04:41:22 +02:00
|
|
|
static Oid
|
1996-07-09 08:22:35 +02:00
|
|
|
TypeGetWithOpenRelation(Relation pg_type_desc,
|
1997-09-07 07:04:48 +02:00
|
|
|
char *typeName,
|
1997-09-08 23:56:23 +02:00
|
|
|
bool *defined)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
HeapScanDesc scan;
|
|
|
|
HeapTuple tup;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
static ScanKeyData typeKey[1] = {
|
1998-04-27 06:08:07 +02:00
|
|
|
{0, Anum_pg_type_typname, F_NAMEEQ}
|
1997-09-07 07:04:48 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* initialize the scan key and begin a scan of pg_type
|
|
|
|
* ----------------
|
|
|
|
*/
|
1998-04-27 06:08:07 +02:00
|
|
|
fmgr_info(F_NAMEEQ, &typeKey[0].sk_func);
|
1998-01-15 20:46:37 +01:00
|
|
|
typeKey[0].sk_nargs = typeKey[0].sk_func.fn_nargs;
|
1997-09-07 07:04:48 +02:00
|
|
|
typeKey[0].sk_argument = PointerGetDatum(typeName);
|
|
|
|
|
|
|
|
scan = heap_beginscan(pg_type_desc,
|
|
|
|
0,
|
1998-08-19 04:04:17 +02:00
|
|
|
SnapshotSelf, /* cache? */
|
1997-09-07 07:04:48 +02:00
|
|
|
1,
|
|
|
|
typeKey);
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* get the type tuple, if it exists.
|
|
|
|
* ----------------
|
|
|
|
*/
|
1998-08-19 04:04:17 +02:00
|
|
|
tup = heap_getnext(scan, 0);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* 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.
|
|
|
|
* ----------------
|
|
|
|
*/
|
1996-07-09 08:22:35 +02:00
|
|
|
heap_endscan(scan);
|
1997-09-07 07:04:48 +02:00
|
|
|
*defined = (bool) ((TypeTupleForm) GETSTRUCT(tup))->typisdefined;
|
|
|
|
|
1998-08-19 04:04:17 +02:00
|
|
|
return tup->t_oid;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* TypeGet
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* 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.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* Note: the meat of this function is now in the function
|
|
|
|
* TypeGetWithOpenRelation(). -cim 6/15/90
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* Also called from util/remove.c
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
Oid
|
1997-09-07 07:04:48 +02:00
|
|
|
TypeGet(char *typeName, /* name of type to be fetched */
|
1997-09-08 23:56:23 +02:00
|
|
|
bool *defined) /* has the type been defined? */
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Relation pg_type_desc;
|
|
|
|
Oid typeoid;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* 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);
|
|
|
|
|
1998-08-19 04:04:17 +02:00
|
|
|
return typeoid;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* TypeShellMakeWithOpenRelation
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
1997-09-08 04:41:22 +02:00
|
|
|
static Oid
|
1996-07-09 08:22:35 +02:00
|
|
|
TypeShellMakeWithOpenRelation(Relation pg_type_desc, char *typeName)
|
|
|
|
{
|
1998-02-26 05:46:47 +01:00
|
|
|
int i;
|
1997-09-08 04:41:22 +02:00
|
|
|
HeapTuple tup;
|
|
|
|
Datum values[Natts_pg_type];
|
|
|
|
char nulls[Natts_pg_type];
|
|
|
|
Oid typoid;
|
1998-04-01 17:35:33 +02:00
|
|
|
NameData name;
|
1997-09-08 04:41:22 +02:00
|
|
|
TupleDesc tupDesc;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* 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;
|
1998-04-01 17:35:33 +02:00
|
|
|
namestrcpy(&name, typeName);
|
|
|
|
values[i++] = NameGetDatum(&name); /* 1 */
|
1997-09-07 07:04:48 +02:00
|
|
|
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++] =
|
1998-04-27 06:08:07 +02:00
|
|
|
(Datum) fmgr(F_TEXTIN, typeName); /* 15 */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* 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_oid;
|
|
|
|
|
|
|
|
if (RelationGetRelationTupleForm(pg_type_desc)->relhasindex)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Relation idescs[Num_pg_type_indices];
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
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);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
/* ----------------
|
|
|
|
* free the tuple and return the type-oid
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
pfree(tup);
|
|
|
|
|
|
|
|
return
|
|
|
|
typoid;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* TypeShellMake
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* 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.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* 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
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
Oid
|
|
|
|
TypeShellMake(char *typeName)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Relation pg_type_desc;
|
|
|
|
Oid typoid;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
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;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* TypeCreate
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* This does all the necessary work needed to define a new type.
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
Oid
|
|
|
|
TypeCreate(char *typeName,
|
1997-09-07 07:04:48 +02:00
|
|
|
Oid relationOid, /* only for 'c'atalog typeTypes */
|
|
|
|
int16 internalSize,
|
|
|
|
int16 externalSize,
|
|
|
|
char typeType,
|
|
|
|
char typDelim,
|
|
|
|
char *inputProcedure,
|
|
|
|
char *outputProcedure,
|
|
|
|
char *receiveProcedure,
|
1997-11-26 05:50:47 +01:00
|
|
|
char *sendProcedure,
|
1997-09-07 07:04:48 +02:00
|
|
|
char *elementTypeName,
|
|
|
|
char *defaultTypeValue, /* internal rep */
|
|
|
|
bool passedByValue,
|
|
|
|
char alignment)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1998-02-11 20:14:04 +01:00
|
|
|
int i,
|
1997-09-08 04:41:22 +02:00
|
|
|
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;
|
1998-04-01 17:35:33 +02:00
|
|
|
NameData name;
|
1997-09-08 04:41:22 +02:00
|
|
|
TupleDesc tupDesc;
|
|
|
|
Oid argList[8];
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
static ScanKeyData typeKey[1] = {
|
1998-04-27 06:08:07 +02:00
|
|
|
{0, Anum_pg_type_typname, F_NAMEEQ}
|
1997-09-07 07:04:48 +02:00
|
|
|
};
|
|
|
|
|
1998-04-27 06:08:07 +02:00
|
|
|
fmgr_info(F_NAMEEQ, &typeKey[0].sk_func);
|
1998-01-15 20:46:37 +01:00
|
|
|
typeKey[0].sk_nargs = typeKey[0].sk_func.fn_nargs;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* check that the type is not already defined.
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
typeObjectId = TypeGet(typeName, &defined);
|
|
|
|
if (OidIsValid(typeObjectId) && defined)
|
1998-01-06 20:42:33 +01:00
|
|
|
elog(ERROR, "TypeCreate: type %s already defined", typeName);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* if this type has an associated elementType, then we check that
|
|
|
|
* it is defined.
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
if (elementTypeName)
|
|
|
|
{
|
|
|
|
elementObjectId = TypeGet(elementTypeName, &defined);
|
|
|
|
if (!defined)
|
1998-01-06 20:42:33 +01:00
|
|
|
elog(ERROR, "TypeCreate: type %s is not defined", elementTypeName);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* 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 */
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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;
|
1998-03-30 19:46:45 +02:00
|
|
|
namestrcpy(&name,typeName);
|
|
|
|
values[i++] = NameGetDatum(&name); /* 1 */
|
1997-09-07 07:04:48 +02:00
|
|
|
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 */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* arguments to type input and output functions must be 0
|
|
|
|
*/
|
1997-09-18 22:22:58 +02:00
|
|
|
MemSet(argList, 0, 8 * sizeof(Oid));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
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];
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
tup = SearchSysCacheTuple(PRONAME,
|
1997-09-07 07:04:48 +02:00
|
|
|
PointerGetDatum(procname),
|
|
|
|
Int32GetDatum(1),
|
|
|
|
PointerGetDatum(argList),
|
|
|
|
0);
|
|
|
|
|
|
|
|
if (!HeapTupleIsValid(tup))
|
|
|
|
{
|
|
|
|
|
|
|
|
/*
|
|
|
|
* it is possible for the input/output procedure to take two
|
|
|
|
* arguments, where the second argument is the element type
|
|
|
|
* (eg array_in/array_out)
|
|
|
|
*/
|
|
|
|
if (OidIsValid(elementObjectId))
|
|
|
|
{
|
|
|
|
tup = SearchSysCacheTuple(PRONAME,
|
|
|
|
PointerGetDatum(procname),
|
|
|
|
Int32GetDatum(2),
|
|
|
|
PointerGetDatum(argList),
|
|
|
|
0);
|
|
|
|
}
|
|
|
|
if (!HeapTupleIsValid(tup))
|
1998-05-10 01:43:45 +02:00
|
|
|
func_error("TypeCreate", procname, 1, argList, NULL);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
values[i++] = (Datum) tup->t_oid; /* 11 - 14 */
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* ----------------
|
|
|
|
* set default alignment
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
values[i++] = (Datum) alignment; /* 15 */
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* initialize the default value for this type.
|
|
|
|
* ----------------
|
|
|
|
*/
|
1998-04-27 06:08:07 +02:00
|
|
|
values[i] = (Datum) fmgr(F_TEXTIN, /* 16 */
|
1997-09-07 07:04:48 +02:00
|
|
|
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.
|
|
|
|
* -----------------
|
|
|
|
*/
|
|
|
|
RelationSetLockForWrite(pg_type_desc);
|
|
|
|
|
|
|
|
typeKey[0].sk_argument = PointerGetDatum(typeName);
|
|
|
|
pg_type_scan = heap_beginscan(pg_type_desc,
|
|
|
|
0,
|
1998-08-19 04:04:17 +02:00
|
|
|
SnapshotSelf, /* cache? */
|
1997-09-07 07:04:48 +02:00
|
|
|
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.
|
|
|
|
* ----------------
|
|
|
|
*/
|
1998-08-19 04:04:17 +02:00
|
|
|
tup = heap_getnext(pg_type_scan, 0);
|
1997-09-07 07:04:48 +02:00
|
|
|
if (HeapTupleIsValid(tup))
|
|
|
|
{
|
|
|
|
tup = heap_modifytuple(tup,
|
|
|
|
pg_type_desc,
|
|
|
|
values,
|
|
|
|
nulls,
|
|
|
|
replaces);
|
|
|
|
|
|
|
|
setheapoverride(true);
|
1998-08-19 04:04:17 +02:00
|
|
|
heap_replace(pg_type_desc, &tup->t_ctid, tup);
|
1997-09-07 07:04:48 +02:00
|
|
|
setheapoverride(false);
|
|
|
|
|
|
|
|
typeObjectId = tup->t_oid;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tupDesc = pg_type_desc->rd_att;
|
|
|
|
|
|
|
|
tup = heap_formtuple(tupDesc,
|
|
|
|
values,
|
|
|
|
nulls);
|
|
|
|
|
|
|
|
heap_insert(pg_type_desc, tup);
|
|
|
|
|
|
|
|
typeObjectId = tup->t_oid;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------
|
|
|
|
* finish up
|
|
|
|
* ----------------
|
|
|
|
*/
|
|
|
|
heap_endscan(pg_type_scan);
|
|
|
|
|
|
|
|
if (RelationGetRelationTupleForm(pg_type_desc)->relhasindex)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Relation idescs[Num_pg_type_indices];
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
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);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
RelationUnsetLockForWrite(pg_type_desc);
|
|
|
|
heap_close(pg_type_desc);
|
|
|
|
|
1998-08-19 04:04:17 +02:00
|
|
|
return typeObjectId;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* TypeRename
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* This renames a type
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
TypeRename(char *oldTypeName, char *newTypeName)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Relation pg_type_desc;
|
|
|
|
Relation idescs[Num_pg_type_indices];
|
1998-08-19 04:04:17 +02:00
|
|
|
HeapTuple oldtup, newtup;
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
pg_type_desc = heap_openr(TypeRelationName);
|
|
|
|
|
1998-08-19 04:04:17 +02:00
|
|
|
oldtup = SearchSysCacheTupleCopy(TYPNAME,
|
|
|
|
PointerGetDatum(oldTypeName),
|
|
|
|
0, 0, 0);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-08-19 04:04:17 +02:00
|
|
|
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(&(((TypeTupleForm) GETSTRUCT(oldtup))->typname), newTypeName);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-08-19 04:04:17 +02:00
|
|
|
setheapoverride(true);
|
|
|
|
heap_replace(pg_type_desc, &oldtup->t_ctid, oldtup);
|
|
|
|
setheapoverride(false);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-08-19 04:04:17 +02:00
|
|
|
/* 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);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-08-19 04:04:17 +02:00
|
|
|
pfree(oldtup);
|
1997-09-07 07:04:48 +02:00
|
|
|
heap_close(pg_type_desc);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* makeArrayTypeName(typeName);
|
1997-09-07 07:04:48 +02:00
|
|
|
* - given a base type name, make an array of type name out of it
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* the CALLER is responsible for pfreeing the
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
|
1998-02-26 05:46:47 +01:00
|
|
|
char *
|
1997-09-07 07:04:48 +02:00
|
|
|
makeArrayTypeName(char *typeName)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
char *arr;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
if (!typeName)
|
|
|
|
return NULL;
|
|
|
|
arr = palloc(strlen(typeName) + 2);
|
|
|
|
arr[0] = '_';
|
|
|
|
strcpy(arr + 1, typeName);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
return arr;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
}
|