From: Tom Lane Date: Sun, 20 Aug 2000 00:44:19 +0000 (+0000) Subject: Make functional indexes accept binary-compatible functions, for example X-Git-Tag: REL7_1_BETA~772 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4b8f1bcb9cbc297c63521bcb3ea64e9eed29ff8a;p=postgresql Make functional indexes accept binary-compatible functions, for example CREATE INDEX fooi ON foo (lower(f1)) where f1 is varchar rather than text. --- diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 85de47a676..0fb1129f73 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.36 2000/08/03 16:34:01 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.37 2000/08/20 00:44:19 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -370,9 +370,12 @@ FuncIndexArgs(IndexInfo *indexInfo, { Oid argTypes[FUNC_MAX_ARGS]; List *arglist; - HeapTuple tuple; - Oid retType; - int argn = 0; + int nargs = 0; + int i; + Oid funcid; + Oid rettype; + bool retset; + Oid *true_typeids; /* * process the function arguments, which are a list of T_String @@ -385,6 +388,7 @@ FuncIndexArgs(IndexInfo *indexInfo, foreach(arglist, funcIndex->args) { char *arg = strVal(lfirst(arglist)); + HeapTuple tuple; Form_pg_attribute att; tuple = SearchSysCacheTuple(ATTNAME, @@ -395,40 +399,47 @@ FuncIndexArgs(IndexInfo *indexInfo, elog(ERROR, "DefineIndex: attribute \"%s\" not found", arg); att = (Form_pg_attribute) GETSTRUCT(tuple); - indexInfo->ii_KeyAttrNumbers[argn] = att->attnum; - argTypes[argn] = att->atttypid; - argn++; + indexInfo->ii_KeyAttrNumbers[nargs] = att->attnum; + argTypes[nargs] = att->atttypid; + nargs++; } /* ---------------- * Lookup the function procedure to get its OID and result type. * - * XXX need to accept binary-compatible functions here, not just - * an exact match. + * We rely on parse_func.c to find the correct function in the + * possible presence of binary-compatible types. However, parse_func + * may do too much: it will accept a function that requires run-time + * coercion of input types, and the executor is not currently set up + * to support that. So, check to make sure that the selected function + * has exact-match or binary-compatible input types. * ---------------- */ - tuple = SearchSysCacheTuple(PROCNAME, - PointerGetDatum(funcIndex->name), - Int32GetDatum(indexInfo->ii_NumKeyAttrs), - PointerGetDatum(argTypes), - 0); - if (!HeapTupleIsValid(tuple)) + if (! func_get_detail(funcIndex->name, nargs, argTypes, + &funcid, &rettype, &retset, &true_typeids)) + func_error("DefineIndex", funcIndex->name, nargs, argTypes, NULL); + + if (retset) + elog(ERROR, "DefineIndex: cannot index on a function returning a set"); + + for (i = 0; i < nargs; i++) { - func_error("DefineIndex", funcIndex->name, - indexInfo->ii_NumKeyAttrs, argTypes, NULL); + if (argTypes[i] != true_typeids[i] && + ! IS_BINARY_COMPATIBLE(argTypes[i], true_typeids[i])) + func_error("DefineIndex", funcIndex->name, nargs, argTypes, + "Index function must be binary-compatible with table datatype"); } - indexInfo->ii_FuncOid = tuple->t_data->t_oid; - retType = ((Form_pg_proc) GETSTRUCT(tuple))->prorettype; - /* Process opclass, using func return type as default type */ - classOidP[0] = GetAttrOpClass(funcIndex, retType, + classOidP[0] = GetAttrOpClass(funcIndex, rettype, accessMethodName, accessMethodId); - /* Need to do the fmgr function lookup now, too */ + /* OK, return results */ - fmgr_info(indexInfo->ii_FuncOid, & indexInfo->ii_FuncInfo); + indexInfo->ii_FuncOid = funcid; + /* Need to do the fmgr function lookup now, too */ + fmgr_info(funcid, & indexInfo->ii_FuncInfo); } static void diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index 44a750c166..551e7d2b58 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.87 2000/08/08 15:42:04 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.88 2000/08/20 00:44:18 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -37,18 +37,10 @@ static Node *ParseComplexProjection(ParseState *pstate, char *funcname, Node *first_arg, bool *attisset); -static Oid **argtype_inherit(int nargs, Oid *oid_array); +static Oid **argtype_inherit(int nargs, Oid *argtypes); static int find_inheritors(Oid relid, Oid **supervec); static CandidateList func_get_candidates(char *funcname, int nargs); -static bool -func_get_detail(char *funcname, - int nargs, - Oid *oid_array, - Oid *funcid, /* return value */ - Oid *rettype, /* return value */ - bool *retset, /* return value */ - Oid **true_typeids); static Oid **gen_cross_product(InhPaths *arginh, int nargs); static void make_arguments(ParseState *pstate, int nargs, @@ -1097,10 +1089,10 @@ func_select_candidate(int nargs, * c) if the answer is more than one, attempt to resolve the conflict * d) if the answer is zero, try the next array from vector #1 */ -static bool +bool func_get_detail(char *funcname, int nargs, - Oid *oid_array, + Oid *argtypes, Oid *funcid, /* return value */ Oid *rettype, /* return value */ bool *retset, /* return value */ @@ -1112,13 +1104,13 @@ func_get_detail(char *funcname, ftup = SearchSysCacheTuple(PROCNAME, PointerGetDatum(funcname), Int32GetDatum(nargs), - PointerGetDatum(oid_array), + PointerGetDatum(argtypes), 0); if (HeapTupleIsValid(ftup)) { /* given argument types are the right ones */ - *true_typeids = oid_array; + *true_typeids = argtypes; } else { @@ -1138,11 +1130,11 @@ func_get_detail(char *funcname, Oid *current_input_typeids; /* - * First we will search with the given oid_array, then with + * First we will search with the given argtypes, then with * variants based on replacing complex types with their * inheritance ancestors. Stop as soon as any match is found. */ - current_input_typeids = oid_array; + current_input_typeids = argtypes; do { @@ -1200,7 +1192,7 @@ func_get_detail(char *funcname, * vectors. */ if (input_typeid_vector == NULL) - input_typeid_vector = argtype_inherit(nargs, oid_array); + input_typeid_vector = argtype_inherit(nargs, argtypes); current_input_typeids = *input_typeid_vector++; } @@ -1243,7 +1235,7 @@ func_get_detail(char *funcname, * catalogs. */ static Oid ** -argtype_inherit(int nargs, Oid *oid_array) +argtype_inherit(int nargs, Oid *argtypes) { Oid relid; int i; @@ -1253,8 +1245,8 @@ argtype_inherit(int nargs, Oid *oid_array) { if (i < nargs) { - arginh[i].self = oid_array[i]; - if ((relid = typeidTypeRelid(oid_array[i])) != InvalidOid) + arginh[i].self = argtypes[i]; + if ((relid = typeidTypeRelid(argtypes[i])) != InvalidOid) arginh[i].nsupers = find_inheritors(relid, &(arginh[i].supervec)); else { @@ -1467,16 +1459,6 @@ typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId) /* make_arguments() * Given the number and types of arguments to a function, and the * actual arguments and argument types, do the necessary typecasting. - * - * There are two ways an input typeid can differ from a function typeid: - * 1) the input type inherits the function type, so no typecasting required - * 2) the input type can be typecast into the function type - * Right now, we only typecast unknowns, and that is all we check for. - * - * func_get_detail() now can find coercions for function arguments which - * will make this function executable. So, we need to recover these - * results here too. - * - thomas 1998-03-25 */ static void make_arguments(ParseState *pstate, diff --git a/src/include/parser/parse_func.h b/src/include/parser/parse_func.h index 79b193a2b5..be96652cfb 100644 --- a/src/include/parser/parse_func.h +++ b/src/include/parser/parse_func.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: parse_func.h,v 1.25 2000/08/08 15:42:59 tgl Exp $ + * $Id: parse_func.h,v 1.26 2000/08/20 00:44:17 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -45,6 +45,10 @@ extern Node *ParseFuncOrColumn(ParseState *pstate, bool agg_star, bool agg_distinct, int *curr_resno, int precedence); +extern bool func_get_detail(char *funcname, int nargs, Oid *argtypes, + Oid *funcid, Oid *rettype, + bool *retset, Oid **true_typeids); + extern bool typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId); extern void func_error(char *caller, char *funcname,