diff options
Diffstat (limited to 'src/backend/utils/adt/sets.c')
-rw-r--r-- | src/backend/utils/adt/sets.c | 96 |
1 files changed, 79 insertions, 17 deletions
diff --git a/src/backend/utils/adt/sets.c b/src/backend/utils/adt/sets.c index a0c0aa8cb14..9a5f05134cd 100644 --- a/src/backend/utils/adt/sets.c +++ b/src/backend/utils/adt/sets.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.32 2000/06/09 01:11:09 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.33 2000/08/24 03:29:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -21,6 +21,8 @@ #include "catalog/catname.h" #include "catalog/indexing.h" #include "catalog/pg_proc.h" +#include "executor/executor.h" +#include "utils/fcache.h" #include "utils/sets.h" #include "utils/syscache.h" @@ -30,9 +32,9 @@ extern CommandDest whereToSendOutput; /* defined in tcop/postgres.c */ /* * SetDefine - converts query string defining set to an oid * - * The query string is used to store the set as a function in - * pg_proc. The name of the function is then changed to use the - * OID of its tuple in pg_proc. + * We create an SQL function having the given querystring as its body. + * The name of the function is then changed to use the OID of its tuple + * in pg_proc. */ Oid SetDefine(char *querystr, char *typename) @@ -57,11 +59,11 @@ SetDefine(char *querystr, char *typename) querystr, /* sourceCode */ fileName, /* fileName */ true, /* trusted */ - false, /* canCache XXX appropriate? */ - false, /* isStrict XXX appropriate? */ + false, /* canCache (assume unsafe) */ + false, /* isStrict (irrelevant, no args) */ 100, /* byte_pct */ - 0, /* perbyte_cpu */ - 0, /* percall_cpu */ + 0, /* perbyte_cpu */ + 0, /* percall_cpu */ 100, /* outin_ratio */ NIL, /* argList */ whereToSendOutput); @@ -74,11 +76,12 @@ SetDefine(char *querystr, char *typename) * until you start the next command.) */ CommandCounterIncrement(); + tup = SearchSysCacheTuple(PROCOID, ObjectIdGetDatum(setoid), 0, 0, 0); if (!HeapTupleIsValid(tup)) - elog(ERROR, "setin: unable to define set %s", querystr); + elog(ERROR, "SetDefine: unable to define set %s", querystr); /* * We can tell whether the set was already defined by checking the @@ -86,7 +89,7 @@ SetDefine(char *querystr, char *typename) * oid>" it's already defined. */ proc = (Form_pg_proc) GETSTRUCT(tup); - if (!strcmp((char *) procname, (char *) &(proc->proname))) + if (strcmp(procname, NameStr(proc->proname)) == 0) { /* make the real proc name */ sprintf(realprocname, "set%u", setoid); @@ -120,7 +123,7 @@ SetDefine(char *querystr, char *typename) setoid = newtup->t_data->t_oid; } else - elog(ERROR, "setin: could not find new set oid tuple"); + elog(ERROR, "SetDefine: could not find new set oid tuple"); if (RelationGetForm(procrel)->relhasindex) { @@ -132,20 +135,79 @@ SetDefine(char *querystr, char *typename) } heap_close(procrel, RowExclusiveLock); } + return setoid; } -/* This function is a placeholder. The parser uses the OID of this - * function to fill in the :funcid field of a set. This routine is - * never executed. At runtime, the OID of the actual set is substituted - * into the :funcid. +/* + * This function executes set evaluation. The parser sets up a set reference + * as a call to this function with the OID of the set to evaluate as argument. + * + * We build a new fcache for execution of the set's function and run the + * function until it says "no mas". The fn_extra field of the call's + * FmgrInfo record is a handy place to hold onto the fcache. (Since this + * is a built-in function, there is no competing use of fn_extra.) */ Datum seteval(PG_FUNCTION_ARGS) { Oid funcoid = PG_GETARG_OID(0); + FunctionCachePtr fcache; + Datum result; + bool isNull; + ExprDoneCond isDone; + + /* + * If this is the first call, we need to set up the fcache for the + * target set's function. + */ + fcache = (FunctionCachePtr) fcinfo->flinfo->fn_extra; + if (fcache == NULL) + { + fcache = init_fcache(funcoid, 0, fcinfo->flinfo->fn_mcxt); + fcinfo->flinfo->fn_extra = (void *) fcache; + } + + /* + * Evaluate the function. NOTE: we need no econtext because there + * are no arguments to evaluate. + */ + + /* ExecMakeFunctionResult assumes these are initialized at call: */ + isNull = false; + isDone = ExprSingleResult; - elog(ERROR, "seteval called for OID %u", funcoid); + result = ExecMakeFunctionResult(fcache, + NIL, + NULL, /* no econtext, see above */ + &isNull, + &isDone); + + /* + * If we're done with the results of this set function, get rid of + * its func cache so that we will start from the top next time. + * (Can you say "memory leak"? This feature is a crock anyway...) + */ + if (isDone != ExprMultipleResult) + { + pfree(fcache); + fcinfo->flinfo->fn_extra = NULL; + } + + /* + * Return isNull/isDone status. + */ + fcinfo->isnull = isNull; + + if (isDone != ExprSingleResult) + { + ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo; + + if (rsi && IsA(rsi, ReturnSetInfo)) + rsi->isDone = isDone; + else + elog(ERROR, "Set-valued function called in context that cannot accept a set"); + } - PG_RETURN_INT32(0); /* keep compiler happy */ + PG_RETURN_DATUM(result); } |