aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2003-06-25 20:07:54 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2003-06-25 20:07:54 +0000
commit263b42f28918e3b1938cd50e3401ac34c25a1016 (patch)
tree0192d692dfb615292f404a71c072af6103e20cab
parent612cbaf5ed7e4a50b45eb7efd4bae7302918eb24 (diff)
downloadpostgresql-263b42f28918e3b1938cd50e3401ac34c25a1016.tar.gz
postgresql-263b42f28918e3b1938cd50e3401ac34c25a1016.zip
Don't generate 'zero' typeids in the output from gen_cross_product.
This is no longer necessary or appropriate since we don't use zero typeid as a wildcard anymore, and it fixes a nasty performance problem with functions with many parameters. Per recent example from Reuven Lerner.
-rw-r--r--src/backend/parser/parse_func.c127
1 files changed, 77 insertions, 50 deletions
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index deb095f7c8c..f9c61c063e2 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.139.2.1 2003/04/23 18:20:10 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.139.2.2 2003/06/25 20:07:54 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -904,23 +904,29 @@ func_get_detail(List *funcname,
* argtype_inherit() -- Construct an argtype vector reflecting the
* inheritance properties of the supplied argv.
*
- * This function is used to disambiguate among functions with the
- * same name but different signatures. It takes an array of input
- * type ids. For each type id in the array that's a complex type
- * (a class), it walks up the inheritance tree, finding all
- * superclasses of that type. A vector of new Oid type arrays
- * is returned to the caller, reflecting the structure of the
- * inheritance tree above the supplied arguments.
+ * This function is used to handle resolution of function calls when
+ * there is no match to the given argument types, but there might be
+ * matches based on considering complex types as members of their
+ * superclass types (parent classes).
+ *
+ * It takes an array of input type ids. For each type id in the array
+ * that's a complex type (a class), it walks up the inheritance tree,
+ * finding all superclasses of that type. A vector of new Oid type
+ * arrays is returned to the caller, listing possible alternative
+ * interpretations of the input typeids as members of their superclasses
+ * rather than the actually given argument types. The vector is
+ * terminated by a NULL pointer.
*
* The order of this vector is as follows: all superclasses of the
* rightmost complex class are explored first. The exploration
* continues from right to left. This policy means that we favor
* keeping the leftmost argument type as low in the inheritance tree
* as possible. This is intentional; it is exactly what we need to
- * do for method dispatch. The last type array we return is all
- * zeroes. This will match any functions for which return types are
- * not defined. There are lots of these (mostly builtins) in the
- * catalogs.
+ * do for method dispatch.
+ *
+ * The vector does not include the case where no complex classes have
+ * been promoted, since that was already tried before this routine
+ * got called.
*/
static Oid **
argtype_inherit(int nargs, Oid *argtypes)
@@ -929,22 +935,13 @@ argtype_inherit(int nargs, Oid *argtypes)
int i;
InhPaths arginh[FUNC_MAX_ARGS];
- for (i = 0; i < FUNC_MAX_ARGS; i++)
+ for (i = 0; i < nargs; i++)
{
- if (i < nargs)
- {
- arginh[i].self = argtypes[i];
- if ((relid = typeidTypeRelid(argtypes[i])) != InvalidOid)
- arginh[i].nsupers = find_inheritors(relid, &(arginh[i].supervec));
- else
- {
- arginh[i].nsupers = 0;
- arginh[i].supervec = (Oid *) NULL;
- }
- }
+ arginh[i].self = argtypes[i];
+ if ((relid = typeidTypeRelid(argtypes[i])) != InvalidOid)
+ arginh[i].nsupers = find_inheritors(relid, &(arginh[i].supervec));
else
{
- arginh[i].self = InvalidOid;
arginh[i].nsupers = 0;
arginh[i].supervec = (Oid *) NULL;
}
@@ -954,6 +951,13 @@ argtype_inherit(int nargs, Oid *argtypes)
return gen_cross_product(arginh, nargs);
}
+/*
+ * Look up the parent superclass(es) of the given relation.
+ *
+ * *supervec is set to an array of the type OIDs (not the relation OIDs)
+ * of the parents, with nearest ancestors listed first. It's set to NULL
+ * if there are no parents. The return value is the number of parents.
+ */
static int
find_inheritors(Oid relid, Oid **supervec)
{
@@ -1047,59 +1051,82 @@ find_inheritors(Oid relid, Oid **supervec)
return nvisited;
}
+/*
+ * Generate the ordered list of substitute argtype vectors to try.
+ *
+ * See comments for argtype_inherit.
+ */
static Oid **
gen_cross_product(InhPaths *arginh, int nargs)
{
int nanswers;
- Oid **result,
- **iter;
+ Oid **result;
Oid *oneres;
int i,
j;
int cur[FUNC_MAX_ARGS];
+ /*
+ * At each position we want to try the original datatype, plus each
+ * supertype. So the number of possible combinations is this:
+ */
nanswers = 1;
for (i = 0; i < nargs; i++)
- {
- nanswers *= (arginh[i].nsupers + 2);
- cur[i] = 0;
- }
+ nanswers *= (arginh[i].nsupers + 1);
- iter = result = (Oid **) palloc(sizeof(Oid *) * nanswers);
+ /*
+ * We also need an extra slot for the terminating NULL in the result
+ * array, but that cancels out with the fact that we don't want to
+ * generate the zero-changes case. So we need exactly nanswers slots.
+ */
+ result = (Oid **) palloc(sizeof(Oid *) * nanswers);
+ j = 0;
+
+ /*
+ * Compute the cross product from right to left. When cur[i] == 0,
+ * generate the original input type at position i. When cur[i] == k
+ * for k > 0, generate its k'th supertype.
+ */
+ MemSet(cur, 0, sizeof(cur));
- /* compute the cross product from right to left */
for (;;)
{
- oneres = (Oid *) palloc(FUNC_MAX_ARGS * sizeof(Oid));
- MemSet(oneres, 0, FUNC_MAX_ARGS * sizeof(Oid));
-
- for (i = nargs - 1; i >= 0 && cur[i] > arginh[i].nsupers; i--)
- continue;
+ /*
+ * Find a column we can increment. All the columns after it get
+ * reset to zero. (Essentially, we're adding one to the multi-
+ * digit number represented by cur[].)
+ */
+ for (i = nargs - 1; i >= 0 && cur[i] >= arginh[i].nsupers; i--)
+ cur[i] = 0;
- /* if we're done, terminate with NULL pointer */
+ /* if none, we're done */
if (i < 0)
- {
- *iter = NULL;
- return result;
- }
+ break;
+
+ /* increment this column */
+ cur[i] += 1;
- /* no, increment this column and zero the ones after it */
- cur[i] = cur[i] + 1;
- for (j = nargs - 1; j > i; j--)
- cur[j] = 0;
+ /* Generate the proper output type-OID vector */
+ oneres = (Oid *) palloc(FUNC_MAX_ARGS * sizeof(Oid));
+ MemSet(oneres, 0, FUNC_MAX_ARGS * sizeof(Oid));
for (i = 0; i < nargs; i++)
{
if (cur[i] == 0)
oneres[i] = arginh[i].self;
- else if (cur[i] > arginh[i].nsupers)
- oneres[i] = 0; /* wild card */
else
oneres[i] = arginh[i].supervec[cur[i] - 1];
}
- *iter++ = oneres;
+ result[j++] = oneres;
}
+
+ /* terminate result vector with NULL pointer */
+ result[j++] = NULL;
+
+ Assert(j == nanswers);
+
+ return result;
}