diff options
Diffstat (limited to 'src/backend/utils')
-rw-r--r-- | src/backend/utils/Gen_fmgrtab.sh.in | 196 | ||||
-rw-r--r-- | src/backend/utils/Makefile | 17 | ||||
-rw-r--r-- | src/backend/utils/adt/int8.c | 11 | ||||
-rw-r--r-- | src/backend/utils/adt/regproc.c | 3 | ||||
-rw-r--r-- | src/backend/utils/adt/selfuncs.c | 10 | ||||
-rw-r--r-- | src/backend/utils/adt/sets.c | 5 | ||||
-rw-r--r-- | src/backend/utils/cache/catcache.c | 3 | ||||
-rw-r--r-- | src/backend/utils/cache/fcache.c | 56 | ||||
-rw-r--r-- | src/backend/utils/cache/relcache.c | 3 | ||||
-rw-r--r-- | src/backend/utils/fmgr/dfmgr.c | 306 | ||||
-rw-r--r-- | src/backend/utils/fmgr/fmgr.c | 1765 | ||||
-rw-r--r-- | src/backend/utils/init/postinit.c | 3 |
12 files changed, 1383 insertions, 995 deletions
diff --git a/src/backend/utils/Gen_fmgrtab.sh.in b/src/backend/utils/Gen_fmgrtab.sh.in index 975e2a0f9a2..f075ac28376 100644 --- a/src/backend/utils/Gen_fmgrtab.sh.in +++ b/src/backend/utils/Gen_fmgrtab.sh.in @@ -1,14 +1,15 @@ #!/bin/sh #------------------------------------------------------------------------- # -# Gen_fmgrtab.sh-- -# shell script to generate fmgr.h and fmgrtab.c from pg_proc.h +# Gen_fmgrtab.sh +# shell script to generate fmgroids.h and fmgrtab.c from pg_proc.h # -# Copyright (c) 1994, Regents of the University of California +# Portions Copyright (c) 1996-2000, PostgreSQL, Inc +# Portions Copyright (c) 1994, Regents of the University of California # # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/backend/utils/Attic/Gen_fmgrtab.sh.in,v 1.21 2000/05/22 02:34:21 momjian Exp $ +# $Header: /cvsroot/pgsql/src/backend/utils/Attic/Gen_fmgrtab.sh.in,v 1.22 2000/05/28 17:56:05 tgl Exp $ # # NOTES # Passes any -D options on to cpp prior to generating the list @@ -16,12 +17,6 @@ # #------------------------------------------------------------------------- -if [ $? != 0 ] -then - echo `basename $0`: Bad option - exit 1 -fi - BKIOPTS='' # @@ -32,7 +27,7 @@ for opt in $* do case $opt in -D) BKIOPTS="$BKIOPTS -D$2"; shift; shift;; - -D*) BKIOPTS="$BKIOPTS $1";shift;; + -D*) BKIOPTS="$BKIOPTS $1"; shift;; --) shift; break;; -*) shift;; esac @@ -41,8 +36,8 @@ done INFILE=$1 RAWFILE=fmgr.raw CPPTMPFILE=fmgrtmp.c -HFILE=fmgr.h -TABCFILE=fmgrtab.c +OIDSFILE=fmgroids.h +TABLEFILE=fmgrtab.c # # Generate the file containing raw pg_proc tuple data @@ -63,7 +58,8 @@ sed -e 's/^.*OID[^=]*=[^0-9]*//' \ -e 's/[ ]*).*$//' | \ awk ' /^#/ { print; next; } -$4 == "11" { print; next; }' > $CPPTMPFILE +$4 == "11" { print; next; } +$4 == "12" { print; next; }' > $CPPTMPFILE @CPP@ $BKIOPTS $CPPTMPFILE | \ egrep '^[0-9]' | \ @@ -72,18 +68,21 @@ sort -n > $RAWFILE rm -f $CPPTMPFILE # -# Generate fmgr.h +# Generate fmgroids.h # -cat > $HFILE <<FuNkYfMgRsTuFf +cat > $OIDSFILE <<FuNkYfMgRsTuFf /*------------------------------------------------------------------------- * - * $HFILE-- - * Definitions for using internal procedures. + * $OIDSFILE + * Macros that define the OIDs of built-in functions. * + * These macros can be used to avoid a catalog lookup when a specific + * fmgr-callable function needs to be referenced. * - * Copyright (c) 1994, Regents of the University of California + * Portions Copyright (c) 1996-2000, PostgreSQL, Inc + * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: Gen_fmgrtab.sh.in,v 1.21 2000/05/22 02:34:21 momjian Exp $ + * $Id: Gen_fmgrtab.sh.in,v 1.22 2000/05/28 17:56:05 tgl Exp $ * * NOTES * ****************************** @@ -91,77 +90,12 @@ cat > $HFILE <<FuNkYfMgRsTuFf * ****************************** * * It has been GENERATED by $0 - * from $1 + * from $INFILE * *------------------------------------------------------------------------- */ -#ifndef FMGR_H -#define FMGR_H - -#include "postgres.h" - -typedef struct { - char *data[FUNC_MAX_ARGS]; -} FmgrValues; - -typedef struct { - func_ptr fn_addr; - func_ptr fn_plhandler; - Oid fn_oid; - int fn_nargs; -} FmgrInfo; - -/* - * defined in fmgr.c - */ -extern char *fmgr_c(FmgrInfo *finfo, FmgrValues *values, bool *isNull); -extern void fmgr_info(Oid procedureId, FmgrInfo *finfo); -extern char *fmgr(Oid procedureId, ... ); -extern char *fmgr_ptr(FmgrInfo *finfo, ... ); -extern char *fmgr_array_args(Oid procedureId, int nargs, - char *args[], bool *isNull); - -/* - * defined in dfmgr.c - */ -extern func_ptr fmgr_dynamic(Oid procedureId, int *pronargs); -extern void load_file(char *filename); - -/* - * For performance reasons, we often want to simply jump through a - * a function pointer (if it's valid, that is). These calls have - * been macroized so we can run them through a routine that does - * sanity-checking (and so we can track them down more easily when - * we must). - */ - -/* We don't make this static so fmgr_faddr() macros can access it */ -extern FmgrInfo *fmgr_pl_finfo; - -#define fmgr_faddr(finfo) \ -( \ - fmgr_pl_finfo = (finfo), \ - (func_ptr)(finfo)->fn_addr \ -) - -#ifdef TRACE_FMGR_PTR -#define FMGR_PTR2(FINFO, ARG1, ARG2) \ - fmgr_ptr(FINFO, 2, ARG1, ARG2) -#else -#define FMGR_PTR2(FINFO, ARG1, ARG2) \ -( \ - ((FINFO)->fn_addr) ? \ - (*(fmgr_faddr(FINFO)))(ARG1, ARG2) \ - : \ - fmgr((FINFO)->fn_oid, ARG1, ARG2) \ -) -#endif - -/* - * Flags for the builtin oprrest selectivity routines. - */ -#define SEL_CONSTANT 1 /* constant does not vary (not a parameter) */ -#define SEL_RIGHT 2 /* constant appears to right of operator */ +#ifndef FMGROIDS_H +#define FMGROIDS_H /* * Constant macros for the OIDs of entries in pg_proc. @@ -174,30 +108,33 @@ FuNkYfMgRsTuFf tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' < $RAWFILE | \ awk ' BEGIN { OFS = ""; } - { if (seenit[$2]++ == 0) print "#define F_", $2, " ", $1; }' >> $HFILE + { if (seenit[$2]++ == 0) print "#define F_", $2, " ", $1; }' >> $OIDSFILE -cat >> $HFILE <<FuNkYfMgRsTuFf +cat >> $OIDSFILE <<FuNkYfMgRsTuFf -#endif /* FMGR_H */ +#endif /* FMGROIDS_H */ FuNkYfMgRsTuFf # -# Generate fmgr function table file. +# Generate fmgr's built-in-function table. # -# Print out the bogus function declarations, then the table that -# refers to them. +# Print out the function declarations, then the table that refers to them. +# NB: the function declarations are bogus in the case of old-style functions, +# although they should be correct for new-style. Therefore we need to compile +# this table definition as a separate C file that won't need to include any +# "real" declarations for those functions! # -cat > $TABCFILE <<FuNkYfMgRtAbStUfF +cat > $TABLEFILE <<FuNkYfMgRtAbStUfF /*------------------------------------------------------------------------- * - * $TABCFILE-- + * $TABLEFILE * The function manager's table of internal functions. * - * Copyright (c) 1994, Regents of the University of California - * + * Portions Copyright (c) 1996-2000, PostgreSQL, Inc + * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/Attic/Gen_fmgrtab.sh.in,v 1.21 2000/05/22 02:34:21 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/Attic/Gen_fmgrtab.sh.in,v 1.22 2000/05/28 17:56:05 tgl Exp $ * * NOTES * @@ -206,72 +143,41 @@ cat > $TABCFILE <<FuNkYfMgRtAbStUfF * ****************************** * * It has been GENERATED by $0 - * from $1 + * from $INFILE * - * We lie here to cc about the return type and arguments of the + * We lie here to cc about the return type and arguments of old-style * builtin functions; all ld cares about is the fact that it * will need to resolve an external function reference. * *------------------------------------------------------------------------- */ -#include <string.h> #include "postgres.h" + #include "utils/fmgrtab.h" FuNkYfMgRtAbStUfF -awk '{ print "extern char *", $(NF-1), "();"; }' $RAWFILE >> $TABCFILE +awk '{ print "extern Datum", $(NF-1), "(PG_FUNCTION_ARGS);"; }' $RAWFILE >> $TABLEFILE -cat >> $TABCFILE <<FuNkYfMgRtAbStUfF +cat >> $TABLEFILE <<FuNkYfMgRtAbStUfF -static FmgrCall fmgr_builtins[] = { +const FmgrBuiltin fmgr_builtins[] = { FuNkYfMgRtAbStUfF -awk '{ printf (" {%d, %d, %s, \"%s\" },\n"), $1, $8, $(NF-1), $(NF-1) }' $RAWFILE >> $TABCFILE +awk '{ printf (" { %d, \"%s\", %d, %s, %s, %s },\n"), \ + $1, $(NF-1), $9, \ + ($8 == "t") ? "true" : "false", \ + ($4 == "11") ? "true" : "false", \ + $(NF-1) }' $RAWFILE >> $TABLEFILE -cat >> $TABCFILE <<FuNkYfMgRtAbStUfF +cat >> $TABLEFILE <<FuNkYfMgRtAbStUfF /* dummy entry is easier than getting rid of comma after last real one */ - { 0, 0, (func_ptr) NULL, NULL } + { 0, NULL, 0, false, false, (PGFunction) NULL } }; -/* Note FMGR_NBUILTINS excludes the dummy entry */ -#define FMGR_NBUILTINS ((sizeof(fmgr_builtins) / sizeof(FmgrCall)) - 1) - -FmgrCall *fmgr_isbuiltin(Oid id) -{ - int low = 0; - int high = FMGR_NBUILTINS - 1; - - /* Loop invariant: low is the first index that could contain target - * entry, and high is the last index that could contain it. - */ - while (low <= high) { - int i = (high + low) / 2; - FmgrCall * ptr = &fmgr_builtins[i]; - if (id == ptr->proid) - return ptr; - else if (id > ptr->proid) - low = i + 1; - else - high = i - 1; - } - return (FmgrCall *) NULL; -} - -func_ptr fmgr_lookupByName(char *name) -{ - /* Lookup a builtin by name. Note there can be more than one entry in - * the array matching this name, but they should all point to the same - * routine. - */ - int i; - for (i=0; i<FMGR_NBUILTINS; i++) { - if (strcmp(name, fmgr_builtins[i].funcName) == 0) - return fmgr_builtins[i].func; - } - return (func_ptr) NULL; -} +/* Note fmgr_nbuiltins excludes the dummy entry */ +const int fmgr_nbuiltins = (sizeof(fmgr_builtins) / sizeof(FmgrBuiltin)) - 1; FuNkYfMgRtAbStUfF diff --git a/src/backend/utils/Makefile b/src/backend/utils/Makefile index e37c85761e6..eba9b13af29 100644 --- a/src/backend/utils/Makefile +++ b/src/backend/utils/Makefile @@ -4,12 +4,12 @@ # Makefile for utils # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/backend/utils/Makefile,v 1.10 1999/12/13 22:34:28 momjian Exp $ +# $Header: /cvsroot/pgsql/src/backend/utils/Makefile,v 1.11 2000/05/28 17:56:05 tgl Exp $ # #------------------------------------------------------------------------- SRCDIR = ../.. -include ../../Makefile.global +include $(SRCDIR)/Makefile.global INCLUDE_OPT = -I.. @@ -35,19 +35,14 @@ SUBSYS.o: $(OBJS) submake: for i in $(DIRS); do $(MAKE) -C $$i SUBSYS.o; done -fmgrtab.o: ../fmgr.h - -../fmgr.h: - $(MAKE) -C .. fmgr.h - -fmgr.h fmgrtab.c: ./Gen_fmgrtab.sh ../../include/catalog/pg_proc.h - sh $(SHOPTS) Gen_fmgrtab.sh ../../include/catalog/pg_proc.h +fmgroids.h fmgrtab.c: Gen_fmgrtab.sh $(SRCDIR)/include/catalog/pg_proc.h + $(SHELL) $(SHOPTS) Gen_fmgrtab.sh $(SRCDIR)/include/catalog/pg_proc.h clean: - rm -f SUBSYS.o fmgr.h fmgrtab.o fmgrtab.c + rm -f SUBSYS.o fmgroids.h fmgrtab.o fmgrtab.c for i in $(DIRS); do $(MAKE) -C $$i clean; done -dep depend: fmgr.h fmgrtab.c +dep depend: fmgroids.h fmgrtab.c for i in $(DIRS); do $(MAKE) -C $$i depend; done ifeq (depend,$(wildcard depend)) diff --git a/src/backend/utils/adt/int8.c b/src/backend/utils/adt/int8.c index 018352df1ad..a30a920b6a4 100644 --- a/src/backend/utils/adt/int8.c +++ b/src/backend/utils/adt/int8.c @@ -3,6 +3,12 @@ * int8.c * Internal 64-bit integer operations * + * Portions Copyright (c) 1996-2000, PostgreSQL, Inc + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/utils/adt/int8.c,v 1.19 2000/05/28 17:56:05 tgl Exp $ + * *------------------------------------------------------------------------- */ #include <ctype.h> @@ -18,6 +24,11 @@ #include "utils/int8.h" +/* this should be set in config.h, but just in case it wasn't: */ +#ifndef INT64_FORMAT +#define INT64_FORMAT "%ld" +#endif + #define MAXINT8LEN 25 #ifndef INT_MAX diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c index 4060a846655..6db76ac8c5a 100644 --- a/src/backend/utils/adt/regproc.c +++ b/src/backend/utils/adt/regproc.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/regproc.c,v 1.54 2000/04/12 17:15:51 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/regproc.c,v 1.55 2000/05/28 17:56:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -22,6 +22,7 @@ #include "catalog/pg_type.h" #include "miscadmin.h" #include "utils/builtins.h" +#include "utils/fmgroids.h" #include "utils/syscache.h" /***************************************************************************** diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index 4718dc668a7..c93ef767d8e 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -15,7 +15,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.66 2000/05/26 17:19:15 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.67 2000/05/28 17:56:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -889,17 +889,17 @@ convert_numeric_to_scalar(Datum value, Oid typid) switch (typid) { case BOOLOID: - return (double) DatumGetUInt8(value); + return (double) DatumGetBool(value); case INT2OID: return (double) DatumGetInt16(value); case INT4OID: return (double) DatumGetInt32(value); case INT8OID: - return (double) (*i8tod((int64 *) DatumGetPointer(value))); + return (double) DatumGetInt64(value); case FLOAT4OID: - return (double) (*DatumGetFloat32(value)); + return (double) DatumGetFloat4(value); case FLOAT8OID: - return (double) (*DatumGetFloat64(value)); + return (double) DatumGetFloat8(value); case NUMERICOID: return (double) (*numeric_float8((Numeric) DatumGetPointer(value))); case OIDOID: diff --git a/src/backend/utils/adt/sets.c b/src/backend/utils/adt/sets.c index dbc5ea4b8fa..cc629c3ad85 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.30 2000/01/26 05:57:14 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.31 2000/05/28 17:56:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -56,8 +56,9 @@ SetDefine(char *querystr, char *typename) "sql", /* languageName */ querystr, /* sourceCode */ fileName, /* fileName */ - false, /* canCache */ true, /* trusted */ + false, /* canCache XXX appropriate? */ + false, /* isStrict XXX appropriate? */ 100, /* byte_pct */ 0, /* perbyte_cpu */ 0, /* percall_cpu */ diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c index b593920b1a8..e5fb546ca70 100644 --- a/src/backend/utils/cache/catcache.c +++ b/src/backend/utils/cache/catcache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.63 2000/04/12 17:15:52 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.64 2000/05/28 17:56:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -24,6 +24,7 @@ #include "catalog/indexing.h" #include "miscadmin.h" #include "utils/builtins.h" +#include "utils/fmgroids.h" #include "utils/catcache.h" #include "utils/syscache.h" diff --git a/src/backend/utils/cache/fcache.c b/src/backend/utils/cache/fcache.c index 26f4cbd8d06..33528d7bb20 100644 --- a/src/backend/utils/cache/fcache.c +++ b/src/backend/utils/cache/fcache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/fcache.c,v 1.30 2000/04/12 17:15:53 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/fcache.c,v 1.31 2000/05/28 17:56:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -24,20 +24,9 @@ static Oid GetDynamicFuncArgType(Var *arg, ExprContext *econtext); static FunctionCachePtr init_fcache(Oid foid, - bool use_syscache, - List *argList, - ExprContext *econtext); + List *argList, + ExprContext *econtext); -/*----------------------------------------------------------------- - * - * Initialize the 'FunctionCache' given the PG_PROC oid. - * - * - * NOTE: This function can be called when the system cache is being - * initialized. Therefore, use_syscache should ONLY be true - * when the function return type is interesting (ie: set_fcache). - *----------------------------------------------------------------- - */ #define FuncArgTypeIsDynamic(arg) \ (IsA(arg,Var) && ((Var*)arg)->varattno == InvalidAttrNumber) @@ -53,7 +42,6 @@ GetDynamicFuncArgType(Var *arg, ExprContext *econtext) rtid = ((Var *) arg)->varno; relname = (char *) getrelname(rtid, econtext->ecxt_range_table); - tup = SearchSysCacheTuple(TYPENAME, PointerGetDatum(relname), 0, 0, 0); @@ -64,9 +52,14 @@ GetDynamicFuncArgType(Var *arg, ExprContext *econtext) return tup->t_data->t_oid; } +/*----------------------------------------------------------------- + * + * Initialize a 'FunctionCache' struct given the PG_PROC oid. + * + *----------------------------------------------------------------- + */ static FunctionCachePtr init_fcache(Oid foid, - bool use_syscache, List *argList, ExprContext *econtext) { @@ -79,16 +72,13 @@ init_fcache(Oid foid, text *tmp; bool isNull; + retval = (FunctionCachePtr) palloc(sizeof(FunctionCache)); + MemSet(retval, 0, sizeof(FunctionCache)); + /* ---------------- * get the procedure tuple corresponding to the given functionOid * ---------------- */ - retval = (FunctionCachePtr) palloc(sizeof(FunctionCache)); - memset(retval, 0, sizeof(FunctionCache)); - - if (!use_syscache) - elog(ERROR, "what the ????, init the fcache without the catalogs?"); - procedureTuple = SearchSysCacheTuple(PROCOID, ObjectIdGetDatum(foid), 0, 0, 0); @@ -114,8 +104,7 @@ init_fcache(Oid foid, typeStruct = (Form_pg_type) GETSTRUCT(typeTuple); /* ---------------- - * get the type length and by-value from the type tuple and - * save the information in our one element cache. + * get the type length and by-value flag from the type tuple * ---------------- */ retval->typlen = typeStruct->typlen; @@ -136,10 +125,9 @@ init_fcache(Oid foid, retval->foid = foid; retval->language = procedureStruct->prolang; retval->func_state = (char *) NULL; - retval->setArg = NULL; + retval->setArg = (Datum) 0; retval->hasSetArg = false; retval->oneResult = !procedureStruct->proretset; - retval->istrusted = procedureStruct->proistrusted; /* * If we are returning exactly one result then we have to copy tuples @@ -162,9 +150,8 @@ init_fcache(Oid foid, slot->ttc_tupleDescriptor = (TupleDesc) NULL; slot->ttc_buffer = InvalidBuffer; slot->ttc_whichplan = -1; - retval->funcSlot = (Pointer) slot; - relationTuple = (HeapTuple) + relationTuple = SearchSysCacheTuple(RELNAME, PointerGetDatum(&typeStruct->typname), 0, 0, 0); @@ -177,10 +164,12 @@ init_fcache(Oid foid, else td = CreateTemplateTupleDesc(1); - ((TupleTableSlot *) retval->funcSlot)->ttc_tupleDescriptor = td; + slot->ttc_tupleDescriptor = td; + + retval->funcSlot = (Pointer) slot; } else - retval->funcSlot = (char *) NULL; + retval->funcSlot = (Pointer) NULL; nargs = procedureStruct->pronargs; retval->nargs = nargs; @@ -189,8 +178,6 @@ init_fcache(Oid foid, { Oid *argTypes; - retval->nullVect = (bool *) palloc(retval->nargs * sizeof(bool)); - if (retval->language == SQLlanguageId) { int i; @@ -218,7 +205,6 @@ init_fcache(Oid foid, else { retval->argOidVect = (Oid *) NULL; - retval->nullVect = (BoolPtr) NULL; } if (procedureStruct->prolang == SQLlanguageId) @@ -257,7 +243,7 @@ init_fcache(Oid foid, retval->nargs = retval->func.fn_nargs; } else - retval->func.fn_addr = (func_ptr) NULL; + retval->func.fn_addr = (PGFunction) NULL; return retval; } @@ -269,7 +255,7 @@ setFcache(Node *node, Oid foid, List *argList, ExprContext *econtext) Oper *onode; FunctionCachePtr fcache; - fcache = init_fcache(foid, true, argList, econtext); + fcache = init_fcache(foid, argList, econtext); if (IsA(node, Oper)) { diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index b9e86d905ec..30f422de7f0 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.96 2000/05/21 02:28:55 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.97 2000/05/28 17:56:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -58,6 +58,7 @@ #include "storage/bufmgr.h" #include "storage/smgr.h" #include "utils/catcache.h" +#include "utils/fmgroids.h" #include "utils/relcache.h" #include "utils/temprel.h" diff --git a/src/backend/utils/fmgr/dfmgr.c b/src/backend/utils/fmgr/dfmgr.c index a460fab05c2..2dfb54391c3 100644 --- a/src/backend/utils/fmgr/dfmgr.c +++ b/src/backend/utils/fmgr/dfmgr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.39 2000/04/12 17:15:57 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.40 2000/05/28 17:56:07 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -17,190 +17,127 @@ #include "postgres.h" -#include "utils/dynamic_loader.h" - #include "access/heapam.h" -#include "catalog/catname.h" #include "catalog/pg_proc.h" #include "dynloader.h" #include "utils/builtins.h" +#include "utils/dynamic_loader.h" #include "utils/syscache.h" + +/* + * List of dynamically loaded files. + */ + +typedef struct df_files +{ + struct df_files *next; /* List link */ + dev_t device; /* Device file is on */ + ino_t inode; /* Inode number of file */ + void *handle; /* a handle for pg_dl* functions */ + char filename[1]; /* Full pathname of file */ + /* we allocate the block big enough for actual length of pathname. + * filename[] must be last item in struct! + */ +} DynamicFileList; + static DynamicFileList *file_list = (DynamicFileList *) NULL; static DynamicFileList *file_tail = (DynamicFileList *) NULL; -#define NOT_EQUAL(A, B) (((A).st_ino != (B).inode) \ - || ((A).st_dev != (B).device)) +#define SAME_INODE(A,B) ((A).st_ino == (B).inode && (A).st_dev == (B).device) -static Oid procedureId_save = -1; -static int pronargs_save; -static func_ptr user_fn_save = (func_ptr) NULL; -static func_ptr handle_load(char *filename, char *funcname); -func_ptr -fmgr_dynamic(Oid procedureId, int *pronargs) +PGFunction +fmgr_dynamic(Oid functionId) { HeapTuple procedureTuple; Form_pg_proc procedureStruct; char *proname, - *linksymbol, + *prosrcstring, *probinstring; - char *prosrcstring = NULL; - Datum probinattr; - Datum prosrcattr; - func_ptr user_fn; - Relation rel; + Datum prosrcattr, + probinattr; + PGFunction user_fn; bool isnull; - /* Implement simple one-element cache for function lookups */ - if (procedureId == procedureId_save) - { - *pronargs = pronargs_save; - return user_fn_save; - } - - /* - * The procedure isn't a builtin, so we'll have to do a catalog lookup - * to find its pg_proc entry. Moreover, since probin is varlena, - * we're going to have to use heap_getattr, which means we need the - * reldesc, which means we need to open the relation. So we might as - * well do that first and get the benefit of SI inval if needed. - */ - rel = heap_openr(ProcedureRelationName, AccessShareLock); - procedureTuple = SearchSysCacheTuple(PROCOID, - ObjectIdGetDatum(procedureId), + ObjectIdGetDatum(functionId), 0, 0, 0); if (!HeapTupleIsValid(procedureTuple)) - { - elog(ERROR, "fmgr: Cache lookup failed for procedure %u\n", - procedureId); - return (func_ptr) NULL; - } - + elog(ERROR, "fmgr_dynamic: function %u: cache lookup failed", + functionId); procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple); + proname = NameStr(procedureStruct->proname); - pronargs_save = *pronargs = procedureStruct->pronargs; - probinattr = heap_getattr(procedureTuple, - Anum_pg_proc_probin, - RelationGetDescr(rel), &isnull); - if (!PointerIsValid(probinattr) /* || isnull */ ) + + prosrcattr = SysCacheGetAttr(PROCOID, procedureTuple, + Anum_pg_proc_prosrc, &isnull); + if (isnull || !PointerIsValid(prosrcattr)) { - heap_close(rel, AccessShareLock); - elog(ERROR, "fmgr: Could not extract probin for %u from %s", - procedureId, ProcedureRelationName); - return (func_ptr) NULL; + elog(ERROR, "fmgr: Could not extract prosrc for %u from pg_proc", + functionId); } - probinstring = textout((struct varlena *) probinattr); - - prosrcattr = heap_getattr(procedureTuple, - Anum_pg_proc_prosrc, - RelationGetDescr(rel), &isnull); + prosrcstring = textout((text *) DatumGetPointer(prosrcattr)); - if (isnull) - { /* Use the proname for the link symbol */ - linksymbol = proname; - } - else if (!PointerIsValid(prosrcattr)) - { /* pg_proc must be messed up! */ - heap_close(rel, AccessShareLock); - elog(ERROR, "fmgr: Could not extract prosrc for %u from %s", - procedureId, ProcedureRelationName); - return (func_ptr) NULL; - } - else - { /* The text in prosrcattr is either "-" or - * a link symbol */ - prosrcstring = textout((struct varlena *) prosrcattr); - if (strcmp(prosrcstring, "-") == 0) - linksymbol = proname; - else - linksymbol = prosrcstring; + probinattr = SysCacheGetAttr(PROCOID, procedureTuple, + Anum_pg_proc_probin, &isnull); + if (isnull || !PointerIsValid(probinattr)) + { + elog(ERROR, "fmgr: Could not extract probin for %u from pg_proc", + functionId); } + probinstring = textout((text *) DatumGetPointer(probinattr)); - heap_close(rel, AccessShareLock); - - user_fn = handle_load(probinstring, linksymbol); + user_fn = load_external_function(probinstring, prosrcstring); + pfree(prosrcstring); pfree(probinstring); - if (prosrcstring) - pfree(prosrcstring); - - procedureId_save = procedureId; - user_fn_save = user_fn; return user_fn; } -static func_ptr -handle_load(char *filename, char *funcname) +PGFunction +load_external_function(char *filename, char *funcname) { - DynamicFileList *file_scanner = (DynamicFileList *) NULL; - func_ptr retval = (func_ptr) NULL; + DynamicFileList *file_scanner; + PGFunction retval; char *load_error; struct stat stat_buf; /* - * Do this because loading files may screw up the dynamic function - * manager otherwise. - */ - procedureId_save = -1; - - /* - * Scan the list of loaded FILES to see if the function has been - * loaded. + * Scan the list of loaded FILES to see if the file has been loaded. */ - - if (filename != (char *) NULL) + for (file_scanner = file_list; + file_scanner != (DynamicFileList *) NULL && + strcmp(filename, file_scanner->filename) != 0; + file_scanner = file_scanner->next) + ; + if (file_scanner == (DynamicFileList *) NULL) { + /* + * Check for same files - different paths (ie, symlink or link) + */ + if (stat(filename, &stat_buf) == -1) + elog(ERROR, "stat failed on file '%s': %m", filename); + for (file_scanner = file_list; - file_scanner != (DynamicFileList *) NULL - && file_scanner->filename != (char *) NULL - && strcmp(filename, file_scanner->filename) != 0; + file_scanner != (DynamicFileList *) NULL && + !SAME_INODE(stat_buf, *file_scanner); file_scanner = file_scanner->next) ; - if (file_scanner == (DynamicFileList *) NULL) - { - if (stat(filename, &stat_buf) == -1) - elog(ERROR, "stat failed on file '%s': %m", filename); - - for (file_scanner = file_list; - file_scanner != (DynamicFileList *) NULL - && (NOT_EQUAL(stat_buf, *file_scanner)); - file_scanner = file_scanner->next) - ; - - /* - * Same files - different paths (ie, symlink or link) - */ - if (file_scanner != (DynamicFileList *) NULL) - strcpy(file_scanner->filename, filename); - - } } - else - file_scanner = (DynamicFileList *) NULL; - - /* - * File not loaded yet. - */ if (file_scanner == (DynamicFileList *) NULL) { - if (file_list == (DynamicFileList *) NULL) - { - file_list = (DynamicFileList *) - malloc(sizeof(DynamicFileList)); - file_scanner = file_list; - } - else - { - file_tail->next = (DynamicFileList *) - malloc(sizeof(DynamicFileList)); - file_scanner = file_tail->next; - } - MemSet((char *) file_scanner, 0, sizeof(DynamicFileList)); + /* + * File not loaded yet. + */ + file_scanner = (DynamicFileList *) + malloc(sizeof(DynamicFileList) + strlen(filename)); + if (file_scanner == NULL) + elog(FATAL, "Out of memory in load_external_function"); + MemSet((char *) file_scanner, 0, sizeof(DynamicFileList)); strcpy(file_scanner->filename, filename); file_scanner->device = stat_buf.st_dev; file_scanner->inode = stat_buf.st_ino; @@ -210,42 +147,36 @@ handle_load(char *filename, char *funcname) if (file_scanner->handle == (void *) NULL) { load_error = (char *) pg_dlerror(); - if (file_scanner == file_list) - file_list = (DynamicFileList *) NULL; - else - file_tail->next = (DynamicFileList *) NULL; - free((char *) file_scanner); elog(ERROR, "Load of file %s failed: %s", filename, load_error); } - /* - * Just load the file - we are done with that so return. - */ + /* OK to link it into list */ + if (file_list == (DynamicFileList *) NULL) + file_list = file_scanner; + else + file_tail->next = file_scanner; file_tail = file_scanner; - - if (funcname == (char *) NULL) - return (func_ptr) NULL; } - retval = (func_ptr) pg_dlsym(file_scanner->handle, funcname); + /* + * If funcname is NULL, we only wanted to load the file. + */ + if (funcname == (char *) NULL) + return (PGFunction) NULL; + + retval = pg_dlsym(file_scanner->handle, funcname); - if (retval == (func_ptr) NULL) + if (retval == (PGFunction) NULL) elog(ERROR, "Can't find function %s in file %s", funcname, filename); return retval; } /* - * This function loads files by the following: - * - * If the file is already loaded: - * o Zero out that file's loaded space (so it doesn't screw up linking) - * o Free all space associated with that file - * o Free that file's descriptor. - * - * Now load the file by calling handle_load with a NULL argument as the - * function. + * This function loads a shlib file without looking up any particular + * function in it. If the same shlib has previously been loaded, + * unload and reload it. */ void load_file(char *filename) @@ -253,7 +184,6 @@ load_file(char *filename) DynamicFileList *file_scanner, *p; struct stat stat_buf; - int done = 0; /* * We need to do stat() in order to determine whether this is the same @@ -263,48 +193,32 @@ load_file(char *filename) if (stat(filename, &stat_buf) == -1) elog(ERROR, "LOAD: could not open file '%s': %m", filename); - if (file_list != (DynamicFileList *) NULL - && !NOT_EQUAL(stat_buf, *file_list)) + if (file_list != (DynamicFileList *) NULL) { - file_scanner = file_list; - file_list = file_list->next; - pg_dlclose(file_scanner->handle); - free((char *) file_scanner); - } - else if (file_list != (DynamicFileList *) NULL) - { - file_scanner = file_list; - while (!done) + if (SAME_INODE(stat_buf, *file_list)) { - if (file_scanner->next == (DynamicFileList *) NULL) - done = 1; - else if (!NOT_EQUAL(stat_buf, *(file_scanner->next))) - done = 1; - else - file_scanner = file_scanner->next; + p = file_list; + file_list = p->next; + pg_dlclose(p->handle); + free((char *) p); } - - if (file_scanner->next != (DynamicFileList *) NULL) + else { - p = file_scanner->next; - file_scanner->next = file_scanner->next->next; - pg_dlclose(file_scanner->handle); - free((char *) p); + for (file_scanner = file_list; + file_scanner->next != (DynamicFileList *) NULL; + file_scanner = file_scanner->next) + { + if (SAME_INODE(stat_buf, *(file_scanner->next))) + { + p = file_scanner->next; + file_scanner->next = p->next; + pg_dlclose(p->handle); + free((char *) p); + break; + } + } } } - handle_load(filename, (char *) NULL); -} - -/* Is this used? bjm 1998/10/08 No. tgl 1999/02/07 */ -#ifdef NOT_USED -func_ptr -trigger_dynamic(char *filename, char *funcname) -{ - func_ptr trigger_fn; - trigger_fn = handle_load(filename, funcname); - - return trigger_fn; + load_external_function(filename, (char *) NULL); } - -#endif diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c index bdac32a2551..793497834fd 100644 --- a/src/backend/utils/fmgr/fmgr.c +++ b/src/backend/utils/fmgr/fmgr.c @@ -1,14 +1,14 @@ /*------------------------------------------------------------------------- * * fmgr.c - * Interface routines for the table-driven function manager. + * The Postgres function manager. * * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.39 2000/05/22 02:34:22 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.40 2000/05/28 17:56:07 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -17,112 +17,249 @@ #include "catalog/pg_language.h" #include "catalog/pg_proc.h" -#include "commands/trigger.h" +#include "commands/trigger.h" /* TEMPORARY: for CurrentTriggerData */ #include "utils/builtins.h" #include "utils/fmgrtab.h" #include "utils/syscache.h" +static Datum fmgr_oldstyle(PG_FUNCTION_ARGS); +static Datum fmgr_untrusted(PG_FUNCTION_ARGS); +static Datum fmgr_sql(PG_FUNCTION_ARGS); + /* - * Interface for PL functions - * - * XXX: use of global fmgr_pl_finfo variable is really ugly. FIXME + * Lookup routines for builtin-function table. We can search by either Oid + * or name, but search by Oid is much faster. */ -FmgrInfo *fmgr_pl_finfo; -static char * -fmgr_pl(char *arg0,...) +static const FmgrBuiltin * +fmgr_isbuiltin(Oid id) { - va_list pvar; - FmgrValues values; - int n_arguments = fmgr_pl_finfo->fn_nargs; - bool isNull = false; - int i; + int low = 0; + int high = fmgr_nbuiltins - 1; - memset(&values, 0, sizeof(values)); + /* Loop invariant: low is the first index that could contain target + * entry, and high is the last index that could contain it. + */ + while (low <= high) + { + int i = (high + low) / 2; + const FmgrBuiltin *ptr = &fmgr_builtins[i]; - if (n_arguments > 0) + if (id == ptr->foid) + return ptr; + else if (id > ptr->foid) + low = i + 1; + else + high = i - 1; + } + return (const FmgrBuiltin *) NULL; +} + +/* + * Lookup a builtin by name. Note there can be more than one entry in + * the array with the same name, but they should all point to the same + * routine. + */ +static const FmgrBuiltin * +fmgr_lookupByName(const char *name) +{ + int i; + + for (i = 0; i < fmgr_nbuiltins; i++) { - values.data[0] = arg0; - if (n_arguments > 1) + if (strcmp(name, fmgr_builtins[i].funcName) == 0) + return fmgr_builtins + i; + } + return (const FmgrBuiltin *) NULL; +} + +/* + * This routine fills a FmgrInfo struct, given the OID + * of the function to be called. + */ +void +fmgr_info(Oid functionId, FmgrInfo *finfo) +{ + const FmgrBuiltin *fbp; + HeapTuple procedureTuple; + Form_pg_proc procedureStruct; + HeapTuple languageTuple; + Form_pg_language languageStruct; + Oid language; + char *prosrc; + + finfo->fn_oid = functionId; + finfo->fn_extra = NULL; + + if ((fbp = fmgr_isbuiltin(functionId)) != NULL) + { + /* + * Fast path for builtin functions: don't bother consulting pg_proc + */ + finfo->fn_nargs = fbp->nargs; + finfo->fn_strict = fbp->strict; + if (fbp->oldstyle) { - if (n_arguments > FUNC_MAX_ARGS) - elog(ERROR, "fmgr_pl: function %u: too many arguments (%d > %d)", - fmgr_pl_finfo->fn_oid, n_arguments, FUNC_MAX_ARGS); - va_start(pvar, arg0); - for (i = 1; i < n_arguments; i++) - values.data[i] = va_arg(pvar, char *); - va_end(pvar); + finfo->fn_addr = fmgr_oldstyle; + finfo->fn_extra = (void *) fbp->func; } + else + { + finfo->fn_addr = fbp->func; + } + return; } - /* Call the PL handler */ - CurrentTriggerData = NULL; - return (*(fmgr_pl_finfo->fn_plhandler)) (fmgr_pl_finfo, - &values, - &isNull); -} + /* Otherwise we need the pg_proc entry */ + procedureTuple = SearchSysCacheTuple(PROCOID, + ObjectIdGetDatum(functionId), + 0, 0, 0); + if (!HeapTupleIsValid(procedureTuple)) + elog(ERROR, "fmgr_info: function %u: cache lookup failed", + functionId); + procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple); + finfo->fn_nargs = procedureStruct->pronargs; + finfo->fn_strict = procedureStruct->proisstrict; -/* - * Interface for untrusted functions - */ + if (!procedureStruct->proistrusted) + { + finfo->fn_addr = fmgr_untrusted; + return; + } -static char * -fmgr_untrusted(char *arg0,...) -{ + language = procedureStruct->prolang; + switch (language) + { + case INTERNALlanguageId: + case NEWINTERNALlanguageId: + /* + * For an ordinary builtin function, we should never get + * here because the isbuiltin() search above will have + * succeeded. However, if the user has done a CREATE + * FUNCTION to create an alias for a builtin function, we + * can end up here. In that case we have to look up the + * function by name. The name of the internal function is + * stored in prosrc (it doesn't have to be the same as the + * name of the alias!) + */ + prosrc = textout(&(procedureStruct->prosrc)); + fbp = fmgr_lookupByName(prosrc); + if (fbp == NULL) + elog(ERROR, "fmgr_info: function %s not in internal table", + prosrc); + pfree(prosrc); + if (fbp->oldstyle) + { + finfo->fn_addr = fmgr_oldstyle; + finfo->fn_extra = (void *) fbp->func; + } + else + { + finfo->fn_addr = fbp->func; + } + break; - /* - * Currently these are unsupported. Someday we might do something - * like forking a subprocess to execute 'em. - */ - elog(ERROR, "Untrusted functions not supported."); - return NULL; /* keep compiler happy */ + case ClanguageId: + finfo->fn_addr = fmgr_oldstyle; + finfo->fn_extra = (void *) fmgr_dynamic(functionId); + break; + + case NEWClanguageId: + finfo->fn_addr = fmgr_dynamic(functionId); + break; + + case SQLlanguageId: + finfo->fn_addr = fmgr_sql; + break; + + default: + /* + * Might be a created procedural language; try to look it up. + */ + languageTuple = SearchSysCacheTuple(LANGOID, + ObjectIdGetDatum(language), + 0, 0, 0); + if (!HeapTupleIsValid(languageTuple)) + { + elog(ERROR, "fmgr_info: cache lookup for language %u failed", + language); + } + languageStruct = (Form_pg_language) GETSTRUCT(languageTuple); + if (languageStruct->lanispl) + { + FmgrInfo plfinfo; + + fmgr_info(languageStruct->lanplcallfoid, &plfinfo); + finfo->fn_addr = plfinfo.fn_addr; + /* + * If lookup of the PL handler function produced nonnull + * fn_extra, complain --- it must be an oldstyle function! + * We no longer support oldstyle PL handlers. + */ + if (plfinfo.fn_extra != NULL) + elog(ERROR, "fmgr_info: language %u has old-style handler", + language); + } + else + { + elog(ERROR, "fmgr_info: function %u: unsupported language %u", + functionId, language); + } + break; + } } /* - * Interface for SQL-language functions + * Specialized lookup routine for pg_proc.c: given the alleged name of + * an internal function, return the OID of the function's language. + * If the name is not known, return InvalidOid. */ - -static char * -fmgr_sql(char *arg0,...) +Oid +fmgr_internal_language(const char *proname) { + const FmgrBuiltin *fbp = fmgr_lookupByName(proname); - /* - * XXX It'd be really nice to support SQL functions anywhere that - * builtins are supported. What would we have to do? What pitfalls - * are there? - */ - elog(ERROR, "SQL-language function not supported in this context."); - return NULL; /* keep compiler happy */ + if (fbp == NULL) + return InvalidOid; + return fbp->oldstyle ? INTERNALlanguageId : NEWINTERNALlanguageId; } /* - * fmgr_c is not really for C functions only; it can be called for functions - * in any language. Many parts of the system use this entry point if they - * want to pass the arguments in an array rather than as explicit arguments. + * Handler for old-style internal and "C" language functions + * + * We expect fmgr_info to have placed the old-style function's address + * in fn_extra of *flinfo. This is a bit of a hack since fn_extra is really + * void * which might be a different size than a pointer to function, but + * it will work on any machine that our old-style call interface works on... */ - -char * -fmgr_c(FmgrInfo *finfo, - FmgrValues *values, - bool *isNull) +static Datum +fmgr_oldstyle(PG_FUNCTION_ARGS) { - char *returnValue = (char *) NULL; - int n_arguments = finfo->fn_nargs; - func_ptr user_fn = fmgr_faddr(finfo); + char *returnValue = NULL; + int n_arguments = fcinfo->nargs; + int i; + bool isnull; + func_ptr user_fn; + + if (fcinfo->flinfo == NULL || fcinfo->flinfo->fn_extra == NULL) + elog(ERROR, "Internal error: fmgr_oldstyle received NULL function pointer"); /* - * If finfo contains a PL handler for this function, call that - * instead. + * Result is NULL if any argument is NULL, but we still call the function + * (peculiar, but that's the way it worked before, and after all this is + * a backwards-compatibility wrapper). Note, however, that we'll never + * get here with NULL arguments if the function is marked strict. */ - if (finfo->fn_plhandler != NULL) - return (*(finfo->fn_plhandler)) (finfo, values, isNull); + isnull = false; + for (i = 0; i < n_arguments; i++) + isnull |= PG_ARGISNULL(i); + fcinfo->isnull = isnull; - if (user_fn == (func_ptr) NULL) - elog(ERROR, "Internal error: fmgr_c received NULL function pointer."); + user_fn = (func_ptr) fcinfo->flinfo->fn_extra; switch (n_arguments) { @@ -130,604 +267,1038 @@ fmgr_c(FmgrInfo *finfo, returnValue = (*user_fn) (); break; case 1: - /* NullValue() uses isNull to check if args[0] is NULL */ - returnValue = (*user_fn) (values->data[0], isNull); + /* + * nullvalue() used to use isNull to check if arg is NULL; + * perhaps there are other functions still out there that + * also rely on this undocumented hack? + */ + returnValue = (*user_fn) (fcinfo->arg[0], & fcinfo->isnull); break; case 2: - returnValue = (*user_fn) (values->data[0], values->data[1]); + returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1]); break; case 3: - returnValue = (*user_fn) (values->data[0], values->data[1], - values->data[2]); + returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], + fcinfo->arg[2]); break; case 4: - returnValue = (*user_fn) (values->data[0], values->data[1], - values->data[2], values->data[3]); + returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], + fcinfo->arg[2], fcinfo->arg[3]); break; case 5: - returnValue = (*user_fn) (values->data[0], values->data[1], - values->data[2], values->data[3], - values->data[4]); + returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], + fcinfo->arg[2], fcinfo->arg[3], + fcinfo->arg[4]); break; case 6: - returnValue = (*user_fn) (values->data[0], values->data[1], - values->data[2], values->data[3], - values->data[4], values->data[5]); + returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], + fcinfo->arg[2], fcinfo->arg[3], + fcinfo->arg[4], fcinfo->arg[5]); break; case 7: - returnValue = (*user_fn) (values->data[0], values->data[1], - values->data[2], values->data[3], - values->data[4], values->data[5], - values->data[6]); + returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], + fcinfo->arg[2], fcinfo->arg[3], + fcinfo->arg[4], fcinfo->arg[5], + fcinfo->arg[6]); break; case 8: - returnValue = (*user_fn) (values->data[0], values->data[1], - values->data[2], values->data[3], - values->data[4], values->data[5], - values->data[6], values->data[7]); + returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], + fcinfo->arg[2], fcinfo->arg[3], + fcinfo->arg[4], fcinfo->arg[5], + fcinfo->arg[6], fcinfo->arg[7]); break; case 9: - returnValue = (*user_fn) (values->data[0], values->data[1], - values->data[2], values->data[3], - values->data[4], values->data[5], - values->data[6], values->data[7], - values->data[8]); + returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], + fcinfo->arg[2], fcinfo->arg[3], + fcinfo->arg[4], fcinfo->arg[5], + fcinfo->arg[6], fcinfo->arg[7], + fcinfo->arg[8]); break; -#if FUNC_MAX_ARGS >= 10 case 10: - returnValue = (*user_fn) (values->data[0], values->data[1], - values->data[2], values->data[3], - values->data[4], values->data[5], - values->data[6], values->data[7], - values->data[8], values->data[9]); + returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], + fcinfo->arg[2], fcinfo->arg[3], + fcinfo->arg[4], fcinfo->arg[5], + fcinfo->arg[6], fcinfo->arg[7], + fcinfo->arg[8], fcinfo->arg[9]); break; -#endif -#if FUNC_MAX_ARGS >= 11 case 11: - returnValue = (*user_fn) (values->data[0], values->data[1], - values->data[2], values->data[3], - values->data[4], values->data[5], - values->data[6], values->data[7], - values->data[8], values->data[9], - values->data[10]); + returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], + fcinfo->arg[2], fcinfo->arg[3], + fcinfo->arg[4], fcinfo->arg[5], + fcinfo->arg[6], fcinfo->arg[7], + fcinfo->arg[8], fcinfo->arg[9], + fcinfo->arg[10]); break; -#endif -#if FUNC_MAX_ARGS >= 12 case 12: - returnValue = (*user_fn) (values->data[0], values->data[1], - values->data[2], values->data[3], - values->data[4], values->data[5], - values->data[6], values->data[7], - values->data[8], values->data[9], - values->data[10], values->data[11]); + returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], + fcinfo->arg[2], fcinfo->arg[3], + fcinfo->arg[4], fcinfo->arg[5], + fcinfo->arg[6], fcinfo->arg[7], + fcinfo->arg[8], fcinfo->arg[9], + fcinfo->arg[10], fcinfo->arg[11]); break; -#endif -#if FUNC_MAX_ARGS >= 13 case 13: - returnValue = (*user_fn) (values->data[0], values->data[1], - values->data[2], values->data[3], - values->data[4], values->data[5], - values->data[6], values->data[7], - values->data[8], values->data[9], - values->data[10], values->data[11], - values->data[12]); + returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], + fcinfo->arg[2], fcinfo->arg[3], + fcinfo->arg[4], fcinfo->arg[5], + fcinfo->arg[6], fcinfo->arg[7], + fcinfo->arg[8], fcinfo->arg[9], + fcinfo->arg[10], fcinfo->arg[11], + fcinfo->arg[12]); break; -#endif -#if FUNC_MAX_ARGS >= 14 case 14: - returnValue = (*user_fn) (values->data[0], values->data[1], - values->data[2], values->data[3], - values->data[4], values->data[5], - values->data[6], values->data[7], - values->data[8], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13]); + returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], + fcinfo->arg[2], fcinfo->arg[3], + fcinfo->arg[4], fcinfo->arg[5], + fcinfo->arg[6], fcinfo->arg[7], + fcinfo->arg[8], fcinfo->arg[9], + fcinfo->arg[10], fcinfo->arg[11], + fcinfo->arg[12], fcinfo->arg[13]); break; -#endif -#if FUNC_MAX_ARGS >= 15 case 15: - returnValue = (*user_fn) (values->data[0], values->data[1], - values->data[2], values->data[3], - values->data[4], values->data[5], - values->data[6], values->data[7], - values->data[8], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14]); + returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], + fcinfo->arg[2], fcinfo->arg[3], + fcinfo->arg[4], fcinfo->arg[5], + fcinfo->arg[6], fcinfo->arg[7], + fcinfo->arg[8], fcinfo->arg[9], + fcinfo->arg[10], fcinfo->arg[11], + fcinfo->arg[12], fcinfo->arg[13], + fcinfo->arg[14]); break; -#endif -#if FUNC_MAX_ARGS >= 16 case 16: - returnValue = (*user_fn) (values->data[0], values->data[1], - values->data[2], values->data[3], - values->data[4], values->data[5], - values->data[6], values->data[7], - values->data[8], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15]); - break; -#endif -#if FUNC_MAX_ARGS >= 17 - case 17: - returnValue = (*user_fn) (values->data[0], values->data[1], - values->data[2], values->data[3], - values->data[4], values->data[5], - values->data[6], values->data[7], - values->data[8], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15], - values->data[16]); - break; -#endif -#if FUNC_MAX_ARGS >= 18 - case 18: - returnValue = (*user_fn) (values->data[0], values->data[1], - values->data[2], values->data[3], - values->data[4], values->data[5], - values->data[6], values->data[7], - values->data[8], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15], - values->data[16], values->data[17]); - break; -#endif -#if FUNC_MAX_ARGS >= 19 - case 19: - returnValue = (*user_fn) (values->data[0], values->data[1], - values->data[2], values->data[3], - values->data[4], values->data[5], - values->data[6], values->data[7], - values->data[8], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15], - values->data[16], values->data[17], - values->data[18]); - break; -#endif -#if FUNC_MAX_ARGS >= 20 - case 20: - returnValue = (*user_fn) (values->data[0], values->data[1], - values->data[2], values->data[3], - values->data[4], values->data[5], - values->data[6], values->data[7], - values->data[8], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15], - values->data[16], values->data[17], - values->data[18], values->data[19]); - break; -#endif -#if FUNC_MAX_ARGS >= 21 - case 21: - returnValue = (*user_fn) (values->data[0], values->data[1], - values->data[2], values->data[3], - values->data[4], values->data[5], - values->data[6], values->data[7], - values->data[8], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15], - values->data[16], values->data[17], - values->data[18], values->data[19], - values->data[20]); - break; -#endif -#if FUNC_MAX_ARGS >= 22 - case 22: - returnValue = (*user_fn) (values->data[0], values->data[1], - values->data[2], values->data[3], - values->data[4], values->data[5], - values->data[6], values->data[7], - values->data[8], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15], - values->data[16], values->data[17], - values->data[18], values->data[19], - values->data[20], values->data[21]); - break; -#endif -#if FUNC_MAX_ARGS >= 23 - case 23: - returnValue = (*user_fn) (values->data[0], values->data[1], - values->data[2], values->data[3], - values->data[4], values->data[5], - values->data[6], values->data[7], - values->data[8], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15], - values->data[16], values->data[17], - values->data[18], values->data[19], - values->data[20], values->data[21], - values->data[22]); - break; -#endif -#if FUNC_MAX_ARGS >= 24 - case 24: - returnValue = (*user_fn) (values->data[0], values->data[1], - values->data[2], values->data[3], - values->data[4], values->data[5], - values->data[6], values->data[7], - values->data[8], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15], - values->data[16], values->data[17], - values->data[18], values->data[19], - values->data[20], values->data[21], - values->data[22], values->data[23]); - break; -#endif -#if FUNC_MAX_ARGS >= 25 - case 25: - returnValue = (*user_fn) (values->data[0], values->data[1], - values->data[2], values->data[3], - values->data[4], values->data[5], - values->data[6], values->data[7], - values->data[8], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15], - values->data[16], values->data[17], - values->data[18], values->data[19], - values->data[20], values->data[21], - values->data[22], values->data[23], - values->data[24]); - break; -#endif -#if FUNC_MAX_ARGS >= 26 - case 26: - returnValue = (*user_fn) (values->data[0], values->data[1], - values->data[2], values->data[3], - values->data[4], values->data[5], - values->data[6], values->data[7], - values->data[8], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15], - values->data[16], values->data[17], - values->data[18], values->data[19], - values->data[20], values->data[21], - values->data[22], values->data[23], - values->data[24], values->data[25]); + returnValue = (*user_fn) (fcinfo->arg[0], fcinfo->arg[1], + fcinfo->arg[2], fcinfo->arg[3], + fcinfo->arg[4], fcinfo->arg[5], + fcinfo->arg[6], fcinfo->arg[7], + fcinfo->arg[8], fcinfo->arg[9], + fcinfo->arg[10], fcinfo->arg[11], + fcinfo->arg[12], fcinfo->arg[13], + fcinfo->arg[14], fcinfo->arg[15]); break; -#endif -#if FUNC_MAX_ARGS >= 27 - case 27: - returnValue = (*user_fn) (values->data[0], values->data[1], - values->data[2], values->data[3], - values->data[4], values->data[5], - values->data[6], values->data[7], - values->data[8], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15], - values->data[16], values->data[17], - values->data[18], values->data[19], - values->data[20], values->data[21], - values->data[22], values->data[23], - values->data[24], values->data[25], - values->data[26]); - break; -#endif -#if FUNC_MAX_ARGS >= 28 - case 28: - returnValue = (*user_fn) (values->data[0], values->data[1], - values->data[2], values->data[3], - values->data[4], values->data[5], - values->data[6], values->data[7], - values->data[8], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15], - values->data[16], values->data[17], - values->data[18], values->data[19], - values->data[20], values->data[21], - values->data[22], values->data[23], - values->data[24], values->data[25], - values->data[26], values->data[27]); - break; -#endif -#if FUNC_MAX_ARGS >= 29 - case 29: - returnValue = (*user_fn) (values->data[0], values->data[1], - values->data[2], values->data[3], - values->data[4], values->data[5], - values->data[6], values->data[7], - values->data[8], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15], - values->data[16], values->data[17], - values->data[18], values->data[19], - values->data[20], values->data[21], - values->data[22], values->data[23], - values->data[24], values->data[25], - values->data[26], values->data[27], - values->data[28]); - break; -#endif -#if FUNC_MAX_ARGS >= 30 - case 30: - returnValue = (*user_fn) (values->data[0], values->data[1], - values->data[2], values->data[3], - values->data[4], values->data[5], - values->data[6], values->data[7], - values->data[8], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15], - values->data[16], values->data[17], - values->data[18], values->data[19], - values->data[20], values->data[21], - values->data[22], values->data[23], - values->data[24], values->data[25], - values->data[26], values->data[27], - values->data[28], values->data[29]); - break; -#endif -#if FUNC_MAX_ARGS >= 31 - case 31: - returnValue = (*user_fn) (values->data[0], values->data[1], - values->data[2], values->data[3], - values->data[4], values->data[5], - values->data[6], values->data[7], - values->data[8], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15], - values->data[16], values->data[17], - values->data[18], values->data[19], - values->data[20], values->data[21], - values->data[22], values->data[23], - values->data[24], values->data[25], - values->data[26], values->data[27], - values->data[28], values->data[29], - values->data[30]); - break; -#endif -#if FUNC_MAX_ARGS >= 32 - case 32: - returnValue = (*user_fn) (values->data[0], values->data[1], - values->data[2], values->data[3], - values->data[4], values->data[5], - values->data[6], values->data[7], - values->data[8], values->data[9], - values->data[10], values->data[11], - values->data[12], values->data[13], - values->data[14], values->data[15], - values->data[16], values->data[17], - values->data[18], values->data[19], - values->data[20], values->data[21], - values->data[22], values->data[23], - values->data[24], values->data[25], - values->data[26], values->data[27], - values->data[28], values->data[29], - values->data[30], values->data[31]); - break; -#endif default: - elog(ERROR, "fmgr_c: function %u: too many arguments (%d > %d)", - finfo->fn_oid, n_arguments, FUNC_MAX_ARGS); + /* + * Increasing FUNC_MAX_ARGS doesn't automatically add cases + * to the above code, so give the actual value in this error + * not FUNC_MAX_ARGS. You could add cases to the above if you + * needed to support old-style functions with many arguments, + * but making 'em be new-style is probably a better idea. + */ + elog(ERROR, "fmgr_oldstyle: function %u: too many arguments (%d > %d)", + fcinfo->flinfo->fn_oid, n_arguments, 16); break; } - return returnValue; + + return (Datum) returnValue; } + /* - * Expand a regproc OID into an FmgrInfo cache struct. + * Handler for all functions marked "untrusted" */ +static Datum +fmgr_untrusted(PG_FUNCTION_ARGS) +{ + /* + * Currently these are unsupported. Someday we might do something + * like forking a subprocess to execute 'em. + */ + elog(ERROR, "Untrusted functions not supported"); + return 0; /* keep compiler happy */ +} -void -fmgr_info(Oid procedureId, FmgrInfo *finfo) +/* + * Handler for SQL-language functions + */ +static Datum +fmgr_sql(PG_FUNCTION_ARGS) { - FmgrCall *fcp; - HeapTuple procedureTuple; - FormData_pg_proc *procedureStruct; - HeapTuple languageTuple; - Form_pg_language languageStruct; - Oid language; - char *prosrc; + /* + * XXX It'd be really nice to support SQL functions anywhere that + * builtins are supported. What would we have to do? What pitfalls + * are there? + */ + elog(ERROR, "SQL-language function not supported in this context"); + return 0; /* keep compiler happy */ +} - finfo->fn_addr = NULL; - finfo->fn_plhandler = NULL; - finfo->fn_oid = procedureId; +/* + * Interface routine for functions using fmgr_faddr + */ +FmgrInfo *fmgr_pl_finfo; /* should GO AWAY */ - if ((fcp = fmgr_isbuiltin(procedureId)) != NULL) - { +char * +fmgr_faddr_link(char *arg0, ...) +{ + FunctionCallInfoData fcinfo; + int n_arguments; + Datum result; - /* - * Fast path for builtin functions: don't bother consulting - * pg_proc - */ - finfo->fn_addr = fcp->func; - finfo->fn_nargs = fcp->nargs; - } - else + MemSet(&fcinfo, 0, sizeof(fcinfo)); + /* We rely on fmgr_faddr macro to have set back-link to FmgrInfo (ugh) */ + fcinfo.flinfo = fmgr_pl_finfo; + fcinfo.nargs = fcinfo.flinfo->fn_nargs; + n_arguments = fcinfo.nargs; + + if (n_arguments > 0) { - procedureTuple = SearchSysCacheTuple(PROCOID, - ObjectIdGetDatum(procedureId), - 0, 0, 0); - if (!HeapTupleIsValid(procedureTuple)) - { - elog(ERROR, "fmgr_info: function %u: cache lookup failed", - procedureId); - } - procedureStruct = (FormData_pg_proc *) GETSTRUCT(procedureTuple); - if (!procedureStruct->proistrusted) - { - finfo->fn_addr = (func_ptr) fmgr_untrusted; - finfo->fn_nargs = procedureStruct->pronargs; - return; - } - language = procedureStruct->prolang; - switch (language) + fcinfo.arg[0] = (Datum) arg0; + if (n_arguments > 1) { - case INTERNALlanguageId: - - /* - * For an ordinary builtin function, we should never get - * here because the isbuiltin() search above will have - * succeeded. However, if the user has done a CREATE - * FUNCTION to create an alias for a builtin function, we - * end up here. In that case we have to look up the - * function by name. The name of the internal function is - * stored in prosrc (it doesn't have to be the same as the - * name of the alias!) - */ - prosrc = textout(&(procedureStruct->prosrc)); - finfo->fn_addr = fmgr_lookupByName(prosrc); - if (!finfo->fn_addr) - elog(ERROR, "fmgr_info: function %s not in internal table", - prosrc); - finfo->fn_nargs = procedureStruct->pronargs; - pfree(prosrc); - break; - case ClanguageId: - finfo->fn_addr = fmgr_dynamic(procedureId, &(finfo->fn_nargs)); - break; - case SQLlanguageId: - finfo->fn_addr = (func_ptr) fmgr_sql; - finfo->fn_nargs = procedureStruct->pronargs; - break; - default: + va_list pvar; + int i; - /* - * Might be a created procedural language Lookup the - * syscache for the language and check the lanispl flag If - * this is the case, we return a NULL function pointer and - * the number of arguments from the procedure. - */ - languageTuple = SearchSysCacheTuple(LANGOID, - ObjectIdGetDatum(procedureStruct->prolang), - 0, 0, 0); - if (!HeapTupleIsValid(languageTuple)) - { - elog(ERROR, "fmgr_info: %s %u", - "Cache lookup for language failed", - DatumGetObjectId(procedureStruct->prolang)); - } - languageStruct = (Form_pg_language) GETSTRUCT(languageTuple); - if (languageStruct->lanispl) - { - FmgrInfo plfinfo; - - fmgr_info(languageStruct->lanplcallfoid, &plfinfo); - finfo->fn_addr = (func_ptr) fmgr_pl; - finfo->fn_plhandler = plfinfo.fn_addr; - finfo->fn_nargs = procedureStruct->pronargs; - } - else - { - elog(ERROR, "fmgr_info: function %u: unknown language %d", - procedureId, language); - } - break; + if (n_arguments > FUNC_MAX_ARGS) + elog(ERROR, "fmgr_faddr_link: function %u: too many arguments (%d > %d)", + fcinfo.flinfo->fn_oid, n_arguments, FUNC_MAX_ARGS); + va_start(pvar, arg0); + for (i = 1; i < n_arguments; i++) + fcinfo.arg[i] = (Datum) va_arg(pvar, char *); + va_end(pvar); } } + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "fmgr_faddr_link: function %u returned NULL", + fcinfo.flinfo->fn_oid); + + return (char *) result; } /* * fmgr - return the value of a function call * - * If the function is a system routine, it's compiled in, so call - * it directly. - * - * Otherwise pass it to the the appropriate 'language' function caller. - * - * Returns the return value of the invoked function if succesful, - * 0 if unsuccessful. + * This is essentially fmgr_info plus call the function. */ char * fmgr(Oid procedureId,...) { - va_list pvar; - int i; - int pronargs; - FmgrValues values; - FmgrInfo finfo; - bool isNull = false; + FmgrInfo flinfo; + FunctionCallInfoData fcinfo; + int n_arguments; + Datum result; + + fmgr_info(procedureId, &flinfo); + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = &flinfo; + fcinfo.nargs = flinfo.fn_nargs; + n_arguments = fcinfo.nargs; + + if (n_arguments > 0) + { + va_list pvar; + int i; - fmgr_info(procedureId, &finfo); - pronargs = finfo.fn_nargs; + if (n_arguments > FUNC_MAX_ARGS) + elog(ERROR, "fmgr: function %u: too many arguments (%d > %d)", + flinfo.fn_oid, n_arguments, FUNC_MAX_ARGS); + va_start(pvar, procedureId); + for (i = 0; i < n_arguments; i++) + fcinfo.arg[i] = (Datum) va_arg(pvar, char *); + va_end(pvar); + } - if (pronargs > FUNC_MAX_ARGS) - elog(ERROR, "fmgr: function %u: too many arguments (%d > %d)", - procedureId, pronargs, FUNC_MAX_ARGS); + result = FunctionCallInvoke(&fcinfo); - va_start(pvar, procedureId); - for (i = 0; i < pronargs; ++i) - values.data[i] = va_arg(pvar, char *); - va_end(pvar); + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "fmgr: function %u returned NULL", + flinfo.fn_oid); - /* XXX see WAY_COOL_ORTHOGONAL_FUNCTIONS */ - return fmgr_c(&finfo, &values, &isNull); + return (char *) result; } -/* - * This is just a version of fmgr() in which the hacker can prepend a C - * function pointer. This routine is not normally called; generally, - * if you have all of this information you're likely to just jump through - * the pointer, but it's available for use with macros in fmgr.h if you - * want this routine to do sanity-checking for you. - * - * funcinfo, n_arguments, args... + +/*------------------------------------------------------------------------- + * Support routines for callers of fmgr-compatible functions + *------------------------------------------------------------------------- */ -#ifdef TRACE_FMGR_PTR -char * -fmgr_ptr(FmgrInfo *finfo,...) +/* These are for invocation of a specifically named function with a + * directly-computed parameter list. Note that neither arguments nor result + * are allowed to be NULL. Also, the function cannot be one that needs to + * look at FmgrInfo, since there won't be any. + */ +Datum +DirectFunctionCall1(PGFunction func, Datum arg1) { - va_list pvar; - int i; - int n_arguments; - FmgrInfo local_finfo; - FmgrValues values; - bool isNull = false; - - local_finfo->fn_addr = finfo->fn_addr; - local_finfo->fn_plhandler = finfo->fn_plhandler; - local_finfo->fn_oid = finfo->fn_oid; - - va_start(pvar, finfo); - n_arguments = va_arg(pvar, int); - local_finfo->fn_nargs = n_arguments; - if (n_arguments > FUNC_MAX_ARGS) - { - elog(ERROR, "fmgr_ptr: function %u: too many arguments (%d > %d)", - func_id, n_arguments, FUNC_MAX_ARGS); - } - for (i = 0; i < n_arguments; ++i) - values.data[i] = va_arg(pvar, char *); - va_end(pvar); + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.nargs = 1; + fcinfo.arg[0] = arg1; - /* XXX see WAY_COOL_ORTHOGONAL_FUNCTIONS */ - return fmgr_c(&local_finfo, &values, &isNull); + result = (* func) (&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "DirectFunctionCall1: function %p returned NULL", + (void *) func); + + return result; } -#endif +Datum +DirectFunctionCall2(PGFunction func, Datum arg1, Datum arg2) +{ + FunctionCallInfoData fcinfo; + Datum result; -/* - * This routine is not well thought out. When I get around to adding a - * function pointer field to FuncIndexInfo, it will be replace by calls - * to fmgr_c(). + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.nargs = 2; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + + result = (* func) (&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "DirectFunctionCall2: function %p returned NULL", + (void *) func); + + return result; +} + +Datum +DirectFunctionCall3(PGFunction func, Datum arg1, Datum arg2, + Datum arg3) +{ + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.nargs = 3; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + + result = (* func) (&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "DirectFunctionCall3: function %p returned NULL", + (void *) func); + + return result; +} + +Datum +DirectFunctionCall4(PGFunction func, Datum arg1, Datum arg2, + Datum arg3, Datum arg4) +{ + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.nargs = 4; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + + result = (* func) (&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "DirectFunctionCall4: function %p returned NULL", + (void *) func); + + return result; +} + +Datum +DirectFunctionCall5(PGFunction func, Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5) +{ + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.nargs = 5; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + fcinfo.arg[4] = arg5; + + result = (* func) (&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "DirectFunctionCall5: function %p returned NULL", + (void *) func); + + return result; +} + +Datum +DirectFunctionCall6(PGFunction func, Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6) +{ + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.nargs = 6; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + fcinfo.arg[4] = arg5; + fcinfo.arg[5] = arg6; + + result = (* func) (&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "DirectFunctionCall6: function %p returned NULL", + (void *) func); + + return result; +} + +Datum +DirectFunctionCall7(PGFunction func, Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6, Datum arg7) +{ + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.nargs = 7; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + fcinfo.arg[4] = arg5; + fcinfo.arg[5] = arg6; + fcinfo.arg[6] = arg7; + + result = (* func) (&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "DirectFunctionCall7: function %p returned NULL", + (void *) func); + + return result; +} + +Datum +DirectFunctionCall8(PGFunction func, Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6, Datum arg7, Datum arg8) +{ + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.nargs = 8; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + fcinfo.arg[4] = arg5; + fcinfo.arg[5] = arg6; + fcinfo.arg[6] = arg7; + fcinfo.arg[7] = arg8; + + result = (* func) (&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "DirectFunctionCall8: function %p returned NULL", + (void *) func); + + return result; +} + +Datum +DirectFunctionCall9(PGFunction func, Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6, Datum arg7, Datum arg8, + Datum arg9) +{ + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.nargs = 9; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + fcinfo.arg[4] = arg5; + fcinfo.arg[5] = arg6; + fcinfo.arg[6] = arg7; + fcinfo.arg[7] = arg8; + fcinfo.arg[8] = arg9; + + result = (* func) (&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "DirectFunctionCall9: function %p returned NULL", + (void *) func); + + return result; +} + + +/* These are for invocation of a previously-looked-up function with a + * directly-computed parameter list. Note that neither arguments nor result + * are allowed to be NULL. */ -char * -fmgr_array_args(Oid procedureId, int nargs, char *args[], bool *isNull) +Datum +FunctionCall1(FmgrInfo *flinfo, Datum arg1) +{ + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = flinfo; + fcinfo.nargs = 1; + fcinfo.arg[0] = arg1; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "FunctionCall1: function %u returned NULL", + fcinfo.flinfo->fn_oid); + + return result; +} + +Datum +FunctionCall2(FmgrInfo *flinfo, Datum arg1, Datum arg2) +{ + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = flinfo; + fcinfo.nargs = 2; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "FunctionCall2: function %u returned NULL", + fcinfo.flinfo->fn_oid); + + return result; +} + +Datum +FunctionCall3(FmgrInfo *flinfo, Datum arg1, Datum arg2, + Datum arg3) +{ + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = flinfo; + fcinfo.nargs = 3; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "FunctionCall3: function %u returned NULL", + fcinfo.flinfo->fn_oid); + + return result; +} + +Datum +FunctionCall4(FmgrInfo *flinfo, Datum arg1, Datum arg2, + Datum arg3, Datum arg4) +{ + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = flinfo; + fcinfo.nargs = 4; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "FunctionCall4: function %u returned NULL", + fcinfo.flinfo->fn_oid); + + return result; +} + +Datum +FunctionCall5(FmgrInfo *flinfo, Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5) +{ + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = flinfo; + fcinfo.nargs = 5; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + fcinfo.arg[4] = arg5; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "FunctionCall5: function %u returned NULL", + fcinfo.flinfo->fn_oid); + + return result; +} + +Datum +FunctionCall6(FmgrInfo *flinfo, Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6) +{ + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = flinfo; + fcinfo.nargs = 6; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + fcinfo.arg[4] = arg5; + fcinfo.arg[5] = arg6; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "FunctionCall6: function %u returned NULL", + fcinfo.flinfo->fn_oid); + + return result; +} + +Datum +FunctionCall7(FmgrInfo *flinfo, Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6, Datum arg7) { - FmgrInfo finfo; + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = flinfo; + fcinfo.nargs = 7; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + fcinfo.arg[4] = arg5; + fcinfo.arg[5] = arg6; + fcinfo.arg[6] = arg7; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "FunctionCall7: function %u returned NULL", + fcinfo.flinfo->fn_oid); + + return result; +} + +Datum +FunctionCall8(FmgrInfo *flinfo, Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6, Datum arg7, Datum arg8) +{ + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = flinfo; + fcinfo.nargs = 8; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + fcinfo.arg[4] = arg5; + fcinfo.arg[5] = arg6; + fcinfo.arg[6] = arg7; + fcinfo.arg[7] = arg8; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "FunctionCall8: function %u returned NULL", + fcinfo.flinfo->fn_oid); + + return result; +} + +Datum +FunctionCall9(FmgrInfo *flinfo, Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6, Datum arg7, Datum arg8, + Datum arg9) +{ + FunctionCallInfoData fcinfo; + Datum result; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = flinfo; + fcinfo.nargs = 9; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + fcinfo.arg[4] = arg5; + fcinfo.arg[5] = arg6; + fcinfo.arg[6] = arg7; + fcinfo.arg[7] = arg8; + fcinfo.arg[8] = arg9; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "FunctionCall9: function %u returned NULL", + fcinfo.flinfo->fn_oid); - fmgr_info(procedureId, &finfo); - finfo.fn_nargs = nargs; + return result; +} + + +/* These are for invocation of a function identified by OID with a + * directly-computed parameter list. Note that neither arguments nor result + * are allowed to be NULL. These are essentially fmgr_info() followed + * by FunctionCallN(). If the same function is to be invoked repeatedly, + * do the fmgr_info() once and then use FunctionCallN(). + */ +Datum +OidFunctionCall1(Oid functionId, Datum arg1) +{ + FmgrInfo flinfo; + FunctionCallInfoData fcinfo; + Datum result; + + fmgr_info(functionId, &flinfo); + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = &flinfo; + fcinfo.nargs = 1; + fcinfo.arg[0] = arg1; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "OidFunctionCall1: function %u returned NULL", + flinfo.fn_oid); + + return result; +} + +Datum +OidFunctionCall2(Oid functionId, Datum arg1, Datum arg2) +{ + FmgrInfo flinfo; + FunctionCallInfoData fcinfo; + Datum result; + + fmgr_info(functionId, &flinfo); + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = &flinfo; + fcinfo.nargs = 2; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "OidFunctionCall2: function %u returned NULL", + flinfo.fn_oid); + + return result; +} + +Datum +OidFunctionCall3(Oid functionId, Datum arg1, Datum arg2, + Datum arg3) +{ + FmgrInfo flinfo; + FunctionCallInfoData fcinfo; + Datum result; + + fmgr_info(functionId, &flinfo); + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = &flinfo; + fcinfo.nargs = 3; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "OidFunctionCall3: function %u returned NULL", + flinfo.fn_oid); + + return result; +} + +Datum +OidFunctionCall4(Oid functionId, Datum arg1, Datum arg2, + Datum arg3, Datum arg4) +{ + FmgrInfo flinfo; + FunctionCallInfoData fcinfo; + Datum result; + + fmgr_info(functionId, &flinfo); + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = &flinfo; + fcinfo.nargs = 4; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "OidFunctionCall4: function %u returned NULL", + flinfo.fn_oid); + + return result; +} + +Datum +OidFunctionCall5(Oid functionId, Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5) +{ + FmgrInfo flinfo; + FunctionCallInfoData fcinfo; + Datum result; + + fmgr_info(functionId, &flinfo); + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = &flinfo; + fcinfo.nargs = 5; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + fcinfo.arg[4] = arg5; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "OidFunctionCall5: function %u returned NULL", + flinfo.fn_oid); + + return result; +} + +Datum +OidFunctionCall6(Oid functionId, Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6) +{ + FmgrInfo flinfo; + FunctionCallInfoData fcinfo; + Datum result; + + fmgr_info(functionId, &flinfo); + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = &flinfo; + fcinfo.nargs = 6; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + fcinfo.arg[4] = arg5; + fcinfo.arg[5] = arg6; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "OidFunctionCall6: function %u returned NULL", + flinfo.fn_oid); + + return result; +} + +Datum +OidFunctionCall7(Oid functionId, Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6, Datum arg7) +{ + FmgrInfo flinfo; + FunctionCallInfoData fcinfo; + Datum result; + + fmgr_info(functionId, &flinfo); + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = &flinfo; + fcinfo.nargs = 7; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + fcinfo.arg[4] = arg5; + fcinfo.arg[5] = arg6; + fcinfo.arg[6] = arg7; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "OidFunctionCall7: function %u returned NULL", + flinfo.fn_oid); + + return result; +} + +Datum +OidFunctionCall8(Oid functionId, Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6, Datum arg7, Datum arg8) +{ + FmgrInfo flinfo; + FunctionCallInfoData fcinfo; + Datum result; + + fmgr_info(functionId, &flinfo); + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = &flinfo; + fcinfo.nargs = 8; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + fcinfo.arg[4] = arg5; + fcinfo.arg[5] = arg6; + fcinfo.arg[6] = arg7; + fcinfo.arg[7] = arg8; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "OidFunctionCall8: function %u returned NULL", + flinfo.fn_oid); + + return result; +} + +Datum +OidFunctionCall9(Oid functionId, Datum arg1, Datum arg2, + Datum arg3, Datum arg4, Datum arg5, + Datum arg6, Datum arg7, Datum arg8, + Datum arg9) +{ + FmgrInfo flinfo; + FunctionCallInfoData fcinfo; + Datum result; + + fmgr_info(functionId, &flinfo); + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = &flinfo; + fcinfo.nargs = 9; + fcinfo.arg[0] = arg1; + fcinfo.arg[1] = arg2; + fcinfo.arg[2] = arg3; + fcinfo.arg[3] = arg4; + fcinfo.arg[4] = arg5; + fcinfo.arg[5] = arg6; + fcinfo.arg[6] = arg7; + fcinfo.arg[7] = arg8; + fcinfo.arg[8] = arg9; + + result = FunctionCallInvoke(&fcinfo); + + /* Check for null result, since caller is clearly not expecting one */ + if (fcinfo.isnull) + elog(ERROR, "OidFunctionCall9: function %u returned NULL", + flinfo.fn_oid); + + return result; +} + + +/*------------------------------------------------------------------------- + * Support routines for standard pass-by-reference datatypes + * + * Note: at some point, at least on some platforms, these might become + * pass-by-value types. Obviously Datum must be >= 8 bytes to allow + * int64 or float8 to be pass-by-value. I think that Float4GetDatum + * and Float8GetDatum will need to be out-of-line routines anyway, + * since just casting from float to Datum will not do the right thing; + * some kind of trick with pointer-casting or a union will be needed. + *------------------------------------------------------------------------- + */ + +Datum +Int64GetDatum(int64 X) +{ + int64 *retval = (int64 *) palloc(sizeof(int64)); + + *retval = X; + return PointerGetDatum(retval); +} + +Datum +Float4GetDatum(float4 X) +{ + float4 *retval = (float4 *) palloc(sizeof(float4)); + + *retval = X; + return PointerGetDatum(retval); +} + +Datum +Float8GetDatum(float8 X) +{ + float8 *retval = (float8 *) palloc(sizeof(float8)); - /* XXX see WAY_COOL_ORTHOGONAL_FUNCTIONS */ - return fmgr_c(&finfo, - (FmgrValues *) args, - isNull); + *retval = X; + return PointerGetDatum(retval); } diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c index c4675a6b57d..68e293ef1da 100644 --- a/src/backend/utils/init/postinit.c +++ b/src/backend/utils/init/postinit.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.57 2000/04/12 17:16:02 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.58 2000/05/28 17:56:08 tgl Exp $ * * *------------------------------------------------------------------------- @@ -30,6 +30,7 @@ #include "storage/proc.h" #include "storage/sinval.h" #include "storage/smgr.h" +#include "utils/fmgroids.h" #include "utils/inval.h" #include "utils/portal.h" #include "utils/relcache.h" |