1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-18 17:42:25 +03:00

Support enum data types. Along the way, use macros for the values of

pg_type.typtype whereever practical.  Tom Dunstan, with some kibitzing
from Tom Lane.
This commit is contained in:
Tom Lane
2007-04-02 03:49:42 +00:00
parent a482a3e58b
commit 57690c6803
74 changed files with 2398 additions and 332 deletions

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/aggregatecmds.c,v 1.42 2007/01/05 22:19:25 momjian Exp $
* $PostgreSQL: pgsql/src/backend/commands/aggregatecmds.c,v 1.43 2007/04/02 03:49:37 tgl Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
@ -176,9 +176,8 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
* in some cases (AggregateCreate will check).
*/
transTypeId = typenameTypeId(NULL, transType);
if (get_typtype(transTypeId) == 'p' &&
transTypeId != ANYARRAYOID &&
transTypeId != ANYELEMENTOID)
if (get_typtype(transTypeId) == TYPTYPE_PSEUDO &&
!IsPolymorphicType(transTypeId))
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("aggregate transition data type cannot be %s",

View File

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.82 2007/01/22 01:35:20 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.83 2007/04/02 03:49:37 tgl Exp $
*
* DESCRIPTION
* These routines take the parse tree and pick out the
@ -1259,13 +1259,13 @@ CreateCast(CreateCastStmt *stmt)
targettypeid = typenameTypeId(NULL, stmt->targettype);
/* No pseudo-types allowed */
if (get_typtype(sourcetypeid) == 'p')
if (get_typtype(sourcetypeid) == TYPTYPE_PSEUDO)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("source data type %s is a pseudo-type",
TypeNameToString(stmt->sourcetype))));
if (get_typtype(targettypeid) == 'p')
if (get_typtype(targettypeid) == TYPTYPE_PSEUDO)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("target data type %s is a pseudo-type",

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.100 2007/02/14 01:58:57 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.101 2007/04/02 03:49:38 tgl Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
@ -39,6 +39,7 @@
#include "catalog/indexing.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_depend.h"
#include "catalog/pg_enum.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
@ -205,7 +206,7 @@ DefineType(List *names, List *parameters)
{
elemType = typenameTypeId(NULL, defGetTypeName(defel));
/* disallow arrays of pseudotypes */
if (get_typtype(elemType) == 'p')
if (get_typtype(elemType) == TYPTYPE_PSEUDO)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("array element type cannot be %s",
@ -404,7 +405,7 @@ DefineType(List *names, List *parameters)
InvalidOid, /* relation oid (n/a here) */
0, /* relation kind (ditto) */
internalLength, /* internal size */
'b', /* type-type (base type) */
TYPTYPE_BASE, /* type-type (base type) */
delimiter, /* array element delimiter */
inputOid, /* input procedure */
outputOid, /* output procedure */
@ -438,7 +439,7 @@ DefineType(List *names, List *parameters)
InvalidOid, /* relation oid (n/a here) */
0, /* relation kind (ditto) */
-1, /* internal size */
'b', /* type-type (base type) */
TYPTYPE_BASE, /* type-type (base type) */
DEFAULT_TYPDELIM, /* array element delimiter */
F_ARRAY_IN, /* input procedure */
F_ARRAY_OUT, /* output procedure */
@ -543,6 +544,14 @@ RemoveTypeById(Oid typeOid)
simple_heap_delete(relation, &tup->t_self);
/*
* If it is an enum, delete the pg_enum entries too; we don't bother
* with making dependency entries for those, so it has to be done
* "by hand" here.
*/
if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_ENUM)
EnumValuesDelete(typeOid);
ReleaseSysCache(tup);
heap_close(relation, RowExclusiveLock);
@ -620,12 +629,15 @@ DefineDomain(CreateDomainStmt *stmt)
basetypeMod = typenameTypeMod(NULL, stmt->typename, basetypeoid);
/*
* Base type must be a plain base type or another domain. Domains over
* pseudotypes would create a security hole. Domains over composite types
* might be made to work in the future, but not today.
* Base type must be a plain base type, another domain or an enum.
* Domains over pseudotypes would create a security hole. Domains
* over composite types might be made to work in the future, but not
* today.
*/
typtype = baseType->typtype;
if (typtype != 'b' && typtype != 'd')
if (typtype != TYPTYPE_BASE &&
typtype != TYPTYPE_DOMAIN &&
typtype != TYPTYPE_ENUM)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("\"%s\" is not a valid base type for a domain",
@ -798,7 +810,7 @@ DefineDomain(CreateDomainStmt *stmt)
InvalidOid, /* relation oid (n/a here) */
0, /* relation kind (ditto) */
internalLength, /* internal size */
'd', /* type-type (domain type) */
TYPTYPE_DOMAIN, /* type-type (domain type) */
delimiter, /* array element delimiter */
inputProcedure, /* input procedure */
outputProcedure, /* output procedure */
@ -907,7 +919,7 @@ RemoveDomain(List *names, DropBehavior behavior, bool missing_ok)
/* Check that this is actually a domain */
typtype = ((Form_pg_type) GETSTRUCT(tup))->typtype;
if (typtype != 'd')
if (typtype != TYPTYPE_DOMAIN)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is not a domain",
@ -925,6 +937,100 @@ RemoveDomain(List *names, DropBehavior behavior, bool missing_ok)
performDeletion(&object, behavior);
}
/*
* DefineEnum
* Registers a new enum.
*/
void
DefineEnum(CreateEnumStmt *stmt)
{
char *enumName;
char *enumArrayName;
Oid enumNamespace;
Oid enumTypeOid;
AclResult aclresult;
/* Convert list of names to a name and namespace */
enumNamespace = QualifiedNameGetCreationNamespace(stmt->typename,
&enumName);
/* Check we have creation rights in target namespace */
aclresult = pg_namespace_aclcheck(enumNamespace, GetUserId(), ACL_CREATE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(enumNamespace));
/*
* Type names must be one character shorter than other names, allowing
* room to create the corresponding array type name with prepended "_".
*/
if (strlen(enumName) > (NAMEDATALEN - 2))
ereport(ERROR,
(errcode(ERRCODE_INVALID_NAME),
errmsg("type names must be %d characters or less",
NAMEDATALEN - 2)));
/* Create the pg_type entry */
enumTypeOid =
TypeCreate(enumName, /* type name */
enumNamespace, /* namespace */
InvalidOid, /* relation oid (n/a here) */
0, /* relation kind (ditto) */
sizeof(Oid), /* internal size */
TYPTYPE_ENUM, /* type-type (enum type) */
DEFAULT_TYPDELIM, /* array element delimiter */
F_ENUM_IN, /* input procedure */
F_ENUM_OUT, /* output procedure */
InvalidOid, /* receive procedure - none */
InvalidOid, /* send procedure - none */
InvalidOid, /* typmodin procedure - none */
InvalidOid, /* typmodout procedure - none */
InvalidOid, /* analyze procedure - default */
InvalidOid, /* element type ID */
InvalidOid, /* base type ID (only for domains) */
NULL, /* never a default type value */
NULL, /* binary default isn't sent either */
true, /* always passed by value */
'i', /* int alignment */
'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);
/* Create array type for enum */
enumArrayName = makeArrayTypeName(enumName);
TypeCreate(enumArrayName, /* type name */
enumNamespace, /* namespace */
InvalidOid, /* relation oid (n/a here) */
0, /* relation kind (ditto) */
-1, /* internal size */
TYPTYPE_BASE, /* type-type (base type) */
DEFAULT_TYPDELIM, /* array element delimiter */
F_ARRAY_IN, /* input procedure */
F_ARRAY_OUT, /* output procedure */
F_ARRAY_RECV, /* receive procedure */
F_ARRAY_SEND, /* send procedure */
InvalidOid, /* typmodin procedure - none */
InvalidOid, /* typmodout procedure - none */
InvalidOid, /* analyze procedure - default */
enumTypeOid, /* element type ID */
InvalidOid, /* base type ID */
NULL, /* never a default type value */
NULL, /* binary default isn't sent either */
false, /* never passed by value */
'i', /* enums have align i, so do their arrays */
'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.
@ -1835,7 +1941,7 @@ checkDomainOwner(HeapTuple tup, TypeName *typename)
Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
/* Check that this is actually a domain */
if (typTup->typtype != 'd')
if (typTup->typtype != TYPTYPE_DOMAIN)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is not a domain",
@ -2021,7 +2127,7 @@ GetDomainConstraints(Oid typeOid)
elog(ERROR, "cache lookup failed for type %u", typeOid);
typTup = (Form_pg_type) GETSTRUCT(tup);
if (typTup->typtype != 'd')
if (typTup->typtype != TYPTYPE_DOMAIN)
{
/* Not a domain, so done */
ReleaseSysCache(tup);
@ -2148,7 +2254,7 @@ AlterTypeOwner(List *names, Oid newOwnerId)
* free-standing composite type, and not a table's underlying type. We
* want people to use ALTER TABLE not ALTER TYPE for that case.
*/
if (typTup->typtype == 'c' &&
if (typTup->typtype == TYPTYPE_COMPOSITE &&
get_rel_relkind(typTup->typrelid) != RELKIND_COMPOSITE_TYPE)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
@ -2325,11 +2431,12 @@ AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
/* Detect whether type is a composite type (but not a table rowtype) */
isCompositeType =
(typform->typtype == 'c' &&
(typform->typtype == TYPTYPE_COMPOSITE &&
get_rel_relkind(typform->typrelid) == RELKIND_COMPOSITE_TYPE);
/* Enforce not-table-type if requested */
if (typform->typtype == 'c' && !isCompositeType && errorOnTableType)
if (typform->typtype == TYPTYPE_COMPOSITE && !isCompositeType &&
errorOnTableType)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("%s is a table's row type",
@ -2376,14 +2483,14 @@ AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
else
{
/* If it's a domain, it might have constraints */
if (typform->typtype == 'd')
if (typform->typtype == TYPTYPE_DOMAIN)
AlterConstraintNamespaces(typeOid, oldNspOid, nspOid, true);
/*
* Update dependency on schema, if any --- a table rowtype has not got
* one.
*/
if (typform->typtype != 'c')
if (typform->typtype != TYPTYPE_COMPOSITE)
if (changeDependencyFor(TypeRelationId, typeOid,
NamespaceRelationId, oldNspOid, nspOid) != 1)
elog(ERROR, "failed to change schema dependency for type %s",