diff options
author | Tom Lane | 2000-05-28 17:56:29 +0000 |
---|---|---|
committer | Tom Lane | 2000-05-28 17:56:29 +0000 |
commit | 0a7fb4e9184539afcb6fed0f1d2bc0abddc2b0a6 (patch) | |
tree | affcce1c5b6367468fb6dcfd2790585f2e967629 /src/backend | |
parent | 5005bb060b3f3a82cd1bd662c7f8946c9be59db5 (diff) |
First round of changes for new fmgr interface. fmgr itself and the
key call sites are changed, but most called functions are still oldstyle.
An exception is that the PL managers are updated (so, for example, NULL
handling now behaves as expected in plperl and plpgsql functions).
NOTE initdb is forced due to added column in pg_proc.
Diffstat (limited to 'src/backend')
59 files changed, 1944 insertions, 1428 deletions
diff --git a/src/backend/Makefile b/src/backend/Makefile index ae90a17b042..6af51106bd3 100644 --- a/src/backend/Makefile +++ b/src/backend/Makefile @@ -34,7 +34,7 @@ # # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/backend/Makefile,v 1.47 2000/05/11 17:46:28 momjian Exp $ +# $Header: /cvsroot/pgsql/src/backend/Makefile,v 1.48 2000/05/28 17:55:51 tgl Exp $ # #------------------------------------------------------------------------- @@ -79,7 +79,7 @@ all: postgres $(POSTGRES_IMP) global1.bki.source local1_template1.bki.source \ global1.description local1_template1.description ifneq ($(PORTNAME), win) -postgres: fmgr.h $(OBJS) $(VERSIONOBJ) +postgres: utils/fmgroids.h $(OBJS) $(VERSIONOBJ) $(CC) $(CFLAGS) -o postgres $(OBJS) $(OBJS1) $(VERSIONOBJ) $(LDFLAGS) else postgres: $(DLLOBJS) $(SRCDIR)/utils/dllinit.o postgres.def libpostgres.a @@ -126,15 +126,12 @@ parse.h: parser/parse.h parser/parse.h: $(MAKE) -C parser parse.h -fmgr.h: utils/fmgr.h - cp utils/fmgr.h . - -utils/fmgr.h: - $(MAKE) -C utils fmgr.h +utils/fmgroids.h: + $(MAKE) -C utils fmgroids.h ############################################################################# clean: - rm -f postgres$(X) $(POSTGRES_IMP) fmgr.h parse.h \ + rm -f postgres$(X) $(POSTGRES_IMP) parse.h \ global1.bki.source local1_template1.bki.source \ global1.description local1_template1.description ifeq ($(PORTNAME), win) @@ -205,7 +202,7 @@ install-templates: $(TEMPLATEDIR) \ $(INSTALL) $(INSTLOPTS) pg_options.sample \ $(TEMPLATEDIR)/pg_options.sample -install-headers: fmgr.h $(SRCDIR)/include/config.h +install-headers: utils/fmgroids.h $(SRCDIR)/include/config.h -@if [ ! -d $(HEADERDIR) ]; then mkdir $(HEADERDIR); fi -@if [ ! -d $(HEADERDIR)/port ]; then mkdir $(HEADERDIR)/port; fi -@if [ ! -d $(HEADERDIR)/port/$(PORTNAME) ]; \ @@ -222,8 +219,6 @@ install-headers: fmgr.h $(SRCDIR)/include/config.h then mkdir $(HEADERDIR)/executor; fi -@if [ ! -d $(HEADERDIR)/commands ]; \ then mkdir $(HEADERDIR)/commands; fi - $(INSTALL) $(INSTLOPTS) fmgr.h \ - $(HEADERDIR)/fmgr.h $(INSTALL) $(INSTLOPTS) $(SRCDIR)/include/os.h \ $(HEADERDIR)/os.h $(INSTALL) $(INSTLOPTS) $(SRCDIR)/include/config.h \ @@ -244,6 +239,8 @@ install-headers: fmgr.h $(SRCDIR)/include/config.h $(HEADERDIR)/utils/geo_decls.h $(INSTALL) $(INSTLOPTS) $(SRCDIR)/include/utils/elog.h \ $(HEADERDIR)/utils/elog.h + $(INSTALL) $(INSTLOPTS) utils/fmgroids.h \ + $(HEADERDIR)/utils/fmgroids.h $(INSTALL) $(INSTLOPTS) $(SRCDIR)/include/utils/palloc.h \ $(HEADERDIR)/utils/palloc.h $(INSTALL) $(INSTLOPTS) $(SRCDIR)/include/utils/mcxt.h \ diff --git a/src/backend/access/common/Makefile b/src/backend/access/common/Makefile index 594ed50a59d..847b06b1d21 100644 --- a/src/backend/access/common/Makefile +++ b/src/backend/access/common/Makefile @@ -4,7 +4,7 @@ # Makefile for access/common # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/backend/access/common/Makefile,v 1.16 2000/01/19 02:58:50 petere Exp $ +# $Header: /cvsroot/pgsql/src/backend/access/common/Makefile,v 1.17 2000/05/28 17:55:52 tgl Exp $ # #------------------------------------------------------------------------- @@ -21,12 +21,7 @@ all: SUBSYS.o SUBSYS.o: $(OBJS) $(LD) $(LDREL) $(LDOUT) SUBSYS.o $(OBJS) -heaptuple.o heapvalid.o tupdesc.o: ../../fmgr.h - -../../fmgr.h: - $(MAKE) -C ../.. fmgr.h - -dep depend: ../../fmgr.h +dep depend: $(CC) -MM $(CFLAGS) *.c >depend clean: diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c index e0672667c7f..43d8a3850f5 100644 --- a/src/backend/access/index/indexam.c +++ b/src/backend/access/index/indexam.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.42 2000/04/12 17:14:47 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.43 2000/05/28 17:55:52 tgl Exp $ * * INTERFACE ROUTINES * index_open - open an index relation by relationId @@ -418,28 +418,43 @@ GetIndexValue(HeapTuple tuple, bool *attNull) { Datum returnVal; - bool isNull = FALSE; if (PointerIsValid(fInfo) && FIgetProcOid(fInfo) != InvalidOid) { - int i; - Datum *attData = (Datum *) palloc(FIgetnArgs(fInfo) * sizeof(Datum)); + FmgrInfo flinfo; + FunctionCallInfoData fcinfo; + int i; + bool anynull = false; + + /* + * XXX ought to store lookup info in FuncIndexInfo so it need not + * be repeated on each call? + */ + fmgr_info(FIgetProcOid(fInfo), &flinfo); + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = &flinfo; + fcinfo.nargs = FIgetnArgs(fInfo); for (i = 0; i < FIgetnArgs(fInfo); i++) { - attData[i] = heap_getattr(tuple, - attrNums[i], - hTupDesc, - attNull); - if (*attNull) - isNull = TRUE; + fcinfo.arg[i] = heap_getattr(tuple, + attrNums[i], + hTupDesc, + &fcinfo.argnull[i]); + anynull |= fcinfo.argnull[i]; + } + if (flinfo.fn_strict && anynull) + { + /* force a null result for strict function */ + returnVal = (Datum) 0; + *attNull = true; + } + else + { + returnVal = FunctionCallInvoke(&fcinfo); + *attNull = fcinfo.isnull; } - returnVal = (Datum) fmgr_array_args(FIgetProcOid(fInfo), - FIgetnArgs(fInfo), - (char **) attData, - &isNull); - pfree(attData); - *attNull = isNull; } else returnVal = heap_getattr(tuple, attrNums[attOff], hTupDesc, attNull); diff --git a/src/backend/access/index/istrat.c b/src/backend/access/index/istrat.c index b0864e505fa..5116b622dd1 100644 --- a/src/backend/access/index/istrat.c +++ b/src/backend/access/index/istrat.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.42 2000/04/12 17:14:47 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/index/Attic/istrat.c,v 1.43 2000/05/28 17:55:52 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -24,6 +24,7 @@ #include "catalog/pg_index.h" #include "catalog/pg_operator.h" #include "miscadmin.h" +#include "utils/fmgroids.h" #include "utils/syscache.h" #ifdef USE_ASSERT_CHECKING diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c index a12bca94932..beb4b079045 100644 --- a/src/backend/bootstrap/bootstrap.c +++ b/src/backend/bootstrap/bootstrap.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.81 2000/04/12 17:14:54 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.82 2000/05/28 17:55:53 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -34,6 +34,7 @@ #include "miscadmin.h" #include "tcop/tcopprot.h" #include "utils/builtins.h" +#include "utils/fmgroids.h" #include "utils/lsyscache.h" #include "utils/portal.h" diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 762bff810d0..5c0eff6e7c7 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.128 2000/05/25 21:25:32 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.129 2000/05/28 17:55:54 tgl Exp $ * * * INTERFACE ROUTINES @@ -63,6 +63,7 @@ #include "tcop/tcopprot.h" #include "utils/builtins.h" #include "utils/catcache.h" +#include "utils/fmgroids.h" #include "utils/portal.h" #include "utils/relcache.h" #include "utils/syscache.h" @@ -1148,7 +1149,7 @@ RelationTruncateIndexes(Relation heapRelation) /* If a valid where predicate, compute predicate Node */ if (VARSIZE(&index->indpred) != 0) { - predString = fmgr(F_TEXTOUT, &index->indpred); + predString = textout(&index->indpred); oldPred = stringToNode(predString); pfree(predString); } diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index cfc5805b7c5..3ef1931e593 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.110 2000/05/20 23:11:28 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.111 2000/05/28 17:55:54 tgl Exp $ * * * INTERFACE ROUTINES @@ -42,6 +42,7 @@ #include "storage/smgr.h" #include "utils/builtins.h" #include "utils/catcache.h" +#include "utils/fmgroids.h" #include "utils/relcache.h" #include "utils/syscache.h" #include "utils/temprel.h" @@ -688,11 +689,11 @@ UpdateIndexRelation(Oid indexoid, if (predicate != NULL) { predString = nodeToString(predicate); - predText = (text *) fmgr(F_TEXTIN, predString); + predText = textin(predString); pfree(predString); } else - predText = (text *) fmgr(F_TEXTIN, ""); + predText = textin(""); predLen = VARSIZE(predText); itupLen = predLen + sizeof(FormData_pg_index); @@ -832,11 +833,11 @@ UpdateIndexPredicate(Oid indexoid, Node *oldPred, Node *predicate) if (newPred != NULL) { predString = nodeToString(newPred); - predText = (text *) fmgr(F_TEXTIN, predString); + predText = textin(predString); pfree(predString); } else - predText = (text *) fmgr(F_TEXTIN, ""); + predText = textin(""); /* open the index system catalog relation */ pg_index = heap_openr(IndexRelationName, RowExclusiveLock); @@ -2109,7 +2110,7 @@ reindex_index(Oid indexId, bool force) /* If a valid where predicate, compute predicate Node */ if (VARSIZE(&index->indpred) != 0) { - predString = fmgr(F_TEXTOUT, &index->indpred); + predString = textout(&index->indpred); oldPred = stringToNode(predString); pfree(predString); } diff --git a/src/backend/catalog/indexing.c b/src/backend/catalog/indexing.c index eb3d6debcc5..79a987ba59c 100644 --- a/src/backend/catalog/indexing.c +++ b/src/backend/catalog/indexing.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.60 2000/04/12 17:14:56 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.61 2000/05/28 17:55:54 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -24,6 +24,7 @@ #include "catalog/indexing.h" #include "catalog/pg_index.h" #include "miscadmin.h" +#include "utils/fmgroids.h" #include "utils/syscache.h" /* diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c index b0508d259a1..5796b11b988 100644 --- a/src/backend/catalog/pg_operator.c +++ b/src/backend/catalog/pg_operator.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.49 2000/01/26 05:56:10 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.50 2000/05/28 17:55:54 tgl Exp $ * * NOTES * these routines moved here from commands/define.c and somewhat cleaned up. @@ -26,6 +26,7 @@ #include "miscadmin.h" #include "parser/parse_func.h" #include "utils/builtins.h" +#include "utils/fmgroids.h" #include "utils/syscache.h" diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c index aa23a3be8c2..6ddc343aaa6 100644 --- a/src/backend/catalog/pg_proc.c +++ b/src/backend/catalog/pg_proc.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.42 2000/04/12 17:14:56 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.43 2000/05/28 17:55:54 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -17,6 +17,7 @@ #include "access/heapam.h" #include "catalog/catname.h" #include "catalog/indexing.h" +#include "catalog/pg_language.h" #include "catalog/pg_proc.h" #include "catalog/pg_type.h" #include "miscadmin.h" @@ -24,7 +25,6 @@ #include "parser/parse_type.h" #include "tcop/tcopprot.h" #include "utils/builtins.h" -#include "utils/fmgrtab.h" #include "utils/lsyscache.h" #include "utils/sets.h" #include "utils/syscache.h" @@ -41,8 +41,9 @@ ProcedureCreate(char *procedureName, char *languageName, char *prosrc, char *probin, - bool canCache, bool trusted, + bool canCache, + bool isStrict, int32 byte_pct, int32 perbyte_cpu, int32 percall_cpu, @@ -74,6 +75,15 @@ ProcedureCreate(char *procedureName, Assert(PointerIsValid(prosrc)); Assert(PointerIsValid(probin)); + tup = SearchSysCacheTuple(LANGNAME, + PointerGetDatum(languageName), + 0, 0, 0); + + if (!HeapTupleIsValid(tup)) + elog(ERROR, "ProcedureCreate: no such language '%s'", languageName); + + languageObjectId = tup->t_data->t_oid; + parameterCount = 0; MemSet(typev, 0, FUNC_MAX_ARGS * sizeof(Oid)); foreach(x, argList) @@ -86,7 +96,7 @@ ProcedureCreate(char *procedureName, if (strcmp(strVal(t), "opaque") == 0) { - if (strcmp(languageName, "sql") == 0) + if (languageObjectId == SQLlanguageId) elog(ERROR, "ProcedureCreate: sql functions cannot take type \"opaque\""); toid = 0; } @@ -120,7 +130,7 @@ ProcedureCreate(char *procedureName, elog(ERROR, "ProcedureCreate: procedure %s already exists with same arguments", procedureName); - if (!strcmp(languageName, "sql")) + if (languageObjectId == SQLlanguageId) { /* @@ -129,7 +139,7 @@ ProcedureCreate(char *procedureName, * matches a function already in pg_proc. If so just return the * OID of the existing set. */ - if (!strcmp(procedureName, GENERICSETNAME)) + if (strcmp(procedureName, GENERICSETNAME) == 0) { #ifdef SETS_FIXED /* ---------- @@ -138,7 +148,7 @@ ProcedureCreate(char *procedureName, * have been removed. Instead a sequential heap scan * or something better must get implemented. The reason * for removing is that nbtree index crashes if sources - * exceed 2K what's likely for procedural languages. + * exceed 2K --- what's likely for procedural languages. * * 1999/09/30 Jan * ---------- @@ -158,18 +168,9 @@ ProcedureCreate(char *procedureName, } } - tup = SearchSysCacheTuple(LANGNAME, - PointerGetDatum(languageName), - 0, 0, 0); - - if (!HeapTupleIsValid(tup)) - elog(ERROR, "ProcedureCreate: no such language %s", languageName); - - languageObjectId = tup->t_data->t_oid; - if (strcmp(returnTypeName, "opaque") == 0) { - if (strcmp(languageName, "sql") == 0) + if (languageObjectId == SQLlanguageId) elog(ERROR, "ProcedureCreate: sql functions cannot return type \"opaque\""); typeObjectId = 0; } @@ -181,16 +182,10 @@ ProcedureCreate(char *procedureName, { elog(NOTICE, "ProcedureCreate: type '%s' is not yet defined", returnTypeName); -#ifdef NOT_USED - elog(NOTICE, "ProcedureCreate: creating a shell for type '%s'", - returnTypeName); -#endif typeObjectId = TypeShellMake(returnTypeName); if (!OidIsValid(typeObjectId)) - { elog(ERROR, "ProcedureCreate: could not create type '%s'", returnTypeName); - } } else if (!defined) { @@ -219,7 +214,7 @@ ProcedureCreate(char *procedureName, * procedure's text in the prosrc attribute. */ - if (strcmp(languageName, "sql") == 0) + if (languageObjectId == SQLlanguageId) { querytree_list = pg_parse_and_rewrite(prosrc, typev, parameterCount, FALSE); @@ -237,16 +232,50 @@ ProcedureCreate(char *procedureName, * FUNCTION xyz AS '' LANGUAGE 'internal'. To preserve some modicum * of backwards compatibility, accept an empty 'prosrc' value as * meaning the supplied SQL function name. + * + * XXX: we could treat "internal" and "newinternal" language specs + * as equivalent, and take the actual language ID from the table of + * known builtin functions. Is that a better idea than making the + * user specify the right thing? Not sure. */ - if (strcmp(languageName, "internal") == 0) + if (languageObjectId == INTERNALlanguageId || + languageObjectId == NEWINTERNALlanguageId) { + Oid actualLangID; + if (strlen(prosrc) == 0) prosrc = procedureName; - if (fmgr_lookupByName(prosrc) == (func_ptr) NULL) + actualLangID = fmgr_internal_language(prosrc); + if (actualLangID == InvalidOid) elog(ERROR, - "ProcedureCreate: there is no builtin function named \"%s\"", + "ProcedureCreate: there is no builtin function named \"%s\"", prosrc); + if (actualLangID != languageObjectId) + elog(ERROR, + "ProcedureCreate: \"%s\" is not %s internal function", + prosrc, + ((languageObjectId == INTERNALlanguageId) ? + "an old-style" : "a new-style")); + } + + /* + * If this is a dynamically loadable procedure, make sure that the + * library file exists, is loadable, and contains the specified link + * symbol. + * + * We used to perform these checks only when the function was first + * called, but it seems friendlier to verify the library's validity + * at CREATE FUNCTION time. + */ + + if (languageObjectId == ClanguageId || + languageObjectId == NEWClanguageId) + { + /* If link symbol is specified as "-", substitute procedure name */ + if (strcmp(prosrc, "-") == 0) + prosrc = procedureName; + (void) load_external_function(probin, prosrc); } /* @@ -265,9 +294,10 @@ ProcedureCreate(char *procedureName, values[i++] = Int32GetDatum(GetUserId()); values[i++] = ObjectIdGetDatum(languageObjectId); /* XXX isinherited is always false for now */ - values[i++] = Int8GetDatum((bool) 0); + values[i++] = Int8GetDatum((bool) false); values[i++] = Int8GetDatum(trusted); values[i++] = Int8GetDatum(canCache); + values[i++] = Int8GetDatum(isStrict); values[i++] = UInt16GetDatum(parameterCount); values[i++] = Int8GetDatum(returnsSet); values[i++] = ObjectIdGetDatum(typeObjectId); @@ -276,8 +306,8 @@ ProcedureCreate(char *procedureName, values[i++] = Int32GetDatum(perbyte_cpu); /* properbyte_cpu */ values[i++] = Int32GetDatum(percall_cpu); /* propercall_cpu */ values[i++] = Int32GetDatum(outin_ratio); /* prooutin_ratio */ - values[i++] = (Datum) fmgr(F_TEXTIN, prosrc); /* prosrc */ - values[i++] = (Datum) fmgr(F_TEXTIN, probin); /* probin */ + values[i++] = (Datum) textin(prosrc); /* prosrc */ + values[i++] = (Datum) textin(probin); /* probin */ rel = heap_openr(ProcedureRelationName, RowExclusiveLock); diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c index 4c3120c40f4..9386079997e 100644 --- a/src/backend/catalog/pg_type.c +++ b/src/backend/catalog/pg_type.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.50 2000/04/12 17:14:56 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.51 2000/05/28 17:55:54 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -21,6 +21,7 @@ #include "miscadmin.h" #include "parser/parse_func.h" #include "utils/builtins.h" +#include "utils/fmgroids.h" #include "utils/syscache.h" @@ -190,7 +191,7 @@ TypeShellMakeWithOpenRelation(Relation pg_type_desc, char *typeName) /* * ... and fill typdefault with a bogus value */ - values[i++] = (Datum) fmgr(F_TEXTIN, typeName); /* 15 */ + values[i++] = (Datum) textin(typeName); /* 15 */ /* ---------------- * create a new type tuple with FormHeapTuple @@ -449,10 +450,9 @@ TypeCreate(char *typeName, * initialize the default value for this type. * ---------------- */ - values[i] = (Datum) fmgr(F_TEXTIN, /* 16 */ - PointerIsValid(defaultTypeValue) - ? defaultTypeValue : "-"); /* XXX default - * typdefault */ + values[i] = (Datum) textin(PointerIsValid(defaultTypeValue) /* 16 */ + ? defaultTypeValue : "-"); /* XXX default + * typdefault */ /* ---------------- * open pg_type and begin a scan for the type name. diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c index c045f09b83d..8225f3a7ca4 100644 --- a/src/backend/commands/async.c +++ b/src/backend/commands/async.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.60 2000/05/14 03:18:35 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.61 2000/05/28 17:55:54 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -87,6 +87,7 @@ #include "libpq/libpq.h" #include "libpq/pqformat.h" #include "miscadmin.h" +#include "utils/fmgroids.h" #include "utils/ps_status.h" #include "utils/syscache.h" #include "utils/trace.h" diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c index 2b9f6a257b1..4fb184b7f6d 100644 --- a/src/backend/commands/command.c +++ b/src/backend/commands/command.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.71 2000/04/12 17:14:57 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.72 2000/05/28 17:55:54 tgl Exp $ * * NOTES * The PortalExecutorHeapMemory crap needs to be eliminated @@ -40,6 +40,7 @@ #include "optimizer/prep.h" #include "utils/acl.h" #include "utils/builtins.h" +#include "utils/fmgroids.h" #include "utils/syscache.h" #include "utils/temprel.h" #include "commands/trigger.h" @@ -614,12 +615,15 @@ AlterTableAlterColumn(const char *relationName, HeapTuple tuple; attr_rel = heap_openr(AttributeRelationName, AccessExclusiveLock); - ScanKeyEntryInitialize(&scankeys[0], 0x0, Anum_pg_attribute_attrelid, F_OIDEQ, + ScanKeyEntryInitialize(&scankeys[0], 0x0, + Anum_pg_attribute_attrelid, F_OIDEQ, ObjectIdGetDatum(myrelid)); - ScanKeyEntryInitialize(&scankeys[1], 0x0, Anum_pg_attribute_attnum, F_INT2EQ, + ScanKeyEntryInitialize(&scankeys[1], 0x0, + Anum_pg_attribute_attnum, F_INT2EQ, Int16GetDatum(attnum)); - ScanKeyEntryInitialize(&scankeys[2], 0x0, Anum_pg_attribute_atthasdef, F_BOOLEQ, - TRUE); + ScanKeyEntryInitialize(&scankeys[2], 0x0, + Anum_pg_attribute_atthasdef, F_BOOLEQ, + Int32GetDatum(TRUE)); scan = heap_beginscan(attr_rel, false, SnapshotNow, 3, scankeys); AssertState(scan != NULL); @@ -661,9 +665,11 @@ drop_default(Oid relid, int16 attnum) HeapTuple tuple; attrdef_rel = heap_openr(AttrDefaultRelationName, AccessExclusiveLock); - ScanKeyEntryInitialize(&scankeys[0], 0x0, Anum_pg_attrdef_adrelid, F_OIDEQ, + ScanKeyEntryInitialize(&scankeys[0], 0x0, + Anum_pg_attrdef_adrelid, F_OIDEQ, ObjectIdGetDatum(relid)); - ScanKeyEntryInitialize(&scankeys[1], 0x0, Anum_pg_attrdef_adnum, F_INT2EQ, + ScanKeyEntryInitialize(&scankeys[1], 0x0, + Anum_pg_attrdef_adnum, F_INT2EQ, Int16GetDatum(attnum)); scan = heap_beginscan(attrdef_rel, false, SnapshotNow, 2, scankeys); diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c index 3fe7b6f6347..f33189d3ee9 100644 --- a/src/backend/commands/comment.c +++ b/src/backend/commands/comment.c @@ -27,11 +27,12 @@ #include "catalog/pg_type.h" #include "commands/comment.h" #include "miscadmin.h" +#include "parser/parse.h" #include "rewrite/rewriteRemove.h" #include "utils/acl.h" +#include "utils/fmgroids.h" #include "utils/syscache.h" -#include "../backend/parser/parse.h" /*------------------------------------------------------------------ * Static Function Prototypes -- @@ -153,7 +154,7 @@ CreateComments(Oid oid, char *comment) } i = 0; values[i++] = ObjectIdGetDatum(oid); - values[i++] = (Datum) fmgr(F_TEXTIN, comment); + values[i++] = (Datum) textin(comment); } /*** Now, open pg_description and attempt to find the old tuple ***/ diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 65dff8ed442..4285663a162 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.106 2000/05/18 01:52:45 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.107 2000/05/28 17:55:54 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -680,7 +680,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null indexNatts[i] = natts; if (VARSIZE(&pgIndexP[i]->indpred) != 0) { - predString = fmgr(F_TEXTOUT, &pgIndexP[i]->indpred); + predString = textout(&pgIndexP[i]->indpred); indexPred[i] = stringToNode(predString); pfree(predString); /* make dummy ExprContext for use by ExecQual */ diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index 4458edafaf2..b08f6545044 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.54 2000/05/25 06:53:43 ishii Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.55 2000/05/28 17:55:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -37,6 +37,7 @@ #include "storage/fd.h" /* for closeAllVfds */ #include "storage/sinval.h" /* for DatabaseHasActiveBackends */ #include "utils/builtins.h" +#include "utils/fmgroids.h" #include "utils/elog.h" #include "utils/palloc.h" #include "utils/rel.h" diff --git a/src/backend/commands/define.c b/src/backend/commands/define.c index 5bc75faaec7..da872872175 100644 --- a/src/backend/commands/define.c +++ b/src/backend/commands/define.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.42 2000/05/12 18:51:59 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.43 2000/05/28 17:55:55 tgl Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -35,8 +35,6 @@ */ #include <ctype.h> #include <math.h> -#include <sys/stat.h> - #include "postgres.h" @@ -66,18 +64,20 @@ static void case_translate_language_name(const char *input, char *output) { /*------------------------------------------------------------------------- - Translate the input language name to lower case, except if it's C, - translate to upper case. + Translate the input language name to lower case, except if it's "C", + translate to upper case, or "newC", translate to that spelling. --------------------------------------------------------------------------*/ int i; - for (i = 0; i < NAMEDATALEN && input[i]; ++i) + for (i = 0; i < NAMEDATALEN-1 && input[i]; ++i) output[i] = tolower(input[i]); output[i] = '\0'; if (strcmp(output, "c") == 0) output[0] = 'C'; + else if (strcmp(output, "newc") == 0) + output[3] = 'C'; } @@ -108,9 +108,10 @@ compute_return_type(const Node *returnType, static void -compute_full_attributes(List *parameters, int32 *byte_pct_p, - int32 *perbyte_cpu_p, int32 *percall_cpu_p, - int32 *outin_ratio_p, bool *canCache_p) +compute_full_attributes(List *parameters, + int32 *byte_pct_p, int32 *perbyte_cpu_p, + int32 *percall_cpu_p, int32 *outin_ratio_p, + bool *canCache_p, bool *isStrict_p) { /*-------------------------------------------------------------------------- Interpret the parameters *parameters and return their contents as @@ -119,14 +120,20 @@ compute_full_attributes(List *parameters, int32 *byte_pct_p, These parameters supply optional information about a function. All have defaults if not specified. - Note: as of version 6.6, canCache is used (if set, the optimizer's - constant-folder is allowed to pre-evaluate the function if all its - inputs are constant). The other four are not used. They used to be + Note: currently, only two of these parameters actually do anything: + + * canCache means the optimizer's constant-folder is allowed to + pre-evaluate the function when all its inputs are constants. + + * isStrict means the function should not be called when any NULL + inputs are present; instead a NULL result value should be assumed. + + The other four parameters are not used anywhere. They used to be used in the "expensive functions" optimizer, but that's been dead code for a long time. - Since canCache is useful for any function, we now allow attributes to be - supplied for all functions regardless of language. + Since canCache and isStrict are useful for any function, we now allow + attributes to be supplied for all functions regardless of language. ---------------------------------------------------------------------------*/ List *pl; @@ -136,6 +143,7 @@ compute_full_attributes(List *parameters, int32 *byte_pct_p, *percall_cpu_p = PERCALL_CPU; *outin_ratio_p = OUTIN_RATIO; *canCache_p = false; + *isStrict_p = false; foreach(pl, parameters) { @@ -143,6 +151,8 @@ compute_full_attributes(List *parameters, int32 *byte_pct_p, if (strcasecmp(param->defname, "iscachable") == 0) *canCache_p = true; + else if (strcasecmp(param->defname, "isstrict") == 0) + *isStrict_p = true; else if (strcasecmp(param->defname, "trusted") == 0) { @@ -182,24 +192,17 @@ static void interpret_AS_clause(const char *languageName, const List *as, char **prosrc_str_p, char **probin_str_p) { - struct stat stat_buf; - Assert(as != NIL); - if (strcmp(languageName, "C") == 0) + if (strcmp(languageName, "C") == 0 || + strcmp(languageName, "newC") == 0) { /* * For "C" language, store the file name in probin and, when - * given, the link symbol name in prosrc. But first, stat the - * file to make sure it's there! + * given, the link symbol name in prosrc. */ - - if (stat(strVal(lfirst(as)), &stat_buf) == -1) - elog(ERROR, "stat failed on file '%s': %m", strVal(lfirst(as))); - *probin_str_p = strVal(lfirst(as)); - if (lnext(as) == NULL) *prosrc_str_p = "-"; else @@ -239,8 +242,8 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest) char languageName[NAMEDATALEN]; /* - * name of language of function, with case adjusted: "C", "internal", - * or "SQL" + * name of language of function, with case adjusted: "C", "newC", + * "internal", "newinternal", "sql", etc. */ bool returnsSet; @@ -257,19 +260,21 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest) perbyte_cpu, percall_cpu, outin_ratio; - bool canCache; - + bool canCache, + isStrict; case_translate_language_name(stmt->language, languageName); if (strcmp(languageName, "C") == 0 || - strcmp(languageName, "internal") == 0) + strcmp(languageName, "newC") == 0 || + strcmp(languageName, "internal") == 0 || + strcmp(languageName, "newinternal") == 0) { if (!superuser()) elog(ERROR, "Only users with Postgres superuser privilege are " - "permitted to create a function " - "in the '%s' language. Others may use the 'sql' language " + "permitted to create a function in the '%s' language.\n\t" + "Others may use the 'sql' language " "or the created procedural languages.", languageName); } @@ -288,28 +293,23 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest) 0, 0, 0); if (!HeapTupleIsValid(languageTuple)) - { - elog(ERROR, "Unrecognized language specified in a CREATE FUNCTION: " - "'%s'. Recognized languages are sql, C, internal " - "and the created procedural languages.", + "'%s'.\n\tRecognized languages are sql, C, newC, " + "internal, newinternal, and created procedural languages.", languageName); - } /* Check that this language is a PL */ languageStruct = (Form_pg_language) GETSTRUCT(languageTuple); if (!(languageStruct->lanispl)) - { elog(ERROR, "Language '%s' isn't defined as PL", languageName); - } /* * Functions in untrusted procedural languages are restricted to * be defined by postgres superusers only */ - if (languageStruct->lanpltrusted == false && !superuser()) + if (!languageStruct->lanpltrusted && !superuser()) { elog(ERROR, "Only users with Postgres superuser privilege " "are permitted to create a function in the '%s' " @@ -324,7 +324,7 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest) compute_full_attributes(stmt->withClause, &byte_pct, &perbyte_cpu, &percall_cpu, - &outin_ratio, &canCache); + &outin_ratio, &canCache, &isStrict); interpret_AS_clause(languageName, stmt->as, &prosrc_str, &probin_str); @@ -338,8 +338,9 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest) languageName, prosrc_str, /* converted to text later */ probin_str, /* converted to text later */ - canCache, true, /* (obsolete "trusted") */ + canCache, + isStrict, byte_pct, perbyte_cpu, percall_cpu, diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 16ad849d8ff..826efa40bbd 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.26 2000/04/25 10:38:38 inoue Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.27 2000/05/28 17:55:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -37,6 +37,7 @@ #include "parser/parse_func.h" #include "parser/parse_type.h" #include "utils/builtins.h" +#include "utils/fmgroids.h" #include "utils/syscache.h" #include "miscadmin.h" /* ReindexDatabase() */ #include "utils/portal.h" /* ReindexDatabase() */ @@ -298,7 +299,7 @@ ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable) { char *predString; - predString = fmgr(F_TEXTOUT, &index->indpred); + predString = textout(&index->indpred); oldPred = stringToNode(predString); pfree(predString); } diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c index 47d2201c82a..9b5f7c1ddff 100644 --- a/src/backend/commands/proclang.c +++ b/src/backend/commands/proclang.c @@ -17,6 +17,7 @@ #include "catalog/pg_shadow.h" #include "commands/proclang.h" #include "fmgr.h" +#include "utils/builtins.h" #include "utils/syscache.h" @@ -119,7 +120,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) values[i++] = Int8GetDatum((bool) 1); values[i++] = Int8GetDatum(stmt->pltrusted); values[i++] = ObjectIdGetDatum(procTup->t_data->t_oid); - values[i++] = (Datum) fmgr(F_TEXTIN, stmt->plcompiler); + values[i++] = (Datum) textin(stmt->plcompiler); rel = heap_openr(LanguageRelationName, RowExclusiveLock); diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index c79ce0cea50..49f5570e8fc 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.64 2000/04/16 04:25:42 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.65 2000/05/28 17:55:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -27,6 +27,7 @@ #include "miscadmin.h" #include "utils/acl.h" #include "utils/builtins.h" +#include "utils/fmgroids.h" #include "utils/inval.h" #include "utils/syscache.h" #include "utils/tqual.h" @@ -757,16 +758,9 @@ equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2) static HeapTuple ExecCallTriggerFunc(Trigger *trigger) { - if (trigger->tgfunc.fn_addr == NULL) fmgr_info(trigger->tgfoid, &trigger->tgfunc); - if (trigger->tgfunc.fn_plhandler != NULL) - { - return (HeapTuple) (*(trigger->tgfunc.fn_plhandler)) - (&trigger->tgfunc); - } - return (HeapTuple) ((*fmgr_faddr(&trigger->tgfunc)) ()); } diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index 2e01e6e202c..ea5f457448f 100644 --- a/src/backend/commands/user.c +++ b/src/backend/commands/user.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: user.c,v 1.53 2000/05/04 20:06:07 tgl Exp $ + * $Id: user.c,v 1.54 2000/05/28 17:55:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -33,6 +33,7 @@ #include "utils/acl.h" #include "utils/array.h" #include "utils/builtins.h" +#include "utils/fmgroids.h" #include "utils/syscache.h" static void CheckPgUserAclNotNull(void); diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 0c0c5f4785d..3a9b972b9ed 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.148 2000/05/19 03:22:29 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.149 2000/05/28 17:55:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -38,6 +38,7 @@ #include "tcop/tcopprot.h" #include "utils/acl.h" #include "utils/builtins.h" +#include "utils/fmgroids.h" #include "utils/inval.h" #include "utils/portal.h" #include "utils/relcache.h" diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index 58307e6a695..a53957c4f4a 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.69 2000/04/12 17:15:08 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.70 2000/05/28 17:55:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -41,6 +41,7 @@ #include "executor/functions.h" #include "executor/nodeSubplan.h" #include "utils/builtins.h" +#include "utils/fmgroids.h" #include "utils/fcache2.h" @@ -64,7 +65,8 @@ static Datum ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull); static Datum ExecEvalFunc(Expr *funcClause, ExprContext *econtext, bool *isNull, bool *isDone); static void ExecEvalFuncArgs(FunctionCachePtr fcache, ExprContext *econtext, - List *argList, Datum argV[], bool *argIsDone); + List *argList, FunctionCallInfo fcinfo, + bool *argIsDone); static Datum ExecEvalNot(Expr *notclause, ExprContext *econtext, bool *isNull); static Datum ExecEvalOper(Expr *opClause, ExprContext *econtext, bool *isNull); @@ -614,15 +616,12 @@ static void ExecEvalFuncArgs(FunctionCachePtr fcache, ExprContext *econtext, List *argList, - Datum argV[], + FunctionCallInfo fcinfo, bool *argIsDone) { int i; - bool *nullVect; List *arg; - nullVect = fcache->nullVect; - i = 0; foreach(arg, argList) { @@ -632,16 +631,16 @@ ExecEvalFuncArgs(FunctionCachePtr fcache, * as arguments but we make an exception in the case of nested dot * expressions. We have to watch out for this case here. */ - argV[i] = ExecEvalExpr((Node *) lfirst(arg), - econtext, - &nullVect[i], - argIsDone); + fcinfo->arg[i] = ExecEvalExpr((Node *) lfirst(arg), + econtext, + &fcinfo->argnull[i], + argIsDone); if (!(*argIsDone)) { if (i != 0) elog(ERROR, "functions can only take sets in their first argument"); - fcache->setArg = (char *) argV[0]; + fcache->setArg = fcinfo->arg[0]; fcache->hasSetArg = true; } i++; @@ -658,40 +657,45 @@ ExecMakeFunctionResult(Node *node, bool *isNull, bool *isDone) { - Datum argV[FUNC_MAX_ARGS]; - FunctionCachePtr fcache; - Func *funcNode = NULL; - Oper *operNode = NULL; - bool funcisset = false; + FunctionCallInfoData fcinfo; + FunctionCachePtr fcache; + List *ftlist; + bool funcisset; + Datum result; + bool argDone; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); /* * This is kind of ugly, Func nodes now have targetlists so that we * know when and what to project out from postquel function results. - * This means we have to pass the func node all the way down instead - * of using only the fcache struct as before. ExecMakeFunctionResult - * becomes a little bit more of a dual personality as a result. + * ExecMakeFunctionResult becomes a little bit more of a dual personality + * as a result. */ if (IsA(node, Func)) { - funcNode = (Func *) node; - fcache = funcNode->func_fcache; + fcache = ((Func *) node)->func_fcache; + ftlist = ((Func *) node)->func_tlist; + funcisset = (((Func *) node)->funcid == F_SETEVAL); } else { - operNode = (Oper *) node; - fcache = operNode->op_fcache; + fcache = ((Oper *) node)->op_fcache; + ftlist = NIL; + funcisset = false; } + fcinfo.flinfo = &fcache->func; + fcinfo.nargs = fcache->nargs; + /* * arguments is a list of expressions to evaluate before passing to - * the function manager. We collect the results of evaluating the - * expressions into a datum array (argV) and pass this array to - * arrayFmgr() + * the function manager. We collect the results of evaluating the + * expressions into the FunctionCallInfo struct. Note we assume that + * fcache->nargs is the correct length of the arguments list! */ - if (fcache->nargs != 0) + if (fcache->nargs > 0) { - bool argDone; - if (fcache->nargs > FUNC_MAX_ARGS) elog(ERROR, "ExecMakeFunctionResult: too many arguments"); @@ -700,21 +704,23 @@ ExecMakeFunctionResult(Node *node, * returning a set of tuples (i.e. a nested dot expression). We * don't want to evaluate the arguments again until the function * is done. hasSetArg will always be false until we eval the args - * for the first time. We should set this in the parser. + * for the first time. */ - if ((fcache->hasSetArg) && fcache->setArg != NULL) + if (fcache->hasSetArg && fcache->setArg != (Datum) 0) { - argV[0] = (Datum) fcache->setArg; + fcinfo.arg[0] = fcache->setArg; argDone = false; } else - ExecEvalFuncArgs(fcache, econtext, arguments, argV, &argDone); + ExecEvalFuncArgs(fcache, econtext, arguments, &fcinfo, &argDone); - if ((fcache->hasSetArg) && (argDone)) + if (fcache->hasSetArg && argDone) { + /* can only get here if input is an empty set. */ if (isDone) *isDone = true; - return (Datum) NULL; + *isNull = true; + return (Datum) 0; } } @@ -731,27 +737,23 @@ ExecMakeFunctionResult(Node *node, * which defines this set. So replace the existing funcid in the * funcnode with the set's OID. Also, we want a new fcache which * points to the right function, so get that, now that we have the - * right OID. Also zero out the argV, since the real set doesn't take + * right OID. Also zero out fcinfo.arg, since the real set doesn't take * any arguments. */ - if (((Func *) node)->funcid == F_SETEVAL) + if (funcisset) { - funcisset = true; if (fcache->setArg) { - argV[0] = 0; - - ((Func *) node)->funcid = (Oid) PointerGetDatum(fcache->setArg); - + ((Func *) node)->funcid = DatumGetObjectId(fcache->setArg); } else { - ((Func *) node)->funcid = (Oid) argV[0]; - setFcache(node, argV[0], NIL, econtext); + ((Func *) node)->funcid = DatumGetObjectId(fcinfo.arg[0]); + setFcache(node, DatumGetObjectId(fcinfo.arg[0]), NIL, econtext); fcache = ((Func *) node)->func_fcache; - fcache->setArg = (char *) argV[0]; - argV[0] = (Datum) 0; + fcache->setArg = fcinfo.arg[0]; } + fcinfo.arg[0] = (Datum) 0; } /* @@ -760,11 +762,6 @@ ExecMakeFunctionResult(Node *node, */ if (fcache->language == SQLlanguageId) { - Datum result; - bool argDone; - - Assert(funcNode); - /*-------------------- * This loop handles the situation where we are iterating through * all results in a nested dot function (whose argument function @@ -777,8 +774,37 @@ ExecMakeFunctionResult(Node *node, */ for (;;) { - result = postquel_function(funcNode, (char **) argV, - isNull, isDone); + /* + * If function is strict, and there are any NULL arguments, + * skip calling the function (at least for this set of args). + */ + bool callit = true; + + if (fcinfo.flinfo->fn_strict) + { + int i; + + for (i = 0; i < fcinfo.nargs; i++) + { + if (fcinfo.argnull[i]) + { + callit = false; + break; + } + } + } + + if (callit) + { + result = postquel_function(&fcinfo, fcache, ftlist, isDone); + *isNull = fcinfo.isnull; + } + else + { + result = (Datum) 0; + *isDone = true; + *isNull = true; + } if (!*isDone) break; /* got a result from current argument */ @@ -786,7 +812,7 @@ ExecMakeFunctionResult(Node *node, break; /* input not a set, so done */ /* OK, get the next argument... */ - ExecEvalFuncArgs(fcache, econtext, arguments, argV, &argDone); + ExecEvalFuncArgs(fcache, econtext, arguments, &fcinfo, &argDone); if (argDone) { @@ -795,10 +821,11 @@ ExecMakeFunctionResult(Node *node, * End of arguments, so reset the setArg flag and say * "Done" */ - fcache->setArg = (char *) NULL; + fcache->setArg = (Datum) 0; fcache->hasSetArg = false; *isDone = true; - result = (Datum) NULL; + *isNull = true; + result = (Datum) 0; break; } @@ -826,21 +853,34 @@ ExecMakeFunctionResult(Node *node, if (*isDone) ((Func *) node)->func_fcache = NULL; } - - return result; } else { - int i; - + /* A non-SQL function cannot return a set, at present. */ if (isDone) *isDone = true; - for (i = 0; i < fcache->nargs; i++) - if (fcache->nullVect[i] == true) - *isNull = true; + /* + * If function is strict, and there are any NULL arguments, + * skip calling the function and return NULL. + */ + if (fcinfo.flinfo->fn_strict) + { + int i; - return (Datum) fmgr_c(&fcache->func, (FmgrValues *) argV, isNull); + for (i = 0; i < fcinfo.nargs; i++) + { + if (fcinfo.argnull[i]) + { + *isNull = true; + return (Datum) 0; + } + } + } + result = FunctionCallInvoke(&fcinfo); + *isNull = fcinfo.isnull; } + + return result; } diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index e3783473f96..39b29138e19 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.55 2000/04/12 17:15:08 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.56 2000/05/28 17:55:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -52,6 +52,8 @@ #include "executor/execdebug.h" #include "executor/executor.h" #include "miscadmin.h" +#include "utils/builtins.h" +#include "utils/fmgroids.h" static void ExecGetIndexKeyInfo(Form_pg_index indexTuple, int *numAttsOutP, AttrNumber **attsOutP, FuncIndexInfoPtr fInfoP); @@ -843,7 +845,7 @@ ExecOpenIndices(Oid resultRelationOid, */ if (VARSIZE(&indexStruct->indpred) != 0) { - predString = fmgr(F_TEXTOUT, &indexStruct->indpred); + predString = textout(&indexStruct->indpred); predicate = (PredInfo *) stringToNode(predString); pfree(predString); } diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index c8d119df482..ee5fabf1708 100644 --- a/src/backend/executor/functions.c +++ b/src/backend/executor/functions.c @@ -2,14 +2,13 @@ * * functions.c * Routines to handle functions called from the executor - * Putting this stuff in fmgr makes the postmaster a mess.... * * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.33 2000/04/12 17:15:09 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.34 2000/05/28 17:55:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -24,7 +23,6 @@ #include "tcop/utility.h" #include "utils/datum.h" -#undef new typedef enum { @@ -39,18 +37,18 @@ typedef struct local_es ExecStatus status; } execution_state; -#define LAST_POSTQUEL_COMMAND(es) ((es)->next == (execution_state *)NULL) +#define LAST_POSTQUEL_COMMAND(es) ((es)->next == (execution_state *) NULL) /* non-export function prototypes */ static TupleDesc postquel_start(execution_state *es); -static execution_state *init_execution_state(FunctionCachePtr fcache, - char *args[]); +static execution_state *init_execution_state(FunctionCachePtr fcache); static TupleTableSlot *postquel_getnext(execution_state *es); static void postquel_end(execution_state *es); -static void postquel_sub_params(execution_state *es, int nargs, - char *args[], bool *nullV); -static Datum postquel_execute(execution_state *es, FunctionCachePtr fcache, - List *fTlist, char **args, bool *isNull); +static void postquel_sub_params(execution_state *es, FunctionCallInfo fcinfo); +static Datum postquel_execute(execution_state *es, + FunctionCallInfo fcinfo, + FunctionCachePtr fcache, + List *func_tlist); Datum @@ -64,7 +62,6 @@ ProjectAttribute(TupleDesc TD, Var *attrVar = (Var *) tlist->expr; AttrNumber attrno = attrVar->varattno; - val = heap_getattr(tup, attrno, TD, isnullP); if (*isnullP) return (Datum) NULL; @@ -77,8 +74,7 @@ ProjectAttribute(TupleDesc TD, } static execution_state * -init_execution_state(FunctionCachePtr fcache, - char *args[]) +init_execution_state(FunctionCachePtr fcache) { execution_state *newes; execution_state *nextes; @@ -196,13 +192,10 @@ postquel_end(execution_state *es) } static void -postquel_sub_params(execution_state *es, - int nargs, - char *args[], - bool *nullV) +postquel_sub_params(execution_state *es, FunctionCallInfo fcinfo) { - ParamListInfo paramLI; EState *estate; + ParamListInfo paramLI; estate = es->estate; paramLI = estate->es_param_list_info; @@ -211,9 +204,9 @@ postquel_sub_params(execution_state *es, { if (paramLI->kind == PARAM_NUM) { - Assert(paramLI->id <= nargs); - paramLI->value = (Datum) args[(paramLI->id - 1)]; - paramLI->isnull = nullV[(paramLI->id - 1)]; + Assert(paramLI->id <= fcinfo->nargs); + paramLI->value = fcinfo->arg[paramLI->id - 1]; + paramLI->isnull = fcinfo->argnull[paramLI->id - 1]; } paramLI++; } @@ -264,10 +257,9 @@ copy_function_result(FunctionCachePtr fcache, static Datum postquel_execute(execution_state *es, + FunctionCallInfo fcinfo, FunctionCachePtr fcache, - List *fTlist, - char **args, - bool *isNull) + List *func_tlist) { TupleTableSlot *slot; Datum value; @@ -278,8 +270,8 @@ postquel_execute(execution_state *es, * ExecutorStart->ExecInitIndexScan->ExecEvalParam works ok. (But * note: I HOPE we can do it here). - vadim 01/22/97 */ - if (fcache->nargs > 0) - postquel_sub_params(es, fcache->nargs, args, fcache->nullVect); + if (fcinfo->nargs > 0) + postquel_sub_params(es, fcinfo); if (es->status == F_EXEC_START) { @@ -293,7 +285,7 @@ postquel_execute(execution_state *es, { postquel_end(es); es->status = F_EXEC_DONE; - *isNull = true; + fcinfo->isnull = true; /* * If this isn't the last command for the function we have to @@ -315,19 +307,20 @@ postquel_execute(execution_state *es, * logic and code redundancy here. */ resSlot = copy_function_result(fcache, slot); - if (fTlist != NIL) + if (func_tlist != NIL) { - TargetEntry *tle = lfirst(fTlist); + TargetEntry *tle = lfirst(func_tlist); value = ProjectAttribute(resSlot->ttc_tupleDescriptor, tle, resSlot->val, - isNull); + &fcinfo->isnull); } else { - value = (Datum) resSlot; - *isNull = false; + /* XXX is this right? Return whole tuple slot?? */ + value = PointerGetDatum(resSlot); + fcinfo->isnull = false; } /* @@ -353,11 +346,13 @@ postquel_execute(execution_state *es, } Datum -postquel_function(Func *funcNode, char **args, bool *isNull, bool *isDone) +postquel_function(FunctionCallInfo fcinfo, + FunctionCachePtr fcache, + List *func_tlist, + bool *isDone) { execution_state *es; Datum result = 0; - FunctionCachePtr fcache = funcNode->func_fcache; CommandId savedId; /* @@ -371,7 +366,7 @@ postquel_function(Func *funcNode, char **args, bool *isNull, bool *isDone) es = (execution_state *) fcache->func_state; if (es == NULL) { - es = init_execution_state(fcache, args); + es = init_execution_state(fcache); fcache->func_state = (char *) es; } @@ -388,16 +383,20 @@ postquel_function(Func *funcNode, char **args, bool *isNull, bool *isDone) while (es != (execution_state *) NULL) { result = postquel_execute(es, + fcinfo, fcache, - funcNode->func_tlist, - args, - isNull); + func_tlist); if (es->status != F_EXEC_DONE) break; es = es->next; } /* + * Restore outer command ID. + */ + SetScanCommandId(savedId); + + /* * If we've gone through every command in this function, we are done. */ if (es == (execution_state *) NULL) @@ -417,17 +416,15 @@ postquel_function(Func *funcNode, char **args, bool *isNull, bool *isDone) * Let caller know we're finished. */ *isDone = true; - SetScanCommandId(savedId); return (fcache->oneResult) ? result : (Datum) NULL; } /* * If we got a result from a command within the function it has to be - * the final command. All others shouldn't be returing anything. + * the final command. All others shouldn't be returning anything. */ Assert(LAST_POSTQUEL_COMMAND(es)); - *isDone = false; - SetScanCommandId(savedId); + *isDone = false; return result; } diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index e2db06f84d1..853fa96e2c3 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -32,7 +32,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.63 2000/04/12 17:15:09 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.64 2000/05/28 17:55:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -218,8 +218,13 @@ static void advance_transition_functions(AggStatePerAgg peraggstate, Datum newVal, bool isNull) { - Datum args[2]; + FunctionCallInfoData fcinfo; + MemSet(&fcinfo, 0, sizeof(fcinfo)); + + /* + * XXX reconsider isNULL handling here + */ if (OidIsValid(peraggstate->xfn1_oid) && !isNull) { if (peraggstate->noInitValue) @@ -244,28 +249,48 @@ advance_transition_functions(AggStatePerAgg peraggstate, else { /* apply transition function 1 */ - args[0] = peraggstate->value1; - args[1] = newVal; - newVal = (Datum) fmgr_c(&peraggstate->xfn1, - (FmgrValues *) args, - &isNull); - if (!peraggstate->transtype1ByVal) + fcinfo.flinfo = &peraggstate->xfn1; + fcinfo.nargs = 2; + fcinfo.arg[0] = peraggstate->value1; + fcinfo.argnull[0] = peraggstate->value1IsNull; + fcinfo.arg[1] = newVal; + fcinfo.argnull[1] = isNull; + if (fcinfo.flinfo->fn_strict && + (peraggstate->value1IsNull || isNull)) + { + /* don't call a strict function with NULL inputs */ + newVal = (Datum) 0; + fcinfo.isnull = true; + } + else + newVal = FunctionCallInvoke(&fcinfo); + if (!peraggstate->transtype1ByVal && !peraggstate->value1IsNull) pfree(peraggstate->value1); peraggstate->value1 = newVal; + peraggstate->value1IsNull = fcinfo.isnull; } } if (OidIsValid(peraggstate->xfn2_oid)) { /* apply transition function 2 */ - args[0] = peraggstate->value2; - isNull = false; /* value2 cannot be null, currently */ - newVal = (Datum) fmgr_c(&peraggstate->xfn2, - (FmgrValues *) args, - &isNull); - if (!peraggstate->transtype2ByVal) + fcinfo.flinfo = &peraggstate->xfn2; + fcinfo.nargs = 1; + fcinfo.arg[0] = peraggstate->value2; + fcinfo.argnull[0] = peraggstate->value2IsNull; + fcinfo.isnull = false; /* must reset after use by xfn1 */ + if (fcinfo.flinfo->fn_strict && peraggstate->value2IsNull) + { + /* don't call a strict function with NULL inputs */ + newVal = (Datum) 0; + fcinfo.isnull = true; + } + else + newVal = FunctionCallInvoke(&fcinfo); + if (!peraggstate->transtype2ByVal && !peraggstate->value2IsNull) pfree(peraggstate->value2); peraggstate->value2 = newVal; + peraggstate->value2IsNull = fcinfo.isnull; } } @@ -276,8 +301,10 @@ static void finalize_aggregate(AggStatePerAgg peraggstate, Datum *resultVal, bool *resultIsNull) { - Aggref *aggref = peraggstate->aggref; - char *args[2]; + Aggref *aggref = peraggstate->aggref; + FunctionCallInfoData fcinfo; + + MemSet(&fcinfo, 0, sizeof(fcinfo)); /* * If it's a DISTINCT aggregate, all we've done so far is to stuff the @@ -337,21 +364,41 @@ finalize_aggregate(AggStatePerAgg peraggstate, if (OidIsValid(peraggstate->finalfn_oid) && !peraggstate->noInitValue) { + fcinfo.flinfo = &peraggstate->finalfn; if (peraggstate->finalfn.fn_nargs > 1) { - args[0] = (char *) peraggstate->value1; - args[1] = (char *) peraggstate->value2; + fcinfo.nargs = 2; + fcinfo.arg[0] = peraggstate->value1; + fcinfo.argnull[0] = peraggstate->value1IsNull; + fcinfo.arg[1] = peraggstate->value2; + fcinfo.argnull[1] = peraggstate->value2IsNull; } else if (OidIsValid(peraggstate->xfn1_oid)) - args[0] = (char *) peraggstate->value1; + { + fcinfo.nargs = 1; + fcinfo.arg[0] = peraggstate->value1; + fcinfo.argnull[0] = peraggstate->value1IsNull; + } else if (OidIsValid(peraggstate->xfn2_oid)) - args[0] = (char *) peraggstate->value2; + { + fcinfo.nargs = 1; + fcinfo.arg[0] = peraggstate->value2; + fcinfo.argnull[0] = peraggstate->value2IsNull; + } else elog(ERROR, "ExecAgg: no valid transition functions??"); - *resultIsNull = false; - *resultVal = (Datum) fmgr_c(&peraggstate->finalfn, - (FmgrValues *) args, - resultIsNull); + if (fcinfo.flinfo->fn_strict && + (fcinfo.argnull[0] || fcinfo.argnull[1])) + { + /* don't call a strict function with NULL inputs */ + *resultVal = (Datum) 0; + *resultIsNull = true; + } + else + { + *resultVal = FunctionCallInvoke(&fcinfo); + *resultIsNull = fcinfo.isnull; + } } else if (OidIsValid(peraggstate->xfn1_oid)) { diff --git a/src/backend/libpq/Makefile b/src/backend/libpq/Makefile index 656fbdb480d..50f5f1b7206 100644 --- a/src/backend/libpq/Makefile +++ b/src/backend/libpq/Makefile @@ -4,7 +4,7 @@ # Makefile for libpq subsystem (backend half of libpq interface) # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/backend/libpq/Makefile,v 1.17 2000/01/19 02:58:52 petere Exp $ +# $Header: /cvsroot/pgsql/src/backend/libpq/Makefile,v 1.18 2000/05/28 17:55:56 tgl Exp $ # #------------------------------------------------------------------------- @@ -29,11 +29,6 @@ all: SUBSYS.o SUBSYS.o: $(OBJS) $(LD) $(LDREL) $(LDOUT) SUBSYS.o $(OBJS) -be-dumpdata.o be-pqexec.o: ../fmgr.h - -../fmgr.h: - $(MAKE) -C .. fmgr.h - depend dep: $(CC) -MM $(CFLAGS) *.c >depend diff --git a/src/backend/libpq/be-pqexec.c b/src/backend/libpq/be-pqexec.c index 0c29ea25184..42d48281e08 100644 --- a/src/backend/libpq/be-pqexec.c +++ b/src/backend/libpq/be-pqexec.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-pqexec.c,v 1.31 2000/03/17 02:36:08 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-pqexec.c,v 1.32 2000/05/28 17:55:56 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -42,11 +42,11 @@ static char *strmake(char *str, int len); * result_buf : pointer to result buffer (&int if integer) * result_len : length of return value. * result_is_int : If the result is an integer, this must be non-zero - * args : pointer to a NULL terminated arg array. + * args : pointer to an array of PQArgBlock items. * (length, if integer, and result-pointer) * nargs : # of arguments in args array. * - * This code scavanged from HandleFunctionRequest() in tcop/fastpath.h + * This code scavenged from HandleFunctionRequest() in tcop/fastpath.h * ---------------- */ char * @@ -57,46 +57,53 @@ PQfn(int fnid, PQArgBlock *args, int nargs) { - char *retval; /* XXX - should be datum, maybe ? */ - char *arg[FUNC_MAX_ARGS]; - bool isNull; - int i; + FmgrInfo flinfo; + FunctionCallInfoData fcinfo; + Datum retval; + int i; - /* ---------------- - * fill args[] array - * ---------------- - */ if (nargs > FUNC_MAX_ARGS) elog(ERROR, "functions cannot have more than %d arguments", FUNC_MAX_ARGS); + + /* ---------------- + * set up the argument block for the function manager + * ---------------- + */ + fmgr_info((Oid) fnid, &flinfo); + + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = &flinfo; + fcinfo.nargs = nargs; + for (i = 0; i < nargs; i++) { if (args[i].len == VAR_LENGTH_ARG) - arg[i] = (char *) args[i].u.ptr; + fcinfo.arg[i] = (Datum) args[i].u.ptr; else if ((Size) args[i].len > sizeof(int4)) elog(ERROR, "arg_length of argument %d too long", i); else - arg[i] = (char *) args[i].u.integer; + fcinfo.arg[i] = (Datum) args[i].u.integer; } /* ---------------- * call the postgres function manager * ---------------- */ - retval = fmgr_array_args(fnid, nargs, arg, &isNull); + retval = FunctionCallInvoke(&fcinfo); /* ---------------- * put the result in the buffer the user specified and * return the proper code. * ---------------- */ - if (isNull) /* void retval */ + if (fcinfo.isnull) /* void retval */ return "0"; if (result_is_int) - *result_buf = (int) retval; + *result_buf = DatumGetInt32(retval); else - memmove(result_buf, retval, result_len); + memmove(result_buf, DatumGetPointer(retval), result_len); return "G"; } diff --git a/src/backend/nodes/freefuncs.c b/src/backend/nodes/freefuncs.c index c0d07a05dba..59e2ac1154e 100644 --- a/src/backend/nodes/freefuncs.c +++ b/src/backend/nodes/freefuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/nodes/Attic/freefuncs.c,v 1.40 2000/04/12 17:15:16 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/Attic/freefuncs.c,v 1.41 2000/05/28 17:55:57 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -530,16 +530,12 @@ _freeFcache(FunctionCachePtr ptr) { if (ptr->argOidVect) pfree(ptr->argOidVect); - if (ptr->nullVect) - pfree(ptr->nullVect); if (ptr->src) pfree(ptr->src); if (ptr->bin) pfree(ptr->bin); if (ptr->func_state) pfree(ptr->func_state); - if (ptr->setArg) - pfree(ptr->setArg); pfree(ptr); } diff --git a/src/backend/optimizer/path/clausesel.c b/src/backend/optimizer/path/clausesel.c index d430059a1e0..460417f2417 100644 --- a/src/backend/optimizer/path/clausesel.c +++ b/src/backend/optimizer/path/clausesel.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.34 2000/04/12 17:15:19 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.35 2000/05/28 17:55:58 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -21,6 +21,7 @@ #include "optimizer/plancat.h" #include "optimizer/restrictinfo.h" #include "parser/parsetree.h" +#include "utils/fmgroids.h" #include "utils/lsyscache.h" diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index 06f9cd0247f..b862cf7f129 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.83 2000/04/16 04:41:01 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.84 2000/05/28 17:55:58 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -37,6 +37,7 @@ #include "parser/parse_oper.h" #include "parser/parsetree.h" #include "utils/builtins.h" +#include "utils/fmgroids.h" #include "utils/lsyscache.h" #include "utils/syscache.h" diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index e9d7690e00c..fca1bd0ab17 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.50 2000/04/12 17:15:24 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.51 2000/05/28 17:55:59 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -28,6 +28,8 @@ #include "optimizer/paths.h" #include "optimizer/plancat.h" #include "parser/parsetree.h" +#include "utils/builtins.h" +#include "utils/fmgroids.h" #include "utils/syscache.h" #include "catalog/catalog.h" #include "miscadmin.h" @@ -117,7 +119,7 @@ find_secondary_indexes(Query *root, Index relid) info->indproc = index->indproc; /* functional index ?? */ if (VARSIZE(&index->indpred) != 0) /* partial index ?? */ { - char *predString = fmgr(F_TEXTOUT, &index->indpred); + char *predString = textout(&index->indpred); info->indpred = (List *) stringToNode(predString); pfree(predString); diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 7658443a378..6f454063626 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: analyze.c,v 1.142 2000/04/12 17:15:26 momjian Exp $ + * $Id: analyze.c,v 1.143 2000/05/28 17:56:00 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -26,6 +26,7 @@ #include "parser/parse_target.h" #include "parser/parse_type.h" #include "utils/builtins.h" +#include "utils/fmgroids.h" #include "utils/numeric.h" void CheckSelectForUpdate(Query *qry); /* no points for style... */ diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index ed6a910f273..1866cd37b28 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.79 2000/05/26 03:56:40 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.80 2000/05/28 17:56:00 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -34,6 +34,7 @@ #include "parser/parse_target.h" #include "utils/acl.h" #include "utils/builtins.h" +#include "utils/fmgroids.h" #include "utils/lsyscache.h" #include "utils/syscache.h" diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c index 0f386b84c71..dcec30b1589 100644 --- a/src/backend/parser/parse_node.c +++ b/src/backend/parser/parse_node.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.39 2000/04/12 17:15:27 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.40 2000/05/28 17:56:00 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -442,14 +442,11 @@ make_const(Value *value) case T_Float: if (fitsInFloat(value)) { - float64 fltval = (float64) palloc(sizeof(float64data)); - - *fltval = floatVal(value); - val = Float64GetDatum(fltval); + val = Float8GetDatum(floatVal(value)); typeid = FLOAT8OID; - typelen = sizeof(float64data); - typebyval = false; + typelen = sizeof(float8); + typebyval = false; /* XXX might change someday */ } else { diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c index 2a9de556b26..73be990c010 100644 --- a/src/backend/parser/parse_oper.c +++ b/src/backend/parser/parse_oper.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.40 2000/04/12 17:15:27 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.41 2000/05/28 17:56:00 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -22,6 +22,7 @@ #include "parser/parse_func.h" #include "parser/parse_oper.h" #include "parser/parse_type.h" +#include "utils/fmgroids.h" #include "utils/syscache.h" static Oid *oper_select_candidate(int nargs, Oid *input_typeids, diff --git a/src/backend/port/dynloader/alpha.h b/src/backend/port/dynloader/alpha.h index bc1046a24ec..9fee0463401 100644 --- a/src/backend/port/dynloader/alpha.h +++ b/src/backend/port/dynloader/alpha.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: alpha.h,v 1.4 2000/01/26 05:56:44 momjian Exp $ + * $Id: alpha.h,v 1.5 2000/05/28 17:56:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -29,7 +29,7 @@ * */ #define pg_dlopen(f) dlopen(f, RTLD_LAZY) -#define pg_dlsym(h, f) ((func_ptr)dlsym(h, f)) +#define pg_dlsym(h, f) ((PGFunction) dlsym(h, f)) #define pg_dlclose(h) dlclose(h) #define pg_dlerror() dlerror() diff --git a/src/backend/port/dynloader/bsdi.h b/src/backend/port/dynloader/bsdi.h index 5c8b3058aa1..b85bf1b6f38 100644 --- a/src/backend/port/dynloader/bsdi.h +++ b/src/backend/port/dynloader/bsdi.h @@ -26,7 +26,7 @@ #define pg_dlclose dlclose #define pg_dlerror dlerror #else -#define pg_dlsym(handle, funcname) ((func_ptr) dld_get_func((funcname))) +#define pg_dlsym(handle, funcname) ((PGFunction) dld_get_func((funcname))) #define pg_dlclose(handle) ({ dld_unlink_by_file(handle, 1); free(handle); }) #endif diff --git a/src/backend/port/dynloader/hpux.c b/src/backend/port/dynloader/hpux.c index 562b59ee770..ba904fd2bcf 100644 --- a/src/backend/port/dynloader/hpux.c +++ b/src/backend/port/dynloader/hpux.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/port/dynloader/hpux.c,v 1.13 2000/04/26 23:35:34 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/port/dynloader/hpux.c,v 1.14 2000/05/28 17:56:02 tgl Exp $ * * NOTES * all functions are defined here -- it's impossible to trace the @@ -39,13 +39,13 @@ pg_dlopen(char *filename) return (void *) handle; } -func_ptr +PGFunction pg_dlsym(void *handle, char *funcname) { - func_ptr f; + PGFunction f; if (shl_findsym((shl_t *) & handle, funcname, TYPE_PROCEDURE, &f) == -1) - f = (func_ptr) NULL; + f = (PGFunction) NULL; return f; } diff --git a/src/backend/port/dynloader/hpux.h b/src/backend/port/dynloader/hpux.h index 470e43f951a..e5f39baee8a 100644 --- a/src/backend/port/dynloader/hpux.h +++ b/src/backend/port/dynloader/hpux.h @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/port/dynloader/hpux.h,v 1.3 2000/01/26 05:56:44 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/port/dynloader/hpux.h,v 1.4 2000/05/28 17:56:02 tgl Exp $ * * NOTES * all functions are defined here -- it's impossible to trace the @@ -17,7 +17,9 @@ *------------------------------------------------------------------------- */ /* System includes */ +#include "fmgr.h" + void *pg_dlopen(char *filename); -func_ptr pg_dlsym(void *handle, char *funcname); +PGFunction pg_dlsym(void *handle, char *funcname); void pg_dlclose(void *handle); char *pg_dlerror(); diff --git a/src/backend/port/dynloader/linux.h b/src/backend/port/dynloader/linux.h index 029143aa1f6..ad50aa821d3 100644 --- a/src/backend/port/dynloader/linux.h +++ b/src/backend/port/dynloader/linux.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: linux.h,v 1.8 2000/01/26 05:56:44 momjian Exp $ + * $Id: linux.h,v 1.9 2000/05/28 17:56:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -27,7 +27,7 @@ #define pg_dlsym(handle, funcname) (NULL) #define pg_dlclose(handle) ({}) #else -#define pg_dlsym(handle, funcname) ((func_ptr) dld_get_func((funcname))) +#define pg_dlsym(handle, funcname) ((PGFunction) dld_get_func((funcname))) #define pg_dlclose(handle) ({ dld_unlink_by_file(handle, 1); free(handle); }) #endif #else diff --git a/src/backend/port/dynloader/qnx4.c b/src/backend/port/dynloader/qnx4.c index eae3e2393d3..60bed57c632 100644 --- a/src/backend/port/dynloader/qnx4.c +++ b/src/backend/port/dynloader/qnx4.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/port/dynloader/Attic/qnx4.c,v 1.1 1999/12/16 01:25:04 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/port/dynloader/Attic/qnx4.c,v 1.2 2000/05/28 17:56:02 tgl Exp $ * * NOTES * @@ -30,7 +30,7 @@ pg_dlopen(char *filename) return (void *) NULL; } -func_ptr +PGFunction pg_dlsym(void *handle, char *funcname) { return NULL; diff --git a/src/backend/port/dynloader/qnx4.h b/src/backend/port/dynloader/qnx4.h index 6197d09a6fa..6ac94a8206d 100644 --- a/src/backend/port/dynloader/qnx4.h +++ b/src/backend/port/dynloader/qnx4.h @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/port/dynloader/Attic/qnx4.h,v 1.1 1999/12/16 01:25:04 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/port/dynloader/Attic/qnx4.h,v 1.2 2000/05/28 17:56:02 tgl Exp $ * * NOTES * @@ -15,6 +15,6 @@ */ /* System includes */ void *pg_dlopen(char *filename); -func_ptr pg_dlsym(void *handle, char *funcname); +PGFunction pg_dlsym(void *handle, char *funcname); void pg_dlclose(void *handle); char *pg_dlerror(); diff --git a/src/backend/rewrite/rewriteRemove.c b/src/backend/rewrite/rewriteRemove.c index 821f93440e2..13a07adbd8c 100644 --- a/src/backend/rewrite/rewriteRemove.c +++ b/src/backend/rewrite/rewriteRemove.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteRemove.c,v 1.36 2000/04/12 17:15:32 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteRemove.c,v 1.37 2000/05/28 17:56:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -23,6 +23,7 @@ #include "commands/comment.h" #include "rewrite/rewriteRemove.h" #include "rewrite/rewriteSupport.h" +#include "utils/fmgroids.h" #include "utils/syscache.h" /*----------------------------------------------------------------------- diff --git a/src/backend/storage/large_object/inv_api.c b/src/backend/storage/large_object/inv_api.c index 38961ff34c1..6f60e902ca8 100644 --- a/src/backend/storage/large_object/inv_api.c +++ b/src/backend/storage/large_object/inv_api.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/large_object/inv_api.c,v 1.67 2000/04/12 17:15:37 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/large_object/inv_api.c,v 1.68 2000/05/28 17:56:03 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -31,6 +31,7 @@ #include "miscadmin.h" #include "storage/large_object.h" #include "storage/smgr.h" +#include "utils/fmgroids.h" #include "utils/relcache.h" /* diff --git a/src/backend/tcop/Makefile b/src/backend/tcop/Makefile index 2ee1faefcd1..aaeda91f44f 100644 --- a/src/backend/tcop/Makefile +++ b/src/backend/tcop/Makefile @@ -4,7 +4,7 @@ # Makefile for tcop # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/backend/tcop/Makefile,v 1.21 2000/01/19 02:58:56 petere Exp $ +# $Header: /cvsroot/pgsql/src/backend/tcop/Makefile,v 1.22 2000/05/28 17:56:04 tgl Exp $ # #------------------------------------------------------------------------- @@ -29,18 +29,12 @@ SUBSYS.o: $(OBJS) # dependencies (because they don't even exist until you make them), # they are hardcoded here. -utility.o: ../parse.h ../fmgr.h -aclchk.o: ../fmgr.h -fastpath.o: ../fmgr.h -postgres.o: ../fmgr.h +utility.o: ../parse.h ../parse.h: $(MAKE) -C .. parse.h -../fmgr.h: - $(MAKE) -C .. fmgr.h - -dep depend: ../parse.h ../fmgr.h +dep depend: ../parse.h $(CC) -MM $(CFLAGS) *.c >depend clean: diff --git a/src/backend/tcop/fastpath.c b/src/backend/tcop/fastpath.c index 1b38fe7ed08..60e1c7c4454 100644 --- a/src/backend/tcop/fastpath.c +++ b/src/backend/tcop/fastpath.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.38 2000/04/12 17:15:43 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.39 2000/05/28 17:56:04 tgl Exp $ * * NOTES * This cruft is the server side of PQfn. @@ -76,11 +76,9 @@ * ---------------- */ static void -SendFunctionResult(Oid fid, /* function id */ - char *retval,/* actual return value */ +SendFunctionResult(Datum retval, /* actual return value */ bool retbyval, - int retlen /* the length according to the catalogs */ -) + int retlen) /* the length according to the catalogs */ { StringInfoData buf; @@ -93,19 +91,21 @@ SendFunctionResult(Oid fid, /* function id */ if (retbyval) { /* by-value */ pq_sendint(&buf, retlen, 4); - pq_sendint(&buf, (int) (Datum) retval, retlen); + pq_sendint(&buf, DatumGetInt32(retval), retlen); } else { /* by-reference ... */ if (retlen < 0) { /* ... varlena */ - pq_sendint(&buf, VARSIZE(retval) - VARHDRSZ, VARHDRSZ); - pq_sendbytes(&buf, VARDATA(retval), VARSIZE(retval) - VARHDRSZ); + struct varlena *v = (struct varlena *) DatumGetPointer(retval); + + pq_sendint(&buf, VARSIZE(v) - VARHDRSZ, VARHDRSZ); + pq_sendbytes(&buf, VARDATA(v), VARSIZE(v) - VARHDRSZ); } else { /* ... fixed */ pq_sendint(&buf, retlen, 4); - pq_sendbytes(&buf, retval, retlen); + pq_sendbytes(&buf, DatumGetPointer(retval), retlen); } } } @@ -127,12 +127,12 @@ SendFunctionResult(Oid fid, /* function id */ struct fp_info { Oid funcid; - int nargs; + FmgrInfo flinfo; /* function lookup info for funcid */ bool argbyval[FUNC_MAX_ARGS]; int32 arglen[FUNC_MAX_ARGS]; /* signed (for varlena) */ bool retbyval; int32 retlen; /* signed (for varlena) */ - TransactionId xid; + TransactionId xid; /* when the lookup was done */ CommandId cid; }; @@ -147,17 +147,17 @@ static struct fp_info last_fp = {InvalidOid}; * valid_fp_info * * RETURNS: - * 1 if the state in 'fip' is valid - * 0 otherwise + * T if the state in 'fip' is valid for the given func OID + * F otherwise * - * "valid" means: + * "invalid" means: * The saved state was either uninitialized, for another function, * or from a previous command. (Commands can do updates, which * may invalidate catalog entries for subsequent commands. This * is overly pessimistic but since there is no smarter invalidation * scheme...). */ -static int +static bool valid_fp_info(Oid func_id, struct fp_info * fip) { Assert(OidIsValid(func_id)); @@ -212,11 +212,10 @@ update_fp_info(Oid func_id, struct fp_info * fip) func_id); } pp = (Form_pg_proc) GETSTRUCT(func_htp); - fip->nargs = pp->pronargs; rettype = pp->prorettype; argtypes = pp->proargtypes; - for (i = 0; i < fip->nargs; ++i) + for (i = 0; i < fip->flinfo.fn_nargs; ++i) { if (OidIsValid(argtypes[i])) { @@ -252,6 +251,8 @@ update_fp_info(Oid func_id, struct fp_info * fip) fip->xid = GetCurrentTransactionId(); fip->cid = GetCurrentCommandId(); + fmgr_info(func_id, &fip->flinfo); + /* * This must be last! */ @@ -279,11 +280,9 @@ HandleFunctionRequest() int argsize; int nargs; int tmp; - char *arg[FUNC_MAX_ARGS]; - char *retval; - bool isNull; + FunctionCallInfoData fcinfo; + Datum retval; int i; - uint32 palloced; char *p; struct fp_info *fip; @@ -305,89 +304,81 @@ HandleFunctionRequest() * XXX FIXME: elog() here means we lose sync with the frontend, since * we have not swallowed all of its input message. What should happen * is we absorb all of the input message per protocol syntax, and - * *then* do error checking and elog if appropriate. + * *then* do error checking (including lookup of the given function ID) + * and elog if appropriate. Unfortunately, because we cannot even read + * the message properly without knowing whether the data types are + * pass-by-ref or pass-by-value, it's not all that easy to fix :-(. + * This protocol is misdesigned. */ - if (fip->nargs != nargs) + if (fip->flinfo.fn_nargs != nargs || nargs > FUNC_MAX_ARGS) { elog(ERROR, "HandleFunctionRequest: actual arguments (%d) != registered arguments (%d)", - nargs, fip->nargs); + nargs, fip->flinfo.fn_nargs); } + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = &fip->flinfo; + fcinfo.nargs = nargs; + /* - * Copy arguments into arg vector. If we palloc() an argument, we - * need to remember, so that we pfree() it after the call. + * Copy supplied arguments into arg vector. Note there is no way for + * frontend to specify a NULL argument --- more misdesign. */ - palloced = 0x0; - for (i = 0; i < FUNC_MAX_ARGS; ++i) + for (i = 0; i < nargs; ++i) { - if (i >= nargs) - arg[i] = (char *) NULL; - else - { - if (pq_getint(&argsize, 4)) + if (pq_getint(&argsize, 4)) + return EOF; + if (fip->argbyval[i]) + { /* by-value */ + if (argsize < 1 || argsize > 4) + elog(ERROR, "HandleFunctionRequest: bogus argsize %d", + argsize); + /* XXX should we demand argsize == fip->arglen[i] ? */ + if (pq_getint(&tmp, argsize)) return EOF; - - Assert(argsize > 0); - if (fip->argbyval[i]) - { /* by-value */ - Assert(argsize <= 4); - if (pq_getint(&tmp, argsize)) + fcinfo.arg[i] = (Datum) tmp; + } + else + { /* by-reference ... */ + if (fip->arglen[i] < 0) + { /* ... varlena */ + if (argsize < 0) + elog(ERROR, "HandleFunctionRequest: bogus argsize %d", + argsize); + /* I suspect this +1 isn't really needed - tgl 5/2000 */ + p = palloc(argsize + VARHDRSZ + 1); /* Added +1 to solve + * memory leak - Peter + * 98 Jan 6 */ + VARSIZE(p) = argsize + VARHDRSZ; + if (pq_getbytes(VARDATA(p), argsize)) return EOF; - arg[i] = (char *) tmp; } else - { /* by-reference ... */ - if (fip->arglen[i] < 0) - { /* ... varlena */ - if (!(p = palloc(argsize + VARHDRSZ + 1))) /* Added +1 to solve - * memory leak - Peter - * 98 Jan 6 */ - elog(ERROR, "HandleFunctionRequest: palloc failed"); - VARSIZE(p) = argsize + VARHDRSZ; - if (pq_getbytes(VARDATA(p), argsize)) - return EOF; - } - else - { /* ... fixed */ - /* XXX cross our fingers and trust "argsize" */ - if (!(p = palloc(argsize + 1))) - elog(ERROR, "HandleFunctionRequest: palloc failed"); - if (pq_getbytes(p, argsize)) - return EOF; - } - palloced |= (1 << i); - arg[i] = p; + { /* ... fixed */ + if (argsize != fip->arglen[i]) + elog(ERROR, "HandleFunctionRequest: bogus argsize %d, should be %d", + argsize, fip->arglen[i]); + p = palloc(argsize + 1); /* +1 in case argsize is 0 */ + if (pq_getbytes(p, argsize)) + return EOF; } + fcinfo.arg[i] = PointerGetDatum(p); } } -#ifndef NO_FASTPATH - retval = fmgr_array_args(fid, nargs, arg, &isNull); -#else - retval = NULL; -#endif /* NO_FASTPATH */ - - /* free palloc'ed arguments */ - for (i = 0; i < nargs; ++i) - { - if (palloced & (1 << i)) - pfree(arg[i]); - } - - /* - * If this is an ordinary query (not a retrieve portal p ...), then we - * return the data to the user. If the return value was palloc'ed, - * then it must also be freed. - */ -#ifndef NO_FASTPATH - SendFunctionResult(fid, retval, fip->retbyval, fip->retlen); +#ifdef NO_FASTPATH + /* force a NULL return */ + retval = (Datum) 0; + fcinfo.isnull = true; #else - SendFunctionResult(fid, retval, fip->retbyval, 0); + retval = FunctionCallInvoke(&fcinfo); #endif /* NO_FASTPATH */ - if (!fip->retbyval) - pfree(retval); + if (fcinfo.isnull) + SendFunctionResult(retval, fip->retbyval, 0); + else + SendFunctionResult(retval, fip->retbyval, fip->retlen); return 0; } 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" |