mirror of
https://github.com/postgres/postgres.git
synced 2025-11-26 23:43:30 +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:
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/hash/hashfunc.c,v 1.50 2007/01/05 22:19:22 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/hash/hashfunc.c,v 1.51 2007/04/02 03:49:37 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* These functions are stored in pg_amproc. For each operator class
|
||||
@@ -72,6 +72,12 @@ hashoid(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_UINT32(~((uint32) PG_GETARG_OID(0)));
|
||||
}
|
||||
|
||||
Datum
|
||||
hashenum(PG_FUNCTION_ARGS)
|
||||
{
|
||||
PG_RETURN_UINT32(~((uint32) PG_GETARG_OID(0)));
|
||||
}
|
||||
|
||||
Datum
|
||||
hashfloat4(PG_FUNCTION_ARGS)
|
||||
{
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# Makefile for backend/catalog
|
||||
#
|
||||
# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.63 2007/02/09 15:55:58 petere Exp $
|
||||
# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.64 2007/04/02 03:49:37 tgl Exp $
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
@@ -11,7 +11,7 @@ top_builddir = ../../..
|
||||
include $(top_builddir)/src/Makefile.global
|
||||
|
||||
OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \
|
||||
pg_aggregate.o pg_constraint.o pg_conversion.o pg_depend.o \
|
||||
pg_aggregate.o pg_constraint.o pg_conversion.o pg_depend.o pg_enum.o \
|
||||
pg_largeobject.o pg_namespace.o pg_operator.o pg_proc.o pg_shdepend.o \
|
||||
pg_type.o toasting.o
|
||||
|
||||
@@ -32,7 +32,7 @@ POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\
|
||||
pg_opfamily.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \
|
||||
pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \
|
||||
pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h pg_cast.h \
|
||||
pg_namespace.h pg_conversion.h pg_depend.h \
|
||||
pg_enum.h pg_namespace.h pg_conversion.h pg_depend.h \
|
||||
pg_database.h pg_tablespace.h pg_pltemplate.h \
|
||||
pg_authid.h pg_auth_members.h pg_shdepend.h pg_shdescription.h \
|
||||
toasting.h indexing.h \
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.317 2007/02/14 01:58:56 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.318 2007/04/02 03:49:37 tgl Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
@@ -412,7 +412,7 @@ CheckAttributeType(const char *attname, Oid atttypid)
|
||||
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
|
||||
errmsg("column \"%s\" has type \"unknown\"", attname),
|
||||
errdetail("Proceeding with relation creation anyway.")));
|
||||
else if (att_typtype == 'p')
|
||||
else if (att_typtype == TYPTYPE_PSEUDO)
|
||||
{
|
||||
/* Special hack for pg_statistic: allow ANYARRAY during initdb */
|
||||
if (atttypid != ANYARRAYOID || IsUnderPostmaster)
|
||||
@@ -718,7 +718,7 @@ AddNewRelationType(const char *typeName,
|
||||
new_rel_oid, /* relation oid */
|
||||
new_rel_kind, /* relation kind */
|
||||
-1, /* internal size (varlena) */
|
||||
'c', /* type-type (complex) */
|
||||
TYPTYPE_COMPOSITE, /* type-type (composite) */
|
||||
',', /* default array delimiter */
|
||||
F_RECORD_IN, /* input procedure */
|
||||
F_RECORD_OUT, /* output procedure */
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/pg_aggregate.c,v 1.85 2007/01/22 01:35:20 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/pg_aggregate.c,v 1.86 2007/04/02 03:49:37 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -80,8 +80,7 @@ AggregateCreate(const char *aggName,
|
||||
hasPolyArg = false;
|
||||
for (i = 0; i < numArgs; i++)
|
||||
{
|
||||
if (aggArgTypes[i] == ANYARRAYOID ||
|
||||
aggArgTypes[i] == ANYELEMENTOID)
|
||||
if (IsPolymorphicType(aggArgTypes[i]))
|
||||
{
|
||||
hasPolyArg = true;
|
||||
break;
|
||||
@@ -92,12 +91,11 @@ AggregateCreate(const char *aggName,
|
||||
* If transtype is polymorphic, must have polymorphic argument also; else
|
||||
* we will have no way to deduce the actual transtype.
|
||||
*/
|
||||
if (!hasPolyArg &&
|
||||
(aggTransType == ANYARRAYOID || aggTransType == ANYELEMENTOID))
|
||||
if (IsPolymorphicType(aggTransType) && !hasPolyArg)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
||||
errmsg("cannot determine transition data type"),
|
||||
errdetail("An aggregate using \"anyarray\" or \"anyelement\" as transition type must have at least one argument of either type.")));
|
||||
errdetail("An aggregate using a polymorphic transition type must have at least one polymorphic argument.")));
|
||||
|
||||
/* find the transfn */
|
||||
nargs_transfn = numArgs + 1;
|
||||
@@ -170,13 +168,12 @@ AggregateCreate(const char *aggName,
|
||||
* that itself violates the rule against polymorphic result with no
|
||||
* polymorphic input.)
|
||||
*/
|
||||
if (!hasPolyArg &&
|
||||
(finaltype == ANYARRAYOID || finaltype == ANYELEMENTOID))
|
||||
if (IsPolymorphicType(finaltype) && !hasPolyArg)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||
errmsg("cannot determine result data type"),
|
||||
errdetail("An aggregate returning \"anyarray\" or \"anyelement\" "
|
||||
"must have at least one argument of either type.")));
|
||||
errdetail("An aggregate returning a polymorphic type "
|
||||
"must have at least one polymorphic argument.")));
|
||||
|
||||
/* handle sortop, if supplied */
|
||||
if (aggsortopName)
|
||||
@@ -329,8 +326,7 @@ lookup_agg_function(List *fnName,
|
||||
*/
|
||||
for (i = 0; i < nargs; i++)
|
||||
{
|
||||
if (input_types[i] != ANYARRAYOID &&
|
||||
input_types[i] != ANYELEMENTOID)
|
||||
if (!IsPolymorphicType(input_types[i]))
|
||||
{
|
||||
allPolyArgs = false;
|
||||
break;
|
||||
@@ -351,8 +347,7 @@ lookup_agg_function(List *fnName,
|
||||
*/
|
||||
for (i = 0; i < nargs; i++)
|
||||
{
|
||||
if (true_oid_array[i] != ANYARRAYOID &&
|
||||
true_oid_array[i] != ANYELEMENTOID &&
|
||||
if (!IsPolymorphicType(true_oid_array[i]) &&
|
||||
!IsBinaryCoercible(input_types[i], true_oid_array[i]))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||
|
||||
146
src/backend/catalog/pg_enum.c
Normal file
146
src/backend/catalog/pg_enum.c
Normal file
@@ -0,0 +1,146 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* pg_enum.c
|
||||
* routines to support manipulation of the pg_enum relation
|
||||
*
|
||||
* Copyright (c) 2006-2007, PostgreSQL Global Development Group
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/pg_enum.c,v 1.1 2007/04/02 03:49:37 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include "access/genam.h"
|
||||
#include "access/heapam.h"
|
||||
#include "catalog/catalog.h"
|
||||
#include "catalog/indexing.h"
|
||||
#include "catalog/pg_enum.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/fmgroids.h"
|
||||
|
||||
static int oid_cmp(const void *p1, const void *p2);
|
||||
|
||||
|
||||
/*
|
||||
* EnumValuesCreate
|
||||
* Create an entry in pg_enum for each of the supplied enum values.
|
||||
*
|
||||
* vals is a list of Value strings.
|
||||
*/
|
||||
void
|
||||
EnumValuesCreate(Oid enumTypeOid, List *vals)
|
||||
{
|
||||
Relation pg_enum;
|
||||
TupleDesc tupDesc;
|
||||
NameData enumlabel;
|
||||
Oid *oids;
|
||||
int i, n;
|
||||
Datum values[Natts_pg_enum];
|
||||
char nulls[Natts_pg_enum];
|
||||
ListCell *lc;
|
||||
HeapTuple tup;
|
||||
|
||||
n = 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);
|
||||
tupDesc = pg_enum->rd_att;
|
||||
|
||||
/*
|
||||
* Allocate oids. 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.
|
||||
*/
|
||||
oids = (Oid *) palloc(n * sizeof(Oid));
|
||||
for(i = 0; i < n; i++)
|
||||
{
|
||||
oids[i] = GetNewOid(pg_enum);
|
||||
}
|
||||
|
||||
/* sort them, just in case counter wrapped from high to low */
|
||||
qsort(oids, n, sizeof(Oid), oid_cmp);
|
||||
|
||||
/* and make the entries */
|
||||
memset(nulls, ' ', sizeof(nulls));
|
||||
|
||||
i = 0;
|
||||
foreach(lc, vals)
|
||||
{
|
||||
char *lab = strVal(lfirst(lc));
|
||||
|
||||
values[Anum_pg_enum_enumtypid - 1] = ObjectIdGetDatum(enumTypeOid);
|
||||
namestrcpy(&enumlabel, lab);
|
||||
values[Anum_pg_enum_enumlabel - 1] = NameGetDatum(&enumlabel);
|
||||
|
||||
tup = heap_formtuple(tupDesc, values, nulls);
|
||||
HeapTupleSetOid(tup, oids[i]);
|
||||
|
||||
simple_heap_insert(pg_enum, tup);
|
||||
CatalogUpdateIndexes(pg_enum, tup);
|
||||
heap_freetuple(tup);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
/* clean up */
|
||||
pfree(oids);
|
||||
heap_close(pg_enum, RowExclusiveLock);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* EnumValuesDelete
|
||||
* Remove all the pg_enum entries for the specified enum type.
|
||||
*/
|
||||
void
|
||||
EnumValuesDelete(Oid enumTypeOid)
|
||||
{
|
||||
Relation pg_enum;
|
||||
ScanKeyData key[1];
|
||||
SysScanDesc scan;
|
||||
HeapTuple tup;
|
||||
|
||||
pg_enum = heap_open(EnumRelationId, RowExclusiveLock);
|
||||
|
||||
ScanKeyInit(&key[0],
|
||||
Anum_pg_enum_enumtypid,
|
||||
BTEqualStrategyNumber, F_OIDEQ,
|
||||
ObjectIdGetDatum(enumTypeOid));
|
||||
|
||||
scan = systable_beginscan(pg_enum, EnumTypIdLabelIndexId, true,
|
||||
SnapshotNow, 1, key);
|
||||
|
||||
while (HeapTupleIsValid(tup = systable_getnext(scan)))
|
||||
{
|
||||
simple_heap_delete(pg_enum, &tup->t_self);
|
||||
}
|
||||
|
||||
systable_endscan(scan);
|
||||
|
||||
heap_close(pg_enum, RowExclusiveLock);
|
||||
}
|
||||
|
||||
|
||||
/* qsort comparison function */
|
||||
static int
|
||||
oid_cmp(const void *p1, const void *p2)
|
||||
{
|
||||
Oid v1 = *((const Oid *) p1);
|
||||
Oid v2 = *((const Oid *) p2);
|
||||
|
||||
if (v1 < v2)
|
||||
return -1;
|
||||
if (v1 > v2)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.143 2007/01/22 01:35:20 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.144 2007/04/02 03:49:37 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -137,9 +137,9 @@ ProcedureCreate(const char *procedureName,
|
||||
}
|
||||
|
||||
/*
|
||||
* Do not allow return type ANYARRAY or ANYELEMENT unless at least one
|
||||
* input argument is ANYARRAY or ANYELEMENT. Also, do not allow return
|
||||
* type INTERNAL unless at least one input argument is INTERNAL.
|
||||
* Do not allow polymorphic return type unless at least one input argument
|
||||
* is polymorphic. Also, do not allow return type INTERNAL unless at
|
||||
* least one input argument is INTERNAL.
|
||||
*/
|
||||
for (i = 0; i < parameterCount; i++)
|
||||
{
|
||||
@@ -147,6 +147,7 @@ ProcedureCreate(const char *procedureName,
|
||||
{
|
||||
case ANYARRAYOID:
|
||||
case ANYELEMENTOID:
|
||||
case ANYENUMOID:
|
||||
genericInParam = true;
|
||||
break;
|
||||
case INTERNALOID:
|
||||
@@ -169,6 +170,7 @@ ProcedureCreate(const char *procedureName,
|
||||
{
|
||||
case ANYARRAYOID:
|
||||
case ANYELEMENTOID:
|
||||
case ANYENUMOID:
|
||||
genericOutParam = true;
|
||||
break;
|
||||
case INTERNALOID:
|
||||
@@ -178,12 +180,12 @@ ProcedureCreate(const char *procedureName,
|
||||
}
|
||||
}
|
||||
|
||||
if ((returnType == ANYARRAYOID || returnType == ANYELEMENTOID ||
|
||||
genericOutParam) && !genericInParam)
|
||||
if ((IsPolymorphicType(returnType) || genericOutParam)
|
||||
&& !genericInParam)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
||||
errmsg("cannot determine result data type"),
|
||||
errdetail("A function returning \"anyarray\" or \"anyelement\" must have at least one argument of either type.")));
|
||||
errdetail("A function returning a polymorphic type must have at least one polymorphic argument.")));
|
||||
|
||||
if ((returnType == INTERNALOID || internalOutParam) && !internalInParam)
|
||||
ereport(ERROR,
|
||||
@@ -533,26 +535,24 @@ fmgr_sql_validator(PG_FUNCTION_ARGS)
|
||||
proc = (Form_pg_proc) GETSTRUCT(tuple);
|
||||
|
||||
/* Disallow pseudotype result */
|
||||
/* except for RECORD, VOID, ANYARRAY, or ANYELEMENT */
|
||||
if (get_typtype(proc->prorettype) == 'p' &&
|
||||
/* except for RECORD, VOID, or polymorphic */
|
||||
if (get_typtype(proc->prorettype) == TYPTYPE_PSEUDO &&
|
||||
proc->prorettype != RECORDOID &&
|
||||
proc->prorettype != VOIDOID &&
|
||||
proc->prorettype != ANYARRAYOID &&
|
||||
proc->prorettype != ANYELEMENTOID)
|
||||
!IsPolymorphicType(proc->prorettype))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
||||
errmsg("SQL functions cannot return type %s",
|
||||
format_type_be(proc->prorettype))));
|
||||
|
||||
/* Disallow pseudotypes in arguments */
|
||||
/* except for ANYARRAY or ANYELEMENT */
|
||||
/* except for polymorphic */
|
||||
haspolyarg = false;
|
||||
for (i = 0; i < proc->pronargs; i++)
|
||||
{
|
||||
if (get_typtype(proc->proargtypes.values[i]) == 'p')
|
||||
if (get_typtype(proc->proargtypes.values[i]) == TYPTYPE_PSEUDO)
|
||||
{
|
||||
if (proc->proargtypes.values[i] == ANYARRAYOID ||
|
||||
proc->proargtypes.values[i] == ANYELEMENTOID)
|
||||
if (IsPolymorphicType(proc->proargtypes.values[i]))
|
||||
haspolyarg = true;
|
||||
else
|
||||
ereport(ERROR,
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.110 2007/01/05 22:19:25 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.111 2007/04/02 03:49:37 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -75,7 +75,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
|
||||
*
|
||||
* The representational details are the same as int4 ... it doesn't really
|
||||
* matter what they are so long as they are consistent. Also note that we
|
||||
* give it typtype = 'p' (pseudotype) as extra insurance that it won't be
|
||||
* give it typtype = TYPTYPE_PSEUDO as extra insurance that it won't be
|
||||
* mistaken for a usable type.
|
||||
*/
|
||||
i = 0;
|
||||
@@ -85,7 +85,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
|
||||
values[i++] = ObjectIdGetDatum(GetUserId()); /* typowner */
|
||||
values[i++] = Int16GetDatum(sizeof(int4)); /* typlen */
|
||||
values[i++] = BoolGetDatum(true); /* typbyval */
|
||||
values[i++] = CharGetDatum('p'); /* typtype */
|
||||
values[i++] = CharGetDatum(TYPTYPE_PSEUDO); /* typtype */
|
||||
values[i++] = BoolGetDatum(false); /* typisdefined */
|
||||
values[i++] = CharGetDatum(DEFAULT_TYPDELIM); /* typdelim */
|
||||
values[i++] = ObjectIdGetDatum(InvalidOid); /* typrelid */
|
||||
@@ -159,7 +159,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
|
||||
Oid
|
||||
TypeCreate(const char *typeName,
|
||||
Oid typeNamespace,
|
||||
Oid relationOid, /* only for 'c'atalog types */
|
||||
Oid relationOid, /* only for composite types */
|
||||
char relationKind, /* ditto */
|
||||
int16 internalSize,
|
||||
char typeType,
|
||||
@@ -243,7 +243,8 @@ TypeCreate(const char *typeName,
|
||||
values[i++] = CharGetDatum(typeType); /* typtype */
|
||||
values[i++] = BoolGetDatum(true); /* typisdefined */
|
||||
values[i++] = CharGetDatum(typDelim); /* typdelim */
|
||||
values[i++] = ObjectIdGetDatum(typeType == 'c' ? relationOid : InvalidOid); /* typrelid */
|
||||
values[i++] = ObjectIdGetDatum(typeType == TYPTYPE_COMPOSITE ?
|
||||
relationOid : InvalidOid); /* typrelid */
|
||||
values[i++] = ObjectIdGetDatum(elementType); /* typelem */
|
||||
values[i++] = ObjectIdGetDatum(inputProcedure); /* typinput */
|
||||
values[i++] = ObjectIdGetDatum(outputProcedure); /* typoutput */
|
||||
@@ -377,7 +378,7 @@ TypeCreate(const char *typeName,
|
||||
void
|
||||
GenerateTypeDependencies(Oid typeNamespace,
|
||||
Oid typeObjectId,
|
||||
Oid relationOid, /* only for 'c'atalog types */
|
||||
Oid relationOid, /* only for composite types */
|
||||
char relationKind, /* ditto */
|
||||
Oid owner,
|
||||
Oid inputProcedure,
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.112 2007/03/13 00:33:40 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.113 2007/04/02 03:49:38 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -182,7 +182,7 @@ init_sql_fcache(FmgrInfo *finfo)
|
||||
*/
|
||||
rettype = procedureStruct->prorettype;
|
||||
|
||||
if (rettype == ANYARRAYOID || rettype == ANYELEMENTOID)
|
||||
if (IsPolymorphicType(rettype))
|
||||
{
|
||||
rettype = get_fn_expr_rettype(finfo);
|
||||
if (rettype == InvalidOid) /* this probably should not happen */
|
||||
@@ -218,7 +218,7 @@ init_sql_fcache(FmgrInfo *finfo)
|
||||
{
|
||||
Oid argtype = argOidVect[argnum];
|
||||
|
||||
if (argtype == ANYARRAYOID || argtype == ANYELEMENTOID)
|
||||
if (IsPolymorphicType(argtype))
|
||||
{
|
||||
argtype = get_fn_expr_argtype(finfo, argnum);
|
||||
if (argtype == InvalidOid)
|
||||
@@ -845,9 +845,9 @@ ShutdownSQLFunction(Datum arg)
|
||||
* to be sure that the user is returning the type he claims.
|
||||
*
|
||||
* For a polymorphic function the passed rettype must be the actual resolved
|
||||
* output type of the function; we should never see ANYARRAY or ANYELEMENT
|
||||
* as rettype. (This means we can't check the type during function definition
|
||||
* of a polymorphic function.)
|
||||
* output type of the function; we should never see ANYARRAY, ANYENUM or
|
||||
* ANYELEMENT as rettype. (This means we can't check the type during function
|
||||
* definition of a polymorphic function.)
|
||||
*
|
||||
* The return value is true if the function returns the entire tuple result
|
||||
* of its final SELECT, and false otherwise. Note that because we allow
|
||||
@@ -925,7 +925,9 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
|
||||
|
||||
fn_typtype = get_typtype(rettype);
|
||||
|
||||
if (fn_typtype == 'b' || fn_typtype == 'd')
|
||||
if (fn_typtype == TYPTYPE_BASE ||
|
||||
fn_typtype == TYPTYPE_DOMAIN ||
|
||||
fn_typtype == TYPTYPE_ENUM)
|
||||
{
|
||||
/*
|
||||
* For base-type returns, the target list should have exactly one
|
||||
@@ -948,7 +950,7 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
|
||||
errdetail("Actual return type is %s.",
|
||||
format_type_be(restype))));
|
||||
}
|
||||
else if (fn_typtype == 'c' || rettype == RECORDOID)
|
||||
else if (fn_typtype == TYPTYPE_COMPOSITE || rettype == RECORDOID)
|
||||
{
|
||||
/* Returns a rowtype */
|
||||
TupleDesc tupdesc;
|
||||
@@ -1053,13 +1055,13 @@ check_sql_fn_retval(Oid func_id, Oid rettype, List *queryTreeList,
|
||||
/* Report that we are returning entire tuple result */
|
||||
return true;
|
||||
}
|
||||
else if (rettype == ANYARRAYOID || rettype == ANYELEMENTOID)
|
||||
else if (IsPolymorphicType(rettype))
|
||||
{
|
||||
/* This should already have been caught ... */
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
||||
errmsg("cannot determine result data type"),
|
||||
errdetail("A function returning \"anyarray\" or \"anyelement\" must have at least one argument of either type.")));
|
||||
errdetail("A function returning a polymorphic type must have at least one polymorphic argument.")));
|
||||
}
|
||||
else
|
||||
ereport(ERROR,
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/executor/nodeAgg.c,v 1.151 2007/02/22 23:44:24 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/executor/nodeAgg.c,v 1.152 2007/04/02 03:49:38 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1363,8 +1363,8 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
|
||||
|
||||
/*
|
||||
* Get actual datatypes of the inputs. These could be different from
|
||||
* the agg's declared input types, when the agg accepts ANY, ANYARRAY
|
||||
* or ANYELEMENT.
|
||||
* the agg's declared input types, when the agg accepts ANY or
|
||||
* a polymorphic type.
|
||||
*/
|
||||
i = 0;
|
||||
foreach(lc, aggref->args)
|
||||
@@ -1421,7 +1421,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
|
||||
|
||||
/* resolve actual type of transition state, if polymorphic */
|
||||
aggtranstype = aggform->aggtranstype;
|
||||
if (aggtranstype == ANYARRAYOID || aggtranstype == ANYELEMENTOID)
|
||||
if (IsPolymorphicType(aggtranstype))
|
||||
{
|
||||
/* have to fetch the agg's declared input types... */
|
||||
Oid *declaredArgTypes;
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.372 2007/03/27 23:21:09 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.373 2007/04/02 03:49:38 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -2361,6 +2361,17 @@ _copyCompositeTypeStmt(CompositeTypeStmt *from)
|
||||
return newnode;
|
||||
}
|
||||
|
||||
static CreateEnumStmt *
|
||||
_copyCreateEnumStmt(CreateEnumStmt *from)
|
||||
{
|
||||
CreateEnumStmt *newnode = makeNode(CreateEnumStmt);
|
||||
|
||||
COPY_NODE_FIELD(typename);
|
||||
COPY_NODE_FIELD(vals);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
static ViewStmt *
|
||||
_copyViewStmt(ViewStmt *from)
|
||||
{
|
||||
@@ -3312,6 +3323,9 @@ copyObject(void *from)
|
||||
case T_CompositeTypeStmt:
|
||||
retval = _copyCompositeTypeStmt(from);
|
||||
break;
|
||||
case T_CreateEnumStmt:
|
||||
retval = _copyCreateEnumStmt(from);
|
||||
break;
|
||||
case T_ViewStmt:
|
||||
retval = _copyViewStmt(from);
|
||||
break;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.303 2007/03/27 23:21:09 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.304 2007/04/02 03:49:38 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1186,6 +1186,15 @@ _equalCompositeTypeStmt(CompositeTypeStmt *a, CompositeTypeStmt *b)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalCreateEnumStmt(CreateEnumStmt *a, CreateEnumStmt *b)
|
||||
{
|
||||
COMPARE_NODE_FIELD(typename);
|
||||
COMPARE_NODE_FIELD(vals);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalViewStmt(ViewStmt *a, ViewStmt *b)
|
||||
{
|
||||
@@ -2247,6 +2256,9 @@ equal(void *a, void *b)
|
||||
case T_CompositeTypeStmt:
|
||||
retval = _equalCompositeTypeStmt(a, b);
|
||||
break;
|
||||
case T_CreateEnumStmt:
|
||||
retval = _equalCreateEnumStmt(a, b);
|
||||
break;
|
||||
case T_ViewStmt:
|
||||
retval = _equalViewStmt(a, b);
|
||||
break;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.240 2007/03/27 23:21:09 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.241 2007/04/02 03:49:38 tgl Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@@ -435,7 +435,7 @@ count_agg_clauses_walker(Node *node, AggClauseCounts *counts)
|
||||
ReleaseSysCache(aggTuple);
|
||||
|
||||
/* resolve actual type of transition state, if polymorphic */
|
||||
if (aggtranstype == ANYARRAYOID || aggtranstype == ANYELEMENTOID)
|
||||
if (IsPolymorphicType(aggtranstype))
|
||||
{
|
||||
/* have to fetch the agg's declared input types... */
|
||||
Oid *declaredArgTypes;
|
||||
@@ -2907,8 +2907,7 @@ inline_function(Oid funcid, Oid result_type, List *args,
|
||||
funcform->pronargs * sizeof(Oid));
|
||||
for (i = 0; i < funcform->pronargs; i++)
|
||||
{
|
||||
if (argtypes[i] == ANYARRAYOID ||
|
||||
argtypes[i] == ANYELEMENTOID)
|
||||
if (IsPolymorphicType(argtypes[i]))
|
||||
{
|
||||
argtypes[i] = exprType((Node *) list_nth(args, i));
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.584 2007/03/26 16:58:39 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.585 2007/04/02 03:49:38 tgl Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@@ -248,6 +248,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
|
||||
TableFuncElementList opt_type_modifiers
|
||||
prep_type_clause
|
||||
execute_param_clause using_clause returning_clause
|
||||
enum_val_list
|
||||
|
||||
%type <range> OptTempTableName
|
||||
%type <into> into_clause create_as_target
|
||||
@@ -383,7 +384,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
|
||||
DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS
|
||||
DESC DISABLE_P DISTINCT DO DOCUMENT_P DOMAIN_P DOUBLE_P DROP
|
||||
|
||||
EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ESCAPE EXCEPT EXCLUDING
|
||||
EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ENUM_P ESCAPE EXCEPT EXCLUDING
|
||||
EXCLUSIVE EXECUTE EXISTS EXPLAIN EXTERNAL EXTRACT
|
||||
|
||||
FALSE_P FAMILY FETCH FIRST_P FLOAT_P FOR FORCE FOREIGN FORWARD
|
||||
@@ -2922,6 +2923,13 @@ DefineStmt:
|
||||
n->coldeflist = $6;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| CREATE TYPE_P any_name AS ENUM_P '(' enum_val_list ')'
|
||||
{
|
||||
CreateEnumStmt *n = makeNode(CreateEnumStmt);
|
||||
n->typename = $3;
|
||||
n->vals = $7;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
;
|
||||
|
||||
definition: '(' def_list ')' { $$ = $2; }
|
||||
@@ -2966,6 +2974,12 @@ old_aggr_elem: IDENT '=' def_arg
|
||||
}
|
||||
;
|
||||
|
||||
enum_val_list: Sconst
|
||||
{ $$ = list_make1(makeString($1)); }
|
||||
| enum_val_list ',' Sconst
|
||||
{ $$ = lappend($1, makeString($3)); }
|
||||
;
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
@@ -8760,6 +8774,7 @@ unreserved_keyword:
|
||||
| ENABLE_P
|
||||
| ENCODING
|
||||
| ENCRYPTED
|
||||
| ENUM_P
|
||||
| ESCAPE
|
||||
| EXCLUDING
|
||||
| EXCLUSIVE
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.185 2007/03/19 23:38:29 wieck Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.186 2007/04/02 03:49:38 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -136,6 +136,7 @@ static const ScanKeyword ScanKeywords[] = {
|
||||
{"encoding", ENCODING},
|
||||
{"encrypted", ENCRYPTED},
|
||||
{"end", END_P},
|
||||
{"enum", ENUM_P},
|
||||
{"escape", ESCAPE},
|
||||
{"except", EXCEPT},
|
||||
{"excluding", EXCLUDING},
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.152 2007/03/27 23:21:10 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.153 2007/04/02 03:49:38 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -132,7 +132,8 @@ coerce_type(ParseState *pstate, Node *node,
|
||||
}
|
||||
if (targetTypeId == ANYOID ||
|
||||
targetTypeId == ANYELEMENTOID ||
|
||||
(targetTypeId == ANYARRAYOID && inputTypeId != UNKNOWNOID))
|
||||
(targetTypeId == ANYARRAYOID && inputTypeId != UNKNOWNOID) ||
|
||||
(targetTypeId == ANYENUMOID && inputTypeId != UNKNOWNOID))
|
||||
{
|
||||
/*
|
||||
* Assume can_coerce_type verified that implicit coercion is okay.
|
||||
@@ -143,7 +144,8 @@ coerce_type(ParseState *pstate, Node *node,
|
||||
* since an UNKNOWN value is still a perfectly valid Datum. However
|
||||
* an UNKNOWN value is definitely *not* an array, and so we mustn't
|
||||
* accept it for ANYARRAY. (Instead, we will call anyarray_in below,
|
||||
* which will produce an error.)
|
||||
* which will produce an error.) Likewise, UNKNOWN input is no good
|
||||
* for ANYENUM.
|
||||
*
|
||||
* NB: we do NOT want a RelabelType here.
|
||||
*/
|
||||
@@ -406,9 +408,8 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids,
|
||||
if (targetTypeId == ANYOID)
|
||||
continue;
|
||||
|
||||
/* accept if target is ANYARRAY or ANYELEMENT, for now */
|
||||
if (targetTypeId == ANYARRAYOID ||
|
||||
targetTypeId == ANYELEMENTOID)
|
||||
/* accept if target is polymorphic, for now */
|
||||
if (IsPolymorphicType(targetTypeId))
|
||||
{
|
||||
have_generics = true; /* do more checking later */
|
||||
continue;
|
||||
@@ -1048,6 +1049,9 @@ coerce_to_common_type(ParseState *pstate, Node *node,
|
||||
* 3) If there are arguments of both ANYELEMENT and ANYARRAY, make sure
|
||||
* the actual ANYELEMENT datatype is in fact the element type for
|
||||
* the actual ANYARRAY datatype.
|
||||
* 4) ANYENUM is treated the same as ANYELEMENT except that if it is used
|
||||
* (alone or in combination with plain ANYELEMENT), we add the extra
|
||||
* condition that the ANYELEMENT type must be an enum.
|
||||
*
|
||||
* If we have UNKNOWN input (ie, an untyped literal) for any ANYELEMENT
|
||||
* or ANYARRAY argument, assume it is okay.
|
||||
@@ -1070,6 +1074,7 @@ check_generic_type_consistency(Oid *actual_arg_types,
|
||||
Oid array_typeid = InvalidOid;
|
||||
Oid array_typelem;
|
||||
bool have_anyelement = false;
|
||||
bool have_anyenum = false;
|
||||
|
||||
/*
|
||||
* Loop through the arguments to see if we have any that are ANYARRAY or
|
||||
@@ -1079,9 +1084,12 @@ check_generic_type_consistency(Oid *actual_arg_types,
|
||||
{
|
||||
Oid actual_type = actual_arg_types[j];
|
||||
|
||||
if (declared_arg_types[j] == ANYELEMENTOID)
|
||||
if (declared_arg_types[j] == ANYELEMENTOID ||
|
||||
declared_arg_types[j] == ANYENUMOID)
|
||||
{
|
||||
have_anyelement = true;
|
||||
if (declared_arg_types[j] == ANYENUMOID)
|
||||
have_anyenum = true;
|
||||
if (actual_type == UNKNOWNOID)
|
||||
continue;
|
||||
if (OidIsValid(elem_typeid) && actual_type != elem_typeid)
|
||||
@@ -1127,6 +1135,13 @@ check_generic_type_consistency(Oid *actual_arg_types,
|
||||
}
|
||||
}
|
||||
|
||||
if (have_anyenum)
|
||||
{
|
||||
/* require the element type to be an enum */
|
||||
if (!type_is_enum(elem_typeid))
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Looks valid */
|
||||
return true;
|
||||
}
|
||||
@@ -1136,18 +1151,18 @@ check_generic_type_consistency(Oid *actual_arg_types,
|
||||
* Make sure a polymorphic function is legally callable, and
|
||||
* deduce actual argument and result types.
|
||||
*
|
||||
* If ANYARRAY or ANYELEMENT is used for a function's arguments or
|
||||
* If ANYARRAY, ANYELEMENT, or ANYENUM is used for a function's arguments or
|
||||
* return type, we make sure the actual data types are consistent with
|
||||
* each other. The argument consistency rules are shown above for
|
||||
* check_generic_type_consistency().
|
||||
*
|
||||
* If we have UNKNOWN input (ie, an untyped literal) for any ANYELEMENT
|
||||
* or ANYARRAY argument, we attempt to deduce the actual type it should
|
||||
* have. If successful, we alter that position of declared_arg_types[]
|
||||
* so that make_fn_arguments will coerce the literal to the right thing.
|
||||
* If we have UNKNOWN input (ie, an untyped literal) for any polymorphic
|
||||
* argument, we attempt to deduce the actual type it should have. If
|
||||
* successful, we alter that position of declared_arg_types[] so that
|
||||
* make_fn_arguments will coerce the literal to the right thing.
|
||||
*
|
||||
* Rules are applied to the function's return type (possibly altering it)
|
||||
* if it is declared ANYARRAY or ANYELEMENT:
|
||||
* if it is declared as a polymorphic type:
|
||||
*
|
||||
* 1) If return type is ANYARRAY, and any argument is ANYARRAY, use the
|
||||
* argument's actual type as the function's return type.
|
||||
@@ -1167,6 +1182,9 @@ check_generic_type_consistency(Oid *actual_arg_types,
|
||||
* 6) If return type is ANYELEMENT, no argument is ANYARRAY or ANYELEMENT,
|
||||
* generate an ERROR. This condition is prevented by CREATE FUNCTION
|
||||
* and is therefore not expected here.
|
||||
* 7) ANYENUM is treated the same as ANYELEMENT except that if it is used
|
||||
* (alone or in combination with plain ANYELEMENT), we add the extra
|
||||
* condition that the ANYELEMENT type must be an enum.
|
||||
*/
|
||||
Oid
|
||||
enforce_generic_type_consistency(Oid *actual_arg_types,
|
||||
@@ -1180,7 +1198,9 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
|
||||
Oid elem_typeid = InvalidOid;
|
||||
Oid array_typeid = InvalidOid;
|
||||
Oid array_typelem;
|
||||
bool have_anyelement = (rettype == ANYELEMENTOID);
|
||||
bool have_anyelement = (rettype == ANYELEMENTOID ||
|
||||
rettype == ANYENUMOID);
|
||||
bool have_anyenum = (rettype == ANYENUMOID);
|
||||
|
||||
/*
|
||||
* Loop through the arguments to see if we have any that are ANYARRAY or
|
||||
@@ -1190,9 +1210,12 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
|
||||
{
|
||||
Oid actual_type = actual_arg_types[j];
|
||||
|
||||
if (declared_arg_types[j] == ANYELEMENTOID)
|
||||
if (declared_arg_types[j] == ANYELEMENTOID ||
|
||||
declared_arg_types[j] == ANYENUMOID)
|
||||
{
|
||||
have_generics = have_anyelement = true;
|
||||
if (declared_arg_types[j] == ANYENUMOID)
|
||||
have_anyenum = true;
|
||||
if (actual_type == UNKNOWNOID)
|
||||
{
|
||||
have_unknowns = true;
|
||||
@@ -1227,8 +1250,8 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
|
||||
}
|
||||
|
||||
/*
|
||||
* Fast Track: if none of the arguments are ANYARRAY or ANYELEMENT, return
|
||||
* the unmodified rettype.
|
||||
* Fast Track: if none of the arguments are polymorphic, return the
|
||||
* unmodified rettype. We assume it can't be polymorphic either.
|
||||
*/
|
||||
if (!have_generics)
|
||||
return rettype;
|
||||
@@ -1274,7 +1297,17 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
|
||||
/* Only way to get here is if all the generic args are UNKNOWN */
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||
errmsg("could not determine anyarray/anyelement type because input has type \"unknown\"")));
|
||||
errmsg("could not determine polymorphic type because input has type \"unknown\"")));
|
||||
}
|
||||
|
||||
if (have_anyenum)
|
||||
{
|
||||
/* require the element type to be an enum */
|
||||
if (!type_is_enum(elem_typeid))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||
errmsg("type matched to anyenum is not an enum type: %s",
|
||||
format_type_be(elem_typeid))));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1289,7 +1322,8 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
|
||||
if (actual_type != UNKNOWNOID)
|
||||
continue;
|
||||
|
||||
if (declared_arg_types[j] == ANYELEMENTOID)
|
||||
if (declared_arg_types[j] == ANYELEMENTOID ||
|
||||
declared_arg_types[j] == ANYENUMOID)
|
||||
declared_arg_types[j] = elem_typeid;
|
||||
else if (declared_arg_types[j] == ANYARRAYOID)
|
||||
{
|
||||
@@ -1307,7 +1341,7 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
|
||||
}
|
||||
}
|
||||
|
||||
/* if we return ANYARRAYOID use the appropriate argument type */
|
||||
/* if we return ANYARRAY use the appropriate argument type */
|
||||
if (rettype == ANYARRAYOID)
|
||||
{
|
||||
if (!OidIsValid(array_typeid))
|
||||
@@ -1322,8 +1356,8 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
|
||||
return array_typeid;
|
||||
}
|
||||
|
||||
/* if we return ANYELEMENTOID use the appropriate argument type */
|
||||
if (rettype == ANYELEMENTOID)
|
||||
/* if we return ANYELEMENT use the appropriate argument type */
|
||||
if (rettype == ANYELEMENTOID || rettype == ANYENUMOID)
|
||||
return elem_typeid;
|
||||
|
||||
/* we don't return a generic type; send back the original return type */
|
||||
@@ -1333,7 +1367,7 @@ enforce_generic_type_consistency(Oid *actual_arg_types,
|
||||
/*
|
||||
* resolve_generic_type()
|
||||
* Deduce an individual actual datatype on the assumption that
|
||||
* the rules for ANYARRAY/ANYELEMENT are being followed.
|
||||
* the rules for polymorphic types are being followed.
|
||||
*
|
||||
* declared_type is the declared datatype we want to resolve.
|
||||
* context_actual_type is the actual input datatype to some argument
|
||||
@@ -1362,7 +1396,8 @@ resolve_generic_type(Oid declared_type,
|
||||
format_type_be(context_actual_type))));
|
||||
return context_actual_type;
|
||||
}
|
||||
else if (context_declared_type == ANYELEMENTOID)
|
||||
else if (context_declared_type == ANYELEMENTOID ||
|
||||
context_declared_type == ANYENUMOID)
|
||||
{
|
||||
/* Use the array type corresponding to actual type */
|
||||
Oid array_typeid = get_array_type(context_actual_type);
|
||||
@@ -1375,7 +1410,7 @@ resolve_generic_type(Oid declared_type,
|
||||
return array_typeid;
|
||||
}
|
||||
}
|
||||
else if (declared_type == ANYELEMENTOID)
|
||||
else if (declared_type == ANYELEMENTOID || declared_type == ANYENUMOID)
|
||||
{
|
||||
if (context_declared_type == ANYARRAYOID)
|
||||
{
|
||||
@@ -1389,7 +1424,8 @@ resolve_generic_type(Oid declared_type,
|
||||
format_type_be(context_actual_type))));
|
||||
return array_typelem;
|
||||
}
|
||||
else if (context_declared_type == ANYELEMENTOID)
|
||||
else if (context_declared_type == ANYELEMENTOID ||
|
||||
context_declared_type == ANYENUMOID)
|
||||
{
|
||||
/* Use the actual type; it doesn't matter if array or not */
|
||||
return context_actual_type;
|
||||
@@ -1402,7 +1438,7 @@ resolve_generic_type(Oid declared_type,
|
||||
}
|
||||
/* If we get here, declared_type is polymorphic and context isn't */
|
||||
/* NB: this is a calling-code logic error, not a user error */
|
||||
elog(ERROR, "could not determine ANYARRAY/ANYELEMENT type because context isn't polymorphic");
|
||||
elog(ERROR, "could not determine polymorphic type because context isn't polymorphic");
|
||||
return InvalidOid; /* keep compiler quiet */
|
||||
}
|
||||
|
||||
@@ -1502,6 +1538,7 @@ TypeCategory(Oid inType)
|
||||
case (INTERNALOID):
|
||||
case (OPAQUEOID):
|
||||
case (ANYELEMENTOID):
|
||||
case (ANYENUMOID):
|
||||
result = GENERIC_TYPE;
|
||||
break;
|
||||
|
||||
@@ -1647,6 +1684,11 @@ IsBinaryCoercible(Oid srctype, Oid targettype)
|
||||
if (get_element_type(srctype) != InvalidOid)
|
||||
return true;
|
||||
|
||||
/* Also accept any enum type as coercible to ANYENUM */
|
||||
if (targettype == ANYENUMOID)
|
||||
if (type_is_enum(srctype))
|
||||
return true;
|
||||
|
||||
/* Else look in pg_cast */
|
||||
tuple = SearchSysCache(CASTSOURCETARGET,
|
||||
ObjectIdGetDatum(srctype),
|
||||
@@ -1777,6 +1819,22 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId,
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we still haven't found a possibility, check for enums,
|
||||
* and retry looking for a cast to or from ANYENUM. But don't
|
||||
* mistakenly conclude that ANYENUM-to-some-enum-type is a
|
||||
* trivial cast.
|
||||
*/
|
||||
if (!result)
|
||||
{
|
||||
if (type_is_enum(sourceTypeId))
|
||||
result = find_coercion_pathway(targetTypeId, ANYENUMOID,
|
||||
ccontext, funcid, arrayCoerce);
|
||||
else if (sourceTypeId != ANYENUMOID && type_is_enum(targetTypeId))
|
||||
result = find_coercion_pathway(ANYENUMOID, sourceTypeId,
|
||||
ccontext, funcid, arrayCoerce);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -1813,7 +1871,7 @@ find_typmod_coercion_function(Oid typeId,
|
||||
/* Check for a varlena array type (and not a domain) */
|
||||
if (typeForm->typelem != InvalidOid &&
|
||||
typeForm->typlen == -1 &&
|
||||
typeForm->typtype != 'd')
|
||||
typeForm->typtype != TYPTYPE_DOMAIN)
|
||||
{
|
||||
/* Yes, switch our attention to the element type */
|
||||
typeId = typeForm->typelem;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.215 2007/03/27 23:21:10 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.216 2007/04/02 03:49:39 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1627,7 +1627,7 @@ transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname,
|
||||
break;
|
||||
case RTE_FUNCTION:
|
||||
toid = exprType(rte->funcexpr);
|
||||
if (toid == RECORDOID || get_typtype(toid) == 'c')
|
||||
if (type_is_rowtype(toid))
|
||||
{
|
||||
/* func returns composite; same as relation case */
|
||||
result = (Node *) makeVar(vnum,
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_oper.c,v 1.94 2007/02/01 19:10:27 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_oper.c,v 1.95 2007/04/02 03:49:39 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -886,8 +886,8 @@ make_scalar_array_op(ParseState *pstate, List *opname,
|
||||
declared_arg_types[1] = opform->oprright;
|
||||
|
||||
/*
|
||||
* enforce consistency with ANYARRAY and ANYELEMENT argument and return
|
||||
* types, possibly adjusting return type or declared_arg_types (which will
|
||||
* enforce consistency with polymorphic argument and return types,
|
||||
* possibly adjusting return type or declared_arg_types (which will
|
||||
* be used as the cast destination by make_fn_arguments)
|
||||
*/
|
||||
rettype = enforce_generic_type_consistency(actual_arg_types,
|
||||
@@ -911,15 +911,25 @@ make_scalar_array_op(ParseState *pstate, List *opname,
|
||||
|
||||
/*
|
||||
* Now switch back to the array type on the right, arranging for any
|
||||
* needed cast to be applied.
|
||||
* needed cast to be applied. Beware of polymorphic operators here;
|
||||
* enforce_generic_type_consistency may or may not have replaced a
|
||||
* polymorphic type with a real one.
|
||||
*/
|
||||
res_atypeId = get_array_type(declared_arg_types[1]);
|
||||
if (!OidIsValid(res_atypeId))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("could not find array type for data type %s",
|
||||
format_type_be(declared_arg_types[1])),
|
||||
parser_errposition(pstate, location)));
|
||||
if (IsPolymorphicType(declared_arg_types[1]))
|
||||
{
|
||||
/* assume the actual array type is OK */
|
||||
res_atypeId = atypeId;
|
||||
}
|
||||
else
|
||||
{
|
||||
res_atypeId = get_array_type(declared_arg_types[1]);
|
||||
if (!OidIsValid(res_atypeId))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("could not find array type for data type %s",
|
||||
format_type_be(declared_arg_types[1])),
|
||||
parser_errposition(pstate, location)));
|
||||
}
|
||||
actual_arg_types[1] = atypeId;
|
||||
declared_arg_types[1] = res_atypeId;
|
||||
|
||||
@@ -986,8 +996,8 @@ make_op_expr(ParseState *pstate, Operator op,
|
||||
}
|
||||
|
||||
/*
|
||||
* enforce consistency with ANYARRAY and ANYELEMENT argument and return
|
||||
* types, possibly adjusting return type or declared_arg_types (which will
|
||||
* enforce consistency with polymorphic argument and return types,
|
||||
* possibly adjusting return type or declared_arg_types (which will
|
||||
* be used as the cast destination by make_fn_arguments)
|
||||
*/
|
||||
rettype = enforce_generic_type_consistency(actual_arg_types,
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.87 2007/01/05 22:19:34 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.88 2007/04/02 03:49:39 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -398,16 +398,6 @@ typeByVal(Type t)
|
||||
return typ->typbyval;
|
||||
}
|
||||
|
||||
/* given type (as type struct), return the value of its 'typtype' attribute.*/
|
||||
char
|
||||
typeTypType(Type t)
|
||||
{
|
||||
Form_pg_type typ;
|
||||
|
||||
typ = (Form_pg_type) GETSTRUCT(t);
|
||||
return typ->typtype;
|
||||
}
|
||||
|
||||
/* given type (as type struct), return the name of type */
|
||||
char *
|
||||
typeTypeName(Type t)
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.275 2007/03/26 16:58:39 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.276 2007/04/02 03:49:39 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -337,6 +337,7 @@ check_xact_readonly(Node *parsetree)
|
||||
case T_CreateTableSpaceStmt:
|
||||
case T_CreateTrigStmt:
|
||||
case T_CompositeTypeStmt:
|
||||
case T_CreateEnumStmt:
|
||||
case T_ViewStmt:
|
||||
case T_DropCastStmt:
|
||||
case T_DropStmt:
|
||||
@@ -779,6 +780,10 @@ ProcessUtility(Node *parsetree,
|
||||
}
|
||||
break;
|
||||
|
||||
case T_CreateEnumStmt: /* CREATE TYPE (enum) */
|
||||
DefineEnum((CreateEnumStmt *) parsetree);
|
||||
break;
|
||||
|
||||
case T_ViewStmt: /* CREATE VIEW */
|
||||
DefineView((ViewStmt *) parsetree, queryString);
|
||||
break;
|
||||
@@ -1640,6 +1645,10 @@ CreateCommandTag(Node *parsetree)
|
||||
tag = "CREATE TYPE";
|
||||
break;
|
||||
|
||||
case T_CreateEnumStmt:
|
||||
tag = "CREATE TYPE";
|
||||
break;
|
||||
|
||||
case T_ViewStmt:
|
||||
tag = "CREATE VIEW";
|
||||
break;
|
||||
@@ -2075,6 +2084,10 @@ GetCommandLogLevel(Node *parsetree)
|
||||
lev = LOGSTMT_DDL;
|
||||
break;
|
||||
|
||||
case T_CreateEnumStmt:
|
||||
lev = LOGSTMT_DDL;
|
||||
break;
|
||||
|
||||
case T_ViewStmt:
|
||||
lev = LOGSTMT_DDL;
|
||||
break;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
# Makefile for utils/adt
|
||||
#
|
||||
# $PostgreSQL: pgsql/src/backend/utils/adt/Makefile,v 1.63 2007/01/28 16:16:52 neilc Exp $
|
||||
# $PostgreSQL: pgsql/src/backend/utils/adt/Makefile,v 1.64 2007/04/02 03:49:39 tgl Exp $
|
||||
#
|
||||
|
||||
subdir = src/backend/utils/adt
|
||||
@@ -17,7 +17,7 @@ endif
|
||||
|
||||
OBJS = acl.o arrayfuncs.o array_userfuncs.o arrayutils.o bool.o \
|
||||
cash.o char.o date.o datetime.o datum.o domains.o \
|
||||
float.o format_type.o \
|
||||
enum.o float.o format_type.o \
|
||||
geo_ops.o geo_selfuncs.o int.o int8.o like.o lockfuncs.o \
|
||||
misc.o nabstime.o name.o not_in.o numeric.o numutils.o \
|
||||
oid.o oracle_compat.o pseudotypes.o rowtypes.o \
|
||||
|
||||
409
src/backend/utils/adt/enum.c
Normal file
409
src/backend/utils/adt/enum.c
Normal file
@@ -0,0 +1,409 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* enum.c
|
||||
* I/O functions, operators, aggregates etc for enum types
|
||||
*
|
||||
* Copyright (c) 2006-2007, PostgreSQL Global Development Group
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/enum.c,v 1.1 2007/04/02 03:49:39 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include "catalog/pg_enum.h"
|
||||
#include "fmgr.h"
|
||||
#include "utils/array.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/syscache.h"
|
||||
|
||||
|
||||
static Oid cstring_enum(char *name, Oid enumtypoid);
|
||||
static char *enum_cstring(Oid enumval);
|
||||
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 */
|
||||
|
||||
Datum
|
||||
enum_in(PG_FUNCTION_ARGS)
|
||||
{
|
||||
char *name = PG_GETARG_CSTRING(0);
|
||||
Oid enumtypoid = PG_GETARG_OID(1);
|
||||
|
||||
PG_RETURN_OID(cstring_enum(name, enumtypoid));
|
||||
}
|
||||
|
||||
/* guts of enum_in and text-to-enum */
|
||||
static Oid
|
||||
cstring_enum(char *name, Oid enumtypoid)
|
||||
{
|
||||
HeapTuple tup;
|
||||
Oid enumoid;
|
||||
|
||||
tup = SearchSysCache(ENUMTYPOIDNAME,
|
||||
ObjectIdGetDatum(enumtypoid),
|
||||
CStringGetDatum(name),
|
||||
0, 0);
|
||||
if (tup == NULL)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||
errmsg("invalid input value for enum %s: \"%s\"",
|
||||
format_type_be(enumtypoid),
|
||||
name)));
|
||||
|
||||
enumoid = HeapTupleGetOid(tup);
|
||||
|
||||
ReleaseSysCache(tup);
|
||||
return enumoid;
|
||||
}
|
||||
|
||||
Datum
|
||||
enum_out(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid enumoid = PG_GETARG_OID(0);
|
||||
|
||||
PG_RETURN_CSTRING(enum_cstring(enumoid));
|
||||
}
|
||||
|
||||
/* guts of enum_out and enum-to-text */
|
||||
static char *
|
||||
enum_cstring(Oid enumval)
|
||||
{
|
||||
HeapTuple tup;
|
||||
Form_pg_enum en;
|
||||
char *label;
|
||||
|
||||
tup = SearchSysCache(ENUMOID,
|
||||
ObjectIdGetDatum(enumval),
|
||||
0, 0, 0);
|
||||
if (tup == NULL)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
|
||||
errmsg("invalid internal value for enum: %u",
|
||||
enumval)));
|
||||
en = (Form_pg_enum) GETSTRUCT(tup);
|
||||
|
||||
label = pstrdup(NameStr(en->enumlabel));
|
||||
|
||||
ReleaseSysCache(tup);
|
||||
return label;
|
||||
}
|
||||
|
||||
/* 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
|
||||
enum_le(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid a = PG_GETARG_OID(0);
|
||||
Oid b = PG_GETARG_OID(1);
|
||||
|
||||
PG_RETURN_BOOL(a <= b);
|
||||
}
|
||||
|
||||
Datum
|
||||
enum_eq(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid a = PG_GETARG_OID(0);
|
||||
Oid b = PG_GETARG_OID(1);
|
||||
|
||||
PG_RETURN_BOOL(a == b);
|
||||
}
|
||||
|
||||
Datum
|
||||
enum_ne(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid a = PG_GETARG_OID(0);
|
||||
Oid b = PG_GETARG_OID(1);
|
||||
|
||||
PG_RETURN_BOOL(a != b);
|
||||
}
|
||||
|
||||
Datum
|
||||
enum_ge(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid a = PG_GETARG_OID(0);
|
||||
Oid b = PG_GETARG_OID(1);
|
||||
|
||||
PG_RETURN_BOOL(a >= b);
|
||||
}
|
||||
|
||||
Datum
|
||||
enum_gt(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid a = PG_GETARG_OID(0);
|
||||
Oid b = PG_GETARG_OID(1);
|
||||
|
||||
PG_RETURN_BOOL(a > b);
|
||||
}
|
||||
|
||||
Datum
|
||||
enum_smaller(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid a = PG_GETARG_OID(0);
|
||||
Oid b = PG_GETARG_OID(1);
|
||||
|
||||
PG_RETURN_OID(a <= b ? a : b);
|
||||
}
|
||||
|
||||
Datum
|
||||
enum_larger(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid a = PG_GETARG_OID(0);
|
||||
Oid b = PG_GETARG_OID(1);
|
||||
|
||||
PG_RETURN_OID(a >= b ? a : b);
|
||||
}
|
||||
|
||||
Datum
|
||||
enum_cmp(PG_FUNCTION_ARGS)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
/* Casts between text and enum */
|
||||
|
||||
Datum
|
||||
enum_text(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid enumval = PG_GETARG_OID(0);
|
||||
text *result;
|
||||
char *cstr;
|
||||
int len;
|
||||
|
||||
cstr = enum_cstring(enumval);
|
||||
len = strlen(cstr);
|
||||
result = (text *) palloc(VARHDRSZ + len);
|
||||
SET_VARSIZE(result, VARHDRSZ + len);
|
||||
memcpy(VARDATA(result), cstr, len);
|
||||
pfree(cstr);
|
||||
PG_RETURN_TEXT_P(result);
|
||||
}
|
||||
|
||||
Datum
|
||||
text_enum(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *textval = PG_GETARG_TEXT_P(0);
|
||||
Oid enumtypoid;
|
||||
char *str;
|
||||
|
||||
/*
|
||||
* We rely on being able to get the specific enum type from the calling
|
||||
* expression tree.
|
||||
*/
|
||||
enumtypoid = get_fn_expr_rettype(fcinfo->flinfo);
|
||||
if (enumtypoid == InvalidOid)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("could not determine actual enum type")));
|
||||
|
||||
str = DatumGetCString(DirectFunctionCall1(textout,
|
||||
PointerGetDatum(textval)));
|
||||
PG_RETURN_OID(cstring_enum(str, enumtypoid));
|
||||
}
|
||||
|
||||
/* Enum programming support functions */
|
||||
|
||||
Datum
|
||||
enum_first(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid enumtypoid;
|
||||
Oid min = InvalidOid;
|
||||
CatCList *list;
|
||||
int num, i;
|
||||
|
||||
/*
|
||||
* We rely on being able to get the specific enum type from the calling
|
||||
* expression tree. Notice that the actual value of the argument isn't
|
||||
* examined at all; in particular it might be NULL.
|
||||
*/
|
||||
enumtypoid = get_fn_expr_argtype(fcinfo->flinfo, 0);
|
||||
if (enumtypoid == InvalidOid)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("could not determine actual enum type")));
|
||||
|
||||
list = SearchSysCacheList(ENUMTYPOIDNAME, 1,
|
||||
ObjectIdGetDatum(enumtypoid),
|
||||
0, 0, 0);
|
||||
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);
|
||||
|
||||
if (!OidIsValid(min)) /* should not happen */
|
||||
elog(ERROR, "no values found for enum %s",
|
||||
format_type_be(enumtypoid));
|
||||
|
||||
PG_RETURN_OID(min);
|
||||
}
|
||||
|
||||
Datum
|
||||
enum_last(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid enumtypoid;
|
||||
Oid max = InvalidOid;
|
||||
CatCList *list;
|
||||
int num, i;
|
||||
|
||||
/*
|
||||
* We rely on being able to get the specific enum type from the calling
|
||||
* expression tree. Notice that the actual value of the argument isn't
|
||||
* examined at all; in particular it might be NULL.
|
||||
*/
|
||||
enumtypoid = get_fn_expr_argtype(fcinfo->flinfo, 0);
|
||||
if (enumtypoid == InvalidOid)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("could not determine actual enum type")));
|
||||
|
||||
list = SearchSysCacheList(ENUMTYPOIDNAME, 1,
|
||||
ObjectIdGetDatum(enumtypoid),
|
||||
0, 0, 0);
|
||||
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);
|
||||
|
||||
if (!OidIsValid(max)) /* should not happen */
|
||||
elog(ERROR, "no values found for enum %s",
|
||||
format_type_be(enumtypoid));
|
||||
|
||||
PG_RETURN_OID(max);
|
||||
}
|
||||
|
||||
/* 2-argument variant of enum_range */
|
||||
Datum
|
||||
enum_range_bounds(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid lower;
|
||||
Oid upper;
|
||||
Oid enumtypoid;
|
||||
|
||||
if (PG_ARGISNULL(0))
|
||||
lower = InvalidOid;
|
||||
else
|
||||
lower = PG_GETARG_OID(0);
|
||||
if (PG_ARGISNULL(1))
|
||||
upper = InvalidOid;
|
||||
else
|
||||
upper = PG_GETARG_OID(1);
|
||||
|
||||
/*
|
||||
* We rely on being able to get the specific enum type from the calling
|
||||
* expression tree. The generic type mechanism should have ensured that
|
||||
* both are of the same type.
|
||||
*/
|
||||
enumtypoid = get_fn_expr_argtype(fcinfo->flinfo, 0);
|
||||
if (enumtypoid == InvalidOid)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("could not determine actual enum type")));
|
||||
|
||||
PG_RETURN_ARRAYTYPE_P(enum_range_internal(enumtypoid, lower, upper));
|
||||
}
|
||||
|
||||
/* 1-argument variant of enum_range */
|
||||
Datum
|
||||
enum_range_all(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid enumtypoid;
|
||||
|
||||
/*
|
||||
* We rely on being able to get the specific enum type from the calling
|
||||
* expression tree. Notice that the actual value of the argument isn't
|
||||
* examined at all; in particular it might be NULL.
|
||||
*/
|
||||
enumtypoid = get_fn_expr_argtype(fcinfo->flinfo, 0);
|
||||
if (enumtypoid == InvalidOid)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("could not determine actual enum type")));
|
||||
|
||||
PG_RETURN_ARRAYTYPE_P(enum_range_internal(enumtypoid,
|
||||
InvalidOid, InvalidOid));
|
||||
}
|
||||
|
||||
static ArrayType *
|
||||
enum_range_internal(Oid enumtypoid, Oid lower, Oid upper)
|
||||
{
|
||||
ArrayType *result;
|
||||
CatCList *list;
|
||||
int total, i, j;
|
||||
Datum *elems;
|
||||
|
||||
list = SearchSysCacheList(ENUMTYPOIDNAME, 1,
|
||||
ObjectIdGetDatum(enumtypoid),
|
||||
0, 0, 0);
|
||||
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;
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/format_type.c,v 1.46 2007/01/05 22:19:40 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/format_type.c,v 1.47 2007/04/02 03:49:39 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -148,7 +148,7 @@ format_type_internal(Oid type_oid, int32 typemod,
|
||||
|
||||
if (array_base_type != InvalidOid &&
|
||||
typeform->typstorage != 'p' &&
|
||||
typeform->typtype != 'd')
|
||||
typeform->typtype != TYPTYPE_DOMAIN)
|
||||
{
|
||||
/* Switch our attention to the array element type */
|
||||
ReleaseSysCache(tuple);
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/pseudotypes.c,v 1.18 2007/01/05 22:19:41 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/pseudotypes.c,v 1.19 2007/04/02 03:49:39 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -163,6 +163,31 @@ anyarray_send(PG_FUNCTION_ARGS)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* anyenum_in - input routine for pseudo-type ANYENUM.
|
||||
*/
|
||||
Datum
|
||||
anyenum_in(PG_FUNCTION_ARGS)
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("cannot accept a value of type anyenum")));
|
||||
|
||||
PG_RETURN_VOID(); /* keep compiler quiet */
|
||||
}
|
||||
|
||||
/*
|
||||
* anyenum_out - output routine for pseudo-type ANYENUM.
|
||||
*
|
||||
* We may as well allow this, since enum_out will in fact work.
|
||||
*/
|
||||
Datum
|
||||
anyenum_out(PG_FUNCTION_ARGS)
|
||||
{
|
||||
return enum_out(fcinfo);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* void_in - input routine for pseudo-type VOID.
|
||||
*
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.38 2007/04/01 09:00:25 petere Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.39 2007/04/02 03:49:39 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -2648,7 +2648,7 @@ map_sql_type_to_xml_name(Oid typeoid, int typmod)
|
||||
Form_pg_type typtuple = (Form_pg_type) GETSTRUCT(tuple);
|
||||
|
||||
appendStringInfoString(&result,
|
||||
map_multipart_sql_identifier_to_xml_name((typtuple->typtype == 'd') ? "Domain" : "UDT",
|
||||
map_multipart_sql_identifier_to_xml_name((typtuple->typtype == TYPTYPE_DOMAIN) ? "Domain" : "UDT",
|
||||
get_database_name(MyDatabaseId),
|
||||
get_namespace_name(typtuple->typnamespace),
|
||||
NameStr(typtuple->typname)));
|
||||
@@ -2877,7 +2877,7 @@ map_sql_type_to_xmlschema_type(Oid typeoid, int typmod)
|
||||
break;
|
||||
|
||||
default:
|
||||
if (get_typtype(typeoid) == 'd')
|
||||
if (get_typtype(typeoid) == TYPTYPE_DOMAIN)
|
||||
{
|
||||
Oid base_typeoid;
|
||||
int32 base_typmod = -1;
|
||||
|
||||
18
src/backend/utils/cache/lsyscache.c
vendored
18
src/backend/utils/cache/lsyscache.c
vendored
@@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.150 2007/03/19 16:30:31 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.151 2007/04/02 03:49:39 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Eventually, the index information should go through here, too.
|
||||
@@ -1770,7 +1770,7 @@ getTypeIOParam(HeapTuple typeTuple)
|
||||
* own type OID as parameter. (As of 8.2, domains must get their own OID
|
||||
* even if their base type is an array.)
|
||||
*/
|
||||
if (typeStruct->typtype == 'b' && OidIsValid(typeStruct->typelem))
|
||||
if (typeStruct->typtype == TYPTYPE_BASE && OidIsValid(typeStruct->typelem))
|
||||
return typeStruct->typelem;
|
||||
else
|
||||
return HeapTupleGetOid(typeTuple);
|
||||
@@ -2022,7 +2022,7 @@ getBaseTypeAndTypmod(Oid typid, int32 *typmod)
|
||||
if (!HeapTupleIsValid(tup))
|
||||
elog(ERROR, "cache lookup failed for type %u", typid);
|
||||
typTup = (Form_pg_type) GETSTRUCT(tup);
|
||||
if (typTup->typtype != 'd')
|
||||
if (typTup->typtype != TYPTYPE_DOMAIN)
|
||||
{
|
||||
/* Not a domain, so done */
|
||||
ReleaseSysCache(tup);
|
||||
@@ -2128,7 +2128,17 @@ get_typtype(Oid typid)
|
||||
bool
|
||||
type_is_rowtype(Oid typid)
|
||||
{
|
||||
return (typid == RECORDOID || get_typtype(typid) == 'c');
|
||||
return (typid == RECORDOID || get_typtype(typid) == TYPTYPE_COMPOSITE);
|
||||
}
|
||||
|
||||
/*
|
||||
* type_is_enum
|
||||
* Returns true if the given type is an enum type.
|
||||
*/
|
||||
bool
|
||||
type_is_enum(Oid typid)
|
||||
{
|
||||
return (get_typtype(typid) == TYPTYPE_ENUM);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
27
src/backend/utils/cache/syscache.c
vendored
27
src/backend/utils/cache/syscache.c
vendored
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.111 2007/02/14 01:58:57 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.112 2007/04/02 03:49:39 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* These routines allow the parser/planner/executor to perform
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "catalog/pg_constraint.h"
|
||||
#include "catalog/pg_conversion.h"
|
||||
#include "catalog/pg_database.h"
|
||||
#include "catalog/pg_enum.h"
|
||||
#include "catalog/pg_language.h"
|
||||
#include "catalog/pg_namespace.h"
|
||||
#include "catalog/pg_opclass.h"
|
||||
@@ -335,6 +336,30 @@ static const struct cachedesc cacheinfo[] = {
|
||||
},
|
||||
4
|
||||
},
|
||||
{EnumRelationId, /* ENUMOID */
|
||||
EnumOidIndexId,
|
||||
0,
|
||||
1,
|
||||
{
|
||||
ObjectIdAttributeNumber,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
},
|
||||
256
|
||||
},
|
||||
{EnumRelationId, /* ENUMTYPOIDNAME */
|
||||
EnumTypIdLabelIndexId,
|
||||
0,
|
||||
2,
|
||||
{
|
||||
Anum_pg_enum_enumtypid,
|
||||
Anum_pg_enum_enumlabel,
|
||||
0,
|
||||
0
|
||||
},
|
||||
256
|
||||
},
|
||||
{IndexRelationId, /* INDEXRELID */
|
||||
IndexRelidIndexId,
|
||||
Anum_pg_index_indrelid,
|
||||
|
||||
4
src/backend/utils/cache/typcache.c
vendored
4
src/backend/utils/cache/typcache.c
vendored
@@ -36,7 +36,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/cache/typcache.c,v 1.24 2007/01/05 22:19:43 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/cache/typcache.c,v 1.25 2007/04/02 03:49:39 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -275,7 +275,7 @@ lookup_type_cache(Oid type_id, int flags)
|
||||
*/
|
||||
if ((flags & TYPECACHE_TUPDESC) &&
|
||||
typentry->tupDesc == NULL &&
|
||||
typentry->typtype == 'c')
|
||||
typentry->typtype == TYPTYPE_COMPOSITE)
|
||||
{
|
||||
Relation rel;
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* Copyright (c) 2002-2007, PostgreSQL Global Development Group
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/fmgr/funcapi.c,v 1.33 2007/02/01 19:10:28 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/fmgr/funcapi.c,v 1.34 2007/04/02 03:49:39 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -193,8 +193,8 @@ shutdown_MultiFuncCall(Datum arg)
|
||||
* only when we couldn't resolve the actual rowtype for lack of information.
|
||||
*
|
||||
* The other hard case that this handles is resolution of polymorphism.
|
||||
* We will never return ANYELEMENT or ANYARRAY, either as a scalar result
|
||||
* type or as a component of a rowtype.
|
||||
* We will never return ANYELEMENT, ANYARRAY or ANYENUM, either as a scalar
|
||||
* result type or as a component of a rowtype.
|
||||
*
|
||||
* This function is relatively expensive --- in a function returning set,
|
||||
* try to call it only the first time through.
|
||||
@@ -338,7 +338,7 @@ internal_get_result_type(Oid funcid,
|
||||
/*
|
||||
* If scalar polymorphic result, try to resolve it.
|
||||
*/
|
||||
if (rettype == ANYARRAYOID || rettype == ANYELEMENTOID)
|
||||
if (IsPolymorphicType(rettype))
|
||||
{
|
||||
Oid newrettype = exprType(call_expr);
|
||||
|
||||
@@ -389,8 +389,8 @@ internal_get_result_type(Oid funcid,
|
||||
|
||||
/*
|
||||
* Given the result tuple descriptor for a function with OUT parameters,
|
||||
* replace any polymorphic columns (ANYELEMENT/ANYARRAY) with correct data
|
||||
* types deduced from the input arguments. Returns TRUE if able to deduce
|
||||
* replace any polymorphic columns (ANYELEMENT/ANYARRAY/ANYENUM) with correct
|
||||
* data types deduced from the input arguments. Returns TRUE if able to deduce
|
||||
* all types, FALSE if not.
|
||||
*/
|
||||
static bool
|
||||
@@ -401,6 +401,7 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
|
||||
int nargs = declared_args->dim1;
|
||||
bool have_anyelement_result = false;
|
||||
bool have_anyarray_result = false;
|
||||
bool have_anyenum = false;
|
||||
Oid anyelement_type = InvalidOid;
|
||||
Oid anyarray_type = InvalidOid;
|
||||
int i;
|
||||
@@ -416,6 +417,10 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
|
||||
case ANYARRAYOID:
|
||||
have_anyarray_result = true;
|
||||
break;
|
||||
case ANYENUMOID:
|
||||
have_anyelement_result = true;
|
||||
have_anyenum = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -435,6 +440,7 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
|
||||
switch (declared_args->values[i])
|
||||
{
|
||||
case ANYELEMENTOID:
|
||||
case ANYENUMOID:
|
||||
if (!OidIsValid(anyelement_type))
|
||||
anyelement_type = get_call_expr_argtype(call_expr, i);
|
||||
break;
|
||||
@@ -461,12 +467,17 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
|
||||
anyelement_type,
|
||||
ANYELEMENTOID);
|
||||
|
||||
/* Check for enum if needed */
|
||||
if (have_anyenum && !type_is_enum(anyelement_type))
|
||||
return false;
|
||||
|
||||
/* And finally replace the tuple column types as needed */
|
||||
for (i = 0; i < natts; i++)
|
||||
{
|
||||
switch (tupdesc->attrs[i]->atttypid)
|
||||
{
|
||||
case ANYELEMENTOID:
|
||||
case ANYENUMOID:
|
||||
TupleDescInitEntry(tupdesc, i + 1,
|
||||
NameStr(tupdesc->attrs[i]->attname),
|
||||
anyelement_type,
|
||||
@@ -490,8 +501,8 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
|
||||
|
||||
/*
|
||||
* Given the declared argument types and modes for a function,
|
||||
* replace any polymorphic types (ANYELEMENT/ANYARRAY) with correct data
|
||||
* types deduced from the input arguments. Returns TRUE if able to deduce
|
||||
* replace any polymorphic types (ANYELEMENT/ANYARRAY/ANYENUM) with correct
|
||||
* data types deduced from the input arguments. Returns TRUE if able to deduce
|
||||
* all types, FALSE if not. This is the same logic as
|
||||
* resolve_polymorphic_tupdesc, but with a different argument representation.
|
||||
*
|
||||
@@ -517,6 +528,7 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
|
||||
switch (argtypes[i])
|
||||
{
|
||||
case ANYELEMENTOID:
|
||||
case ANYENUMOID:
|
||||
if (argmode == PROARGMODE_OUT)
|
||||
have_anyelement_result = true;
|
||||
else
|
||||
@@ -571,12 +583,15 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
|
||||
anyelement_type,
|
||||
ANYELEMENTOID);
|
||||
|
||||
/* XXX do we need to enforce ANYENUM here? I think not */
|
||||
|
||||
/* And finally replace the output column types as needed */
|
||||
for (i = 0; i < numargs; i++)
|
||||
{
|
||||
switch (argtypes[i])
|
||||
{
|
||||
case ANYELEMENTOID:
|
||||
case ANYENUMOID:
|
||||
argtypes[i] = anyelement_type;
|
||||
break;
|
||||
case ANYARRAYOID:
|
||||
@@ -603,12 +618,13 @@ get_type_func_class(Oid typid)
|
||||
{
|
||||
switch (get_typtype(typid))
|
||||
{
|
||||
case 'c':
|
||||
case TYPTYPE_COMPOSITE:
|
||||
return TYPEFUNC_COMPOSITE;
|
||||
case 'b':
|
||||
case 'd':
|
||||
case TYPTYPE_BASE:
|
||||
case TYPTYPE_DOMAIN:
|
||||
case TYPTYPE_ENUM:
|
||||
return TYPEFUNC_SCALAR;
|
||||
case 'p':
|
||||
case TYPTYPE_PSEUDO:
|
||||
if (typid == RECORDOID)
|
||||
return TYPEFUNC_RECORD;
|
||||
|
||||
@@ -840,7 +856,7 @@ get_func_result_name(Oid functionId)
|
||||
* Given a pg_proc row for a function, return a tuple descriptor for the
|
||||
* result rowtype, or NULL if the function does not have OUT parameters.
|
||||
*
|
||||
* Note that this does not handle resolution of ANYELEMENT/ANYARRAY types;
|
||||
* Note that this does not handle resolution of polymorphic types;
|
||||
* that is deliberate.
|
||||
*/
|
||||
TupleDesc
|
||||
|
||||
Reference in New Issue
Block a user