diff options
| author | Tom Lane <tgl@sss.pgh.pa.us> | 2008-07-30 17:05:05 +0000 |
|---|---|---|
| committer | Tom Lane <tgl@sss.pgh.pa.us> | 2008-07-30 17:05:05 +0000 |
| commit | bac3e83622b588eb449eb4e26c4b1e62e7cca3d5 (patch) | |
| tree | 419f9079e41450aaaaa5ed0b8c8fa849a46d5bf9 /src/backend | |
| parent | ab9907f5e5eba6e4e17a279d07a1a9df21ec5b19 (diff) | |
| download | postgresql-bac3e83622b588eb449eb4e26c4b1e62e7cca3d5.tar.gz | |
Replace the hard-wired type knowledge in TypeCategory() and IsPreferredType()
with system catalog lookups, as was foreseen to be necessary almost since
their creation. Instead put the information into two new pg_type columns,
typcategory and typispreferred. Add support for setting these when
creating a user-defined base type.
The category column is just a "char" (i.e. a poor man's enum), allowing
a crude form of user extensibility of the category list: just use an
otherwise-unused character. This seems sufficient for foreseen uses,
but we could upgrade to having an actual category catalog someday, if
there proves to be a huge demand for custom type categories.
In this patch I have attempted to hew exactly to the behavior of the
previous hardwired logic, except for introducing new type categories for
arrays, composites, and enums. In particular the default preferred state
for user-defined types remains TRUE. That seems worth revisiting, but it
should be done as a separate patch from introducing the infrastructure.
Likewise, any adjustment of the standard set of categories should be done
separately.
Diffstat (limited to 'src/backend')
| -rw-r--r-- | src/backend/catalog/heap.c | 6 | ||||
| -rw-r--r-- | src/backend/catalog/pg_type.c | 8 | ||||
| -rw-r--r-- | src/backend/commands/indexcmds.c | 4 | ||||
| -rw-r--r-- | src/backend/commands/typecmds.c | 35 | ||||
| -rw-r--r-- | src/backend/parser/parse_coerce.c | 224 | ||||
| -rw-r--r-- | src/backend/parser/parse_func.c | 33 | ||||
| -rw-r--r-- | src/backend/utils/cache/lsyscache.c | 25 |
7 files changed, 121 insertions, 214 deletions
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 797bee82a7..5510e72b4e 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.334 2008/05/12 00:00:46 alvherre Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.335 2008/07/30 17:05:04 tgl Exp $ * * * INTERFACE ROUTINES @@ -761,6 +761,8 @@ AddNewRelationType(const char *typeName, new_rel_kind, /* relation kind */ -1, /* internal size (varlena) */ TYPTYPE_COMPOSITE, /* type-type (composite) */ + TYPCATEGORY_COMPOSITE, /* type-category (ditto) */ + true, /* all composite types are preferred */ DEFAULT_TYPDELIM, /* default array delimiter */ F_RECORD_IN, /* input procedure */ F_RECORD_OUT, /* output procedure */ @@ -938,6 +940,8 @@ heap_create_with_catalog(const char *relname, 0, /* relkind, also N/A here */ -1, /* Internal size (varlena) */ TYPTYPE_BASE, /* Not composite - typelem is */ + TYPCATEGORY_ARRAY, /* type-category (array) */ + true, /* all array types are preferred */ DEFAULT_TYPDELIM, /* default array delimiter */ F_ARRAY_IN, /* array input proc */ F_ARRAY_OUT, /* array output proc */ diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c index 42caacc96b..a6aec623ca 100644 --- a/src/backend/catalog/pg_type.c +++ b/src/backend/catalog/pg_type.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.119 2008/06/19 00:46:04 alvherre Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.120 2008/07/30 17:05:04 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -91,6 +91,8 @@ TypeShellMake(const char *typeName, Oid typeNamespace) values[i++] = Int16GetDatum(sizeof(int4)); /* typlen */ values[i++] = BoolGetDatum(true); /* typbyval */ values[i++] = CharGetDatum(TYPTYPE_PSEUDO); /* typtype */ + values[i++] = CharGetDatum(TYPCATEGORY_PSEUDOTYPE); /* typcategory */ + values[i++] = BoolGetDatum(false); /* typispreferred */ values[i++] = BoolGetDatum(false); /* typisdefined */ values[i++] = CharGetDatum(DEFAULT_TYPDELIM); /* typdelim */ values[i++] = ObjectIdGetDatum(InvalidOid); /* typrelid */ @@ -173,6 +175,8 @@ TypeCreate(Oid newTypeOid, char relationKind, /* ditto */ int16 internalSize, char typeType, + char typeCategory, + bool typePreferred, char typDelim, Oid inputProcedure, Oid outputProcedure, @@ -253,6 +257,8 @@ TypeCreate(Oid newTypeOid, values[i++] = Int16GetDatum(internalSize); /* typlen */ values[i++] = BoolGetDatum(passedByValue); /* typbyval */ values[i++] = CharGetDatum(typeType); /* typtype */ + values[i++] = CharGetDatum(typeCategory); /* typcategory */ + values[i++] = BoolGetDatum(typePreferred); /* typispreferred */ values[i++] = BoolGetDatum(true); /* typisdefined */ values[i++] = CharGetDatum(typDelim); /* typdelim */ values[i++] = ObjectIdGetDatum(relationOid); /* typrelid */ diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index a8a78b561f..1427b2a10e 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.177 2008/06/14 18:04:33 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.178 2008/07/30 17:05:04 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1012,7 +1012,7 @@ GetDefaultOpClass(Oid type_id, Oid am_id) ScanKeyData skey[1]; SysScanDesc scan; HeapTuple tup; - CATEGORY tcategory; + TYPCATEGORY tcategory; /* If it's a domain, look at the base type instead */ type_id = getBaseType(type_id); diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 793e9262e3..84d8036057 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.119 2008/06/14 18:04:33 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.120 2008/07/30 17:05:04 tgl Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -111,6 +111,8 @@ DefineType(List *names, List *parameters) List *analyzeName = NIL; char *defaultValue = NULL; bool byValue = false; + char category = TYPCATEGORY_USER; + bool preferred = true; char delimiter = DEFAULT_TYPDELIM; char alignment = 'i'; /* default alignment */ char storage = 'p'; /* default TOAST storage method */ @@ -188,8 +190,6 @@ DefineType(List *names, List *parameters) if (pg_strcasecmp(defel->defname, "internallength") == 0) internalLength = defGetTypeLength(defel); - else if (pg_strcasecmp(defel->defname, "externallength") == 0) - ; /* ignored -- remove after 7.3 */ else if (pg_strcasecmp(defel->defname, "input") == 0) inputName = defGetQualifiedName(defel); else if (pg_strcasecmp(defel->defname, "output") == 0) @@ -205,11 +205,26 @@ DefineType(List *names, List *parameters) else if (pg_strcasecmp(defel->defname, "analyze") == 0 || pg_strcasecmp(defel->defname, "analyse") == 0) analyzeName = defGetQualifiedName(defel); + else if (pg_strcasecmp(defel->defname, "category") == 0) + { + char *p = defGetString(defel); + + category = p[0]; + /* restrict to non-control ASCII */ + if (category < 32 || category > 126) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid type category \"%s\": must be simple ASCII", + p))); + } + else if (pg_strcasecmp(defel->defname, "preferred") == 0) + preferred = defGetBoolean(defel); else if (pg_strcasecmp(defel->defname, "delimiter") == 0) { char *p = defGetString(defel); delimiter = p[0]; + /* XXX shouldn't we restrict the delimiter? */ } else if (pg_strcasecmp(defel->defname, "element") == 0) { @@ -421,6 +436,8 @@ DefineType(List *names, List *parameters) 0, /* relation kind (ditto) */ internalLength, /* internal size */ TYPTYPE_BASE, /* type-type (base type) */ + category, /* type-category */ + preferred, /* is it a preferred type? */ delimiter, /* array element delimiter */ inputOid, /* input procedure */ outputOid, /* output procedure */ @@ -457,6 +474,8 @@ DefineType(List *names, List *parameters) 0, /* relation kind (ditto) */ -1, /* internal size (always varlena) */ TYPTYPE_BASE, /* type-type (base type) */ + TYPCATEGORY_ARRAY, /* type-category (array) */ + true, /* all array types are preferred */ DEFAULT_TYPDELIM, /* array element delimiter */ F_ARRAY_IN, /* input procedure */ F_ARRAY_OUT, /* output procedure */ @@ -624,6 +643,7 @@ DefineDomain(CreateDomainStmt *stmt) Oid analyzeProcedure; bool byValue; Oid typelem; + char category; char delimiter; char alignment; char storage; @@ -705,6 +725,9 @@ DefineDomain(CreateDomainStmt *stmt) /* Storage Length */ internalLength = baseType->typlen; + /* Type Category */ + category = baseType->typcategory; + /* Array element type (in case base type is an array) */ typelem = baseType->typelem; @@ -895,6 +918,8 @@ DefineDomain(CreateDomainStmt *stmt) 0, /* relation kind (ditto) */ internalLength, /* internal size */ TYPTYPE_DOMAIN, /* type-type (domain type) */ + category, /* type-category */ + false, /* domains are never preferred types */ delimiter, /* array element delimiter */ inputProcedure, /* input procedure */ outputProcedure, /* output procedure */ @@ -1006,6 +1031,8 @@ DefineEnum(CreateEnumStmt *stmt) 0, /* relation kind (ditto) */ sizeof(Oid), /* internal size */ TYPTYPE_ENUM, /* type-type (enum type) */ + TYPCATEGORY_ENUM, /* type-category (enum type) */ + true, /* all enum types are preferred */ DEFAULT_TYPDELIM, /* array element delimiter */ F_ENUM_IN, /* input procedure */ F_ENUM_OUT, /* output procedure */ @@ -1042,6 +1069,8 @@ DefineEnum(CreateEnumStmt *stmt) 0, /* relation kind (ditto) */ -1, /* internal size (always varlena) */ TYPTYPE_BASE, /* type-type (base type) */ + TYPCATEGORY_ARRAY, /* type-category (array) */ + true, /* all array types are preferred */ DEFAULT_TYPDELIM, /* array element delimiter */ F_ARRAY_IN, /* input procedure */ F_ARRAY_OUT, /* output procedure */ diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index 2467640434..df5ad09bae 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.161 2008/01/11 18:39:40 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.162 2008/07/30 17:05:04 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -967,7 +967,8 @@ Oid select_common_type(List *typeids, const char *context) { Oid ptype; - CATEGORY pcategory; + TYPCATEGORY pcategory; + bool pispreferred; ListCell *type_item; Assert(typeids != NIL); @@ -993,7 +994,7 @@ select_common_type(List *typeids, const char *context) /* Nope, so set up for the full algorithm */ ptype = getBaseType(ptype); - pcategory = TypeCategory(ptype); + get_type_category_preferred(ptype, &pcategory, &pispreferred); for_each_cell(type_item, lnext(list_head(typeids))) { @@ -1002,13 +1003,18 @@ select_common_type(List *typeids, const char *context) /* move on to next one if no new information... */ if (ntype != UNKNOWNOID && ntype != ptype) { + TYPCATEGORY ncategory; + bool nispreferred; + + get_type_category_preferred(ntype, &ncategory, &nispreferred); if (ptype == UNKNOWNOID) { /* so far, only unknowns so take anything... */ ptype = ntype; - pcategory = TypeCategory(ptype); + pcategory = ncategory; + pispreferred = nispreferred; } - else if (TypeCategory(ntype) != pcategory) + else if (ncategory != pcategory) { /* * both types in different categories? then not much hope... @@ -1023,7 +1029,7 @@ select_common_type(List *typeids, const char *context) format_type_be(ptype), format_type_be(ntype)))); } - else if (!IsPreferredType(pcategory, ptype) && + else if (!pispreferred && can_coerce_type(1, &ptype, &ntype, COERCION_IMPLICIT) && !can_coerce_type(1, &ntype, &ptype, COERCION_IMPLICIT)) { @@ -1032,7 +1038,8 @@ select_common_type(List *typeids, const char *context) * other way; but if we have a preferred type, stay on it. */ ptype = ntype; - pcategory = TypeCategory(ptype); + pcategory = ncategory; + pispreferred = nispreferred; } } } @@ -1549,202 +1556,39 @@ resolve_generic_type(Oid declared_type, /* TypeCategory() * Assign a category to the specified type OID. * - * NB: this must not return INVALID_TYPE. - * - * XXX This should be moved to system catalog lookups - * to allow for better type extensibility. - * - thomas 2001-09-30 + * NB: this must not return TYPCATEGORY_INVALID. */ -CATEGORY -TypeCategory(Oid inType) +TYPCATEGORY +TypeCategory(Oid type) { - CATEGORY result; + char typcategory; + bool typispreferred; - switch (inType) - { - case (BOOLOID): - result = BOOLEAN_TYPE; - break; - - case (CHAROID): - case (NAMEOID): - case (BPCHAROID): - case (VARCHAROID): - case (TEXTOID): - result = STRING_TYPE; - break; - - case (BITOID): - case (VARBITOID): - result = BITSTRING_TYPE; - break; - - case (OIDOID): - case (REGPROCOID): - case (REGPROCEDUREOID): - case (REGOPEROID): - case (REGOPERATOROID): - case (REGCLASSOID): - case (REGTYPEOID): - case (REGCONFIGOID): - case (REGDICTIONARYOID): - case (INT2OID): - case (INT4OID): - case (INT8OID): - case (FLOAT4OID): - case (FLOAT8OID): - case (NUMERICOID): - case (CASHOID): - result = NUMERIC_TYPE; - break; - - case (DATEOID): - case (TIMEOID): - case (TIMETZOID): - case (ABSTIMEOID): - case (TIMESTAMPOID): - case (TIMESTAMPTZOID): - result = DATETIME_TYPE; - break; - - case (RELTIMEOID): - case (TINTERVALOID): - case (INTERVALOID): - result = TIMESPAN_TYPE; - break; - - case (POINTOID): - case (LSEGOID): - case (PATHOID): - case (BOXOID): - case (POLYGONOID): - case (LINEOID): - case (CIRCLEOID): - result = GEOMETRIC_TYPE; - break; - - case (INETOID): - case (CIDROID): - result = NETWORK_TYPE; - break; - - case (UNKNOWNOID): - case (InvalidOid): - result = UNKNOWN_TYPE; - break; - - case (RECORDOID): - case (CSTRINGOID): - case (ANYOID): - case (ANYARRAYOID): - case (VOIDOID): - case (TRIGGEROID): - case (LANGUAGE_HANDLEROID): - case (INTERNALOID): - case (OPAQUEOID): - case (ANYELEMENTOID): - case (ANYNONARRAYOID): - case (ANYENUMOID): - result = GENERIC_TYPE; - break; - - default: - result = USER_TYPE; - break; - } - return result; -} /* TypeCategory() */ + get_type_category_preferred(type, &typcategory, &typispreferred); + Assert(typcategory != TYPCATEGORY_INVALID); + return (TYPCATEGORY) typcategory; +} /* IsPreferredType() * Check if this type is a preferred type for the given category. * - * If category is INVALID_TYPE, then we'll return TRUE for preferred types - * of any category; otherwise, only for preferred types of that category. - * - * XXX This should be moved to system catalog lookups - * to allow for better type extensibility. - * - thomas 2001-09-30 + * If category is TYPCATEGORY_INVALID, then we'll return TRUE for preferred + * types of any category; otherwise, only for preferred types of that + * category. */ bool -IsPreferredType(CATEGORY category, Oid type) +IsPreferredType(TYPCATEGORY category, Oid type) { - Oid preftype; + char typcategory; + bool typispreferred; - if (category == INVALID_TYPE) - category = TypeCategory(type); - else if (category != TypeCategory(type)) + get_type_category_preferred(type, &typcategory, &typispreferred); + if (category == typcategory || category == TYPCATEGORY_INVALID) + return typispreferred; + else return false; - - /* - * This switch should agree with TypeCategory(), above. Note that at this - * point, category certainly matches the type. - */ - switch (category) - { - case (UNKNOWN_TYPE): - case (GENERIC_TYPE): - preftype = UNKNOWNOID; - break; - - case (BOOLEAN_TYPE): - preftype = BOOLOID; - break; - - case (STRING_TYPE): - preftype = TEXTOID; - break; - - case (BITSTRING_TYPE): - preftype = VARBITOID; - break; - - case (NUMERIC_TYPE): - if (type == OIDOID || - type == REGPROCOID || - type == REGPROCEDUREOID || - type == REGOPEROID || - type == REGOPERATOROID || - type == REGCLASSOID || - type == REGTYPEOID || - type == REGCONFIGOID || - type == REGDICTIONARYOID) - preftype = OIDOID; - else - preftype = FLOAT8OID; - break; - - case (DATETIME_TYPE): - if (type == DATEOID) - preftype = TIMESTAMPOID; - else - preftype = TIMESTAMPTZOID; - break; - - case (TIMESPAN_TYPE): - preftype = INTERVALOID; - break; - - case (GEOMETRIC_TYPE): - preftype = type; - break; - - case (NETWORK_TYPE): - preftype = INETOID; - break; - - case (USER_TYPE): - preftype = type; - break; - - default: - elog(ERROR, "unrecognized type category: %d", (int) category); - preftype = UNKNOWNOID; - break; - } - - return (type == preftype); -} /* IsPreferredType() */ +} /* IsBinaryCoercible() diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index 3bb5c452a8..785e8816a9 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.203 2008/07/16 01:30:22 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.204 2008/07/30 17:05:04 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -439,8 +439,9 @@ func_select_candidate(int nargs, int nbestMatch, nmatch; Oid input_base_typeids[FUNC_MAX_ARGS]; - CATEGORY slot_category[FUNC_MAX_ARGS], + TYPCATEGORY slot_category[FUNC_MAX_ARGS], current_category; + bool current_is_preferred; bool slot_has_preferred_type[FUNC_MAX_ARGS]; bool resolved_unknowns; @@ -591,7 +592,7 @@ func_select_candidate(int nargs, if (input_base_typeids[i] != UNKNOWNOID) continue; resolved_unknowns = true; /* assume we can do it */ - slot_category[i] = INVALID_TYPE; + slot_category[i] = TYPCATEGORY_INVALID; slot_has_preferred_type[i] = false; have_conflict = false; for (current_candidate = candidates; @@ -600,29 +601,28 @@ func_select_candidate(int nargs, { current_typeids = current_candidate->args; current_type = current_typeids[i]; - current_category = TypeCategory(current_type); - if (slot_category[i] == INVALID_TYPE) + get_type_category_preferred(current_type, + ¤t_category, + ¤t_is_preferred); + if (slot_category[i] == TYPCATEGORY_INVALID) { /* first candidate */ slot_category[i] = current_category; - slot_has_preferred_type[i] = - IsPreferredType(current_category, current_type); + slot_has_preferred_type[i] = current_is_preferred; } else if (current_category == slot_category[i]) { /* more candidates in same category */ - slot_has_preferred_type[i] |= - IsPreferredType(current_category, current_type); + slot_has_preferred_type[i] |= current_is_preferred; } else { /* category conflict! */ - if (current_category == STRING_TYPE) + if (current_category == TYPCATEGORY_STRING) { /* STRING always wins if available */ slot_category[i] = current_category; - slot_has_preferred_type[i] = - IsPreferredType(current_category, current_type); + slot_has_preferred_type[i] = current_is_preferred; } else { @@ -633,7 +633,7 @@ func_select_candidate(int nargs, } } } - if (have_conflict && slot_category[i] != STRING_TYPE) + if (have_conflict && slot_category[i] != TYPCATEGORY_STRING) { /* Failed to resolve category conflict at this position */ resolved_unknowns = false; @@ -658,14 +658,15 @@ func_select_candidate(int nargs, if (input_base_typeids[i] != UNKNOWNOID) continue; current_type = current_typeids[i]; - current_category = TypeCategory(current_type); + get_type_category_preferred(current_type, + ¤t_category, + ¤t_is_preferred); if (current_category != slot_category[i]) { keepit = false; break; } - if (slot_has_preferred_type[i] && - !IsPreferredType(current_category, current_type)) + if (slot_has_preferred_type[i] && !current_is_preferred) { keepit = false; break; diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index e17bd49e62..79362441f8 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -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.157 2008/04/13 20:51:21 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.158 2008/07/30 17:05:04 tgl Exp $ * * NOTES * Eventually, the index information should go through here, too. @@ -2168,6 +2168,29 @@ type_is_enum(Oid typid) } /* + * get_type_category_preferred + * + * Given the type OID, fetch its category and preferred-type status. + * Throws error on failure. + */ +void +get_type_category_preferred(Oid typid, char *typcategory, bool *typispreferred) +{ + HeapTuple tp; + Form_pg_type typtup; + + tp = SearchSysCache(TYPEOID, + ObjectIdGetDatum(typid), + 0, 0, 0); + if (!HeapTupleIsValid(tp)) + elog(ERROR, "cache lookup failed for type %u", typid); + typtup = (Form_pg_type) GETSTRUCT(tp); + *typcategory = typtup->typcategory; + *typispreferred = typtup->typispreferred; + ReleaseSysCache(tp); +} + +/* * get_typ_typrelid * * Given the type OID, get the typrelid (InvalidOid if not a complex |
