aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands')
-rw-r--r--src/backend/commands/tablecmds.c44
-rw-r--r--src/backend/commands/typecmds.c104
2 files changed, 131 insertions, 17 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 2a1116f7580..c30aa69c555 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.207 2006/12/23 00:43:09 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.208 2006/12/30 21:21:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -889,6 +889,9 @@ MergeAttributes(List *schema, List *supers, bool istemp,
exist_attno = findAttrByName(attributeName, inhSchema);
if (exist_attno > 0)
{
+ Oid defTypeId;
+ int32 deftypmod;
+
/*
* Yes, try to merge the two column definitions. They must
* have the same type and typmod.
@@ -897,8 +900,10 @@ MergeAttributes(List *schema, List *supers, bool istemp,
(errmsg("merging multiple inherited definitions of column \"%s\"",
attributeName)));
def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1);
- if (typenameTypeId(NULL, def->typename) != attribute->atttypid ||
- def->typename->typmod != attribute->atttypmod)
+ defTypeId = typenameTypeId(NULL, def->typename);
+ deftypmod = typenameTypeMod(NULL, def->typename, defTypeId);
+ if (defTypeId != attribute->atttypid ||
+ deftypmod != attribute->atttypmod)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("inherited column \"%s\" has a type conflict",
@@ -1029,6 +1034,8 @@ MergeAttributes(List *schema, List *supers, bool istemp,
if (exist_attno > 0)
{
ColumnDef *def;
+ Oid defTypeId, newTypeId;
+ int32 deftypmod, newtypmod;
/*
* Yes, try to merge the two column definitions. They must
@@ -1038,8 +1045,11 @@ MergeAttributes(List *schema, List *supers, bool istemp,
(errmsg("merging column \"%s\" with inherited definition",
attributeName)));
def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1);
- if (typenameTypeId(NULL, def->typename) != typenameTypeId(NULL, newdef->typename) ||
- def->typename->typmod != newdef->typename->typmod)
+ defTypeId = typenameTypeId(NULL, def->typename);
+ deftypmod = typenameTypeMod(NULL, def->typename, defTypeId);
+ newTypeId = typenameTypeId(NULL, newdef->typename);
+ newtypmod = typenameTypeMod(NULL, newdef->typename, newTypeId);
+ if (defTypeId != newTypeId || deftypmod != newtypmod)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("column \"%s\" has a type conflict",
@@ -3092,6 +3102,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
maxatts;
HeapTuple typeTuple;
Oid typeOid;
+ int32 typmod;
Form_pg_type tform;
Expr *defval;
@@ -3110,10 +3121,14 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
if (HeapTupleIsValid(tuple))
{
Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
+ Oid ctypeId;
+ int32 ctypmod;
/* Okay if child matches by type */
- if (typenameTypeId(NULL, colDef->typename) != childatt->atttypid ||
- colDef->typename->typmod != childatt->atttypmod)
+ ctypeId = typenameTypeId(NULL, colDef->typename);
+ ctypmod = typenameTypeMod(NULL, colDef->typename, ctypeId);
+ if (ctypeId != childatt->atttypid ||
+ ctypmod != childatt->atttypmod)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("child table \"%s\" has different type for column \"%s\"",
@@ -3169,6 +3184,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
typeTuple = typenameType(NULL, colDef->typename);
tform = (Form_pg_type) GETSTRUCT(typeTuple);
typeOid = HeapTupleGetOid(typeTuple);
+ typmod = typenameTypeMod(NULL, colDef->typename, typeOid);
/* make sure datatype is legal for a column */
CheckAttributeType(colDef->colname, typeOid);
@@ -3186,7 +3202,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
attribute->attstattarget = -1;
attribute->attlen = tform->typlen;
attribute->attcacheoff = -1;
- attribute->atttypmod = colDef->typename->typmod;
+ attribute->atttypmod = typmod;
attribute->attnum = i;
attribute->attbyval = tform->typbyval;
attribute->attndims = list_length(colDef->typename->arrayBounds);
@@ -3278,7 +3294,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
(Node *) defval,
basetype,
typeOid,
- colDef->typename->typmod,
+ typmod,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST);
if (defval == NULL) /* should not happen */
@@ -4877,6 +4893,7 @@ ATPrepAlterColumnType(List **wqueue,
Form_pg_attribute attTup;
AttrNumber attnum;
Oid targettype;
+ int32 targettypmod;
Node *transform;
NewColumnValue *newval;
ParseState *pstate = make_parsestate(NULL);
@@ -4907,6 +4924,7 @@ ATPrepAlterColumnType(List **wqueue,
/* Look up the target type */
targettype = typenameTypeId(NULL, typename);
+ targettypmod = typenameTypeMod(NULL, typename, targettype);
/* make sure datatype is legal for a column */
CheckAttributeType(colName, targettype);
@@ -4958,7 +4976,7 @@ ATPrepAlterColumnType(List **wqueue,
transform = coerce_to_target_type(pstate,
transform, exprType(transform),
- targettype, typename->typmod,
+ targettype, targettypmod,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST);
if (transform == NULL)
@@ -5004,6 +5022,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
HeapTuple typeTuple;
Form_pg_type tform;
Oid targettype;
+ int32 targettypmod;
Node *defaultexpr;
Relation attrelation;
Relation depRel;
@@ -5035,6 +5054,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
typeTuple = typenameType(NULL, typename);
tform = (Form_pg_type) GETSTRUCT(typeTuple);
targettype = HeapTupleGetOid(typeTuple);
+ targettypmod = typenameTypeMod(NULL, typename, targettype);
/*
* If there is a default expression for the column, get it and ensure we
@@ -5055,7 +5075,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
defaultexpr = strip_implicit_coercions(defaultexpr);
defaultexpr = coerce_to_target_type(NULL, /* no UNKNOWN params */
defaultexpr, exprType(defaultexpr),
- targettype, typename->typmod,
+ targettype, targettypmod,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST);
if (defaultexpr == NULL)
@@ -5272,7 +5292,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
* copy of the syscache entry, so okay to scribble on.)
*/
attTup->atttypid = targettype;
- attTup->atttypmod = typename->typmod;
+ attTup->atttypmod = targettypmod;
attTup->attndims = list_length(typename->arrayBounds);
attTup->attlen = tform->typlen;
attTup->attbyval = tform->typbyval;
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 53cca73a9dd..2b26f2dfa14 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.97 2006/10/04 00:29:51 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.98 2006/12/30 21:21:53 tgl Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
@@ -75,6 +75,8 @@ static Oid findTypeInputFunction(List *procname, Oid typeOid);
static Oid findTypeOutputFunction(List *procname, Oid typeOid);
static Oid findTypeReceiveFunction(List *procname, Oid typeOid);
static Oid findTypeSendFunction(List *procname, Oid typeOid);
+static Oid findTypeTypmodinFunction(List *procname);
+static Oid findTypeTypmodoutFunction(List *procname);
static Oid findTypeAnalyzeFunction(List *procname, Oid typeOid);
static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
static void checkDomainOwner(HeapTuple tup, TypeName *typename);
@@ -100,6 +102,8 @@ DefineType(List *names, List *parameters)
List *outputName = NIL;
List *receiveName = NIL;
List *sendName = NIL;
+ List *typmodinName = NIL;
+ List *typmodoutName = NIL;
List *analyzeName = NIL;
char *defaultValue = NULL;
bool byValue = false;
@@ -110,6 +114,8 @@ DefineType(List *names, List *parameters)
Oid outputOid;
Oid receiveOid = InvalidOid;
Oid sendOid = InvalidOid;
+ Oid typmodinOid = InvalidOid;
+ Oid typmodoutOid = InvalidOid;
Oid analyzeOid = InvalidOid;
char *shadow_type;
ListCell *pl;
@@ -182,6 +188,10 @@ DefineType(List *names, List *parameters)
receiveName = defGetQualifiedName(defel);
else if (pg_strcasecmp(defel->defname, "send") == 0)
sendName = defGetQualifiedName(defel);
+ else if (pg_strcasecmp(defel->defname, "typmod_in") == 0)
+ typmodinName = defGetQualifiedName(defel);
+ else if (pg_strcasecmp(defel->defname, "typmod_out") == 0)
+ typmodoutName = defGetQualifiedName(defel);
else if (pg_strcasecmp(defel->defname, "analyze") == 0 ||
pg_strcasecmp(defel->defname, "analyse") == 0)
analyzeName = defGetQualifiedName(defel);
@@ -268,6 +278,11 @@ DefineType(List *names, List *parameters)
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("type output function must be specified")));
+ if (typmodinName == NIL && typmodoutName != NIL)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("type modifier output function is useless without a type modifier input function")));
+
/*
* Convert I/O proc names to OIDs
*/
@@ -336,6 +351,14 @@ DefineType(List *names, List *parameters)
}
/*
+ * Convert typmodin/out function proc names to OIDs.
+ */
+ if (typmodinName)
+ typmodinOid = findTypeTypmodinFunction(typmodinName);
+ if (typmodoutName)
+ typmodoutOid = findTypeTypmodoutFunction(typmodoutName);
+
+ /*
* Convert analysis function proc name to an OID. If no analysis function
* is specified, we'll use zero to select the built-in default algorithm.
*/
@@ -362,6 +385,12 @@ DefineType(List *names, List *parameters)
if (sendOid && !pg_proc_ownercheck(sendOid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
NameListToString(sendName));
+ if (typmodinOid && !pg_proc_ownercheck(typmodinOid, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
+ NameListToString(typmodinName));
+ if (typmodoutOid && !pg_proc_ownercheck(typmodoutOid, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
+ NameListToString(typmodoutName));
if (analyzeOid && !pg_proc_ownercheck(analyzeOid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
NameListToString(analyzeName));
@@ -381,6 +410,8 @@ DefineType(List *names, List *parameters)
outputOid, /* output procedure */
receiveOid, /* receive procedure */
sendOid, /* send procedure */
+ typmodinOid, /* typmodin procedure */
+ typmodoutOid,/* typmodout procedure */
analyzeOid, /* analyze procedure */
elemType, /* element type ID */
InvalidOid, /* base type ID (only for domains) */
@@ -413,6 +444,8 @@ DefineType(List *names, List *parameters)
F_ARRAY_OUT, /* output procedure */
F_ARRAY_RECV, /* receive procedure */
F_ARRAY_SEND, /* send procedure */
+ typmodinOid, /* typmodin procedure */
+ typmodoutOid, /* typmodout procedure */
InvalidOid, /* analyze procedure - default */
typoid, /* element type ID */
InvalidOid, /* base type ID */
@@ -552,6 +585,7 @@ DefineDomain(CreateDomainStmt *stmt)
Oid basetypeoid;
Oid domainoid;
Form_pg_type baseType;
+ int32 basetypeMod;
/* Convert list of names to a name and namespace */
domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname,
@@ -581,9 +615,9 @@ DefineDomain(CreateDomainStmt *stmt)
* Look up the base type.
*/
typeTup = typenameType(NULL, stmt->typename);
-
baseType = (Form_pg_type) GETSTRUCT(typeTup);
basetypeoid = HeapTupleGetOid(typeTup);
+ basetypeMod = typenameTypeMod(NULL, stmt->typename, basetypeoid);
/*
* Base type must be a plain base type or another domain. Domains over
@@ -621,6 +655,8 @@ DefineDomain(CreateDomainStmt *stmt)
receiveProcedure = F_DOMAIN_RECV;
sendProcedure = baseType->typsend;
+ /* Domains never accept typmods, so no typmodin/typmodout needed */
+
/* Analysis function */
analyzeProcedure = baseType->typanalyze;
@@ -681,7 +717,7 @@ DefineDomain(CreateDomainStmt *stmt)
*/
defaultExpr = cookDefault(pstate, constr->raw_expr,
basetypeoid,
- stmt->typename->typmod,
+ basetypeMod,
domainName);
/*
@@ -768,6 +804,8 @@ DefineDomain(CreateDomainStmt *stmt)
outputProcedure, /* output procedure */
receiveProcedure, /* receive procedure */
sendProcedure, /* send procedure */
+ InvalidOid, /* typmodin procedure - none */
+ InvalidOid, /* typmodout procedure - none */
analyzeProcedure, /* analyze procedure */
typelem, /* element type ID */
basetypeoid, /* base type ID */
@@ -776,7 +814,7 @@ DefineDomain(CreateDomainStmt *stmt)
byValue, /* passed by value */
alignment, /* required alignment */
storage, /* TOAST strategy */
- stmt->typename->typmod, /* typeMod value */
+ basetypeMod, /* typeMod value */
typNDims, /* Array dimensions for base type */
typNotNull); /* Type NOT NULL */
@@ -793,7 +831,7 @@ DefineDomain(CreateDomainStmt *stmt)
{
case CONSTR_CHECK:
domainAddConstraint(domainoid, domainNamespace,
- basetypeoid, stmt->typename->typmod,
+ basetypeoid, basetypeMod,
constr, domainName);
break;
@@ -1068,6 +1106,60 @@ findTypeSendFunction(List *procname, Oid typeOid)
}
static Oid
+findTypeTypmodinFunction(List *procname)
+{
+ Oid argList[1];
+ Oid procOid;
+
+ /*
+ * typmodin functions always take one int4[] argument and return int4.
+ */
+ argList[0] = INT4ARRAYOID;
+
+ procOid = LookupFuncName(procname, 1, argList, true);
+ if (!OidIsValid(procOid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("function %s does not exist",
+ func_signature_string(procname, 1, argList))));
+
+ if (get_func_rettype(procOid) != INT4OID)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("typmod_in function %s must return type \"integer\"",
+ NameListToString(procname))));
+
+ return procOid;
+}
+
+static Oid
+findTypeTypmodoutFunction(List *procname)
+{
+ Oid argList[1];
+ Oid procOid;
+
+ /*
+ * typmodout functions always take one int4 argument and return cstring.
+ */
+ argList[0] = INT4OID;
+
+ procOid = LookupFuncName(procname, 1, argList, true);
+ if (!OidIsValid(procOid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_FUNCTION),
+ errmsg("function %s does not exist",
+ func_signature_string(procname, 1, argList))));
+
+ if (get_func_rettype(procOid) != CSTRINGOID)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("typmod_out function %s must return type \"cstring\"",
+ NameListToString(procname))));
+
+ return procOid;
+}
+
+static Oid
findTypeAnalyzeFunction(List *procname, Oid typeOid)
{
Oid argList[1];
@@ -1244,6 +1336,8 @@ AlterDomainDefault(List *names, Node *defaultRaw)
typTup->typoutput,
typTup->typreceive,
typTup->typsend,
+ typTup->typmodin,
+ typTup->typmodout,
typTup->typanalyze,
typTup->typelem,
typTup->typbasetype,