Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/Makefile19
-rw-r--r--src/backend/access/common/Makefile9
-rw-r--r--src/backend/access/index/indexam.c47
-rw-r--r--src/backend/access/index/istrat.c3
-rw-r--r--src/backend/bootstrap/bootstrap.c3
-rw-r--r--src/backend/catalog/heap.c5
-rw-r--r--src/backend/catalog/index.c13
-rw-r--r--src/backend/catalog/indexing.c3
-rw-r--r--src/backend/catalog/pg_operator.c3
-rw-r--r--src/backend/catalog/pg_proc.c90
-rw-r--r--src/backend/catalog/pg_type.c12
-rw-r--r--src/backend/commands/async.c3
-rw-r--r--src/backend/commands/command.c20
-rw-r--r--src/backend/commands/comment.c5
-rw-r--r--src/backend/commands/copy.c4
-rw-r--r--src/backend/commands/dbcommands.c3
-rw-r--r--src/backend/commands/define.c83
-rw-r--r--src/backend/commands/indexcmds.c5
-rw-r--r--src/backend/commands/proclang.c3
-rw-r--r--src/backend/commands/trigger.c10
-rw-r--r--src/backend/commands/user.c3
-rw-r--r--src/backend/commands/vacuum.c3
-rw-r--r--src/backend/executor/execQual.c168
-rw-r--r--src/backend/executor/execUtils.c6
-rw-r--r--src/backend/executor/functions.c81
-rw-r--r--src/backend/executor/nodeAgg.c95
-rw-r--r--src/backend/libpq/Makefile7
-rw-r--r--src/backend/libpq/be-pqexec.c41
-rw-r--r--src/backend/nodes/freefuncs.c6
-rw-r--r--src/backend/optimizer/path/clausesel.c3
-rw-r--r--src/backend/optimizer/path/indxpath.c3
-rw-r--r--src/backend/optimizer/util/plancat.c6
-rw-r--r--src/backend/parser/analyze.c3
-rw-r--r--src/backend/parser/parse_func.c3
-rw-r--r--src/backend/parser/parse_node.c11
-rw-r--r--src/backend/parser/parse_oper.c3
-rw-r--r--src/backend/port/dynloader/alpha.h4
-rw-r--r--src/backend/port/dynloader/bsdi.h2
-rw-r--r--src/backend/port/dynloader/hpux.c8
-rw-r--r--src/backend/port/dynloader/hpux.h6
-rw-r--r--src/backend/port/dynloader/linux.h4
-rw-r--r--src/backend/port/dynloader/qnx4.c4
-rw-r--r--src/backend/port/dynloader/qnx4.h4
-rw-r--r--src/backend/rewrite/rewriteRemove.c3
-rw-r--r--src/backend/storage/large_object/inv_api.c3
-rw-r--r--src/backend/tcop/Makefile12
-rw-r--r--src/backend/tcop/fastpath.c159
-rw-r--r--src/backend/utils/Gen_fmgrtab.sh.in196
-rw-r--r--src/backend/utils/Makefile17
-rw-r--r--src/backend/utils/adt/int8.c11
-rw-r--r--src/backend/utils/adt/regproc.c3
-rw-r--r--src/backend/utils/adt/selfuncs.c10
-rw-r--r--src/backend/utils/adt/sets.c5
-rw-r--r--src/backend/utils/cache/catcache.c3
-rw-r--r--src/backend/utils/cache/fcache.c56
-rw-r--r--src/backend/utils/cache/relcache.c3
-rw-r--r--src/backend/utils/fmgr/dfmgr.c306
-rw-r--r--src/backend/utils/fmgr/fmgr.c1765
-rw-r--r--src/backend/utils/init/postinit.c3
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"