2007-04-02 05:49:42 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* 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
|
2007-04-02 05:49:42 +02:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/backend/catalog/pg_enum.c
|
2007-04-02 05:49:42 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#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"
|
2008-06-19 02:46:06 +02:00
|
|
|
#include "utils/rel.h"
|
2008-03-26 22:10:39 +01:00
|
|
|
#include "utils/tqual.h"
|
2007-04-02 05:49:42 +02:00
|
|
|
|
|
|
|
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
|
2009-12-27 15:50:46 +01:00
|
|
|
EnumValuesCreate(Oid enumTypeOid, List *vals,
|
|
|
|
Oid binary_upgrade_next_pg_enum_oid)
|
2007-04-02 05:49:42 +02:00
|
|
|
{
|
|
|
|
Relation pg_enum;
|
|
|
|
TupleDesc tupDesc;
|
|
|
|
NameData enumlabel;
|
|
|
|
Oid *oids;
|
2009-12-24 23:17:58 +01:00
|
|
|
int elemno,
|
|
|
|
num_elems;
|
2007-04-02 05:49:42 +02:00
|
|
|
Datum values[Natts_pg_enum];
|
2008-11-02 02:45:28 +01:00
|
|
|
bool nulls[Natts_pg_enum];
|
2007-04-02 05:49:42 +02:00
|
|
|
ListCell *lc;
|
2007-11-15 22:14:46 +01:00
|
|
|
HeapTuple tup;
|
2007-04-02 05:49:42 +02:00
|
|
|
|
2009-12-24 23:17:58 +01:00
|
|
|
num_elems = list_length(vals);
|
2007-04-02 05:49:42 +02:00
|
|
|
|
|
|
|
/*
|
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?
|
2007-04-02 05:49:42 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
pg_enum = heap_open(EnumRelationId, RowExclusiveLock);
|
|
|
|
tupDesc = pg_enum->rd_att;
|
|
|
|
|
|
|
|
/*
|
2010-02-26 03:01:40 +01:00
|
|
|
* Allocate oids
|
2007-04-02 05:49:42 +02:00
|
|
|
*/
|
2009-12-24 23:17:58 +01:00
|
|
|
oids = (Oid *) palloc(num_elems * sizeof(Oid));
|
2009-12-27 15:50:46 +01:00
|
|
|
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;
|
|
|
|
}
|
2009-12-27 15:50:46 +01:00
|
|
|
else
|
2007-04-02 05:49:42 +02:00
|
|
|
{
|
2009-12-19 01:47:57 +01:00
|
|
|
/*
|
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.
|
2009-12-19 01:47:57 +01:00
|
|
|
*/
|
2009-12-27 15:50:46 +01:00
|
|
|
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.
|
2009-12-27 15:50:46 +01:00
|
|
|
*/
|
|
|
|
oids[elemno] = GetNewOid(pg_enum);
|
|
|
|
}
|
|
|
|
/* sort them, just in case counter wrapped from high to low */
|
|
|
|
qsort(oids, num_elems, sizeof(Oid), oid_cmp);
|
2007-04-02 05:49:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* and make the entries */
|
2008-11-02 02:45:28 +01:00
|
|
|
memset(nulls, false, sizeof(nulls));
|
2007-04-02 05:49:42 +02:00
|
|
|
|
2009-12-24 23:17:58 +01:00
|
|
|
elemno = 0;
|
2007-04-02 05:49:42 +02:00
|
|
|
foreach(lc, vals)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
char *lab = strVal(lfirst(lc));
|
2007-04-02 05:49:42 +02:00
|
|
|
|
2007-11-15 22:14:46 +01:00
|
|
|
/*
|
2007-04-03 00:14:17 +02: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)));
|
2007-04-03 00:14:17 +02:00
|
|
|
|
2007-04-02 05:49:42 +02:00
|
|
|
values[Anum_pg_enum_enumtypid - 1] = ObjectIdGetDatum(enumTypeOid);
|
|
|
|
namestrcpy(&enumlabel, lab);
|
|
|
|
values[Anum_pg_enum_enumlabel - 1] = NameGetDatum(&enumlabel);
|
|
|
|
|
2008-11-02 02:45:28 +01:00
|
|
|
tup = heap_form_tuple(tupDesc, values, nulls);
|
2009-12-24 23:17:58 +01:00
|
|
|
HeapTupleSetOid(tup, oids[elemno]);
|
2007-04-02 05:49:42 +02:00
|
|
|
|
|
|
|
simple_heap_insert(pg_enum, tup);
|
|
|
|
CatalogUpdateIndexes(pg_enum, tup);
|
|
|
|
heap_freetuple(tup);
|
|
|
|
|
2009-12-24 23:17:58 +01:00
|
|
|
elemno++;
|
2007-04-02 05:49:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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);
|
2007-04-02 05:49:42 +02:00
|
|
|
|
|
|
|
if (v1 < v2)
|
|
|
|
return -1;
|
|
|
|
if (v1 > v2)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|