postgresql/src/backend/catalog/pg_enum.c

180 lines
4.2 KiB
C
Raw Normal View History

/*-------------------------------------------------------------------------
*
* pg_enum.c
* routines to support manipulation of the pg_enum relation
*
2010-01-02 17:58:17 +01:00
* Copyright (c) 2006-2010, PostgreSQL Global Development Group
*
*
* IDENTIFICATION
2010-02-26 03:01:40 +01:00
* $PostgreSQL: pgsql/src/backend/catalog/pg_enum.c,v 1.14 2010/02/26 02:00:37 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "catalog/catalog.h"
#include "catalog/indexing.h"
#include "catalog/pg_enum.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/rel.h"
#include "utils/tqual.h"
static int oid_cmp(const void *p1, const void *p2);
/*
* EnumValuesCreate
* Create an entry in pg_enum for each of the supplied enum values.
*
* vals is a list of Value strings.
*/
void
EnumValuesCreate(Oid enumTypeOid, List *vals,
Oid binary_upgrade_next_pg_enum_oid)
{
Relation pg_enum;
TupleDesc tupDesc;
NameData enumlabel;
Oid *oids;
int elemno,
num_elems;
Datum values[Natts_pg_enum];
bool nulls[Natts_pg_enum];
ListCell *lc;
2007-11-15 22:14:46 +01:00
HeapTuple tup;
num_elems = list_length(vals);
/*
2007-11-15 22:14:46 +01:00
* XXX we do not bother to check the list of values for duplicates --- if
* you have any, you'll get a less-than-friendly unique-index violation.
* Is it worth trying harder?
*/
pg_enum = heap_open(EnumRelationId, RowExclusiveLock);
tupDesc = pg_enum->rd_att;
/*
2010-02-26 03:01:40 +01:00
* Allocate oids
*/
oids = (Oid *) palloc(num_elems * sizeof(Oid));
if (OidIsValid(binary_upgrade_next_pg_enum_oid))
{
2010-02-26 03:01:40 +01:00
if (num_elems != 1)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("EnumValuesCreate() can only set a single OID")));
oids[0] = binary_upgrade_next_pg_enum_oid;
binary_upgrade_next_pg_enum_oid = InvalidOid;
}
else
{
/*
2010-02-26 03:01:40 +01:00
* While this method does not absolutely guarantee that we generate no
* duplicate oids (since we haven't entered each oid into the table
* before allocating the next), trouble could only occur if the oid
* counter wraps all the way around before we finish. Which seems
* unlikely.
*/
for (elemno = 0; elemno < num_elems; elemno++)
{
/*
2010-02-26 03:01:40 +01:00
* The pg_enum.oid is stored in user tables. This oid must be
* preserved by binary upgrades.
*/
oids[elemno] = GetNewOid(pg_enum);
}
/* sort them, just in case counter wrapped from high to low */
qsort(oids, num_elems, sizeof(Oid), oid_cmp);
}
/* and make the entries */
memset(nulls, false, sizeof(nulls));
elemno = 0;
foreach(lc, vals)
{
2007-11-15 22:14:46 +01:00
char *lab = strVal(lfirst(lc));
2007-11-15 22:14:46 +01:00
/*
* labels are stored in a name field, for easier syscache lookup, so
* check the length to make sure it's within range.
*/
if (strlen(lab) > (NAMEDATALEN - 1))
ereport(ERROR,
(errcode(ERRCODE_INVALID_NAME),
2008-01-20 18:50:41 +01:00
errmsg("invalid enum label \"%s\"", lab),
errdetail("Labels must be %d characters or less.",
NAMEDATALEN - 1)));
values[Anum_pg_enum_enumtypid - 1] = ObjectIdGetDatum(enumTypeOid);
namestrcpy(&enumlabel, lab);
values[Anum_pg_enum_enumlabel - 1] = NameGetDatum(&enumlabel);
tup = heap_form_tuple(tupDesc, values, nulls);
HeapTupleSetOid(tup, oids[elemno]);
simple_heap_insert(pg_enum, tup);
CatalogUpdateIndexes(pg_enum, tup);
heap_freetuple(tup);
elemno++;
}
/* clean up */
pfree(oids);
heap_close(pg_enum, RowExclusiveLock);
}
/*
* EnumValuesDelete
* Remove all the pg_enum entries for the specified enum type.
*/
void
EnumValuesDelete(Oid enumTypeOid)
{
Relation pg_enum;
ScanKeyData key[1];
SysScanDesc scan;
HeapTuple tup;
pg_enum = heap_open(EnumRelationId, RowExclusiveLock);
ScanKeyInit(&key[0],
Anum_pg_enum_enumtypid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(enumTypeOid));
scan = systable_beginscan(pg_enum, EnumTypIdLabelIndexId, true,
SnapshotNow, 1, key);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
simple_heap_delete(pg_enum, &tup->t_self);
}
systable_endscan(scan);
heap_close(pg_enum, RowExclusiveLock);
}
/* qsort comparison function */
static int
oid_cmp(const void *p1, const void *p2)
{
2007-11-15 22:14:46 +01:00
Oid v1 = *((const Oid *) p1);
Oid v2 = *((const Oid *) p2);
if (v1 < v2)
return -1;
if (v1 > v2)
return 1;
return 0;
}