diff --git a/contrib/pg_upgrade/function.c b/contrib/pg_upgrade/function.c index c70f23f..7dc1656 100644 *** a/contrib/pg_upgrade/function.c --- b/contrib/pg_upgrade/function.c *************** install_support_functions(migratorContex *** 61,85 **** "LANGUAGE C STRICT;")); PQclear(executeQueryOrDie(ctx, conn, "CREATE OR REPLACE FUNCTION " ! " binary_upgrade.set_next_heap_relfilenode(OID) " "RETURNS VOID " "AS '$libdir/pg_upgrade_support' " "LANGUAGE C STRICT;")); PQclear(executeQueryOrDie(ctx, conn, "CREATE OR REPLACE FUNCTION " ! " binary_upgrade.set_next_toast_relfilenode(OID) " "RETURNS VOID " "AS '$libdir/pg_upgrade_support' " "LANGUAGE C STRICT;")); PQclear(executeQueryOrDie(ctx, conn, "CREATE OR REPLACE FUNCTION " ! " binary_upgrade.set_next_index_relfilenode(OID) " "RETURNS VOID " "AS '$libdir/pg_upgrade_support' " "LANGUAGE C STRICT;")); PQclear(executeQueryOrDie(ctx, conn, "CREATE OR REPLACE FUNCTION " ! " binary_upgrade.add_pg_enum_label(OID, OID, NAME) " "RETURNS VOID " "AS '$libdir/pg_upgrade_support' " "LANGUAGE C STRICT;")); --- 61,85 ---- "LANGUAGE C STRICT;")); PQclear(executeQueryOrDie(ctx, conn, "CREATE OR REPLACE FUNCTION " ! " binary_upgrade.set_next_pg_enum_oid(OID) " "RETURNS VOID " "AS '$libdir/pg_upgrade_support' " "LANGUAGE C STRICT;")); PQclear(executeQueryOrDie(ctx, conn, "CREATE OR REPLACE FUNCTION " ! " binary_upgrade.set_next_heap_relfilenode(OID) " "RETURNS VOID " "AS '$libdir/pg_upgrade_support' " "LANGUAGE C STRICT;")); PQclear(executeQueryOrDie(ctx, conn, "CREATE OR REPLACE FUNCTION " ! " binary_upgrade.set_next_toast_relfilenode(OID) " "RETURNS VOID " "AS '$libdir/pg_upgrade_support' " "LANGUAGE C STRICT;")); PQclear(executeQueryOrDie(ctx, conn, "CREATE OR REPLACE FUNCTION " ! " binary_upgrade.set_next_index_relfilenode(OID) " "RETURNS VOID " "AS '$libdir/pg_upgrade_support' " "LANGUAGE C STRICT;")); diff --git a/contrib/pg_upgrade_support/pg_upgrade_support.c b/contrib/pg_upgrade_support/pg_upgrade_support.c index c956be1..24f5e59 100644 *** a/contrib/pg_upgrade_support/pg_upgrade_support.c --- b/contrib/pg_upgrade_support/pg_upgrade_support.c *************** PG_MODULE_MAGIC; *** 30,35 **** --- 30,36 ---- extern PGDLLIMPORT Oid binary_upgrade_next_pg_type_oid; extern PGDLLIMPORT Oid binary_upgrade_next_pg_type_array_oid; extern PGDLLIMPORT Oid binary_upgrade_next_pg_type_toast_oid; + extern PGDLLIMPORT Oid binary_upgrade_next_pg_enum_oid; extern PGDLLIMPORT Oid binary_upgrade_next_heap_relfilenode; extern PGDLLIMPORT Oid binary_upgrade_next_toast_relfilenode; extern PGDLLIMPORT Oid binary_upgrade_next_index_relfilenode; *************** extern PGDLLIMPORT Oid binary_upgrade_ne *** 37,54 **** Datum set_next_pg_type_oid(PG_FUNCTION_ARGS); Datum set_next_pg_type_array_oid(PG_FUNCTION_ARGS); Datum set_next_pg_type_toast_oid(PG_FUNCTION_ARGS); Datum set_next_heap_relfilenode(PG_FUNCTION_ARGS); Datum set_next_toast_relfilenode(PG_FUNCTION_ARGS); Datum set_next_index_relfilenode(PG_FUNCTION_ARGS); - Datum add_pg_enum_label(PG_FUNCTION_ARGS); PG_FUNCTION_INFO_V1(set_next_pg_type_oid); PG_FUNCTION_INFO_V1(set_next_pg_type_array_oid); PG_FUNCTION_INFO_V1(set_next_pg_type_toast_oid); PG_FUNCTION_INFO_V1(set_next_heap_relfilenode); PG_FUNCTION_INFO_V1(set_next_toast_relfilenode); PG_FUNCTION_INFO_V1(set_next_index_relfilenode); - PG_FUNCTION_INFO_V1(add_pg_enum_label); Datum set_next_pg_type_oid(PG_FUNCTION_ARGS) --- 38,55 ---- Datum set_next_pg_type_oid(PG_FUNCTION_ARGS); Datum set_next_pg_type_array_oid(PG_FUNCTION_ARGS); Datum set_next_pg_type_toast_oid(PG_FUNCTION_ARGS); + Datum set_next_pg_enum_oid(PG_FUNCTION_ARGS); Datum set_next_heap_relfilenode(PG_FUNCTION_ARGS); Datum set_next_toast_relfilenode(PG_FUNCTION_ARGS); Datum set_next_index_relfilenode(PG_FUNCTION_ARGS); PG_FUNCTION_INFO_V1(set_next_pg_type_oid); PG_FUNCTION_INFO_V1(set_next_pg_type_array_oid); PG_FUNCTION_INFO_V1(set_next_pg_type_toast_oid); + PG_FUNCTION_INFO_V1(set_next_pg_enum_oid); PG_FUNCTION_INFO_V1(set_next_heap_relfilenode); PG_FUNCTION_INFO_V1(set_next_toast_relfilenode); PG_FUNCTION_INFO_V1(set_next_index_relfilenode); Datum set_next_pg_type_oid(PG_FUNCTION_ARGS) *************** set_next_pg_type_toast_oid(PG_FUNCTION_A *** 81,86 **** --- 82,97 ---- } Datum + set_next_pg_enum_oid(PG_FUNCTION_ARGS) + { + Oid enumoid = PG_GETARG_OID(0); + + binary_upgrade_next_pg_enum_oid = enumoid; + + PG_RETURN_VOID(); + } + + Datum set_next_heap_relfilenode(PG_FUNCTION_ARGS) { Oid relfilenode = PG_GETARG_OID(0); *************** set_next_index_relfilenode(PG_FUNCTION_A *** 110,124 **** PG_RETURN_VOID(); } - Datum - add_pg_enum_label(PG_FUNCTION_ARGS) - { - Oid enumoid = PG_GETARG_OID(0); - Oid typoid = PG_GETARG_OID(1); - Name label = PG_GETARG_NAME(2); - - EnumValuesCreate(typoid, list_make1(makeString(NameStr(*label))), - enumoid); - - PG_RETURN_VOID(); - } --- 121,123 ---- diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index c37b995..0db463e 100644 *** a/doc/src/sgml/catalogs.sgml --- b/doc/src/sgml/catalogs.sgml *************** *** 2626,2634 **** matching enum types to their associated values and labels. The internal representation of a given enum value is actually the OID of its associated row in pg_enum. The ! OIDs for a particular enum type are guaranteed to be ordered in ! the way the type should sort, but there is no guarantee about the ! ordering of OIDs of unrelated enum types. --- 2626,2633 ---- matching enum types to their associated values and labels. The internal representation of a given enum value is actually the OID of its associated row in pg_enum. The ! enum values for a particular enum type are ordered using their ! enumsortorder values.
*************** *** 2658,2663 **** --- 2657,2670 ---- The textual label for this enum value + + + enumsortorder + nameinteger + + The position of this enum value within the list of values for the + enum type +
diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml index 02eaedf..78c2dac 100644 *** a/doc/src/sgml/datatype.sgml --- b/doc/src/sgml/datatype.sgml *************** SELECT * FROM person WHERE current_mood *** 2898,2904 **** The ordering of the values in an enum type is the ! order in which the values were listed when the type was created. All standard comparison operators and related aggregate functions are supported for enums. For example: --- 2898,2906 ---- The ordering of the values in an enum type is the ! order in which the values were listed when the type was created, ! but additional values may be inserted at any position within this ! list using ALTER TYPE. All standard comparison operators and related aggregate functions are supported for enums. For example: *************** SELECT * FROM person WHERE current_mood *** 2912,2923 **** Curly | ok (2 rows) SELECT * FROM person WHERE current_mood > 'sad' ORDER BY current_mood; name | current_mood -------+-------------- Curly | ok Moe | happy ! (2 rows) SELECT name FROM person --- 2914,2928 ---- Curly | ok (2 rows) + ALTER TYPE mood ADD 'content' BEFORE 'happy'; + INSERT INTO person VALUES ('Sue', 'content'); SELECT * FROM person WHERE current_mood > 'sad' ORDER BY current_mood; name | current_mood -------+-------------- Curly | ok + Sue | content Moe | happy ! (3 rows) SELECT name FROM person diff --git a/doc/src/sgml/ref/alter_type.sgml b/doc/src/sgml/ref/alter_type.sgml index 315922e..b05b000 100644 *** a/doc/src/sgml/ref/alter_type.sgml --- b/doc/src/sgml/ref/alter_type.sgml *************** ALTER TYPE name RENAME ATTRIBUTE attribute_name TO new_attribute_name ALTER TYPE name RENAME TO new_name ALTER TYPE name SET SCHEMA new_schema + ALTER TYPE name ADD new_enum_value [ BEFORE | AFTER existing_enum_value ] where action is one of: *************** ALTER TYPE + + new_enum_value + + + The new value to be added to the enum type's list of values. Like all + enum literals it needs to be quoted. + + + + + + existing_enum_value + + + The neighbor of the new value to be added to the enum type's list of + values. Like all enum literals it needs to be quoted. + + + + *************** ALTER TYPE email SET SCHEMA customers; *** 232,237 **** --- 275,287 ---- ALTER TYPE compfoo ADD ATTRIBUTE f3 int; + + + To add a new value to an enum type in a particular sort position: + + ALTER TYPE colors ADD 'orange' AFTER 'red'; + + diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index dcc53e1..f42aecb 100644 *** a/src/backend/catalog/heap.c --- b/src/backend/catalog/heap.c *************** AddNewRelationType(const char *typeName, *** 855,861 **** 'x', /* fully TOASTable */ -1, /* typmod */ 0, /* array dimensions for typBaseType */ ! false); /* Type NOT NULL */ } /* -------------------------------- --- 855,863 ---- 'x', /* fully TOASTable */ -1, /* typmod */ 0, /* array dimensions for typBaseType */ ! false, /* Type NOT NULL */ ! -1, /* no enum labels */ ! false); /* type is not an enum, so not sorted */ } /* -------------------------------- *************** heap_create_with_catalog(const char *rel *** 1108,1114 **** 'x', /* fully TOASTable */ -1, /* typmod */ 0, /* array dimensions for typBaseType */ ! false); /* Type NOT NULL */ pfree(relarrayname); } --- 1110,1118 ---- 'x', /* fully TOASTable */ -1, /* typmod */ 0, /* array dimensions for typBaseType */ ! false, /* Type NOT NULL */ ! -1, /* no enum labels */ ! false); /* type is not an enum, so not sorted */ pfree(relarrayname); } diff --git a/src/backend/catalog/pg_enum.c b/src/backend/catalog/pg_enum.c index d544c1f..65f9c71 100644 *** a/src/backend/catalog/pg_enum.c --- b/src/backend/catalog/pg_enum.c *************** *** 18,29 **** --- 18,219 ---- #include "catalog/catalog.h" #include "catalog/indexing.h" #include "catalog/pg_enum.h" + #include "catalog/pg_type.h" + #include "utils/lsyscache.h" + #include "utils/syscache.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); + static int sort_order_cmp(const void *p1, const void *p2); + + Oid binary_upgrade_next_pg_enum_oid = InvalidOid; + + /* + * AddEnumLabel + * Add a new label to the enum set. By default it goes at + * the end, but the user can choose to place it before or + * after any existing set member. + * + * Returns true iff the labels are sorted by oid after the addition. + */ + + bool + AddEnumLabel(Oid enumTypeOid, + char *newVal, + char *neighbour, + bool newValIsAfter, + int nelems, + bool elems_are_sorted) + { + Oid newOid; + Relation pg_enum; + TupleDesc tupDesc; + Datum values[Natts_pg_enum]; + bool nulls[Natts_pg_enum]; + NameData enumlabel; + HeapTuple enum_tup; + bool result = elems_are_sorted; + int newelemorder; + + /* check length of new label is ok */ + if (strlen(newVal) > (NAMEDATALEN - 1)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_NAME), + errmsg("invalid enum label \"%s\"", newVal), + errdetail("Labels must be %d characters or less.", + NAMEDATALEN - 1))); + + /* get a new OID for the label */ + pg_enum = heap_open(EnumRelationId, RowExclusiveLock); + + if (OidIsValid(binary_upgrade_next_pg_enum_oid)) + { + if (neighbour != NULL) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("BEFORE/AFTER incompatible with binary upgrade."))); + + newOid = binary_upgrade_next_pg_enum_oid; + binary_upgrade_next_pg_enum_oid = InvalidOid; + } + else + { + /* non upgrade case */ + newOid = GetNewOid(pg_enum); + } + + if (neighbour == NULL) + { + /* + * Put the new label at the end of the list. + * No change to existing tuples is required. + */ + newelemorder = nelems + 1; + /* are the elements still sorted? */ + if (elems_are_sorted) + { + CatCList *list; + int i; + bool still_sorted = true; + + list = SearchSysCacheList1(ENUMTYPOIDNAME, + ObjectIdGetDatum(enumTypeOid)); + for (i = 0; i < nelems; i++) + { + HeapTuple tup = &(list->members[i]->tuple); + Form_pg_enum en = (Form_pg_enum) GETSTRUCT(tup); + + if (en->enumsortorder == nelems) + { + if (HeapTupleGetOid(tup) > newOid) + still_sorted = false; + break; + } + } + ReleaseCatCacheList(list); + if (! still_sorted) + result = false; + } + } + else + { + /* BEFORE or AFTER specified */ + CatCList *list; + int i; + HeapTuple *existing; + HeapTuple nbr = NULL; + Form_pg_enum nbr_en; + + /* get a list of the existing elements and sort them by enumsortorder */ + list = SearchSysCacheList1(ENUMTYPOIDNAME, + ObjectIdGetDatum(enumTypeOid)); + existing = palloc(nelems * sizeof(HeapTuple)); + + for (i = 0; i < nelems; i++) + existing[i] = &(list->members[i]->tuple); + + qsort(existing, nelems, sizeof(HeapTuple), sort_order_cmp); + + /* locate the neighbour element */ + for (i = 0; i < nelems; i++) + { + Form_pg_enum exists_en; + exists_en = (Form_pg_enum) GETSTRUCT(existing[i]); + if (strcmp(NameStr(exists_en->enumlabel),neighbour) == 0) + nbr = existing[i]; + + } + + if (nbr == NULL) + { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("\"%s\" is not an existing label.", neighbour))); + } + + nbr_en = (Form_pg_enum) GETSTRUCT(nbr); + + /* + * If BEFORE was specified, the new label goes in the neighbour's + * position. Otherwise, it goes in the position after that. + */ + newelemorder = nbr_en->enumsortorder; + if (newValIsAfter) + newelemorder++; + + /* + * Add 1 to the sortorder of all the labels after where the + * new label goes. Do it from the end back so we don't get + * uniqueness violations. + */ + for (i = nelems - 1; i>= 0; i--) + { + HeapTuple newtup; + Form_pg_enum exst_en = (Form_pg_enum) GETSTRUCT(existing[i]); + if (exst_en->enumsortorder < newelemorder) + break; + + newtup = heap_copytuple(existing[i]); + exst_en = (Form_pg_enum) GETSTRUCT(newtup); + exst_en->enumsortorder ++; + + simple_heap_update(pg_enum, &newtup->t_self, newtup); + + CatalogUpdateIndexes(pg_enum, newtup); + + } + + ReleaseCatCacheList(list); + + /* are the labels sorted by OID? */ + if (result && newelemorder > 1) + result = newOid > HeapTupleGetOid(existing[newelemorder-2]); + if (result && newelemorder < nelems + 1) + result = newOid < HeapTupleGetOid(existing[newelemorder-1]); + + } + + /* set up the new entry */ + tupDesc = pg_enum->rd_att; + memset(nulls, false, sizeof(nulls)); + values[Anum_pg_enum_enumtypid - 1] = ObjectIdGetDatum(enumTypeOid); + namestrcpy(&enumlabel, newVal); + values[Anum_pg_enum_enumlabel - 1] = NameGetDatum(&enumlabel); + values[Anum_pg_enum_enumsortorder -1] = Int32GetDatum(newelemorder); + enum_tup = heap_form_tuple(tupDesc, values, nulls); + HeapTupleSetOid(enum_tup, newOid); + simple_heap_insert(pg_enum, enum_tup); + CatalogUpdateIndexes(pg_enum, enum_tup); + heap_freetuple(enum_tup); + + heap_close(pg_enum, RowExclusiveLock); + + return result; + + } /* *************** static int oid_cmp(const void *p1, const *** 33,40 **** * 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; --- 223,229 ---- * vals is a list of Value strings. */ void ! EnumValuesCreate(Oid enumTypeOid, List *vals) { Relation pg_enum; TupleDesc tupDesc; *************** EnumValuesCreate(Oid enumTypeOid, List * *** 50,58 **** num_elems = list_length(vals); /* ! * 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); --- 239,247 ---- num_elems = list_length(vals); /* ! * 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. ! * It is probably not worth trying harder. */ pg_enum = heap_open(EnumRelationId, RowExclusiveLock); *************** EnumValuesCreate(Oid enumTypeOid, List * *** 62,96 **** * Allocate oids */ oids = (Oid *) palloc(num_elems * sizeof(Oid)); ! if (OidIsValid(binary_upgrade_next_pg_enum_oid)) ! { ! 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 { /* ! * 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++) ! { ! /* ! * 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)); --- 251,274 ---- * Allocate oids */ oids = (Oid *) palloc(num_elems * sizeof(Oid)); ! ! /* ! * 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++) { /* ! * 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)); *************** EnumValuesCreate(Oid enumTypeOid, List * *** 114,119 **** --- 292,298 ---- values[Anum_pg_enum_enumtypid - 1] = ObjectIdGetDatum(enumTypeOid); namestrcpy(&enumlabel, lab); values[Anum_pg_enum_enumlabel - 1] = NameGetDatum(&enumlabel); + values[Anum_pg_enum_enumsortorder -1] = Int32GetDatum(elemno+1); tup = heap_form_tuple(tupDesc, values, nulls); HeapTupleSetOid(tup, oids[elemno]); *************** EnumValuesDelete(Oid enumTypeOid) *** 164,170 **** } ! /* qsort comparison function */ static int oid_cmp(const void *p1, const void *p2) { --- 343,349 ---- } ! /* qsort comparison for oids */ static int oid_cmp(const void *p1, const void *p2) { *************** oid_cmp(const void *p1, const void *p2) *** 177,179 **** --- 356,371 ---- return 1; return 0; } + + /* qsort comparison function for tuples by sort order */ + static int + sort_order_cmp(const void *p1, const void *p2) + { + HeapTuple v1 = *((const HeapTuple *) p1); + HeapTuple v2 = *((const HeapTuple *) p2); + Form_pg_enum en1 = (Form_pg_enum) GETSTRUCT(v1); + Form_pg_enum en2 = (Form_pg_enum) GETSTRUCT(v2); + + return en1->enumsortorder - en2->enumsortorder; + } + diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c index d7fccdf..56e0dc1 100644 *** a/src/backend/catalog/pg_type.c --- b/src/backend/catalog/pg_type.c *************** TypeShellMake(const char *typeName, Oid *** 112,117 **** --- 112,119 ---- values[i++] = ObjectIdGetDatum(InvalidOid); /* typbasetype */ values[i++] = Int32GetDatum(-1); /* typtypmod */ values[i++] = Int32GetDatum(0); /* typndims */ + values[i++] = Int32GetDatum(-1); /* typnlabels */ + values[i++] = BoolGetDatum(false); /* typsorted */ nulls[i++] = true; /* typdefaultbin */ nulls[i++] = true; /* typdefault */ *************** TypeCreate(Oid newTypeOid, *** 204,210 **** char storage, int32 typeMod, int32 typNDims, /* Array dimensions for baseType */ ! bool typeNotNull) { Relation pg_type_desc; Oid typeObjectId; --- 206,214 ---- char storage, int32 typeMod, int32 typNDims, /* Array dimensions for baseType */ ! bool typeNotNull, ! int32 typeNLabels, ! bool typeSorted) { Relation pg_type_desc; Oid typeObjectId; *************** TypeCreate(Oid newTypeOid, *** 342,347 **** --- 346,353 ---- values[i++] = ObjectIdGetDatum(baseType); /* typbasetype */ values[i++] = Int32GetDatum(typeMod); /* typtypmod */ values[i++] = Int32GetDatum(typNDims); /* typndims */ + values[i++] = Int32GetDatum(typeNLabels); /* typnlabels */ + values[i++] = BoolGetDatum(typeSorted); /* typsorted */ /* * initialize the default binary value for this type. Check for nulls of diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 25503bd..01e19cf 100644 *** a/src/backend/commands/typecmds.c --- b/src/backend/commands/typecmds.c *************** static Oid findTypeTypmodoutFunction(Lis *** 85,96 **** static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid); static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode); static void checkDomainOwner(HeapTuple tup, TypeName *typename); static char *domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, int typMod, Constraint *constr, char *domainName); - - /* * DefineType * Registers a new base type. --- 85,95 ---- static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid); static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode); static void checkDomainOwner(HeapTuple tup, TypeName *typename); + static void checkEnumOwner(HeapTuple tup, TypeName *typename); static char *domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, int typMod, Constraint *constr, char *domainName); /* * DefineType * Registers a new base type. *************** DefineType(List *names, List *parameters *** 562,569 **** storage, /* TOAST strategy */ -1, /* typMod (Domains only) */ 0, /* Array Dimensions of typbasetype */ ! false); /* Type NOT NULL */ ! /* * Create the array type that goes with it. */ --- 561,569 ---- storage, /* TOAST strategy */ -1, /* typMod (Domains only) */ 0, /* Array Dimensions of typbasetype */ ! false, /* Type NOT NULL */ ! -1, /* no enum labels */ ! false); /* type is not an enum, so not sorted */ /* * Create the array type that goes with it. */ *************** DefineType(List *names, List *parameters *** 601,607 **** 'x', /* ARRAY is always toastable */ -1, /* typMod (Domains only) */ 0, /* Array dimensions of typbasetype */ ! false); /* Type NOT NULL */ pfree(array_type); } --- 601,609 ---- 'x', /* ARRAY is always toastable */ -1, /* typMod (Domains only) */ 0, /* Array dimensions of typbasetype */ ! false, /* Type NOT NULL */ ! -1, /* no enum labels */ ! false); /* type is not an enum, so not sorted */ pfree(array_type); } *************** DefineDomain(CreateDomainStmt *stmt) *** 1044,1050 **** storage, /* TOAST strategy */ basetypeMod, /* typeMod value */ typNDims, /* Array dimensions for base type */ ! typNotNull); /* Type NOT NULL */ /* * Process constraints which refer to the domain ID returned by TypeCreate --- 1046,1054 ---- storage, /* TOAST strategy */ basetypeMod, /* typeMod value */ typNDims, /* Array dimensions for base type */ ! typNotNull, /* Type NOT NULL */ ! -1, /* no enum labels */ ! false); /* type is not an enum, so not sorted */ /* * Process constraints which refer to the domain ID returned by TypeCreate *************** DefineEnum(CreateEnumStmt *stmt) *** 1094,1099 **** --- 1098,1106 ---- AclResult aclresult; Oid old_type_oid; Oid enumArrayOid; + int num_labels; + + num_labels = list_length(stmt->vals); /* Convert list of names to a name and namespace */ enumNamespace = QualifiedNameGetCreationNamespace(stmt->typeName, *************** DefineEnum(CreateEnumStmt *stmt) *** 1153,1162 **** 'p', /* TOAST strategy always plain */ -1, /* typMod (Domains only) */ 0, /* Array dimensions of typbasetype */ ! false); /* Type NOT NULL */ /* Enter the enum's values into pg_enum */ ! EnumValuesCreate(enumTypeOid, stmt->vals, InvalidOid); /* * Create the array type that goes with it. --- 1160,1171 ---- 'p', /* TOAST strategy always plain */ -1, /* typMod (Domains only) */ 0, /* Array dimensions of typbasetype */ ! false, /* Type NOT NULL */ ! num_labels, /* count enum labels */ ! true); /* enums always start sorted */ /* Enter the enum's values into pg_enum */ ! EnumValuesCreate(enumTypeOid, stmt->vals); /* * Create the array type that goes with it. *************** DefineEnum(CreateEnumStmt *stmt) *** 1192,1202 **** 'x', /* ARRAY is always toastable */ -1, /* typMod (Domains only) */ 0, /* Array dimensions of typbasetype */ ! false); /* Type NOT NULL */ pfree(enumArrayName); } /* * Find suitable I/O functions for a type. --- 1201,1288 ---- 'x', /* ARRAY is always toastable */ -1, /* typMod (Domains only) */ 0, /* Array dimensions of typbasetype */ ! false, /* Type NOT NULL */ ! -1, /* no enum labels */ ! false); /* type is not an enum, so not sorted */ pfree(enumArrayName); } + /* + * AlterEnum + * Registers a new label for an existing enum. + */ + void + AlterEnum (AlterEnumStmt *stmt) + { + Oid enum_type_oid; + TypeName *typename; + bool sorted; + HeapTuple tup, newtup; + Relation rel; + Form_pg_type typTup; + + /* Make a TypeName so we can use standard type lookup machinery */ + typename = makeTypeNameFromNameList(stmt->typeName); + enum_type_oid = typenameTypeId(NULL, typename, NULL); + + /* Look up the row in the type table */ + rel = heap_open(TypeRelationId, RowExclusiveLock); + + tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(enum_type_oid)); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "cache lookup failed for type %u", enum_type_oid); + + /* Copy the syscache entry so we can scribble on it below */ + newtup = heap_copytuple(tup); + ReleaseSysCache(tup); + tup = newtup; + typTup = (Form_pg_type) GETSTRUCT(tup); + + /* Check it's an enum and check user has permission to ALTER the enum */ + checkEnumOwner(tup, typename); + + /* Add the new label */ + sorted = AddEnumLabel (enum_type_oid, stmt->newVal, + stmt->newValNeighbour, stmt->newValIsAfter, + typTup->typnlabels, typTup->typsorted); + + /* Update the row in pg_type */ + typTup->typnlabels += 1; + typTup->typsorted = sorted; + + simple_heap_update(rel, &tup->t_self, tup); + + CatalogUpdateIndexes(rel, tup); + + /* Clean up */ + heap_close(rel, RowExclusiveLock); + } + + + /* + * checkEnumOwner + * + * Check that the type is actually an enum and that the current user + * has permission to do ALTER TYPE on it. Throw an error if not. + */ + static void + checkEnumOwner(HeapTuple tup, TypeName *typename) + { + Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup); + + /* Check that this is actually a domain */ + if (typTup->typtype != TYPTYPE_ENUM) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s\" is not an enum", + TypeNameToString(typename)))); + + /* Permission check: must own type */ + if (!pg_type_ownercheck(HeapTupleGetOid(tup), GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE, + format_type_be(HeapTupleGetOid(tup))); + } /* * Find suitable I/O functions for a type. diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 2118a33..dcc063a 100644 *** a/src/backend/nodes/copyfuncs.c --- b/src/backend/nodes/copyfuncs.c *************** _copyCreateEnumStmt(CreateEnumStmt *from *** 2873,2878 **** --- 2873,2891 ---- return newnode; } + static AlterEnumStmt * + _copyAlterEnumStmt(AlterEnumStmt *from) + { + AlterEnumStmt *newnode = makeNode(AlterEnumStmt); + + COPY_NODE_FIELD(typeName); + COPY_STRING_FIELD(newVal); + COPY_STRING_FIELD(newValNeighbour); + COPY_SCALAR_FIELD(newValIsAfter); + + return newnode; + } + static ViewStmt * _copyViewStmt(ViewStmt *from) { *************** copyObject(void *from) *** 4033,4038 **** --- 4046,4054 ---- case T_CreateEnumStmt: retval = _copyCreateEnumStmt(from); break; + case T_AlterEnumStmt: + retval = _copyAlterEnumStmt(from); + break; case T_ViewStmt: retval = _copyViewStmt(from); break; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 6bad724..2439e7f 100644 *** a/src/backend/nodes/equalfuncs.c --- b/src/backend/nodes/equalfuncs.c *************** _equalCreateEnumStmt(CreateEnumStmt *a, *** 1390,1395 **** --- 1390,1406 ---- } static bool + _equalAlterEnumStmt(AlterEnumStmt *a, AlterEnumStmt *b) + { + COMPARE_NODE_FIELD(typeName); + COMPARE_STRING_FIELD(newVal); + COMPARE_STRING_FIELD(newValNeighbour); + COMPARE_SCALAR_FIELD(newValIsAfter); + + return true; + } + + static bool _equalViewStmt(ViewStmt *a, ViewStmt *b) { COMPARE_NODE_FIELD(view); *************** equal(void *a, void *b) *** 2697,2702 **** --- 2708,2716 ---- case T_CreateEnumStmt: retval = _equalCreateEnumStmt(a, b); break; + case T_AlterEnumStmt: + retval = _equalAlterEnumStmt(a, b); + break; case T_ViewStmt: retval = _equalViewStmt(a, b); break; diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 3a74fa5..90d3e4d 100644 *** a/src/backend/parser/gram.y --- b/src/backend/parser/gram.y *************** static RangeVar *makeRangeVarFromAnyName *** 182,189 **** } %type stmt schema_stmt ! AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterFdwStmt ! AlterForeignServerStmt AlterGroupStmt AlterObjectSchemaStmt AlterOwnerStmt AlterSeqStmt AlterTableStmt AlterCompositeTypeStmt AlterUserStmt AlterUserMappingStmt AlterUserSetStmt AlterRoleStmt AlterRoleSetStmt --- 182,189 ---- } %type stmt schema_stmt ! AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterEnumStmt ! AlterFdwStmt AlterForeignServerStmt AlterGroupStmt AlterObjectSchemaStmt AlterOwnerStmt AlterSeqStmt AlterTableStmt AlterCompositeTypeStmt AlterUserStmt AlterUserMappingStmt AlterUserSetStmt AlterRoleStmt AlterRoleSetStmt *************** stmt : *** 652,657 **** --- 652,658 ---- | AlterDatabaseSetStmt | AlterDefaultPrivilegesStmt | AlterDomainStmt + | AlterEnumStmt | AlterFdwStmt | AlterForeignServerStmt | AlterFunctionStmt *************** enum_val_list: Sconst *** 3862,3867 **** --- 3863,3908 ---- { $$ = lappend($1, makeString($3)); } ; + /***************************************************************************** + * + * ALTER TYPE enumtype ADD ... + * + *****************************************************************************/ + + AlterEnumStmt: + ALTER TYPE_P any_name ADD_P Sconst + { + AlterEnumStmt *n = makeNode(AlterEnumStmt); + n->typeName = $3; + n->newVal = $5; + n->newValNeighbour = NULL; + n->newValIsAfter = true; + + $$ = (Node *) n; + } + | ALTER TYPE_P any_name ADD_P Sconst BEFORE Sconst + { + AlterEnumStmt *n = makeNode(AlterEnumStmt); + n->typeName = $3; + n->newVal = $5; + n->newValNeighbour = $7; + n->newValIsAfter = false; + + $$ = (Node *) n; + } + | ALTER TYPE_P any_name ADD_P Sconst AFTER Sconst + { + AlterEnumStmt *n = makeNode(AlterEnumStmt); + n->typeName = $3; + n->newVal = $5; + n->newValNeighbour = $7; + n->newValIsAfter = true; + + $$ = (Node *) n; + } + ; + + /***************************************************************************** * diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 75cb354..2c8b7aa 100644 *** a/src/backend/tcop/utility.c --- b/src/backend/tcop/utility.c *************** check_xact_readonly(Node *parsetree) *** 190,195 **** --- 190,196 ---- case T_CreateTrigStmt: case T_CompositeTypeStmt: case T_CreateEnumStmt: + case T_AlterEnumStmt: case T_ViewStmt: case T_DropCastStmt: case T_DropStmt: *************** standard_ProcessUtility(Node *parsetree, *** 860,865 **** --- 861,870 ---- DefineEnum((CreateEnumStmt *) parsetree); break; + case T_AlterEnumStmt: /* ALTER TYPE (enum) */ + AlterEnum((AlterEnumStmt *) parsetree); + break; + case T_ViewStmt: /* CREATE VIEW */ DefineView((ViewStmt *) parsetree, queryString); break; *************** CreateCommandTag(Node *parsetree) *** 1868,1873 **** --- 1873,1882 ---- tag = "CREATE TYPE"; break; + case T_AlterEnumStmt: + tag = "ALTER TYPE"; + break; + case T_ViewStmt: tag = "CREATE VIEW"; break; *************** GetCommandLogLevel(Node *parsetree) *** 2410,2415 **** --- 2419,2428 ---- lev = LOGSTMT_DDL; break; + case T_AlterEnumStmt: + lev = LOGSTMT_DDL; + break; + case T_ViewStmt: lev = LOGSTMT_DDL; break; diff --git a/src/backend/utils/adt/enum.c b/src/backend/utils/adt/enum.c index e5747a4..f9feda5 100644 *** a/src/backend/utils/adt/enum.c --- b/src/backend/utils/adt/enum.c *************** *** 14,19 **** --- 14,20 ---- #include "postgres.h" #include "catalog/pg_enum.h" + #include "catalog/pg_type.h" #include "fmgr.h" #include "utils/array.h" #include "utils/builtins.h" *************** *** 22,30 **** #include "libpq/pqformat.h" #include "miscadmin.h" static ArrayType *enum_range_internal(Oid enumtypoid, Oid lower, Oid upper); ! static int enum_elem_cmp(const void *left, const void *right); /* Basic I/O support */ --- 23,48 ---- #include "libpq/pqformat.h" #include "miscadmin.h" + typedef struct + { + Oid enum_oid; + int32 sort_order; + } enum_sort; + + typedef struct + { + Oid enumtypoid; + bool oids_are_sorted; + int sort_list_length; + int label_count; + enum_sort sort_order_list[1]; + } enum_sort_cache; + + static ArrayType *enum_range_internal(Oid enumtypoid, Oid lower, Oid upper); ! static int enum_sort_cmp(const void *left, const void *right); ! static int enum_oid_cmp(const void *left, const void *right); /* Basic I/O support */ *************** enum_send(PG_FUNCTION_ARGS) *** 155,167 **** /* Comparison functions and related */ Datum enum_lt(PG_FUNCTION_ARGS) { Oid a = PG_GETARG_OID(0); Oid b = PG_GETARG_OID(1); ! PG_RETURN_BOOL(a < b); } Datum --- 173,347 ---- /* Comparison functions and related */ + + /* enum_ccmp is the common engine for all the visible comparison functions */ + + static inline int + enum_ccmp(Oid arg1, Oid arg2, FunctionCallInfo fcinfo) + { + + /* + * Keep a cache of type information in fcinfo->flinfo->fn_extra. + * If the Oids are sorted, that's all the info we need, and + * we can just return the difference of arg1 and arg2. + * If not, we keep a list of Oid/sortorder pairs in the cache, + * and look up the sortorder by Oid, using a binary search, + * and return the difference between the sortorders. + * + * To keep down the cost of retail comparisons even if + * the label set is very large, we start by just putting + * Oids we are actually comparing into the cache. If this + * grows beyond a handful (10 in fact) it looks like it's a + * bulk operation, and so we just fetch the all the labels + * and sort them. This keeps down the number of times we + * might need to call quicksort. + */ + + enum_sort_cache * mycache; + enum_sort *es1, *es2, srch; + int sort1, sort2; + bool added = false; + HeapTuple enum_tup, type_tup; + Form_pg_enum en; + Oid typeoid; + Form_pg_type typ; + + /* + * Fast path return for equal Oids, sorted or not. + * This shouldn't happen, but it's here just in case. + */ + if (arg1 == arg2) + return 0; + + mycache = (enum_sort_cache *) fcinfo->flinfo->fn_extra; + + /* Initialize the cache if it's not already there */ + if (mycache == NULL ) + { + enum_tup = SearchSysCache1(ENUMOID, ObjectIdGetDatum(arg1)); + en = (Form_pg_enum) GETSTRUCT(enum_tup); + typeoid = en->enumtypid; + type_tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typeoid)); + typ = (Form_pg_type) GETSTRUCT(type_tup); + if (typ->typtype != 'e') + elog(ERROR,"wrong type for oid %u",typeoid); + fcinfo->flinfo->fn_extra = + MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, + sizeof(enum_sort_cache) + + (typ->typnlabels * sizeof(enum_sort))); + mycache = (enum_sort_cache *) fcinfo->flinfo->fn_extra; + mycache->enumtypoid = typeoid; + mycache->sort_list_length = 1; + mycache->label_count = typ->typnlabels; + mycache->oids_are_sorted = typ->typsorted; + mycache->sort_order_list[0].enum_oid = arg1; + mycache->sort_order_list[0].sort_order = en->enumsortorder; + ReleaseSysCache(type_tup); + ReleaseSysCache(enum_tup); + } + + /* Fast path return for Oids are sorted case */ + if (mycache->oids_are_sorted) + return arg1 - arg2; + + /* Look up the Oids in the cache */ + srch.enum_oid = arg1; + es1 = bsearch(&srch, + mycache->sort_order_list, + mycache->sort_list_length, + sizeof(enum_sort), + enum_oid_cmp); + srch.enum_oid = arg2; + es2 = bsearch(&srch, + mycache->sort_order_list, + mycache->sort_list_length, + sizeof(enum_sort), + enum_oid_cmp); + + /* Handle cache misses, or get the sort order from the search results */ + + if (es1 == NULL) + { + + enum_tup = SearchSysCache1(ENUMOID, ObjectIdGetDatum(arg1)); + en = (Form_pg_enum) GETSTRUCT(enum_tup); + mycache->sort_order_list[mycache->sort_list_length].enum_oid = arg1; + sort1 = en->enumsortorder; + mycache->sort_order_list[mycache->sort_list_length].sort_order = + sort1; + ReleaseSysCache(enum_tup); + mycache->sort_list_length ++; + added = true; + } + else + { + /* already in cache */ + sort1 = es1->sort_order; + } + + if (es2 == NULL) + { + + enum_tup = SearchSysCache1(ENUMOID, ObjectIdGetDatum(arg2)); + en = (Form_pg_enum) GETSTRUCT(enum_tup); + sort2 = en->enumsortorder; + mycache->sort_order_list[mycache->sort_list_length].enum_oid = arg2; + mycache->sort_order_list[mycache->sort_list_length].sort_order = + sort2; + ReleaseSysCache(enum_tup); + mycache->sort_list_length ++; + added = true; + } + else + { + /* already in cache */ + sort2 = es2->sort_order; + } + + /* Sort the cache, and possibly complete it, for the next function call */ + if (added) + { + /* + * If we have more than a handful, just fetch them all, so we limit + * the number of sort operations required. + */ + if (mycache->sort_list_length > 10 && + mycache->sort_list_length < mycache->label_count) + { + CatCList *nlist; + int num, i; + + nlist = SearchSysCacheList1(ENUMTYPOIDNAME, + ObjectIdGetDatum(mycache->enumtypoid)); + num = nlist->n_members; + for (i = 0; i < num; i++) + { + HeapTuple tup = &(nlist->members[i]->tuple); + Form_pg_enum en = (Form_pg_enum) GETSTRUCT(tup); + + mycache->sort_order_list[i].enum_oid = HeapTupleGetOid(tup); + mycache->sort_order_list[i].sort_order = en->enumsortorder; + } + mycache->sort_list_length = mycache->label_count; + + ReleaseCatCacheList(nlist); + } + + qsort(mycache->sort_order_list,mycache->sort_list_length, + sizeof(enum_sort),enum_oid_cmp); + } + + /* and we're done */ + return sort1 - sort2; + } + Datum enum_lt(PG_FUNCTION_ARGS) { Oid a = PG_GETARG_OID(0); Oid b = PG_GETARG_OID(1); ! PG_RETURN_BOOL(enum_ccmp(a,b,fcinfo) < 0); } Datum *************** enum_le(PG_FUNCTION_ARGS) *** 170,176 **** Oid a = PG_GETARG_OID(0); Oid b = PG_GETARG_OID(1); ! PG_RETURN_BOOL(a <= b); } Datum --- 350,356 ---- Oid a = PG_GETARG_OID(0); Oid b = PG_GETARG_OID(1); ! PG_RETURN_BOOL(enum_ccmp(a,b,fcinfo) <= 0); } Datum *************** enum_ge(PG_FUNCTION_ARGS) *** 197,203 **** Oid a = PG_GETARG_OID(0); Oid b = PG_GETARG_OID(1); ! PG_RETURN_BOOL(a >= b); } Datum --- 377,383 ---- Oid a = PG_GETARG_OID(0); Oid b = PG_GETARG_OID(1); ! PG_RETURN_BOOL(enum_ccmp(a,b,fcinfo) >= 0); } Datum *************** enum_gt(PG_FUNCTION_ARGS) *** 206,212 **** Oid a = PG_GETARG_OID(0); Oid b = PG_GETARG_OID(1); ! PG_RETURN_BOOL(a > b); } Datum --- 386,392 ---- Oid a = PG_GETARG_OID(0); Oid b = PG_GETARG_OID(1); ! PG_RETURN_BOOL(enum_ccmp(a,b,fcinfo) > 0); } Datum *************** enum_smaller(PG_FUNCTION_ARGS) *** 215,221 **** Oid a = PG_GETARG_OID(0); Oid b = PG_GETARG_OID(1); ! PG_RETURN_OID(a <= b ? a : b); } Datum --- 395,401 ---- Oid a = PG_GETARG_OID(0); Oid b = PG_GETARG_OID(1); ! PG_RETURN_OID(enum_ccmp(a,b,fcinfo) < 0 ? a : b); } Datum *************** enum_larger(PG_FUNCTION_ARGS) *** 224,230 **** Oid a = PG_GETARG_OID(0); Oid b = PG_GETARG_OID(1); ! PG_RETURN_OID(a >= b ? a : b); } Datum --- 404,410 ---- Oid a = PG_GETARG_OID(0); Oid b = PG_GETARG_OID(1); ! PG_RETURN_OID(enum_ccmp(a,b,fcinfo) > 0 ? a : b); } Datum *************** enum_cmp(PG_FUNCTION_ARGS) *** 233,242 **** Oid a = PG_GETARG_OID(0); Oid b = PG_GETARG_OID(1); ! if (a > b) ! PG_RETURN_INT32(1); ! else if (a == b) PG_RETURN_INT32(0); else PG_RETURN_INT32(-1); } --- 413,422 ---- Oid a = PG_GETARG_OID(0); Oid b = PG_GETARG_OID(1); ! if (a == b) PG_RETURN_INT32(0); + else if (enum_ccmp(a,b,fcinfo) > 0) + PG_RETURN_INT32(1); else PG_RETURN_INT32(-1); } *************** enum_first(PG_FUNCTION_ARGS) *** 248,253 **** --- 428,434 ---- { Oid enumtypoid; Oid min = InvalidOid; + int min_sort = -1; /* value will never in fact be used */ CatCList *list; int num, i; *************** enum_first(PG_FUNCTION_ARGS) *** 267,276 **** num = list->n_members; for (i = 0; i < num; i++) { ! Oid valoid = HeapTupleHeaderGetOid(list->members[i]->tuple.t_data); ! if (!OidIsValid(min) || valoid < min) ! min = valoid; } ReleaseCatCacheList(list); --- 448,461 ---- num = list->n_members; for (i = 0; i < num; i++) { ! HeapTuple tup = &(list->members[i]->tuple); ! Form_pg_enum en = (Form_pg_enum) GETSTRUCT(tup); ! if (!OidIsValid(min) || en->enumsortorder < min_sort) ! { ! min = HeapTupleGetOid(tup); ! min_sort = en->enumsortorder; ! } } ReleaseCatCacheList(list); *************** enum_last(PG_FUNCTION_ARGS) *** 287,292 **** --- 472,478 ---- { Oid enumtypoid; Oid max = InvalidOid; + int max_sort = -1; /* value will never in fact be used */ CatCList *list; int num, i; *************** enum_last(PG_FUNCTION_ARGS) *** 306,315 **** num = list->n_members; for (i = 0; i < num; i++) { ! Oid valoid = HeapTupleHeaderGetOid(list->members[i]->tuple.t_data); ! if (!OidIsValid(max) || valoid > max) ! max = valoid; } ReleaseCatCacheList(list); --- 492,505 ---- num = list->n_members; for (i = 0; i < num; i++) { ! HeapTuple tup = &(list->members[i]->tuple); ! Form_pg_enum en = (Form_pg_enum) GETSTRUCT(tup); ! if (!OidIsValid(max) || en->enumsortorder > max_sort) ! { ! max = HeapTupleGetOid(tup); ! max_sort = en->enumsortorder; ! } } ReleaseCatCacheList(list); *************** enum_range_internal(Oid enumtypoid, Oid *** 382,427 **** i, j; Datum *elems; list = SearchSysCacheList1(ENUMTYPOIDNAME, ObjectIdGetDatum(enumtypoid)); total = list->n_members; elems = (Datum *) palloc(total * sizeof(Datum)); - j = 0; for (i = 0; i < total; i++) { ! Oid val = HeapTupleGetOid(&(list->members[i]->tuple)); - if ((!OidIsValid(lower) || lower <= val) && - (!OidIsValid(upper) || val <= upper)) - elems[j++] = ObjectIdGetDatum(val); } /* shouldn't need the cache anymore */ ReleaseCatCacheList(list); ! /* sort results into OID order */ ! qsort(elems, j, sizeof(Datum), enum_elem_cmp); /* note this hardwires some details about the representation of Oid */ result = construct_array(elems, j, enumtypoid, sizeof(Oid), true, 'i'); pfree(elems); return result; } ! /* qsort comparison function for Datums that are OIDs */ static int ! enum_elem_cmp(const void *left, const void *right) { ! Oid l = DatumGetObjectId(*((const Datum *) left)); ! Oid r = DatumGetObjectId(*((const Datum *) right)); ! if (l < r) ! return -1; ! if (l > r) ! return 1; ! return 0; } --- 572,647 ---- i, j; Datum *elems; + enum_sort *sort_items; + bool left_found; list = SearchSysCacheList1(ENUMTYPOIDNAME, ObjectIdGetDatum(enumtypoid)); total = list->n_members; elems = (Datum *) palloc(total * sizeof(Datum)); + sort_items = (enum_sort *) palloc(total * sizeof(enum_sort)); for (i = 0; i < total; i++) { ! HeapTuple tup = &(list->members[i]->tuple); ! Form_pg_enum en = (Form_pg_enum) GETSTRUCT(tup); ! ! sort_items[i].enum_oid = HeapTupleGetOid(tup); ! sort_items[i].sort_order = en->enumsortorder; } /* shouldn't need the cache anymore */ ReleaseCatCacheList(list); ! /* sort results into sort_order sequence */ ! qsort(sort_items, total, sizeof(enum_sort), enum_sort_cmp); ! ! j = 0; ! left_found = !OidIsValid(lower); ! for (i=0; i < total; i++) ! { ! if (! left_found && lower == sort_items[i].enum_oid) ! left_found = true; ! ! if (left_found) ! elems[j++] = ObjectIdGetDatum(sort_items[i].enum_oid); ! ! if (OidIsValid(upper) && upper == sort_items[i].enum_oid) ! break; ! } /* note this hardwires some details about the representation of Oid */ result = construct_array(elems, j, enumtypoid, sizeof(Oid), true, 'i'); pfree(elems); + pfree(sort_items); return result; } ! /* ! * qsort comparison using sort order, for range routines ! */ static int ! enum_sort_cmp(const void *left, const void *right) { ! enum_sort *l = (enum_sort *) left; ! enum_sort *r = (enum_sort *) right; ! return l->sort_order - r->sort_order; } + + /* + * qsort comparison using OID order for comparison search cache + */ + static int + enum_oid_cmp(const void *es1, const void *es2) + { + enum_sort *p1, *p2; + p1 = (enum_sort *)es1; + p2 = (enum_sort *)es2; + return p1->enum_oid - p2->enum_oid; + } + + diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 6a4557b..d413fe5 100644 *** a/src/bin/pg_dump/pg_dump.c --- b/src/bin/pg_dump/pg_dump.c *************** dumpEnumType(Archive *fout, TypeInfo *ty *** 6653,6669 **** PQExpBuffer query = createPQExpBuffer(); PGresult *res; int num, ! i; Oid enum_oid; char *label; /* Set proper schema search path so regproc references list correctly */ selectSourceSchema(tyinfo->dobj.namespace->dobj.name); ! appendPQExpBuffer(query, "SELECT oid, enumlabel " ! "FROM pg_catalog.pg_enum " ! "WHERE enumtypid = '%u'" ! "ORDER BY oid", tyinfo->dobj.catId.oid); res = PQexec(g_conn, query->data); --- 6653,6676 ---- PQExpBuffer query = createPQExpBuffer(); PGresult *res; int num, ! i; Oid enum_oid; char *label; /* Set proper schema search path so regproc references list correctly */ selectSourceSchema(tyinfo->dobj.namespace->dobj.name); ! if (fout->remoteVersion > 90000) ! appendPQExpBuffer(query, "SELECT oid, enumlabel " ! "FROM pg_catalog.pg_enum " ! "WHERE enumtypid = '%u'" ! "ORDER BY enumsortorder", ! tyinfo->dobj.catId.oid); ! else ! appendPQExpBuffer(query, "SELECT oid, enumlabel " ! "FROM pg_catalog.pg_enum " ! "WHERE enumtypid = '%u'" ! "ORDER BY oid", tyinfo->dobj.catId.oid); res = PQexec(g_conn, query->data); *************** dumpEnumType(Archive *fout, TypeInfo *ty *** 6709,6725 **** { enum_oid = atooid(PQgetvalue(res, i, PQfnumber(res, "oid"))); label = PQgetvalue(res, i, PQfnumber(res, "enumlabel")); ! if (i == 0) appendPQExpBuffer(q, "\n-- For binary upgrade, must preserve pg_enum oids\n"); appendPQExpBuffer(q, ! "SELECT binary_upgrade.add_pg_enum_label('%u'::pg_catalog.oid, " ! "'%u'::pg_catalog.oid, ", ! enum_oid, tyinfo->dobj.catId.oid); ! appendStringLiteralAH(q, label, fout); ! appendPQExpBuffer(q, ");\n"); } - appendPQExpBuffer(q, "\n"); } ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, --- 6716,6734 ---- { enum_oid = atooid(PQgetvalue(res, i, PQfnumber(res, "oid"))); label = PQgetvalue(res, i, PQfnumber(res, "enumlabel")); ! if (i == 0) appendPQExpBuffer(q, "\n-- For binary upgrade, must preserve pg_enum oids\n"); appendPQExpBuffer(q, ! "SELECT binary_upgrade.set_next_pg_enum_oid('%u'::pg_catalog.oid);\n", ! enum_oid); ! appendPQExpBuffer(q, "ALTER TYPE %s.", ! fmtId(tyinfo->dobj.namespace->dobj.name)); ! appendPQExpBuffer(q, "%s ADD ", ! fmtId(tyinfo->dobj.name)); ! appendStringLiteralAH(q, label, fout); ! appendPQExpBuffer(q, ";\n\n"); } } ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index 57d74e1..a077948 100644 *** a/src/bin/psql/describe.c --- b/src/bin/psql/describe.c *************** describeTypes(const char *pattern, bool *** 473,489 **** gettext_noop("Internal name"), gettext_noop("Size")); if (verbose && pset.sversion >= 80300) appendPQExpBuffer(&buf, " pg_catalog.array_to_string(\n" " ARRAY(\n" " SELECT e.enumlabel\n" " FROM pg_catalog.pg_enum e\n" ! " WHERE e.enumtypid = t.oid\n" ! " ORDER BY e.oid\n" " ),\n" " E'\\n'\n" " ) AS \"%s\",\n", gettext_noop("Elements")); appendPQExpBuffer(&buf, " pg_catalog.obj_description(t.oid, 'pg_type') as \"%s\"\n", --- 473,499 ---- gettext_noop("Internal name"), gettext_noop("Size")); if (verbose && pset.sversion >= 80300) + { appendPQExpBuffer(&buf, " pg_catalog.array_to_string(\n" " ARRAY(\n" " SELECT e.enumlabel\n" " FROM pg_catalog.pg_enum e\n" ! " WHERE e.enumtypid = t.oid\n"); ! ! if (pset.sversion >= 90100 ) ! appendPQExpBuffer(&buf, ! " ORDER BY e.enumsortorder\n"); ! else ! appendPQExpBuffer(&buf, ! " ORDER BY e.oid\n"); ! ! appendPQExpBuffer(&buf, " ),\n" " E'\\n'\n" " ) AS \"%s\",\n", gettext_noop("Elements")); + } appendPQExpBuffer(&buf, " pg_catalog.obj_description(t.oid, 'pg_type') as \"%s\"\n", diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h index b7c9849..c63724a 100644 *** a/src/include/catalog/indexing.h --- b/src/include/catalog/indexing.h *************** DECLARE_UNIQUE_INDEX(pg_enum_oid_index, *** 147,152 **** --- 147,154 ---- #define EnumOidIndexId 3502 DECLARE_UNIQUE_INDEX(pg_enum_typid_label_index, 3503, on pg_enum using btree(enumtypid oid_ops, enumlabel name_ops)); #define EnumTypIdLabelIndexId 3503 + DECLARE_UNIQUE_INDEX(pg_enum_typid_sortorder_index, 3539, on pg_enum using btree(enumtypid oid_ops, enumsortorder int4_ops)); + #define EnumTypIdSortOrderIndexId 3539 /* This following index is not used for a cache and is not unique */ DECLARE_INDEX(pg_index_indrelid_index, 2678, on pg_index using btree(indrelid oid_ops)); diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h index f50cf9d..824a690 100644 *** a/src/include/catalog/pg_class.h --- b/src/include/catalog/pg_class.h *************** typedef FormData_pg_class *Form_pg_class *** 132,138 **** */ /* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */ ! DATA(insert OID = 1247 ( pg_type PGNSP 71 0 PGUID 0 0 0 0 0 0 0 f f f r 28 0 t f f f f f 3 _null_ _null_ )); DESCR(""); DATA(insert OID = 1249 ( pg_attribute PGNSP 75 0 PGUID 0 0 0 0 0 0 0 f f f r 19 0 f f f f f f 3 _null_ _null_ )); DESCR(""); --- 132,138 ---- */ /* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */ ! DATA(insert OID = 1247 ( pg_type PGNSP 71 0 PGUID 0 0 0 0 0 0 0 f f f r 30 0 t f f f f f 3 _null_ _null_ )); DESCR(""); DATA(insert OID = 1249 ( pg_attribute PGNSP 75 0 PGUID 0 0 0 0 0 0 0 f f f r 19 0 f f f f f f 3 _null_ _null_ )); DESCR(""); diff --git a/src/include/catalog/pg_enum.h b/src/include/catalog/pg_enum.h index 28da42b..06269c6 100644 *** a/src/include/catalog/pg_enum.h --- b/src/include/catalog/pg_enum.h *************** CATALOG(pg_enum,3501) *** 35,40 **** --- 35,41 ---- { Oid enumtypid; /* OID of owning enum type */ NameData enumlabel; /* text representation of enum value */ + int4 enumsortorder; /* sort order for this enum label */ } FormData_pg_enum; /* ---------------- *************** typedef FormData_pg_enum *Form_pg_enum; *** 48,56 **** * compiler constants for pg_enum * ---------------- */ ! #define Natts_pg_enum 2 #define Anum_pg_enum_enumtypid 1 #define Anum_pg_enum_enumlabel 2 /* ---------------- * pg_enum has no initial contents --- 49,58 ---- * compiler constants for pg_enum * ---------------- */ ! #define Natts_pg_enum 3 #define Anum_pg_enum_enumtypid 1 #define Anum_pg_enum_enumlabel 2 + #define Anum_pg_enum_enumsortorder 3 /* ---------------- * pg_enum has no initial contents *************** typedef FormData_pg_enum *Form_pg_enum; *** 60,67 **** /* * prototypes for functions in pg_enum.c */ ! extern void EnumValuesCreate(Oid enumTypeOid, List *vals, ! Oid binary_upgrade_next_pg_enum_oid); extern void EnumValuesDelete(Oid enumTypeOid); #endif /* PG_ENUM_H */ --- 62,70 ---- /* * prototypes for functions in pg_enum.c */ ! extern void EnumValuesCreate(Oid enumTypeOid, List *vals); extern void EnumValuesDelete(Oid enumTypeOid); + extern bool AddEnumLabel(Oid enumTypeOid, char *newVal, char *neighbour, + bool newValIsAfter, int nelems, bool elems_are_sorted); #endif /* PG_ENUM_H */ diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h index fc2c306..f79c0e3 100644 *** a/src/include/catalog/pg_type.h --- b/src/include/catalog/pg_type.h *************** CATALOG(pg_type,1247) BKI_BOOTSTRAP BKI_ *** 194,199 **** --- 194,211 ---- */ int4 typndims; + /* + * typnlabels, contains a count on the number of labels an enum type has, + * -1 for a non-enum type. + */ + int4 typnlabels; + + /* + * typsorted is true if the oids of an enum type reflect the type's sort + * order, false otherwise including for a non-enum type. + */ + bool typsorted; + /* * If typdefaultbin is not NULL, it is the nodeToString representation of * a default expression for the type. Currently this is only used for *************** typedef FormData_pg_type *Form_pg_type; *** 224,230 **** * compiler constants for pg_type * ---------------- */ ! #define Natts_pg_type 28 #define Anum_pg_type_typname 1 #define Anum_pg_type_typnamespace 2 #define Anum_pg_type_typowner 3 --- 236,242 ---- * compiler constants for pg_type * ---------------- */ ! #define Natts_pg_type 30 #define Anum_pg_type_typname 1 #define Anum_pg_type_typnamespace 2 #define Anum_pg_type_typowner 3 *************** typedef FormData_pg_type *Form_pg_type; *** 251,258 **** #define Anum_pg_type_typbasetype 24 #define Anum_pg_type_typtypmod 25 #define Anum_pg_type_typndims 26 ! #define Anum_pg_type_typdefaultbin 27 ! #define Anum_pg_type_typdefault 28 /* ---------------- --- 263,272 ---- #define Anum_pg_type_typbasetype 24 #define Anum_pg_type_typtypmod 25 #define Anum_pg_type_typndims 26 ! #define Anum_pg_type_typnlabels 27 ! #define Anum_pg_type_typsorted 28 ! #define Anum_pg_type_typdefaultbin 29 ! #define Anum_pg_type_typdefault 30 /* ---------------- *************** typedef FormData_pg_type *Form_pg_type; *** 269,355 **** */ /* OIDS 1 - 99 */ ! DATA(insert OID = 16 ( bool PGNSP PGUID 1 t b B t t \054 0 0 1000 boolin boolout boolrecv boolsend - - - c p f 0 -1 0 _null_ _null_ )); DESCR("boolean, 'true'/'false'"); #define BOOLOID 16 ! DATA(insert OID = 17 ( bytea PGNSP PGUID -1 f b U f t \054 0 0 1001 byteain byteaout bytearecv byteasend - - - i x f 0 -1 0 _null_ _null_ )); DESCR("variable-length string, binary values escaped"); #define BYTEAOID 17 ! DATA(insert OID = 18 ( char PGNSP PGUID 1 t b S f t \054 0 0 1002 charin charout charrecv charsend - - - c p f 0 -1 0 _null_ _null_ )); DESCR("single character"); #define CHAROID 18 ! DATA(insert OID = 19 ( name PGNSP PGUID NAMEDATALEN f b S f t \054 0 18 1003 namein nameout namerecv namesend - - - c p f 0 -1 0 _null_ _null_ )); DESCR("63-character type for storing system identifiers"); #define NAMEOID 19 ! DATA(insert OID = 20 ( int8 PGNSP PGUID 8 FLOAT8PASSBYVAL b N f t \054 0 0 1016 int8in int8out int8recv int8send - - - d p f 0 -1 0 _null_ _null_ )); DESCR("~18 digit integer, 8-byte storage"); #define INT8OID 20 ! DATA(insert OID = 21 ( int2 PGNSP PGUID 2 t b N f t \054 0 0 1005 int2in int2out int2recv int2send - - - s p f 0 -1 0 _null_ _null_ )); DESCR("-32 thousand to 32 thousand, 2-byte storage"); #define INT2OID 21 ! DATA(insert OID = 22 ( int2vector PGNSP PGUID -1 f b A f t \054 0 21 1006 int2vectorin int2vectorout int2vectorrecv int2vectorsend - - - i p f 0 -1 0 _null_ _null_ )); DESCR("array of int2, used in system tables"); #define INT2VECTOROID 22 ! DATA(insert OID = 23 ( int4 PGNSP PGUID 4 t b N f t \054 0 0 1007 int4in int4out int4recv int4send - - - i p f 0 -1 0 _null_ _null_ )); DESCR("-2 billion to 2 billion integer, 4-byte storage"); #define INT4OID 23 ! DATA(insert OID = 24 ( regproc PGNSP PGUID 4 t b N f t \054 0 0 1008 regprocin regprocout regprocrecv regprocsend - - - i p f 0 -1 0 _null_ _null_ )); DESCR("registered procedure"); #define REGPROCOID 24 ! DATA(insert OID = 25 ( text PGNSP PGUID -1 f b S t t \054 0 0 1009 textin textout textrecv textsend - - - i x f 0 -1 0 _null_ _null_ )); DESCR("variable-length string, no limit specified"); #define TEXTOID 25 ! DATA(insert OID = 26 ( oid PGNSP PGUID 4 t b N t t \054 0 0 1028 oidin oidout oidrecv oidsend - - - i p f 0 -1 0 _null_ _null_ )); DESCR("object identifier(oid), maximum 4 billion"); #define OIDOID 26 ! DATA(insert OID = 27 ( tid PGNSP PGUID 6 f b U f t \054 0 0 1010 tidin tidout tidrecv tidsend - - - s p f 0 -1 0 _null_ _null_ )); DESCR("(block, offset), physical location of tuple"); #define TIDOID 27 ! DATA(insert OID = 28 ( xid PGNSP PGUID 4 t b U f t \054 0 0 1011 xidin xidout xidrecv xidsend - - - i p f 0 -1 0 _null_ _null_ )); DESCR("transaction id"); #define XIDOID 28 ! DATA(insert OID = 29 ( cid PGNSP PGUID 4 t b U f t \054 0 0 1012 cidin cidout cidrecv cidsend - - - i p f 0 -1 0 _null_ _null_ )); DESCR("command identifier type, sequence in transaction id"); #define CIDOID 29 ! DATA(insert OID = 30 ( oidvector PGNSP PGUID -1 f b A f t \054 0 26 1013 oidvectorin oidvectorout oidvectorrecv oidvectorsend - - - i p f 0 -1 0 _null_ _null_ )); DESCR("array of oids, used in system tables"); #define OIDVECTOROID 30 /* hand-built rowtype entries for bootstrapped catalogs */ /* NB: OIDs assigned here must match the BKI_ROWTYPE_OID declarations */ ! DATA(insert OID = 71 ( pg_type PGNSP PGUID -1 f c C f t \054 1247 0 0 record_in record_out record_recv record_send - - - d x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 75 ( pg_attribute PGNSP PGUID -1 f c C f t \054 1249 0 0 record_in record_out record_recv record_send - - - d x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 81 ( pg_proc PGNSP PGUID -1 f c C f t \054 1255 0 0 record_in record_out record_recv record_send - - - d x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 83 ( pg_class PGNSP PGUID -1 f c C f t \054 1259 0 0 record_in record_out record_recv record_send - - - d x f 0 -1 0 _null_ _null_ )); /* OIDS 100 - 199 */ ! DATA(insert OID = 142 ( xml PGNSP PGUID -1 f b U f t \054 0 0 143 xml_in xml_out xml_recv xml_send - - - i x f 0 -1 0 _null_ _null_ )); DESCR("XML content"); #define XMLOID 142 ! DATA(insert OID = 143 ( _xml PGNSP PGUID -1 f b A f t \054 0 142 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 194 ( pg_node_tree PGNSP PGUID -1 f b S f t \054 0 0 0 pg_node_tree_in pg_node_tree_out pg_node_tree_recv pg_node_tree_send - - - i x f 0 -1 0 _null_ _null_ )); DESCR("string representing an internal node tree"); #define PGNODETREEOID 194 /* OIDS 200 - 299 */ ! DATA(insert OID = 210 ( smgr PGNSP PGUID 2 t b U f t \054 0 0 0 smgrin smgrout - - - - - s p f 0 -1 0 _null_ _null_ )); DESCR("storage manager"); /* OIDS 300 - 399 */ --- 283,369 ---- */ /* OIDS 1 - 99 */ ! DATA(insert OID = 16 ( bool PGNSP PGUID 1 t b B t t \054 0 0 1000 boolin boolout boolrecv boolsend - - - c p f 0 -1 0 -1 f _null_ _null_ )); DESCR("boolean, 'true'/'false'"); #define BOOLOID 16 ! DATA(insert OID = 17 ( bytea PGNSP PGUID -1 f b U f t \054 0 0 1001 byteain byteaout bytearecv byteasend - - - i x f 0 -1 0 -1 f _null_ _null_ )); DESCR("variable-length string, binary values escaped"); #define BYTEAOID 17 ! DATA(insert OID = 18 ( char PGNSP PGUID 1 t b S f t \054 0 0 1002 charin charout charrecv charsend - - - c p f 0 -1 0 -1 f _null_ _null_ )); DESCR("single character"); #define CHAROID 18 ! DATA(insert OID = 19 ( name PGNSP PGUID NAMEDATALEN f b S f t \054 0 18 1003 namein nameout namerecv namesend - - - c p f 0 -1 0 -1 f _null_ _null_ )); DESCR("63-character type for storing system identifiers"); #define NAMEOID 19 ! DATA(insert OID = 20 ( int8 PGNSP PGUID 8 FLOAT8PASSBYVAL b N f t \054 0 0 1016 int8in int8out int8recv int8send - - - d p f 0 -1 0 -1 f _null_ _null_ )); DESCR("~18 digit integer, 8-byte storage"); #define INT8OID 20 ! DATA(insert OID = 21 ( int2 PGNSP PGUID 2 t b N f t \054 0 0 1005 int2in int2out int2recv int2send - - - s p f 0 -1 0 -1 f _null_ _null_ )); DESCR("-32 thousand to 32 thousand, 2-byte storage"); #define INT2OID 21 ! DATA(insert OID = 22 ( int2vector PGNSP PGUID -1 f b A f t \054 0 21 1006 int2vectorin int2vectorout int2vectorrecv int2vectorsend - - - i p f 0 -1 0 -1 f _null_ _null_ )); DESCR("array of int2, used in system tables"); #define INT2VECTOROID 22 ! DATA(insert OID = 23 ( int4 PGNSP PGUID 4 t b N f t \054 0 0 1007 int4in int4out int4recv int4send - - - i p f 0 -1 0 -1 f _null_ _null_ )); DESCR("-2 billion to 2 billion integer, 4-byte storage"); #define INT4OID 23 ! DATA(insert OID = 24 ( regproc PGNSP PGUID 4 t b N f t \054 0 0 1008 regprocin regprocout regprocrecv regprocsend - - - i p f 0 -1 0 -1 f _null_ _null_ )); DESCR("registered procedure"); #define REGPROCOID 24 ! DATA(insert OID = 25 ( text PGNSP PGUID -1 f b S t t \054 0 0 1009 textin textout textrecv textsend - - - i x f 0 -1 0 -1 f _null_ _null_ )); DESCR("variable-length string, no limit specified"); #define TEXTOID 25 ! DATA(insert OID = 26 ( oid PGNSP PGUID 4 t b N t t \054 0 0 1028 oidin oidout oidrecv oidsend - - - i p f 0 -1 0 -1 f _null_ _null_ )); DESCR("object identifier(oid), maximum 4 billion"); #define OIDOID 26 ! DATA(insert OID = 27 ( tid PGNSP PGUID 6 f b U f t \054 0 0 1010 tidin tidout tidrecv tidsend - - - s p f 0 -1 0 -1 f _null_ _null_ )); DESCR("(block, offset), physical location of tuple"); #define TIDOID 27 ! DATA(insert OID = 28 ( xid PGNSP PGUID 4 t b U f t \054 0 0 1011 xidin xidout xidrecv xidsend - - - i p f 0 -1 0 -1 f _null_ _null_ )); DESCR("transaction id"); #define XIDOID 28 ! DATA(insert OID = 29 ( cid PGNSP PGUID 4 t b U f t \054 0 0 1012 cidin cidout cidrecv cidsend - - - i p f 0 -1 0 -1 f _null_ _null_ )); DESCR("command identifier type, sequence in transaction id"); #define CIDOID 29 ! DATA(insert OID = 30 ( oidvector PGNSP PGUID -1 f b A f t \054 0 26 1013 oidvectorin oidvectorout oidvectorrecv oidvectorsend - - - i p f 0 -1 0 -1 f _null_ _null_ )); DESCR("array of oids, used in system tables"); #define OIDVECTOROID 30 /* hand-built rowtype entries for bootstrapped catalogs */ /* NB: OIDs assigned here must match the BKI_ROWTYPE_OID declarations */ ! DATA(insert OID = 71 ( pg_type PGNSP PGUID -1 f c C f t \054 1247 0 0 record_in record_out record_recv record_send - - - d x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 75 ( pg_attribute PGNSP PGUID -1 f c C f t \054 1249 0 0 record_in record_out record_recv record_send - - - d x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 81 ( pg_proc PGNSP PGUID -1 f c C f t \054 1255 0 0 record_in record_out record_recv record_send - - - d x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 83 ( pg_class PGNSP PGUID -1 f c C f t \054 1259 0 0 record_in record_out record_recv record_send - - - d x f 0 -1 0 -1 f _null_ _null_ )); /* OIDS 100 - 199 */ ! DATA(insert OID = 142 ( xml PGNSP PGUID -1 f b U f t \054 0 0 143 xml_in xml_out xml_recv xml_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); DESCR("XML content"); #define XMLOID 142 ! DATA(insert OID = 143 ( _xml PGNSP PGUID -1 f b A f t \054 0 142 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 194 ( pg_node_tree PGNSP PGUID -1 f b S f t \054 0 0 0 pg_node_tree_in pg_node_tree_out pg_node_tree_recv pg_node_tree_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); DESCR("string representing an internal node tree"); #define PGNODETREEOID 194 /* OIDS 200 - 299 */ ! DATA(insert OID = 210 ( smgr PGNSP PGUID 2 t b U f t \054 0 0 0 smgrin smgrout - - - - - s p f 0 -1 0 -1 f _null_ _null_ )); DESCR("storage manager"); /* OIDS 300 - 399 */ *************** DESCR("storage manager"); *** 359,589 **** /* OIDS 500 - 599 */ /* OIDS 600 - 699 */ ! DATA(insert OID = 600 ( point PGNSP PGUID 16 f b G f t \054 0 701 1017 point_in point_out point_recv point_send - - - d p f 0 -1 0 _null_ _null_ )); DESCR("geometric point '(x, y)'"); #define POINTOID 600 ! DATA(insert OID = 601 ( lseg PGNSP PGUID 32 f b G f t \054 0 600 1018 lseg_in lseg_out lseg_recv lseg_send - - - d p f 0 -1 0 _null_ _null_ )); DESCR("geometric line segment '(pt1,pt2)'"); #define LSEGOID 601 ! DATA(insert OID = 602 ( path PGNSP PGUID -1 f b G f t \054 0 0 1019 path_in path_out path_recv path_send - - - d x f 0 -1 0 _null_ _null_ )); DESCR("geometric path '(pt1,...)'"); #define PATHOID 602 ! DATA(insert OID = 603 ( box PGNSP PGUID 32 f b G f t \073 0 600 1020 box_in box_out box_recv box_send - - - d p f 0 -1 0 _null_ _null_ )); DESCR("geometric box '(lower left,upper right)'"); #define BOXOID 603 ! DATA(insert OID = 604 ( polygon PGNSP PGUID -1 f b G f t \054 0 0 1027 poly_in poly_out poly_recv poly_send - - - d x f 0 -1 0 _null_ _null_ )); DESCR("geometric polygon '(pt1,...)'"); #define POLYGONOID 604 ! DATA(insert OID = 628 ( line PGNSP PGUID 32 f b G f t \054 0 701 629 line_in line_out line_recv line_send - - - d p f 0 -1 0 _null_ _null_ )); DESCR("geometric line (not implemented)"); #define LINEOID 628 ! DATA(insert OID = 629 ( _line PGNSP PGUID -1 f b A f t \054 0 628 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ )); DESCR(""); /* OIDS 700 - 799 */ ! DATA(insert OID = 700 ( float4 PGNSP PGUID 4 FLOAT4PASSBYVAL b N f t \054 0 0 1021 float4in float4out float4recv float4send - - - i p f 0 -1 0 _null_ _null_ )); DESCR("single-precision floating point number, 4-byte storage"); #define FLOAT4OID 700 ! DATA(insert OID = 701 ( float8 PGNSP PGUID 8 FLOAT8PASSBYVAL b N t t \054 0 0 1022 float8in float8out float8recv float8send - - - d p f 0 -1 0 _null_ _null_ )); DESCR("double-precision floating point number, 8-byte storage"); #define FLOAT8OID 701 ! DATA(insert OID = 702 ( abstime PGNSP PGUID 4 t b D f t \054 0 0 1023 abstimein abstimeout abstimerecv abstimesend - - - i p f 0 -1 0 _null_ _null_ )); DESCR("absolute, limited-range date and time (Unix system time)"); #define ABSTIMEOID 702 ! DATA(insert OID = 703 ( reltime PGNSP PGUID 4 t b T f t \054 0 0 1024 reltimein reltimeout reltimerecv reltimesend - - - i p f 0 -1 0 _null_ _null_ )); DESCR("relative, limited-range time interval (Unix delta time)"); #define RELTIMEOID 703 ! DATA(insert OID = 704 ( tinterval PGNSP PGUID 12 f b T f t \054 0 0 1025 tintervalin tintervalout tintervalrecv tintervalsend - - - i p f 0 -1 0 _null_ _null_ )); DESCR("(abstime,abstime), time interval"); #define TINTERVALOID 704 ! DATA(insert OID = 705 ( unknown PGNSP PGUID -2 f b X f t \054 0 0 0 unknownin unknownout unknownrecv unknownsend - - - c p f 0 -1 0 _null_ _null_ )); DESCR(""); #define UNKNOWNOID 705 ! DATA(insert OID = 718 ( circle PGNSP PGUID 24 f b G f t \054 0 0 719 circle_in circle_out circle_recv circle_send - - - d p f 0 -1 0 _null_ _null_ )); DESCR("geometric circle '(center,radius)'"); #define CIRCLEOID 718 ! DATA(insert OID = 719 ( _circle PGNSP PGUID -1 f b A f t \054 0 718 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 790 ( money PGNSP PGUID 8 FLOAT8PASSBYVAL b N f t \054 0 0 791 cash_in cash_out cash_recv cash_send - - - d p f 0 -1 0 _null_ _null_ )); DESCR("monetary amounts, $d,ddd.cc"); #define CASHOID 790 ! DATA(insert OID = 791 ( _money PGNSP PGUID -1 f b A f t \054 0 790 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ )); /* OIDS 800 - 899 */ ! DATA(insert OID = 829 ( macaddr PGNSP PGUID 6 f b U f t \054 0 0 1040 macaddr_in macaddr_out macaddr_recv macaddr_send - - - i p f 0 -1 0 _null_ _null_ )); DESCR("XX:XX:XX:XX:XX:XX, MAC address"); #define MACADDROID 829 ! DATA(insert OID = 869 ( inet PGNSP PGUID -1 f b I t t \054 0 0 1041 inet_in inet_out inet_recv inet_send - - - i m f 0 -1 0 _null_ _null_ )); DESCR("IP address/netmask, host address, netmask optional"); #define INETOID 869 ! DATA(insert OID = 650 ( cidr PGNSP PGUID -1 f b I f t \054 0 0 651 cidr_in cidr_out cidr_recv cidr_send - - - i m f 0 -1 0 _null_ _null_ )); DESCR("network IP address/netmask, network address"); #define CIDROID 650 /* OIDS 900 - 999 */ /* OIDS 1000 - 1099 */ ! DATA(insert OID = 1000 ( _bool PGNSP PGUID -1 f b A f t \054 0 16 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 1001 ( _bytea PGNSP PGUID -1 f b A f t \054 0 17 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 1002 ( _char PGNSP PGUID -1 f b A f t \054 0 18 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 1003 ( _name PGNSP PGUID -1 f b A f t \054 0 19 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 1005 ( _int2 PGNSP PGUID -1 f b A f t \054 0 21 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 1006 ( _int2vector PGNSP PGUID -1 f b A f t \054 0 22 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 1007 ( _int4 PGNSP PGUID -1 f b A f t \054 0 23 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); #define INT4ARRAYOID 1007 ! DATA(insert OID = 1008 ( _regproc PGNSP PGUID -1 f b A f t \054 0 24 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 1009 ( _text PGNSP PGUID -1 f b A f t \054 0 25 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); #define TEXTARRAYOID 1009 ! DATA(insert OID = 1028 ( _oid PGNSP PGUID -1 f b A f t \054 0 26 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 1010 ( _tid PGNSP PGUID -1 f b A f t \054 0 27 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 1011 ( _xid PGNSP PGUID -1 f b A f t \054 0 28 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 1012 ( _cid PGNSP PGUID -1 f b A f t \054 0 29 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 1013 ( _oidvector PGNSP PGUID -1 f b A f t \054 0 30 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 1014 ( _bpchar PGNSP PGUID -1 f b A f t \054 0 1042 0 array_in array_out array_recv array_send bpchartypmodin bpchartypmodout - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 1015 ( _varchar PGNSP PGUID -1 f b A f t \054 0 1043 0 array_in array_out array_recv array_send varchartypmodin varchartypmodout - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 1016 ( _int8 PGNSP PGUID -1 f b A f t \054 0 20 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 1017 ( _point PGNSP PGUID -1 f b A f t \054 0 600 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 1018 ( _lseg PGNSP PGUID -1 f b A f t \054 0 601 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 1019 ( _path PGNSP PGUID -1 f b A f t \054 0 602 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 1020 ( _box PGNSP PGUID -1 f b A f t \073 0 603 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 1021 ( _float4 PGNSP PGUID -1 f b A f t \054 0 700 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); #define FLOAT4ARRAYOID 1021 ! DATA(insert OID = 1022 ( _float8 PGNSP PGUID -1 f b A f t \054 0 701 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 1023 ( _abstime PGNSP PGUID -1 f b A f t \054 0 702 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 1024 ( _reltime PGNSP PGUID -1 f b A f t \054 0 703 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 1025 ( _tinterval PGNSP PGUID -1 f b A f t \054 0 704 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 1027 ( _polygon PGNSP PGUID -1 f b A f t \054 0 604 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 1033 ( aclitem PGNSP PGUID 12 f b U f t \054 0 0 1034 aclitemin aclitemout - - - - - i p f 0 -1 0 _null_ _null_ )); DESCR("access control list"); #define ACLITEMOID 1033 ! DATA(insert OID = 1034 ( _aclitem PGNSP PGUID -1 f b A f t \054 0 1033 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 1040 ( _macaddr PGNSP PGUID -1 f b A f t \054 0 829 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 1041 ( _inet PGNSP PGUID -1 f b A f t \054 0 869 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 651 ( _cidr PGNSP PGUID -1 f b A f t \054 0 650 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 1263 ( _cstring PGNSP PGUID -1 f b A f t \054 0 2275 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); #define CSTRINGARRAYOID 1263 ! DATA(insert OID = 1042 ( bpchar PGNSP PGUID -1 f b S f t \054 0 0 1014 bpcharin bpcharout bpcharrecv bpcharsend bpchartypmodin bpchartypmodout - i x f 0 -1 0 _null_ _null_ )); DESCR("char(length), blank-padded string, fixed storage length"); #define BPCHAROID 1042 ! DATA(insert OID = 1043 ( varchar PGNSP PGUID -1 f b S f t \054 0 0 1015 varcharin varcharout varcharrecv varcharsend varchartypmodin varchartypmodout - i x f 0 -1 0 _null_ _null_ )); DESCR("varchar(length), non-blank-padded string, variable storage length"); #define VARCHAROID 1043 ! DATA(insert OID = 1082 ( date PGNSP PGUID 4 t b D f t \054 0 0 1182 date_in date_out date_recv date_send - - - i p f 0 -1 0 _null_ _null_ )); DESCR("date"); #define DATEOID 1082 ! DATA(insert OID = 1083 ( time PGNSP PGUID 8 FLOAT8PASSBYVAL b D f t \054 0 0 1183 time_in time_out time_recv time_send timetypmodin timetypmodout - d p f 0 -1 0 _null_ _null_ )); DESCR("time of day"); #define TIMEOID 1083 /* OIDS 1100 - 1199 */ ! DATA(insert OID = 1114 ( timestamp PGNSP PGUID 8 FLOAT8PASSBYVAL b D f t \054 0 0 1115 timestamp_in timestamp_out timestamp_recv timestamp_send timestamptypmodin timestamptypmodout - d p f 0 -1 0 _null_ _null_ )); DESCR("date and time"); #define TIMESTAMPOID 1114 ! DATA(insert OID = 1115 ( _timestamp PGNSP PGUID -1 f b A f t \054 0 1114 0 array_in array_out array_recv array_send timestamptypmodin timestamptypmodout - d x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 1182 ( _date PGNSP PGUID -1 f b A f t \054 0 1082 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 1183 ( _time PGNSP PGUID -1 f b A f t \054 0 1083 0 array_in array_out array_recv array_send timetypmodin timetypmodout - d x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 1184 ( timestamptz PGNSP PGUID 8 FLOAT8PASSBYVAL b D t t \054 0 0 1185 timestamptz_in timestamptz_out timestamptz_recv timestamptz_send timestamptztypmodin timestamptztypmodout - d p f 0 -1 0 _null_ _null_ )); DESCR("date and time with time zone"); #define TIMESTAMPTZOID 1184 ! DATA(insert OID = 1185 ( _timestamptz PGNSP PGUID -1 f b A f t \054 0 1184 0 array_in array_out array_recv array_send timestamptztypmodin timestamptztypmodout - d x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 1186 ( interval PGNSP PGUID 16 f b T t t \054 0 0 1187 interval_in interval_out interval_recv interval_send intervaltypmodin intervaltypmodout - d p f 0 -1 0 _null_ _null_ )); DESCR("@ , time interval"); #define INTERVALOID 1186 ! DATA(insert OID = 1187 ( _interval PGNSP PGUID -1 f b A f t \054 0 1186 0 array_in array_out array_recv array_send intervaltypmodin intervaltypmodout - d x f 0 -1 0 _null_ _null_ )); /* OIDS 1200 - 1299 */ ! DATA(insert OID = 1231 ( _numeric PGNSP PGUID -1 f b A f t \054 0 1700 0 array_in array_out array_recv array_send numerictypmodin numerictypmodout - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 1266 ( timetz PGNSP PGUID 12 f b D f t \054 0 0 1270 timetz_in timetz_out timetz_recv timetz_send timetztypmodin timetztypmodout - d p f 0 -1 0 _null_ _null_ )); DESCR("time of day with time zone"); #define TIMETZOID 1266 ! DATA(insert OID = 1270 ( _timetz PGNSP PGUID -1 f b A f t \054 0 1266 0 array_in array_out array_recv array_send timetztypmodin timetztypmodout - d x f 0 -1 0 _null_ _null_ )); /* OIDS 1500 - 1599 */ ! DATA(insert OID = 1560 ( bit PGNSP PGUID -1 f b V f t \054 0 0 1561 bit_in bit_out bit_recv bit_send bittypmodin bittypmodout - i x f 0 -1 0 _null_ _null_ )); DESCR("fixed-length bit string"); #define BITOID 1560 ! DATA(insert OID = 1561 ( _bit PGNSP PGUID -1 f b A f t \054 0 1560 0 array_in array_out array_recv array_send bittypmodin bittypmodout - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 1562 ( varbit PGNSP PGUID -1 f b V t t \054 0 0 1563 varbit_in varbit_out varbit_recv varbit_send varbittypmodin varbittypmodout - i x f 0 -1 0 _null_ _null_ )); DESCR("variable-length bit string"); #define VARBITOID 1562 ! DATA(insert OID = 1563 ( _varbit PGNSP PGUID -1 f b A f t \054 0 1562 0 array_in array_out array_recv array_send varbittypmodin varbittypmodout - i x f 0 -1 0 _null_ _null_ )); /* OIDS 1600 - 1699 */ /* OIDS 1700 - 1799 */ ! DATA(insert OID = 1700 ( numeric PGNSP PGUID -1 f b N f t \054 0 0 1231 numeric_in numeric_out numeric_recv numeric_send numerictypmodin numerictypmodout - i m f 0 -1 0 _null_ _null_ )); DESCR("numeric(precision, decimal), arbitrary precision number"); #define NUMERICOID 1700 ! DATA(insert OID = 1790 ( refcursor PGNSP PGUID -1 f b U f t \054 0 0 2201 textin textout textrecv textsend - - - i x f 0 -1 0 _null_ _null_ )); DESCR("reference to cursor (portal name)"); #define REFCURSOROID 1790 /* OIDS 2200 - 2299 */ ! DATA(insert OID = 2201 ( _refcursor PGNSP PGUID -1 f b A f t \054 0 1790 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 2202 ( regprocedure PGNSP PGUID 4 t b N f t \054 0 0 2207 regprocedurein regprocedureout regprocedurerecv regproceduresend - - - i p f 0 -1 0 _null_ _null_ )); DESCR("registered procedure (with args)"); #define REGPROCEDUREOID 2202 ! DATA(insert OID = 2203 ( regoper PGNSP PGUID 4 t b N f t \054 0 0 2208 regoperin regoperout regoperrecv regopersend - - - i p f 0 -1 0 _null_ _null_ )); DESCR("registered operator"); #define REGOPEROID 2203 ! DATA(insert OID = 2204 ( regoperator PGNSP PGUID 4 t b N f t \054 0 0 2209 regoperatorin regoperatorout regoperatorrecv regoperatorsend - - - i p f 0 -1 0 _null_ _null_ )); DESCR("registered operator (with args)"); #define REGOPERATOROID 2204 ! DATA(insert OID = 2205 ( regclass PGNSP PGUID 4 t b N f t \054 0 0 2210 regclassin regclassout regclassrecv regclasssend - - - i p f 0 -1 0 _null_ _null_ )); DESCR("registered class"); #define REGCLASSOID 2205 ! DATA(insert OID = 2206 ( regtype PGNSP PGUID 4 t b N f t \054 0 0 2211 regtypein regtypeout regtyperecv regtypesend - - - i p f 0 -1 0 _null_ _null_ )); DESCR("registered type"); #define REGTYPEOID 2206 ! DATA(insert OID = 2207 ( _regprocedure PGNSP PGUID -1 f b A f t \054 0 2202 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 2208 ( _regoper PGNSP PGUID -1 f b A f t \054 0 2203 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 2209 ( _regoperator PGNSP PGUID -1 f b A f t \054 0 2204 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 2210 ( _regclass PGNSP PGUID -1 f b A f t \054 0 2205 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 2211 ( _regtype PGNSP PGUID -1 f b A f t \054 0 2206 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); #define REGTYPEARRAYOID 2211 /* uuid */ ! DATA(insert OID = 2950 ( uuid PGNSP PGUID 16 f b U f t \054 0 0 2951 uuid_in uuid_out uuid_recv uuid_send - - - c p f 0 -1 0 _null_ _null_ )); DESCR("UUID datatype"); ! DATA(insert OID = 2951 ( _uuid PGNSP PGUID -1 f b A f t \054 0 2950 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); /* text search */ ! DATA(insert OID = 3614 ( tsvector PGNSP PGUID -1 f b U f t \054 0 0 3643 tsvectorin tsvectorout tsvectorrecv tsvectorsend - - ts_typanalyze i x f 0 -1 0 _null_ _null_ )); DESCR("text representation for text search"); #define TSVECTOROID 3614 ! DATA(insert OID = 3642 ( gtsvector PGNSP PGUID -1 f b U f t \054 0 0 3644 gtsvectorin gtsvectorout - - - - - i p f 0 -1 0 _null_ _null_ )); DESCR("GiST index internal text representation for text search"); #define GTSVECTOROID 3642 ! DATA(insert OID = 3615 ( tsquery PGNSP PGUID -1 f b U f t \054 0 0 3645 tsqueryin tsqueryout tsqueryrecv tsquerysend - - - i p f 0 -1 0 _null_ _null_ )); DESCR("query representation for text search"); #define TSQUERYOID 3615 ! DATA(insert OID = 3734 ( regconfig PGNSP PGUID 4 t b N f t \054 0 0 3735 regconfigin regconfigout regconfigrecv regconfigsend - - - i p f 0 -1 0 _null_ _null_ )); DESCR("registered text search configuration"); #define REGCONFIGOID 3734 ! DATA(insert OID = 3769 ( regdictionary PGNSP PGUID 4 t b N f t \054 0 0 3770 regdictionaryin regdictionaryout regdictionaryrecv regdictionarysend - - - i p f 0 -1 0 _null_ _null_ )); DESCR("registered text search dictionary"); #define REGDICTIONARYOID 3769 ! DATA(insert OID = 3643 ( _tsvector PGNSP PGUID -1 f b A f t \054 0 3614 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 3644 ( _gtsvector PGNSP PGUID -1 f b A f t \054 0 3642 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 3645 ( _tsquery PGNSP PGUID -1 f b A f t \054 0 3615 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 3735 ( _regconfig PGNSP PGUID -1 f b A f t \054 0 3734 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 3770 ( _regdictionary PGNSP PGUID -1 f b A f t \054 0 3769 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 _null_ _null_ )); ! DATA(insert OID = 2970 ( txid_snapshot PGNSP PGUID -1 f b U f t \054 0 0 2949 txid_snapshot_in txid_snapshot_out txid_snapshot_recv txid_snapshot_send - - - d x f 0 -1 0 _null_ _null_ )); DESCR("txid snapshot"); ! DATA(insert OID = 2949 ( _txid_snapshot PGNSP PGUID -1 f b A f t \054 0 2970 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ )); /* * pseudo-types --- 373,603 ---- /* OIDS 500 - 599 */ /* OIDS 600 - 699 */ ! DATA(insert OID = 600 ( point PGNSP PGUID 16 f b G f t \054 0 701 1017 point_in point_out point_recv point_send - - - d p f 0 -1 0 -1 f _null_ _null_ )); DESCR("geometric point '(x, y)'"); #define POINTOID 600 ! DATA(insert OID = 601 ( lseg PGNSP PGUID 32 f b G f t \054 0 600 1018 lseg_in lseg_out lseg_recv lseg_send - - - d p f 0 -1 0 -1 f _null_ _null_ )); DESCR("geometric line segment '(pt1,pt2)'"); #define LSEGOID 601 ! DATA(insert OID = 602 ( path PGNSP PGUID -1 f b G f t \054 0 0 1019 path_in path_out path_recv path_send - - - d x f 0 -1 0 -1 f _null_ _null_ )); DESCR("geometric path '(pt1,...)'"); #define PATHOID 602 ! DATA(insert OID = 603 ( box PGNSP PGUID 32 f b G f t \073 0 600 1020 box_in box_out box_recv box_send - - - d p f 0 -1 0 -1 f _null_ _null_ )); DESCR("geometric box '(lower left,upper right)'"); #define BOXOID 603 ! DATA(insert OID = 604 ( polygon PGNSP PGUID -1 f b G f t \054 0 0 1027 poly_in poly_out poly_recv poly_send - - - d x f 0 -1 0 -1 f _null_ _null_ )); DESCR("geometric polygon '(pt1,...)'"); #define POLYGONOID 604 ! DATA(insert OID = 628 ( line PGNSP PGUID 32 f b G f t \054 0 701 629 line_in line_out line_recv line_send - - - d p f 0 -1 0 -1 f _null_ _null_ )); DESCR("geometric line (not implemented)"); #define LINEOID 628 ! DATA(insert OID = 629 ( _line PGNSP PGUID -1 f b A f t \054 0 628 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 -1 f _null_ _null_ )); DESCR(""); /* OIDS 700 - 799 */ ! DATA(insert OID = 700 ( float4 PGNSP PGUID 4 FLOAT4PASSBYVAL b N f t \054 0 0 1021 float4in float4out float4recv float4send - - - i p f 0 -1 0 -1 f _null_ _null_ )); DESCR("single-precision floating point number, 4-byte storage"); #define FLOAT4OID 700 ! DATA(insert OID = 701 ( float8 PGNSP PGUID 8 FLOAT8PASSBYVAL b N t t \054 0 0 1022 float8in float8out float8recv float8send - - - d p f 0 -1 0 -1 f _null_ _null_ )); DESCR("double-precision floating point number, 8-byte storage"); #define FLOAT8OID 701 ! DATA(insert OID = 702 ( abstime PGNSP PGUID 4 t b D f t \054 0 0 1023 abstimein abstimeout abstimerecv abstimesend - - - i p f 0 -1 0 -1 f _null_ _null_ )); DESCR("absolute, limited-range date and time (Unix system time)"); #define ABSTIMEOID 702 ! DATA(insert OID = 703 ( reltime PGNSP PGUID 4 t b T f t \054 0 0 1024 reltimein reltimeout reltimerecv reltimesend - - - i p f 0 -1 0 -1 f _null_ _null_ )); DESCR("relative, limited-range time interval (Unix delta time)"); #define RELTIMEOID 703 ! DATA(insert OID = 704 ( tinterval PGNSP PGUID 12 f b T f t \054 0 0 1025 tintervalin tintervalout tintervalrecv tintervalsend - - - i p f 0 -1 0 -1 f _null_ _null_ )); DESCR("(abstime,abstime), time interval"); #define TINTERVALOID 704 ! DATA(insert OID = 705 ( unknown PGNSP PGUID -2 f b X f t \054 0 0 0 unknownin unknownout unknownrecv unknownsend - - - c p f 0 -1 0 -1 f _null_ _null_ )); DESCR(""); #define UNKNOWNOID 705 ! DATA(insert OID = 718 ( circle PGNSP PGUID 24 f b G f t \054 0 0 719 circle_in circle_out circle_recv circle_send - - - d p f 0 -1 0 -1 f _null_ _null_ )); DESCR("geometric circle '(center,radius)'"); #define CIRCLEOID 718 ! DATA(insert OID = 719 ( _circle PGNSP PGUID -1 f b A f t \054 0 718 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 790 ( money PGNSP PGUID 8 FLOAT8PASSBYVAL b N f t \054 0 0 791 cash_in cash_out cash_recv cash_send - - - d p f 0 -1 0 -1 f _null_ _null_ )); DESCR("monetary amounts, $d,ddd.cc"); #define CASHOID 790 ! DATA(insert OID = 791 ( _money PGNSP PGUID -1 f b A f t \054 0 790 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 -1 f _null_ _null_ )); /* OIDS 800 - 899 */ ! DATA(insert OID = 829 ( macaddr PGNSP PGUID 6 f b U f t \054 0 0 1040 macaddr_in macaddr_out macaddr_recv macaddr_send - - - i p f 0 -1 0 -1 f _null_ _null_ )); DESCR("XX:XX:XX:XX:XX:XX, MAC address"); #define MACADDROID 829 ! DATA(insert OID = 869 ( inet PGNSP PGUID -1 f b I t t \054 0 0 1041 inet_in inet_out inet_recv inet_send - - - i m f 0 -1 0 -1 f _null_ _null_ )); DESCR("IP address/netmask, host address, netmask optional"); #define INETOID 869 ! DATA(insert OID = 650 ( cidr PGNSP PGUID -1 f b I f t \054 0 0 651 cidr_in cidr_out cidr_recv cidr_send - - - i m f 0 -1 0 -1 f _null_ _null_ )); DESCR("network IP address/netmask, network address"); #define CIDROID 650 /* OIDS 900 - 999 */ /* OIDS 1000 - 1099 */ ! DATA(insert OID = 1000 ( _bool PGNSP PGUID -1 f b A f t \054 0 16 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 1001 ( _bytea PGNSP PGUID -1 f b A f t \054 0 17 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 1002 ( _char PGNSP PGUID -1 f b A f t \054 0 18 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 1003 ( _name PGNSP PGUID -1 f b A f t \054 0 19 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 1005 ( _int2 PGNSP PGUID -1 f b A f t \054 0 21 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 1006 ( _int2vector PGNSP PGUID -1 f b A f t \054 0 22 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 1007 ( _int4 PGNSP PGUID -1 f b A f t \054 0 23 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); #define INT4ARRAYOID 1007 ! DATA(insert OID = 1008 ( _regproc PGNSP PGUID -1 f b A f t \054 0 24 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 1009 ( _text PGNSP PGUID -1 f b A f t \054 0 25 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); #define TEXTARRAYOID 1009 ! DATA(insert OID = 1028 ( _oid PGNSP PGUID -1 f b A f t \054 0 26 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 1010 ( _tid PGNSP PGUID -1 f b A f t \054 0 27 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 1011 ( _xid PGNSP PGUID -1 f b A f t \054 0 28 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 1012 ( _cid PGNSP PGUID -1 f b A f t \054 0 29 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 1013 ( _oidvector PGNSP PGUID -1 f b A f t \054 0 30 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 1014 ( _bpchar PGNSP PGUID -1 f b A f t \054 0 1042 0 array_in array_out array_recv array_send bpchartypmodin bpchartypmodout - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 1015 ( _varchar PGNSP PGUID -1 f b A f t \054 0 1043 0 array_in array_out array_recv array_send varchartypmodin varchartypmodout - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 1016 ( _int8 PGNSP PGUID -1 f b A f t \054 0 20 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 1017 ( _point PGNSP PGUID -1 f b A f t \054 0 600 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 1018 ( _lseg PGNSP PGUID -1 f b A f t \054 0 601 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 1019 ( _path PGNSP PGUID -1 f b A f t \054 0 602 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 1020 ( _box PGNSP PGUID -1 f b A f t \073 0 603 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 1021 ( _float4 PGNSP PGUID -1 f b A f t \054 0 700 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); #define FLOAT4ARRAYOID 1021 ! DATA(insert OID = 1022 ( _float8 PGNSP PGUID -1 f b A f t \054 0 701 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 1023 ( _abstime PGNSP PGUID -1 f b A f t \054 0 702 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 1024 ( _reltime PGNSP PGUID -1 f b A f t \054 0 703 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 1025 ( _tinterval PGNSP PGUID -1 f b A f t \054 0 704 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 1027 ( _polygon PGNSP PGUID -1 f b A f t \054 0 604 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 1033 ( aclitem PGNSP PGUID 12 f b U f t \054 0 0 1034 aclitemin aclitemout - - - - - i p f 0 -1 0 -1 f _null_ _null_ )); DESCR("access control list"); #define ACLITEMOID 1033 ! DATA(insert OID = 1034 ( _aclitem PGNSP PGUID -1 f b A f t \054 0 1033 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 1040 ( _macaddr PGNSP PGUID -1 f b A f t \054 0 829 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 1041 ( _inet PGNSP PGUID -1 f b A f t \054 0 869 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 651 ( _cidr PGNSP PGUID -1 f b A f t \054 0 650 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 1263 ( _cstring PGNSP PGUID -1 f b A f t \054 0 2275 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); #define CSTRINGARRAYOID 1263 ! DATA(insert OID = 1042 ( bpchar PGNSP PGUID -1 f b S f t \054 0 0 1014 bpcharin bpcharout bpcharrecv bpcharsend bpchartypmodin bpchartypmodout - i x f 0 -1 0 -1 f _null_ _null_ )); DESCR("char(length), blank-padded string, fixed storage length"); #define BPCHAROID 1042 ! DATA(insert OID = 1043 ( varchar PGNSP PGUID -1 f b S f t \054 0 0 1015 varcharin varcharout varcharrecv varcharsend varchartypmodin varchartypmodout - i x f 0 -1 0 -1 f _null_ _null_ )); DESCR("varchar(length), non-blank-padded string, variable storage length"); #define VARCHAROID 1043 ! DATA(insert OID = 1082 ( date PGNSP PGUID 4 t b D f t \054 0 0 1182 date_in date_out date_recv date_send - - - i p f 0 -1 0 -1 f _null_ _null_ )); DESCR("date"); #define DATEOID 1082 ! DATA(insert OID = 1083 ( time PGNSP PGUID 8 FLOAT8PASSBYVAL b D f t \054 0 0 1183 time_in time_out time_recv time_send timetypmodin timetypmodout - d p f 0 -1 0 -1 f _null_ _null_ )); DESCR("time of day"); #define TIMEOID 1083 /* OIDS 1100 - 1199 */ ! DATA(insert OID = 1114 ( timestamp PGNSP PGUID 8 FLOAT8PASSBYVAL b D f t \054 0 0 1115 timestamp_in timestamp_out timestamp_recv timestamp_send timestamptypmodin timestamptypmodout - d p f 0 -1 0 -1 f _null_ _null_ )); DESCR("date and time"); #define TIMESTAMPOID 1114 ! DATA(insert OID = 1115 ( _timestamp PGNSP PGUID -1 f b A f t \054 0 1114 0 array_in array_out array_recv array_send timestamptypmodin timestamptypmodout - d x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 1182 ( _date PGNSP PGUID -1 f b A f t \054 0 1082 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 1183 ( _time PGNSP PGUID -1 f b A f t \054 0 1083 0 array_in array_out array_recv array_send timetypmodin timetypmodout - d x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 1184 ( timestamptz PGNSP PGUID 8 FLOAT8PASSBYVAL b D t t \054 0 0 1185 timestamptz_in timestamptz_out timestamptz_recv timestamptz_send timestamptztypmodin timestamptztypmodout - d p f 0 -1 0 -1 f _null_ _null_ )); DESCR("date and time with time zone"); #define TIMESTAMPTZOID 1184 ! DATA(insert OID = 1185 ( _timestamptz PGNSP PGUID -1 f b A f t \054 0 1184 0 array_in array_out array_recv array_send timestamptztypmodin timestamptztypmodout - d x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 1186 ( interval PGNSP PGUID 16 f b T t t \054 0 0 1187 interval_in interval_out interval_recv interval_send intervaltypmodin intervaltypmodout - d p f 0 -1 0 -1 f _null_ _null_ )); DESCR("@ , time interval"); #define INTERVALOID 1186 ! DATA(insert OID = 1187 ( _interval PGNSP PGUID -1 f b A f t \054 0 1186 0 array_in array_out array_recv array_send intervaltypmodin intervaltypmodout - d x f 0 -1 0 -1 f _null_ _null_ )); /* OIDS 1200 - 1299 */ ! DATA(insert OID = 1231 ( _numeric PGNSP PGUID -1 f b A f t \054 0 1700 0 array_in array_out array_recv array_send numerictypmodin numerictypmodout - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 1266 ( timetz PGNSP PGUID 12 f b D f t \054 0 0 1270 timetz_in timetz_out timetz_recv timetz_send timetztypmodin timetztypmodout - d p f 0 -1 0 -1 f _null_ _null_ )); DESCR("time of day with time zone"); #define TIMETZOID 1266 ! DATA(insert OID = 1270 ( _timetz PGNSP PGUID -1 f b A f t \054 0 1266 0 array_in array_out array_recv array_send timetztypmodin timetztypmodout - d x f 0 -1 0 -1 f _null_ _null_ )); /* OIDS 1500 - 1599 */ ! DATA(insert OID = 1560 ( bit PGNSP PGUID -1 f b V f t \054 0 0 1561 bit_in bit_out bit_recv bit_send bittypmodin bittypmodout - i x f 0 -1 0 -1 f _null_ _null_ )); DESCR("fixed-length bit string"); #define BITOID 1560 ! DATA(insert OID = 1561 ( _bit PGNSP PGUID -1 f b A f t \054 0 1560 0 array_in array_out array_recv array_send bittypmodin bittypmodout - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 1562 ( varbit PGNSP PGUID -1 f b V t t \054 0 0 1563 varbit_in varbit_out varbit_recv varbit_send varbittypmodin varbittypmodout - i x f 0 -1 0 -1 f _null_ _null_ )); DESCR("variable-length bit string"); #define VARBITOID 1562 ! DATA(insert OID = 1563 ( _varbit PGNSP PGUID -1 f b A f t \054 0 1562 0 array_in array_out array_recv array_send varbittypmodin varbittypmodout - i x f 0 -1 0 -1 f _null_ _null_ )); /* OIDS 1600 - 1699 */ /* OIDS 1700 - 1799 */ ! DATA(insert OID = 1700 ( numeric PGNSP PGUID -1 f b N f t \054 0 0 1231 numeric_in numeric_out numeric_recv numeric_send numerictypmodin numerictypmodout - i m f 0 -1 0 -1 f _null_ _null_ )); DESCR("numeric(precision, decimal), arbitrary precision number"); #define NUMERICOID 1700 ! DATA(insert OID = 1790 ( refcursor PGNSP PGUID -1 f b U f t \054 0 0 2201 textin textout textrecv textsend - - - i x f 0 -1 0 -1 f _null_ _null_ )); DESCR("reference to cursor (portal name)"); #define REFCURSOROID 1790 /* OIDS 2200 - 2299 */ ! DATA(insert OID = 2201 ( _refcursor PGNSP PGUID -1 f b A f t \054 0 1790 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 2202 ( regprocedure PGNSP PGUID 4 t b N f t \054 0 0 2207 regprocedurein regprocedureout regprocedurerecv regproceduresend - - - i p f 0 -1 0 -1 f _null_ _null_ )); DESCR("registered procedure (with args)"); #define REGPROCEDUREOID 2202 ! DATA(insert OID = 2203 ( regoper PGNSP PGUID 4 t b N f t \054 0 0 2208 regoperin regoperout regoperrecv regopersend - - - i p f 0 -1 0 -1 f _null_ _null_ )); DESCR("registered operator"); #define REGOPEROID 2203 ! DATA(insert OID = 2204 ( regoperator PGNSP PGUID 4 t b N f t \054 0 0 2209 regoperatorin regoperatorout regoperatorrecv regoperatorsend - - - i p f 0 -1 0 -1 f _null_ _null_ )); DESCR("registered operator (with args)"); #define REGOPERATOROID 2204 ! DATA(insert OID = 2205 ( regclass PGNSP PGUID 4 t b N f t \054 0 0 2210 regclassin regclassout regclassrecv regclasssend - - - i p f 0 -1 0 -1 f _null_ _null_ )); DESCR("registered class"); #define REGCLASSOID 2205 ! DATA(insert OID = 2206 ( regtype PGNSP PGUID 4 t b N f t \054 0 0 2211 regtypein regtypeout regtyperecv regtypesend - - - i p f 0 -1 0 -1 f _null_ _null_ )); DESCR("registered type"); #define REGTYPEOID 2206 ! DATA(insert OID = 2207 ( _regprocedure PGNSP PGUID -1 f b A f t \054 0 2202 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 2208 ( _regoper PGNSP PGUID -1 f b A f t \054 0 2203 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 2209 ( _regoperator PGNSP PGUID -1 f b A f t \054 0 2204 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 2210 ( _regclass PGNSP PGUID -1 f b A f t \054 0 2205 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 2211 ( _regtype PGNSP PGUID -1 f b A f t \054 0 2206 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); #define REGTYPEARRAYOID 2211 /* uuid */ ! DATA(insert OID = 2950 ( uuid PGNSP PGUID 16 f b U f t \054 0 0 2951 uuid_in uuid_out uuid_recv uuid_send - - - c p f 0 -1 0 -1 f _null_ _null_ )); DESCR("UUID datatype"); ! DATA(insert OID = 2951 ( _uuid PGNSP PGUID -1 f b A f t \054 0 2950 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); /* text search */ ! DATA(insert OID = 3614 ( tsvector PGNSP PGUID -1 f b U f t \054 0 0 3643 tsvectorin tsvectorout tsvectorrecv tsvectorsend - - ts_typanalyze i x f 0 -1 0 -1 f _null_ _null_ )); DESCR("text representation for text search"); #define TSVECTOROID 3614 ! DATA(insert OID = 3642 ( gtsvector PGNSP PGUID -1 f b U f t \054 0 0 3644 gtsvectorin gtsvectorout - - - - - i p f 0 -1 0 -1 f _null_ _null_ )); DESCR("GiST index internal text representation for text search"); #define GTSVECTOROID 3642 ! DATA(insert OID = 3615 ( tsquery PGNSP PGUID -1 f b U f t \054 0 0 3645 tsqueryin tsqueryout tsqueryrecv tsquerysend - - - i p f 0 -1 0 -1 f _null_ _null_ )); DESCR("query representation for text search"); #define TSQUERYOID 3615 ! DATA(insert OID = 3734 ( regconfig PGNSP PGUID 4 t b N f t \054 0 0 3735 regconfigin regconfigout regconfigrecv regconfigsend - - - i p f 0 -1 0 -1 f _null_ _null_ )); DESCR("registered text search configuration"); #define REGCONFIGOID 3734 ! DATA(insert OID = 3769 ( regdictionary PGNSP PGUID 4 t b N f t \054 0 0 3770 regdictionaryin regdictionaryout regdictionaryrecv regdictionarysend - - - i p f 0 -1 0 -1 f _null_ _null_ )); DESCR("registered text search dictionary"); #define REGDICTIONARYOID 3769 ! DATA(insert OID = 3643 ( _tsvector PGNSP PGUID -1 f b A f t \054 0 3614 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 3644 ( _gtsvector PGNSP PGUID -1 f b A f t \054 0 3642 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 3645 ( _tsquery PGNSP PGUID -1 f b A f t \054 0 3615 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 3735 ( _regconfig PGNSP PGUID -1 f b A f t \054 0 3734 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 3770 ( _regdictionary PGNSP PGUID -1 f b A f t \054 0 3769 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 -1 f _null_ _null_ )); ! DATA(insert OID = 2970 ( txid_snapshot PGNSP PGUID -1 f b U f t \054 0 0 2949 txid_snapshot_in txid_snapshot_out txid_snapshot_recv txid_snapshot_send - - - d x f 0 -1 0 -1 f _null_ _null_ )); DESCR("txid snapshot"); ! DATA(insert OID = 2949 ( _txid_snapshot PGNSP PGUID -1 f b A f t \054 0 2970 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 -1 f _null_ _null_ )); /* * pseudo-types *************** DATA(insert OID = 2949 ( _txid_snapshot *** 598,628 **** * but there is now support for it in records and arrays. Perhaps we should * just treat it as a regular base type? */ ! DATA(insert OID = 2249 ( record PGNSP PGUID -1 f p P f t \054 0 0 2287 record_in record_out record_recv record_send - - - d x f 0 -1 0 _null_ _null_ )); #define RECORDOID 2249 ! DATA(insert OID = 2287 ( _record PGNSP PGUID -1 f p P f t \054 0 2249 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 _null_ _null_ )); #define RECORDARRAYOID 2287 ! DATA(insert OID = 2275 ( cstring PGNSP PGUID -2 f p P f t \054 0 0 1263 cstring_in cstring_out cstring_recv cstring_send - - - c p f 0 -1 0 _null_ _null_ )); #define CSTRINGOID 2275 ! DATA(insert OID = 2276 ( any PGNSP PGUID 4 t p P f t \054 0 0 0 any_in any_out - - - - - i p f 0 -1 0 _null_ _null_ )); #define ANYOID 2276 ! DATA(insert OID = 2277 ( anyarray PGNSP PGUID -1 f p P f t \054 0 0 0 anyarray_in anyarray_out anyarray_recv anyarray_send - - - d x f 0 -1 0 _null_ _null_ )); #define ANYARRAYOID 2277 ! DATA(insert OID = 2278 ( void PGNSP PGUID 4 t p P f t \054 0 0 0 void_in void_out - - - - - i p f 0 -1 0 _null_ _null_ )); #define VOIDOID 2278 ! DATA(insert OID = 2279 ( trigger PGNSP PGUID 4 t p P f t \054 0 0 0 trigger_in trigger_out - - - - - i p f 0 -1 0 _null_ _null_ )); #define TRIGGEROID 2279 ! DATA(insert OID = 2280 ( language_handler PGNSP PGUID 4 t p P f t \054 0 0 0 language_handler_in language_handler_out - - - - - i p f 0 -1 0 _null_ _null_ )); #define LANGUAGE_HANDLEROID 2280 ! DATA(insert OID = 2281 ( internal PGNSP PGUID SIZEOF_POINTER t p P f t \054 0 0 0 internal_in internal_out - - - - - ALIGNOF_POINTER p f 0 -1 0 _null_ _null_ )); #define INTERNALOID 2281 ! DATA(insert OID = 2282 ( opaque PGNSP PGUID 4 t p P f t \054 0 0 0 opaque_in opaque_out - - - - - i p f 0 -1 0 _null_ _null_ )); #define OPAQUEOID 2282 ! DATA(insert OID = 2283 ( anyelement PGNSP PGUID 4 t p P f t \054 0 0 0 anyelement_in anyelement_out - - - - - i p f 0 -1 0 _null_ _null_ )); #define ANYELEMENTOID 2283 ! DATA(insert OID = 2776 ( anynonarray PGNSP PGUID 4 t p P f t \054 0 0 0 anynonarray_in anynonarray_out - - - - - i p f 0 -1 0 _null_ _null_ )); #define ANYNONARRAYOID 2776 ! DATA(insert OID = 3500 ( anyenum PGNSP PGUID 4 t p P f t \054 0 0 0 anyenum_in anyenum_out - - - - - i p f 0 -1 0 _null_ _null_ )); #define ANYENUMOID 3500 --- 612,642 ---- * but there is now support for it in records and arrays. Perhaps we should * just treat it as a regular base type? */ ! DATA(insert OID = 2249 ( record PGNSP PGUID -1 f p P f t \054 0 0 2287 record_in record_out record_recv record_send - - - d x f 0 -1 0 -1 f _null_ _null_ )); #define RECORDOID 2249 ! DATA(insert OID = 2287 ( _record PGNSP PGUID -1 f p P f t \054 0 2249 0 array_in array_out array_recv array_send - - - d x f 0 -1 0 -1 f _null_ _null_ )); #define RECORDARRAYOID 2287 ! DATA(insert OID = 2275 ( cstring PGNSP PGUID -2 f p P f t \054 0 0 1263 cstring_in cstring_out cstring_recv cstring_send - - - c p f 0 -1 0 -1 f _null_ _null_ )); #define CSTRINGOID 2275 ! DATA(insert OID = 2276 ( any PGNSP PGUID 4 t p P f t \054 0 0 0 any_in any_out - - - - - i p f 0 -1 0 -1 f _null_ _null_ )); #define ANYOID 2276 ! DATA(insert OID = 2277 ( anyarray PGNSP PGUID -1 f p P f t \054 0 0 0 anyarray_in anyarray_out anyarray_recv anyarray_send - - - d x f 0 -1 0 -1 f _null_ _null_ )); #define ANYARRAYOID 2277 ! DATA(insert OID = 2278 ( void PGNSP PGUID 4 t p P f t \054 0 0 0 void_in void_out - - - - - i p f 0 -1 0 -1 f _null_ _null_ )); #define VOIDOID 2278 ! DATA(insert OID = 2279 ( trigger PGNSP PGUID 4 t p P f t \054 0 0 0 trigger_in trigger_out - - - - - i p f 0 -1 0 -1 f _null_ _null_ )); #define TRIGGEROID 2279 ! DATA(insert OID = 2280 ( language_handler PGNSP PGUID 4 t p P f t \054 0 0 0 language_handler_in language_handler_out - - - - - i p f 0 -1 0 -1 f _null_ _null_ )); #define LANGUAGE_HANDLEROID 2280 ! DATA(insert OID = 2281 ( internal PGNSP PGUID SIZEOF_POINTER t p P f t \054 0 0 0 internal_in internal_out - - - - - ALIGNOF_POINTER p f 0 -1 0 -1 f _null_ _null_ )); #define INTERNALOID 2281 ! DATA(insert OID = 2282 ( opaque PGNSP PGUID 4 t p P f t \054 0 0 0 opaque_in opaque_out - - - - - i p f 0 -1 0 -1 f _null_ _null_ )); #define OPAQUEOID 2282 ! DATA(insert OID = 2283 ( anyelement PGNSP PGUID 4 t p P f t \054 0 0 0 anyelement_in anyelement_out - - - - - i p f 0 -1 0 -1 f _null_ _null_ )); #define ANYELEMENTOID 2283 ! DATA(insert OID = 2776 ( anynonarray PGNSP PGUID 4 t p P f t \054 0 0 0 anynonarray_in anynonarray_out - - - - - i p f 0 -1 0 -1 f _null_ _null_ )); #define ANYNONARRAYOID 2776 ! DATA(insert OID = 3500 ( anyenum PGNSP PGUID 4 t p P f t \054 0 0 0 anyenum_in anyenum_out - - - - - i p f 0 -1 0 -1 f _null_ _null_ )); #define ANYENUMOID 3500 diff --git a/src/include/catalog/pg_type_fn.h b/src/include/catalog/pg_type_fn.h index cc72350..bc34568 100644 *** a/src/include/catalog/pg_type_fn.h --- b/src/include/catalog/pg_type_fn.h *************** extern Oid TypeCreate(Oid newTypeOid, *** 50,56 **** char storage, int32 typeMod, int32 typNDims, ! bool typeNotNull); extern void GenerateTypeDependencies(Oid typeNamespace, Oid typeObjectId, --- 50,58 ---- char storage, int32 typeMod, int32 typNDims, ! bool typeNotNull, ! int32 typeNLabels, ! bool typeSorted); extern void GenerateTypeDependencies(Oid typeNamespace, Oid typeObjectId, diff --git a/src/include/commands/typecmds.h b/src/include/commands/typecmds.h index 2bff7e1..9faf3ea 100644 *** a/src/include/commands/typecmds.h --- b/src/include/commands/typecmds.h *************** extern void RemoveTypes(DropStmt *drop); *** 24,29 **** --- 24,30 ---- extern void RemoveTypeById(Oid typeOid); extern void DefineDomain(CreateDomainStmt *stmt); extern void DefineEnum(CreateEnumStmt *stmt); + extern void AlterEnum (AlterEnumStmt *stmt); extern Oid DefineCompositeType(const RangeVar *typevar, List *coldeflist); extern Oid AssignTypeArrayOid(void); diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 0d33a2e..139c8ed 100644 *** a/src/include/nodes/nodes.h --- b/src/include/nodes/nodes.h *************** typedef enum NodeTag *** 348,354 **** T_DropUserMappingStmt, T_AlterTableSpaceOptionsStmt, T_SecLabelStmt, ! /* * TAGS FOR PARSE TREE NODES (parsenodes.h) */ --- 348,354 ---- T_DropUserMappingStmt, T_AlterTableSpaceOptionsStmt, T_SecLabelStmt, ! T_AlterEnumStmt, /* * TAGS FOR PARSE TREE NODES (parsenodes.h) */ diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index ca225d0..1c3397e 100644 *** a/src/include/nodes/parsenodes.h --- b/src/include/nodes/parsenodes.h *************** typedef struct CreateEnumStmt *** 2192,2197 **** --- 2192,2211 ---- /* ---------------------- + * Alter Type Statement, enum types + * ---------------------- + */ + typedef struct AlterEnumStmt + { + NodeTag type; + List *typeName; /* qualified name (list of Value strings) */ + char *newVal; /* new enum value */ + char *newValNeighbour;/* neighbouring enum value */ + bool newValIsAfter; /* new enum value is after neighbour? */ + } AlterEnumStmt; + + + /* ---------------------- * Create View Statement * ---------------------- */ diff --git a/src/test/regress/expected/enum.out b/src/test/regress/expected/enum.out index 56240c0..f3c86b1 100644 *** a/src/test/regress/expected/enum.out --- b/src/test/regress/expected/enum.out *************** ERROR: invalid input value for enum rai *** 25,30 **** --- 25,122 ---- LINE 1: SELECT 'mauve'::rainbow; ^ -- + -- adding new values + -- + CREATE TYPE planets AS ENUM ( 'venus', 'earth', 'mars' ); + SELECT enumlabel, enumsortorder + FROM pg_enum + WHERE enumtypid = 'planets'::regtype + ORDER by 2; + enumlabel | enumsortorder + -----------+--------------- + venus | 1 + earth | 2 + mars | 3 + (3 rows) + + ALTER TYPE planets ADD 'uranus'; + SELECT typnlabels, typsorted + FROM pg_type + WHERE oid = 'planets'::regtype; + typnlabels | typsorted + ------------+----------- + 4 | t + (1 row) + + SELECT enumlabel, enumsortorder + FROM pg_enum + WHERE enumtypid = 'planets'::regtype + ORDER by 2; + enumlabel | enumsortorder + -----------+--------------- + venus | 1 + earth | 2 + mars | 3 + uranus | 4 + (4 rows) + + ALTER TYPE planets ADD 'mercury' BEFORE 'venus'; + ALTER TYPE planets ADD 'saturn' BEFORE 'uranus'; + ALTER TYPE planets ADD 'jupiter' AFTER 'mars'; + ALTER TYPE planets ADD 'neptune' AFTER 'uranus'; + SELECT typnlabels, typsorted + FROM pg_type + WHERE oid = 'planets'::regtype; + typnlabels | typsorted + ------------+----------- + 8 | f + (1 row) + + SELECT enumlabel, enumsortorder + FROM pg_enum + WHERE enumtypid = 'planets'::regtype + ORDER by CAST(enumlabel AS planets); + enumlabel | enumsortorder + -----------+--------------- + mercury | 1 + venus | 2 + earth | 3 + mars | 4 + jupiter | 5 + saturn | 6 + uranus | 7 + neptune | 8 + (8 rows) + + select 'mars'::planets > 'mercury' as using_sortorder; + using_sortorder + ----------------- + t + (1 row) + + \dT+ planets + List of data types + Schema | Name | Internal name | Size | Elements | Description + --------+---------+---------------+------+----------+------------- + public | planets | planets | 4 | mercury +| + | | | | venus +| + | | | | earth +| + | | | | mars +| + | | | | jupiter +| + | | | | saturn +| + | | | | uranus +| + | | | | neptune | + (1 row) + + -- errors for adding labels + ALTER TYPE planets ADD + 'plutoplutoplutoplutoplutoplutoplutoplutoplutoplutoplutoplutoplutopluto'; + ERROR: invalid enum label "plutoplutoplutoplutoplutoplutoplutoplutoplutoplutoplutoplutoplutopluto" + DETAIL: Labels must be 63 characters or less. + ALTER TYPE planets ADD 'pluto' AFTER 'zeus'; + ERROR: "zeus" is not an existing label. + DROP TYPE planets; + -- -- Basic table creation, row selection -- CREATE TABLE enumtest (col rainbow); *************** SELECT COUNT(*) FROM pg_type WHERE typna *** 403,409 **** SELECT * FROM pg_enum WHERE NOT EXISTS (SELECT 1 FROM pg_type WHERE pg_type.oid = enumtypid); ! enumtypid | enumlabel ! -----------+----------- (0 rows) --- 495,501 ---- SELECT * FROM pg_enum WHERE NOT EXISTS (SELECT 1 FROM pg_type WHERE pg_type.oid = enumtypid); ! enumtypid | enumlabel | enumsortorder ! -----------+-----------+--------------- (0 rows) diff --git a/src/test/regress/sql/enum.sql b/src/test/regress/sql/enum.sql index 387e8e7..6092706 100644 *** a/src/test/regress/sql/enum.sql --- b/src/test/regress/sql/enum.sql *************** SELECT 'red'::rainbow; *** 16,21 **** --- 16,71 ---- SELECT 'mauve'::rainbow; -- + -- adding new values + -- + + CREATE TYPE planets AS ENUM ( 'venus', 'earth', 'mars' ); + + SELECT enumlabel, enumsortorder + FROM pg_enum + WHERE enumtypid = 'planets'::regtype + ORDER by 2; + + ALTER TYPE planets ADD 'uranus'; + + SELECT typnlabels, typsorted + FROM pg_type + WHERE oid = 'planets'::regtype; + + SELECT enumlabel, enumsortorder + FROM pg_enum + WHERE enumtypid = 'planets'::regtype + ORDER by 2; + + ALTER TYPE planets ADD 'mercury' BEFORE 'venus'; + + ALTER TYPE planets ADD 'saturn' BEFORE 'uranus'; + + ALTER TYPE planets ADD 'jupiter' AFTER 'mars'; + + ALTER TYPE planets ADD 'neptune' AFTER 'uranus'; + + SELECT typnlabels, typsorted + FROM pg_type + WHERE oid = 'planets'::regtype; + + SELECT enumlabel, enumsortorder + FROM pg_enum + WHERE enumtypid = 'planets'::regtype + ORDER by CAST(enumlabel AS planets); + + select 'mars'::planets > 'mercury' as using_sortorder; + + \dT+ planets + + -- errors for adding labels + ALTER TYPE planets ADD + 'plutoplutoplutoplutoplutoplutoplutoplutoplutoplutoplutoplutoplutopluto'; + + ALTER TYPE planets ADD 'pluto' AFTER 'zeus'; + + DROP TYPE planets; + -- -- Basic table creation, row selection -- CREATE TABLE enumtest (col rainbow);