diff options
Diffstat (limited to 'src/backend/commands')
-rw-r--r-- | src/backend/commands/tablecmds.c | 44 | ||||
-rw-r--r-- | src/backend/commands/typecmds.c | 104 |
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, |