From 5bb2300b59b74cdc7c8e3f0bf3c8d31c27657670 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Mon, 20 Nov 2000 20:36:57 +0000
Subject: [PATCH] Revise handling of oldstyle/newstyle functions per recent
 discussions in pghackers list.  Support for oldstyle internal functions is
 gone (no longer needed, since conversion is complete) and pg_language entry
 'internal' now implies newstyle call convention.  pg_language entry 'newC' is
 gone; both old and newstyle dynamically loaded C functions are now called
 language 'C'.  A newstyle function must be identified by an associated info
 routine.  See src/backend/utils/fmgr/README.

---
 contrib/fulltextindex/README.fti              |   2 +-
 contrib/fulltextindex/fti.c                   |   4 +-
 contrib/fulltextindex/fti.pl                  |   2 +-
 contrib/fulltextindex/fti.sql.in              |   2 +-
 contrib/lo/lo.c                               |   4 +-
 contrib/lo/lo.sql.in                          |   4 +-
 contrib/noupdate/noup.c                       |   2 +
 contrib/noupdate/noup.sql.in                  |   3 +-
 contrib/pgcrypto/pgcrypto.c                   |   6 +-
 contrib/pgcrypto/pgcrypto.sql.in              |   4 +-
 contrib/soundex/soundex.c                     |  11 +-
 contrib/soundex/soundex.sql.in                |   4 +-
 contrib/spi/autoinc.c                         |   2 +
 contrib/spi/autoinc.sql.in                    |   2 +-
 contrib/spi/insert_username.c                 |   2 +
 contrib/spi/insert_username.sql.in            |   2 +-
 contrib/spi/moddatetime.c                     |   2 +
 contrib/spi/moddatetime.sql.in                |   2 +-
 contrib/spi/refint.c                          |   4 +
 contrib/spi/refint.sql.in                     |   6 +-
 contrib/spi/timetravel.c                      |   4 +
 contrib/spi/timetravel.sql.in                 |   4 +-
 doc/src/sgml/ref/create_function.sgml         |   7 +-
 doc/src/sgml/ref/create_language.sgml         |  16 +-
 doc/src/sgml/trigger.sgml                     |   6 +-
 doc/src/sgml/xfunc.sgml                       |  98 +++---
 src/backend/catalog/pg_proc.c                 |  29 +-
 src/backend/commands/define.c                 |  21 +-
 src/backend/commands/remove.c                 |   5 +-
 src/backend/commands/trigger.c                |  11 +-
 src/backend/utils/Gen_fmgrtab.sh              |  21 +-
 src/backend/utils/cache/lsyscache.c           |  23 +-
 src/backend/utils/fmgr/dfmgr.c                |  70 +----
 src/backend/utils/fmgr/fmgr.c                 | 286 +++++++++++++-----
 src/bin/scripts/createlang.sh                 |   4 +-
 src/include/catalog/catversion.h              |   4 +-
 src/include/catalog/pg_language.h             |  16 +-
 src/include/fmgr.h                            |  46 ++-
 src/include/utils/fmgrtab.h                   |   4 +-
 src/include/utils/lsyscache.h                 |   5 +-
 src/pl/plperl/plperl.c                        |   3 +-
 src/pl/plpgsql/src/pl_handler.c               |   4 +-
 src/pl/tcl/pltcl.c                            |   9 +-
 .../regress/input/create_function_1.source    |  12 +-
 .../regress/input/create_function_2.source    |  13 +-
 src/test/regress/input/misc.source            |  13 +
 .../regress/output/create_function_1.source   |  12 +-
 .../regress/output/create_function_2.source   |  12 +-
 src/test/regress/output/misc.source           |  18 ++
 src/test/regress/regress.c                    |  38 ++-
 src/test/regress/sql/drop.sql                 |   1 +
 src/tutorial/funcs_new.c                      |  12 +
 52 files changed, 570 insertions(+), 327 deletions(-)

diff --git a/contrib/fulltextindex/README.fti b/contrib/fulltextindex/README.fti
index fdb6fcf3b10..10838db6912 100644
--- a/contrib/fulltextindex/README.fti
+++ b/contrib/fulltextindex/README.fti
@@ -57,7 +57,7 @@ sub-string will fit.
 The create the function that contains the trigger::
 
 	create function fti() returns opaque as
-	    '/path/to/fti.so' language 'newC';
+	    '/path/to/fti.so' language 'C';
 
 And finally define the trigger on the 'cds' table:
 
diff --git a/contrib/fulltextindex/fti.c b/contrib/fulltextindex/fti.c
index a98fcd47dc7..bb4636ff3e0 100644
--- a/contrib/fulltextindex/fti.c
+++ b/contrib/fulltextindex/fti.c
@@ -17,7 +17,7 @@
 	Example:
 
 create function fti() returns opaque as
-'/home/boekhold/src/postgresql-6.2/contrib/fti/fti.so' language 'newC';
+'/home/boekhold/src/postgresql-6.2/contrib/fti/fti.so' language 'C';
 
 create table title_fti (string varchar(25), id oid);
 create index title_fti_idx on title_fti (string);
@@ -93,6 +93,8 @@ static int	nDeletePlans = 0;
 static EPlan *find_plan(char *ident, EPlan ** eplan, int *nplans);
 
 /***********************************************************************/
+PG_FUNCTION_INFO_V1(fti);
+
 Datum
 fti(PG_FUNCTION_ARGS)
 {
diff --git a/contrib/fulltextindex/fti.pl b/contrib/fulltextindex/fti.pl
index 6b6d68e4900..02bf057e94a 100644
--- a/contrib/fulltextindex/fti.pl
+++ b/contrib/fulltextindex/fti.pl
@@ -29,7 +29,7 @@
 #
 #		create function fti() returns opaque as
 #			'/path/to/fti/file/fti.so'
-#		language 'newC';
+#		language 'C';
 #
 #		create trigger my_fti_trigger after update or insert or delete
 #			on mytable
diff --git a/contrib/fulltextindex/fti.sql.in b/contrib/fulltextindex/fti.sql.in
index c0b3662ae59..e0da2353c52 100644
--- a/contrib/fulltextindex/fti.sql.in
+++ b/contrib/fulltextindex/fti.sql.in
@@ -1,3 +1,3 @@
 create function fti() returns opaque as
 	'MODULE_PATHNAME'
-	language 'newC';
\ No newline at end of file
+	language 'C';
\ No newline at end of file
diff --git a/contrib/lo/lo.c b/contrib/lo/lo.c
index 386c2c2d2f7..5de00ad5ca4 100644
--- a/contrib/lo/lo.c
+++ b/contrib/lo/lo.c
@@ -1,7 +1,7 @@
 /*
  *	PostgreSQL type definitions for managed LargeObjects.
  *
- *	$Id: lo.c,v 1.4 2000/06/09 01:10:58 tgl Exp $
+ *	$Id: lo.c,v 1.5 2000/11/20 20:36:55 tgl Exp $
  *
  */
 
@@ -140,6 +140,8 @@ lo(Oid oid)
 /*
  * This handles the trigger that protects us from orphaned large objects
  */
+PG_FUNCTION_INFO_V1(lo_manage);
+
 Datum
 lo_manage(PG_FUNCTION_ARGS)
 {
diff --git a/contrib/lo/lo.sql.in b/contrib/lo/lo.sql.in
index 4aa75a60fe1..9b340b196f8 100644
--- a/contrib/lo/lo.sql.in
+++ b/contrib/lo/lo.sql.in
@@ -1,7 +1,7 @@
 --
 --	PostgreSQL code for LargeObjects
 --
---	$Id: lo.sql.in,v 1.4 2000/06/19 13:53:42 momjian Exp $
+--	$Id: lo.sql.in,v 1.5 2000/11/20 20:36:55 tgl Exp $
 --
 --
 --	Create the data type
@@ -44,7 +44,7 @@ create function lo(oid)
 create function lo_manage()
 	returns opaque
 	as 'MODULE_PATHNAME'
-	language 'newC';
+	language 'C';
 
 -- This allows us to map lo to oid
 --
diff --git a/contrib/noupdate/noup.c b/contrib/noupdate/noup.c
index 5035e127be8..af857c41f6e 100644
--- a/contrib/noupdate/noup.c
+++ b/contrib/noupdate/noup.c
@@ -16,6 +16,8 @@ extern Datum noup(PG_FUNCTION_ARGS);
  * EXECUTE PROCEDURE noup ('col').
  */
 
+PG_FUNCTION_INFO_V1(noup);
+
 Datum
 noup(PG_FUNCTION_ARGS)
 {
diff --git a/contrib/noupdate/noup.sql.in b/contrib/noupdate/noup.sql.in
index cc1e6fa146f..abf92837d1d 100644
--- a/contrib/noupdate/noup.sql.in
+++ b/contrib/noupdate/noup.sql.in
@@ -3,5 +3,4 @@ DROP FUNCTION noup ();
 CREATE FUNCTION noup ()
 	RETURNS opaque
 	AS 'MODULE_PATHNAME'
-	LANGUAGE 'newC'
-;
+	LANGUAGE 'C';
diff --git a/contrib/pgcrypto/pgcrypto.c b/contrib/pgcrypto/pgcrypto.c
index 4897edb9d25..e4978dea2da 100644
--- a/contrib/pgcrypto/pgcrypto.c
+++ b/contrib/pgcrypto/pgcrypto.c
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: pgcrypto.c,v 1.1 2000/10/31 13:11:28 petere Exp $
+ * $Id: pgcrypto.c,v 1.2 2000/11/20 20:36:56 tgl Exp $
  */
 
 #include <postgres.h>
@@ -59,6 +59,8 @@ find_digest(pg_digest *hbuf, text *name, int silent);
 
 
 /* SQL function: hash(text, text) returns text */
+PG_FUNCTION_INFO_V1(digest);
+
 Datum
 digest(PG_FUNCTION_ARGS)
 {
@@ -95,6 +97,8 @@ digest(PG_FUNCTION_ARGS)
 }
 
 /* check if given hash exists */
+PG_FUNCTION_INFO_V1(digest_exists);
+
 Datum
 digest_exists(PG_FUNCTION_ARGS)
 {
diff --git a/contrib/pgcrypto/pgcrypto.sql.in b/contrib/pgcrypto/pgcrypto.sql.in
index a30b3116e5e..2059c0d8e59 100644
--- a/contrib/pgcrypto/pgcrypto.sql.in
+++ b/contrib/pgcrypto/pgcrypto.sql.in
@@ -4,9 +4,9 @@
 
 CREATE FUNCTION digest(text, text) RETURNS text
   AS '@MODULE_FILENAME@',
-  'digest' LANGUAGE 'newC';
+  'digest' LANGUAGE 'C';
 
 CREATE FUNCTION digest_exists(text) RETURNS bool
   AS '@MODULE_FILENAME@',
-  'digest_exists' LANGUAGE 'newC';
+  'digest_exists' LANGUAGE 'C';
 
diff --git a/contrib/soundex/soundex.c b/contrib/soundex/soundex.c
index f2acba40366..f66cb21f242 100644
--- a/contrib/soundex/soundex.c
+++ b/contrib/soundex/soundex.c
@@ -1,4 +1,4 @@
-/* $Header: /cvsroot/pgsql/contrib/soundex/Attic/soundex.c,v 1.7 2000/10/04 19:25:34 petere Exp $ */
+/* $Header: /cvsroot/pgsql/contrib/soundex/Attic/soundex.c,v 1.8 2000/11/20 20:36:57 tgl Exp $ */
 #include "postgres.h"
 #include "fmgr.h"
 #include "utils/builtins.h"
@@ -7,11 +7,9 @@
 #include <stdio.h>
 
 
-Datum
-text_soundex(PG_FUNCTION_ARGS);
+Datum text_soundex(PG_FUNCTION_ARGS);
 
-static void
-soundex(const char *instr, char *outstr);
+static void soundex(const char *instr, char *outstr);
 
 #define SOUNDEX_LEN 4
 
@@ -24,6 +22,8 @@ soundex(const char *instr, char *outstr);
 /*
  * SQL function: text_soundex(text) returns text
  */
+PG_FUNCTION_INFO_V1(text_soundex);
+
 Datum
 text_soundex(PG_FUNCTION_ARGS)
 {
@@ -36,6 +36,7 @@ text_soundex(PG_FUNCTION_ARGS)
 
 	PG_RETURN_TEXT_P(_textin(outstr));
 }
+
 #endif /* not SOUNDEX_TEST */
 
 
diff --git a/contrib/soundex/soundex.sql.in b/contrib/soundex/soundex.sql.in
index 4cb0ad0e4db..4805694f9a6 100644
--- a/contrib/soundex/soundex.sql.in
+++ b/contrib/soundex/soundex.sql.in
@@ -1,5 +1,5 @@
 CREATE FUNCTION text_soundex(text) RETURNS text
-  AS '@MODULE_FILENAME@', 'text_soundex' LANGUAGE 'newC';
+  AS '@MODULE_FILENAME@', 'text_soundex' LANGUAGE 'C';
 
 CREATE FUNCTION soundex(text) RETURNS text
-  AS '@MODULE_FILENAME@', 'text_soundex' LANGUAGE 'newC';
+  AS '@MODULE_FILENAME@', 'text_soundex' LANGUAGE 'C';
diff --git a/contrib/spi/autoinc.c b/contrib/spi/autoinc.c
index f8b86217e73..8592ea7ed9b 100644
--- a/contrib/spi/autoinc.c
+++ b/contrib/spi/autoinc.c
@@ -5,6 +5,8 @@
 
 extern Datum autoinc(PG_FUNCTION_ARGS);
 
+PG_FUNCTION_INFO_V1(autoinc);
+
 Datum
 autoinc(PG_FUNCTION_ARGS)
 {
diff --git a/contrib/spi/autoinc.sql.in b/contrib/spi/autoinc.sql.in
index d587b567b37..36767429435 100644
--- a/contrib/spi/autoinc.sql.in
+++ b/contrib/spi/autoinc.sql.in
@@ -3,4 +3,4 @@ DROP FUNCTION autoinc();
 CREATE FUNCTION autoinc() 
 	RETURNS opaque 
 	AS 'MODULE_PATHNAME'
-	LANGUAGE 'newC';
+	LANGUAGE 'C';
diff --git a/contrib/spi/insert_username.c b/contrib/spi/insert_username.c
index 978a873ec90..6bc31444200 100644
--- a/contrib/spi/insert_username.c
+++ b/contrib/spi/insert_username.c
@@ -12,6 +12,8 @@
 
 extern Datum	insert_username(PG_FUNCTION_ARGS);
 
+PG_FUNCTION_INFO_V1(insert_username);
+
 Datum
 insert_username(PG_FUNCTION_ARGS)
 {
diff --git a/contrib/spi/insert_username.sql.in b/contrib/spi/insert_username.sql.in
index d60aebc1b0e..436fc88b73c 100644
--- a/contrib/spi/insert_username.sql.in
+++ b/contrib/spi/insert_username.sql.in
@@ -3,4 +3,4 @@ DROP FUNCTION insert_username();
 CREATE FUNCTION insert_username() 
 	RETURNS opaque 
 	AS 'MODULE_PATHNAME'
-	LANGUAGE 'newC';
+	LANGUAGE 'C';
diff --git a/contrib/spi/moddatetime.c b/contrib/spi/moddatetime.c
index 0229eb8f155..73b15185188 100644
--- a/contrib/spi/moddatetime.c
+++ b/contrib/spi/moddatetime.c
@@ -17,6 +17,8 @@ OH, me, I'm Terry Mackintosh <terry@terrym.com>
 
 extern Datum	moddatetime(PG_FUNCTION_ARGS);
 
+PG_FUNCTION_INFO_V1(moddatetime);
+
 Datum
 moddatetime(PG_FUNCTION_ARGS)
 {
diff --git a/contrib/spi/moddatetime.sql.in b/contrib/spi/moddatetime.sql.in
index cfb7c3c508b..d497900ecf1 100644
--- a/contrib/spi/moddatetime.sql.in
+++ b/contrib/spi/moddatetime.sql.in
@@ -3,4 +3,4 @@ DROP FUNCTION moddatetime();
 CREATE FUNCTION moddatetime() 
 	RETURNS opaque 
 	AS 'MODULE_PATHNAME'
-	LANGUAGE 'newC';
+	LANGUAGE 'C';
diff --git a/contrib/spi/refint.c b/contrib/spi/refint.c
index 4bbe761573b..d7a8d73c8e1 100644
--- a/contrib/spi/refint.c
+++ b/contrib/spi/refint.c
@@ -36,6 +36,8 @@ static EPlan *find_plan(char *ident, EPlan ** eplan, int *nplans);
  * check_primary_key ('Fkey1', 'Fkey2', 'Ptable', 'Pkey1', 'Pkey2').
  */
 
+PG_FUNCTION_INFO_V1(check_primary_key);
+
 Datum
 check_primary_key(PG_FUNCTION_ARGS)
 {
@@ -216,6 +218,8 @@ check_primary_key(PG_FUNCTION_ARGS)
  * 'Ftable1', 'Fkey11', 'Fkey12', 'Ftable2', 'Fkey21', 'Fkey22').
  */
 
+PG_FUNCTION_INFO_V1(check_foreign_key);
+
 Datum
 check_foreign_key(PG_FUNCTION_ARGS)
 {
diff --git a/contrib/spi/refint.sql.in b/contrib/spi/refint.sql.in
index 91448e8a2ed..d193319d9d4 100644
--- a/contrib/spi/refint.sql.in
+++ b/contrib/spi/refint.sql.in
@@ -4,11 +4,9 @@ DROP FUNCTION check_foreign_key ();
 CREATE FUNCTION check_primary_key ()
 	RETURNS opaque
 	AS 'MODULE_PATHNAME'
-	LANGUAGE 'newC'
-;
+	LANGUAGE 'C';
 
 CREATE FUNCTION check_foreign_key ()
 	RETURNS opaque
 	AS 'MODULE_PATHNAME'
-	LANGUAGE 'newC'
-;
+	LANGUAGE 'C';
diff --git a/contrib/spi/timetravel.c b/contrib/spi/timetravel.c
index cd50cd84890..41e7b092b32 100644
--- a/contrib/spi/timetravel.c
+++ b/contrib/spi/timetravel.c
@@ -47,6 +47,8 @@ static EPlan *find_plan(char *ident, EPlan ** eplan, int *nplans);
  * timetravel ('date_on', 'date_off').
  */
 
+PG_FUNCTION_INFO_V1(timetravel);
+
 Datum
 timetravel(PG_FUNCTION_ARGS)
 {
@@ -326,6 +328,8 @@ timetravel(PG_FUNCTION_ARGS)
  * set_timetravel (relname, on) --
  *					turn timetravel for specified relation ON/OFF
  */
+PG_FUNCTION_INFO_V1(set_timetravel);
+
 Datum
 set_timetravel(PG_FUNCTION_ARGS)
 {
diff --git a/contrib/spi/timetravel.sql.in b/contrib/spi/timetravel.sql.in
index 0de680cb39a..46912abf6d7 100644
--- a/contrib/spi/timetravel.sql.in
+++ b/contrib/spi/timetravel.sql.in
@@ -4,9 +4,9 @@ DROP FUNCTION set_timetravel(name, int4);
 CREATE FUNCTION timetravel() 
 	RETURNS opaque 
 	AS 'MODULE_PATHNAME'
-	LANGUAGE 'newC';
+	LANGUAGE 'C';
 
 CREATE FUNCTION set_timetravel(name, int4) 
 	RETURNS int4 
 	AS 'MODULE_PATHNAME'
-	LANGUAGE 'newC' WITH (isStrict);
+	LANGUAGE 'C' WITH (isStrict);
diff --git a/doc/src/sgml/ref/create_function.sgml b/doc/src/sgml/ref/create_function.sgml
index 20a7b6f8b03..bb733b8df2e 100644
--- a/doc/src/sgml/ref/create_function.sgml
+++ b/doc/src/sgml/ref/create_function.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_function.sgml,v 1.19 2000/11/02 19:26:44 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_function.sgml,v 1.20 2000/11/20 20:36:46 tgl Exp $
 Postgres documentation
 -->
 
@@ -119,8 +119,7 @@ CREATE FUNCTION <replaceable class="parameter">name</replaceable> ( [ <replaceab
       <listitem>
        <para>
 	May be '<literal>sql</literal>',
-	'<literal>C</literal>', '<literal>newC</literal>',
-	'<literal>internal</literal>', '<literal>newinternal</literal>',
+	'<literal>C</literal>', '<literal>internal</literal>',
 	or '<replaceable class="parameter">plname</replaceable>',
 	where '<replaceable class="parameter">plname</replaceable>'
 	is the name of a created procedural language. See
@@ -258,7 +257,7 @@ CREATE
    </para>
 
    <para>
-    Two <literal>internal</literal> or <literal>newinternal</literal>
+    Two <literal>internal</literal>
     functions cannot have the same C name without causing
     errors at link time.  To get around that, give them different C names
     (for example, use the argument types as part of the C names), then
diff --git a/doc/src/sgml/ref/create_language.sgml b/doc/src/sgml/ref/create_language.sgml
index 934b6cbaf9e..f5e1c6ffa90 100644
--- a/doc/src/sgml/ref/create_language.sgml
+++ b/doc/src/sgml/ref/create_language.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_language.sgml,v 1.13 2000/11/04 21:04:54 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_language.sgml,v 1.14 2000/11/20 20:36:46 tgl Exp $
 Postgres documentation
 -->
 
@@ -163,7 +163,8 @@ ERROR:  PL handler function <replaceable class="parameter">funcname</replaceable
     <note>
      <para>
       In <productname>Postgres</productname> 7.1 and later, call handlers
-      must adhere to the "new style" function manager interface.
+      must adhere to the "version 1" function manager interface, not the
+      old-style interface.
      </para>
     </note>
 
@@ -180,7 +181,7 @@ ERROR:  PL handler function <replaceable class="parameter">funcname</replaceable
    </para>
 
    <para>
-    The call handler is called in the same way as any other new-style
+    The call handler is called in the same way as any other
     function: it receives a pointer to a FunctionCallInfoData struct
     containing argument values and information about the called function,
     and it is expected to return a Datum result (and possibly set the
@@ -269,9 +270,7 @@ ERROR:  PL handler function <replaceable class="parameter">funcname</replaceable
    lanname   | lanispl | lanpltrusted | lanplcallfoid | lancompiler
 -------------+---------+--------------+---------------+-------------
  internal    | f       | f            |             0 | n/a
- newinternal | f       | f            |             0 | n/a
  C           | f       | f            |             0 | /bin/cc
- newC        | f       | f            |             0 | /bin/cc
  sql         | f       | f            |             0 | postgres
 </computeroutput>
 </programlisting>
@@ -279,8 +278,9 @@ ERROR:  PL handler function <replaceable class="parameter">funcname</replaceable
 
    <para>
     The call handler for a procedural language must normally be written
-    in C and registered as 'newinternal' or 'newC' language, depending
+    in C and registered as 'internal' or 'C' language, depending
     on whether it is linked into the backend or dynamically loaded.
+    The call handler cannot use the old-style 'C' function interface.
    </para>
 
    <para> 
@@ -306,6 +306,8 @@ ERROR:  PL handler function <replaceable class="parameter">funcname</replaceable
 #include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
 
+PG_FUNCTION_INFO_V1(plsample_call_handler);
+
 Datum
 plsample_call_handler(PG_FUNCTION_ARGS)
 {
@@ -344,7 +346,7 @@ plsample_call_handler(PG_FUNCTION_ARGS)
    <programlisting>
 CREATE FUNCTION plsample_call_handler () RETURNS opaque
     AS '/usr/local/pgsql/lib/plsample.so'
-    LANGUAGE 'newC';
+    LANGUAGE 'C';
 CREATE PROCEDURAL LANGUAGE 'plsample'
     HANDLER plsample_call_handler
     LANCOMPILER 'PL/Sample';
diff --git a/doc/src/sgml/trigger.sgml b/doc/src/sgml/trigger.sgml
index 0b3442517c9..d248887a599 100644
--- a/doc/src/sgml/trigger.sgml
+++ b/doc/src/sgml/trigger.sgml
@@ -22,7 +22,7 @@
    <para>
     The trigger function must be created before the trigger is created as a
     function taking no arguments and returning opaque.  If the function is
-    written in C, it must follow the "new style" function manager interface.
+    written in C, it must use the "version 1" function manager interface.
    </para>
 
    <para>
@@ -447,6 +447,8 @@ execution of Q) or after Q is done.
 
 extern Datum trigf(PG_FUNCTION_ARGS);
 
+PG_FUNCTION_INFO_V1(trigf);
+
 Datum
 trigf(PG_FUNCTION_ARGS)
 {
@@ -513,7 +515,7 @@ trigf(PG_FUNCTION_ARGS)
 
     <programlisting>
 create function trigf () returns opaque as 
-'...path_to_so' language 'newC';
+'...path_to_so' language 'C';
 
 create table ttest (x int4);
     </programlisting>
diff --git a/doc/src/sgml/xfunc.sgml b/doc/src/sgml/xfunc.sgml
index d02718d53a7..f2dc2981746 100644
--- a/doc/src/sgml/xfunc.sgml
+++ b/doc/src/sgml/xfunc.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v 1.22 2000/10/23 00:46:06 tgl Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/xfunc.sgml,v 1.23 2000/11/20 20:36:47 tgl Exp $
 -->
 
  <chapter id="xfunc">
@@ -339,9 +339,9 @@ SELECT clean_EMP();
    </para>
 
    <para>
-    There are two procedural languages available with the standard
-    <productname>Postgres</productname> distribution (PLTCL and PLSQL), and other
-    languages can be defined.
+    There are currently three procedural languages available in the standard
+    <productname>Postgres</productname> distribution (PLSQL, PLTCL and
+    PLPERL), and other languages can be defined.
     Refer to <xref linkend="xplang-title" endterm="xplang-title"> for
     more information.
    </para>
@@ -366,12 +366,7 @@ SELECT clean_EMP();
 
    <para>
     Internal functions are declared in <command>CREATE FUNCTION</command>
-    with language name <literal>internal</literal> or
-    <literal>newinternal</literal>, depending on whether they follow the
-    old (pre-7.1) or new (7.1 and later) function call conventions.
-    The details of the call conventions are the same as for
-    <literal>C</literal> and <literal>newC</literal> functions respectively;
-    see the next section for details.
+    with language name <literal>internal</literal>.
    </para>
   </sect1>
 
@@ -404,9 +399,9 @@ SELECT clean_EMP();
    <para>
     The string which specifies the object file (the first string in the AS
     clause) should be the <emphasis>full path</emphasis> of the object
-    code file for the function, bracketed by quotation marks.  If a
+    code file for the function, bracketed by single quote marks.  If a
     link symbol is given in the AS clause, the link symbol should also be
-    bracketed by single quotation marks, and should be exactly the
+    bracketed by single quote marks, and should be exactly the
     same as the name of the function in the C source code. On Unix systems
     the command <command>nm</command> will print all of the link
     symbols in a dynamically loadable object.
@@ -422,11 +417,11 @@ SELECT clean_EMP();
 
    <para>
     Two different calling conventions are currently used for C functions.
-    The "old style" (pre-<productname>Postgres</productname>-7.1) method
-    is selected by writing language name '<literal>C</literal>' in the
-    <command>CREATE FUNCTION</command> command, while the "new style"
-    (7.1 and later) method is selecting by writing language name
-    '<literal>newC</literal>'.  Old-style functions are now deprecated
+    The newer "version 1" calling convention is indicated by writing
+    a <literal>PG_FUNCTION_INFO_V1()</literal> macro call for the function,
+    as illustrated below.  Lack of such a macro indicates an old-style
+    ("version 0") function.  The language name specified in CREATE FUNCTION
+    is 'C' in either case.  Old-style functions are now deprecated
     because of portability problems and lack of functionality, but they
     are still supported for compatibility reasons.
    </para>
@@ -484,7 +479,7 @@ SELECT clean_EMP();
 	 <entry>include/postgres.h</entry>
 	</row>
 	<row>
-	 <entry>char</entry>
+	 <entry>"char"</entry>
 	 <entry>char</entry>
 	 <entry>N/A</entry>
 	</row>
@@ -583,16 +578,6 @@ SELECT clean_EMP();
 	 <entry>TimeInterval</entry>
 	 <entry>utils/nabstime.h</entry>
 	</row>
-	<row>
-	 <entry>uint2</entry>
-	 <entry>uint16</entry>
-	 <entry>include/c.h</entry>
-	</row>
-	<row>
-	 <entry>uint4</entry>
-	 <entry>uint32</entry>
-	 <entry>include/c.h</entry>
-	</row>
 	<row>
 	 <entry>xid</entry>
 	 <entry>(XID *)</entry>
@@ -694,7 +679,7 @@ typedef struct {
     </para>
 
     <para>
-     Obviously,  the  data  field is not long enough to hold
+     Obviously,  the  data  field shown here is not long enough to hold
      all possible strings; it's impossible to declare such
      a  structure  in  <acronym>C</acronym>.  When manipulating 
      variable-length types, we must  be  careful  to  allocate  
@@ -721,12 +706,12 @@ memmove(destination-&gt;data, buffer, 40);
    </sect2>
 
    <sect2>
-    <title>Old-style Calling Conventions for C-Language Functions</title>
+    <title>Version-0 Calling Conventions for C-Language Functions</title>
 
     <para>
      We present the "old style" calling convention first --- although
      this approach is now deprecated, it's easier to get a handle on
-     initially.  In the "old style" method, the arguments and result
+     initially.  In the version-0 method, the arguments and result
      of the C function are just declared in normal C style, but being
      careful to use the C representation of each SQL data type as shown
      above.
@@ -854,26 +839,39 @@ CREATE FUNCTION concat_text(text, text) RETURNS text
     </para>
 
     <para>
-     Although this old-style calling convention is simple to use,
+     Although this calling convention is simple to use,
      it is not very portable; on some architectures there are problems
      with passing smaller-than-int data types this way.  Also, there is
      no simple way to return a NULL result, nor to cope with NULL arguments
-     in any way other than making the function strict.  The new-style
+     in any way other than making the function strict.  The version-1
      convention, presented next, overcomes these objections.
     </para>
    </sect2>
 
    <sect2>
-    <title>New-style Calling Conventions for C-Language Functions</title>
+    <title>Version-1 Calling Conventions for C-Language Functions</title>
 
     <para>
-     The new-style calling convention relies on macros to suppress most
+     The version-1 calling convention relies on macros to suppress most
      of the complexity of passing arguments and results.  The C declaration
-     of a new-style function is always
+     of a version-1 function is always
      <programlisting>
                 Datum funcname(PG_FUNCTION_ARGS)
      </programlisting>
-     Each actual argument is fetched using a PG_GETARG_xxx() macro that
+     In addition, the macro call
+     <programlisting>
+                PG_FUNCTION_INFO_V1(funcname);
+     </programlisting>
+     must appear in the same source file (conventionally it's written
+     just before the function itself).  This macro call is not needed
+     for "internal"-language functions, since Postgres currently assumes
+     all internal functions are version-1.  However, it is
+     <emphasis>required</emphasis> for dynamically-loaded functions.
+    </para>
+
+    <para>
+     In a version-1 function,
+     each actual argument is fetched using a PG_GETARG_xxx() macro that
      corresponds to the argument's datatype, and the result is returned
      using a PG_RETURN_xxx() macro for the return type.
     </para>
@@ -887,6 +885,8 @@ CREATE FUNCTION concat_text(text, text) RETURNS text
 #include "fmgr.h"
 
 /* By Value */
+
+PG_FUNCTION_INFO_V1(add_one);
          
 Datum
 add_one(PG_FUNCTION_ARGS)
@@ -898,6 +898,8 @@ add_one(PG_FUNCTION_ARGS)
 
 /* By Reference, Fixed Length */
 
+PG_FUNCTION_INFO_V1(add_one_float8);
+
 Datum
 add_one_float8(PG_FUNCTION_ARGS)
 {
@@ -907,6 +909,8 @@ add_one_float8(PG_FUNCTION_ARGS)
     PG_RETURN_FLOAT8(arg + 1.0);
 }
 
+PG_FUNCTION_INFO_V1(makepoint);
+
 Datum
 makepoint(PG_FUNCTION_ARGS)
 {
@@ -922,6 +926,8 @@ makepoint(PG_FUNCTION_ARGS)
 
 /* By Reference, Variable Length */
 
+PG_FUNCTION_INFO_V1(copytext);
+
 Datum
 copytext(PG_FUNCTION_ARGS)
 {
@@ -940,6 +946,8 @@ copytext(PG_FUNCTION_ARGS)
     PG_RETURN_TEXT_P(new_t);
 }
 
+PG_FUNCTION_INFO_V1(concat_text);
+
 Datum
 concat_text(PG_FUNCTION_ARGS)
 {
@@ -959,12 +967,11 @@ concat_text(PG_FUNCTION_ARGS)
 
     <para>
      The <command>CREATE FUNCTION</command> commands are the same as
-     for the old-style equivalents, except that the language is specified
-     as '<literal>newC</literal>' not '<literal>C</literal>'.
+     for the old-style equivalents.
     </para>
 
     <para>
-     At first glance, the new-style coding conventions may appear to be
+     At first glance, the version-1 coding conventions may appear to be
      just pointless obscurantism.  However, they do offer a number of
      improvements, because the macros can hide unnecessary detail.
      An example is that in coding add_one_float8, we no longer need to
@@ -973,11 +980,14 @@ concat_text(PG_FUNCTION_ARGS)
      to deal with fetching "toasted" (compressed or out-of-line) values.
      The old-style copytext and concat_text functions shown above are
      actually wrong in the presence of toasted values, because they don't
-     call pg_detoast_datum() on their inputs.
+     call pg_detoast_datum() on their inputs.  (The handler for old-style
+     dynamically-loaded functions currently takes care of this detail,
+     but it does so less efficiently than is possible for a version-1
+     function.)
     </para>
 
     <para>
-     The new-style function call conventions also make it possible to
+     The version-1 function call conventions also make it possible to
      test for NULL inputs to a non-strict function, return a NULL result
      (from either strict or non-strict functions), return "set" results,
      and implement trigger functions and procedural-language call handlers.
@@ -1026,7 +1036,9 @@ c_overpaid(TupleTableSlot *t, /* the current instance of EMP */
     return salary &gt; limit;
 }
 
-/* In new-style coding, the above would look like this: */
+/* In version-1 coding, the above would look like this: */
+
+PG_FUNCTION_INFO_V1(c_overpaid);
 
 Datum
 c_overpaid(PG_FUNCTION_ARGS)
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 9d3ce5c50d6..5d63ebf1616 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.50 2000/11/16 22:30:17 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.51 2000/11/20 20:36:47 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -229,50 +229,35 @@ 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 (languageObjectId == INTERNALlanguageId ||
-		languageObjectId == NEWINTERNALlanguageId)
+	if (languageObjectId == INTERNALlanguageId)
 	{
-		Oid			actualLangID;
-
 		if (strlen(prosrc) == 0)
 			prosrc = procedureName;
-		actualLangID = fmgr_internal_language(prosrc);
-		if (actualLangID == InvalidOid)
+		if (fmgr_internal_function(prosrc) == InvalidOid)
 			elog(ERROR,
 				 "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.
+	 * symbol.  Also check for a valid function information record.
 	 *
 	 * 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 (languageObjectId == ClanguageId)
 	{
 		/* If link symbol is specified as "-", substitute procedure name */
 		if (strcmp(prosrc, "-") == 0)
 			prosrc = procedureName;
-		(void) load_external_function(probin, prosrc);
+		(void) load_external_function(probin, prosrc, true);
+		(void) fetch_finfo_record(probin, prosrc);
 	}
 
 	/*
diff --git a/src/backend/commands/define.c b/src/backend/commands/define.c
index 9d681a4a50f..63ccf32543f 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.48 2000/11/16 22:30:18 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.49 2000/11/20 20:36:47 tgl Exp $
  *
  * DESCRIPTION
  *	  The "DefineFoo" routines take the parse tree and pick out the
@@ -66,7 +66,7 @@ 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, or "newC", translate to that spelling.
+  translate to upper case.
 --------------------------------------------------------------------------*/
 	int			i;
 
@@ -77,8 +77,6 @@ case_translate_language_name(const char *input, char *output)
 
 	if (strcmp(output, "c") == 0)
 		output[0] = 'C';
-	else if (strcmp(output, "newc") == 0)
-		output[3] = 'C';
 }
 
 
@@ -183,8 +181,7 @@ interpret_AS_clause(const char *languageName, const List *as,
 {
 	Assert(as != NIL);
 
-	if (strcmp(languageName, "C") == 0 ||
-		strcmp(languageName, "newC") == 0)
+	if (strcmp(languageName, "C") == 0)
 	{
 
 		/*
@@ -230,8 +227,8 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest)
 
 	char		languageName[NAMEDATALEN];
 	/*
-	 * name of language of function, with case adjusted: "C", "newC",
-	 * "internal", "newinternal", "sql", etc.
+	 * name of language of function, with case adjusted: "C",
+	 * "internal", "sql", etc.
 	 */
 
 	bool		returnsSet;
@@ -255,9 +252,7 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest)
 	 * Apply appropriate security checks depending on language.
 	 */
 	if (strcmp(languageName, "C") == 0 ||
-		strcmp(languageName, "newC") == 0 ||
-		strcmp(languageName, "internal") == 0 ||
-		strcmp(languageName, "newinternal") == 0)
+		strcmp(languageName, "internal") == 0)
 	{
 		if (!superuser())
 			elog(ERROR,
@@ -283,8 +278,8 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest)
 		if (!HeapTupleIsValid(languageTuple))
 			elog(ERROR,
 				 "Unrecognized language specified in a CREATE FUNCTION: "
-				 "'%s'.\n\tRecognized languages are sql, C, newC, "
-				 "internal, newinternal, and created procedural languages.",
+				 "'%s'.\n\tRecognized languages are sql, C, "
+				 "internal, and created procedural languages.",
 				 languageName);
 
 		/* Check that this language is a PL */
diff --git a/src/backend/commands/remove.c b/src/backend/commands/remove.c
index fdcd0e7e744..cb11b47a37c 100644
--- a/src/backend/commands/remove.c
+++ b/src/backend/commands/remove.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.55 2000/11/16 22:30:18 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.56 2000/11/20 20:36:47 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -344,8 +344,7 @@ RemoveFunction(char *functionName,		/* function name to be removed */
 	if (!HeapTupleIsValid(tup))
 		func_error("RemoveFunction", functionName, nargs, argList, NULL);
 
-	if (((Form_pg_proc) GETSTRUCT(tup))->prolang == INTERNALlanguageId ||
-		((Form_pg_proc) GETSTRUCT(tup))->prolang == NEWINTERNALlanguageId)
+	if (((Form_pg_proc) GETSTRUCT(tup))->prolang == INTERNALlanguageId)
 	{
 		/* "Helpful" notice when removing a builtin function ... */
 		elog(NOTICE, "Removing built-in function \"%s\"", functionName);
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 22dfcac0524..cc31a0eb48b 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.80 2000/11/16 22:30:18 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.81 2000/11/20 20:36:47 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -169,10 +169,7 @@ CreateTrigger(CreateTrigStmt *stmt)
 	funclang = ((Form_pg_proc) GETSTRUCT(tuple))->prolang;
 	ReleaseSysCache(tuple);
 
-	if (funclang != ClanguageId &&
-		funclang != NEWClanguageId &&
-		funclang != INTERNALlanguageId &&
-		funclang != NEWINTERNALlanguageId)
+	if (funclang != ClanguageId && funclang != INTERNALlanguageId)
 	{
 		HeapTuple	langTup;
 
@@ -180,10 +177,10 @@ CreateTrigger(CreateTrigStmt *stmt)
 								 ObjectIdGetDatum(funclang),
 								 0, 0, 0);
 		if (!HeapTupleIsValid(langTup))
-			elog(ERROR, "CreateTrigger: cache lookup for PL %u failed",
+			elog(ERROR, "CreateTrigger: cache lookup for language %u failed",
 				 funclang);
 		if (((Form_pg_language) GETSTRUCT(langTup))->lanispl == false)
-			elog(ERROR, "CreateTrigger: only builtin, C and PL functions are supported");
+			elog(ERROR, "CreateTrigger: only internal, C and PL functions are supported");
 		ReleaseSysCache(langTup);
 	}
 
diff --git a/src/backend/utils/Gen_fmgrtab.sh b/src/backend/utils/Gen_fmgrtab.sh
index 41a0bc3d712..00f12e3e1f1 100644
--- a/src/backend/utils/Gen_fmgrtab.sh
+++ b/src/backend/utils/Gen_fmgrtab.sh
@@ -9,7 +9,7 @@
 #
 #
 # IDENTIFICATION
-#    $Header: /cvsroot/pgsql/src/backend/utils/Attic/Gen_fmgrtab.sh,v 1.17 2000/07/13 16:07:06 petere Exp $
+#    $Header: /cvsroot/pgsql/src/backend/utils/Attic/Gen_fmgrtab.sh,v 1.18 2000/11/20 20:36:48 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -82,7 +82,7 @@ trap 'echo "Caught signal." ; cleanup ; exit 1' 1 2 15
 
 #
 # Generate the file containing raw pg_proc tuple data
-# (but only for "internal" and "newinternal" language procedures...).
+# (but only for "internal" language procedures...).
 #
 # Unlike genbki.sh, which can run through cpp last, we have to
 # deal with preprocessor statements first (before we sort the
@@ -99,7 +99,6 @@ sed 	-e 's/^.*OID[^=]*=[^0-9]*//' \
 	-e 's/[ 	]*).*$//' | \
 $AWK '
 /^#/		{ print; next; }
-$4 == "11"	{ print; next; }
 $4 == "12"	{ print; next; }' > $CPPTMPFILE
 
 if [ $? -ne 0 ]; then
@@ -182,10 +181,6 @@ FuNkYfMgRsTuFf
 # Generate fmgr's built-in-function table.
 #
 # 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 > "$$-$TABLEFILE" <<FuNkYfMgRtAbStUfF
 /*-------------------------------------------------------------------------
@@ -205,10 +200,6 @@ cat > "$$-$TABLEFILE" <<FuNkYfMgRtAbStUfF
  *	It has been GENERATED by $CMDNAME
  *	from $INFILE
  *
- *	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.
- *
  *-------------------------------------------------------------------------
  */
 
@@ -237,13 +228,11 @@ FuNkYfMgRtAbStUfF
 # conditional expression instead.  Not all awks have conditional expressions.
 
 $AWK 'BEGIN {
-    Strict["t"] = "true"
-    Strict["f"] = "false"
-    OldStyle["11"] = "true"
-    OldStyle["12"] = "false"
+    Bool["t"] = "true"
+    Bool["f"] = "false"
 }
 { printf ("  { %d, \"%s\", %d, %s, %s, %s },\n"), \
-	$1, $(NF-1), $9, Strict[$8], OldStyle[$4], $(NF-1)
+	$1, $(NF-1), $9, Bool[$8], Bool[$10], $(NF-1)
 }' $RAWFILE >> "$$-$TABLEFILE"
 
 if [ $? -ne 0 ]; then
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index e07445837a5..24b2cbada95 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.47 2000/11/16 22:30:33 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.48 2000/11/20 20:36:49 tgl Exp $
  *
  * NOTES
  *	  Eventually, the index information should go through here, too.
@@ -731,6 +731,27 @@ get_typalign(Oid typid)
 
 #endif
 
+char
+get_typstorage(Oid typid)
+{
+	HeapTuple	tp;
+
+	tp = SearchSysCache(TYPEOID,
+						ObjectIdGetDatum(typid),
+						0, 0, 0);
+	if (HeapTupleIsValid(tp))
+	{
+		Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
+		char	result;
+
+		result = typtup->typstorage;
+		ReleaseSysCache(tp);
+		return result;
+	}
+	else
+		return 'p';
+}
+
 /*
  * get_typdefault
  *
diff --git a/src/backend/utils/fmgr/dfmgr.c b/src/backend/utils/fmgr/dfmgr.c
index 2dfddebd0a8..ae8eb6785e5 100644
--- a/src/backend/utils/fmgr/dfmgr.c
+++ b/src/backend/utils/fmgr/dfmgr.c
@@ -8,20 +8,17 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.45 2000/11/16 22:30:34 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.46 2000/11/20 20:36:49 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
+#include "postgres.h"
+
 #include <sys/types.h>
 #include <sys/stat.h>
 
-#include "postgres.h"
-
-#include "catalog/pg_proc.h"
 #include "dynloader.h"
 #include "utils/dynamic_loader.h"
-#include "utils/builtins.h"
-#include "utils/syscache.h"
 
 
 /*
@@ -46,55 +43,16 @@ static DynamicFileList *file_tail = (DynamicFileList *) NULL;
 #define SAME_INODE(A,B) ((A).st_ino == (B).inode && (A).st_dev == (B).device)
 
 
+/*
+ * Load the specified dynamic-link library file, and look for a function
+ * named funcname in it.  If the function is not found, we raise an error
+ * if signalNotFound is true, else return (PGFunction) NULL.  Note that
+ * errors in loading the library will provoke elog regardless of
+ * signalNotFound. 
+ */
 PGFunction
-fmgr_dynamic(Oid functionId)
-{
-	HeapTuple	procedureTuple;
-	Form_pg_proc procedureStruct;
-	char	   *proname,
-			   *prosrcstring,
-			   *probinstring;
-	Datum		prosrcattr,
-				probinattr;
-	PGFunction	user_fn;
-	bool		isnull;
-
-	procedureTuple = SearchSysCache(PROCOID,
-									ObjectIdGetDatum(functionId),
-									0, 0, 0);
-	if (!HeapTupleIsValid(procedureTuple))
-		elog(ERROR, "fmgr_dynamic: function %u: cache lookup failed",
-			 functionId);
-	procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);
-
-	proname = NameStr(procedureStruct->proname);
-
-	prosrcattr = SysCacheGetAttr(PROCOID, procedureTuple,
-								 Anum_pg_proc_prosrc, &isnull);
-	if (isnull)
-		elog(ERROR, "fmgr: Could not extract prosrc for %u from pg_proc",
-			 functionId);
-	prosrcstring = DatumGetCString(DirectFunctionCall1(textout, prosrcattr));
-
-	probinattr = SysCacheGetAttr(PROCOID, procedureTuple,
-								 Anum_pg_proc_probin, &isnull);
-	if (isnull)
-		elog(ERROR, "fmgr: Could not extract probin for %u from pg_proc",
-			 functionId);
-	probinstring = DatumGetCString(DirectFunctionCall1(textout, probinattr));
-
-	user_fn = load_external_function(probinstring, prosrcstring);
-
-	pfree(prosrcstring);
-	pfree(probinstring);
-
-	ReleaseSysCache(procedureTuple);
-
-	return user_fn;
-}
-
-PGFunction
-load_external_function(char *filename, char *funcname)
+load_external_function(char *filename, char *funcname,
+					   bool signalNotFound)
 {
 	DynamicFileList *file_scanner;
 	PGFunction	retval;
@@ -164,7 +122,7 @@ load_external_function(char *filename, char *funcname)
 
 	retval = pg_dlsym(file_scanner->handle, funcname);
 
-	if (retval == (PGFunction) NULL)
+	if (retval == (PGFunction) NULL && signalNotFound)
 		elog(ERROR, "Can't find function %s in file %s", funcname, filename);
 
 	return retval;
@@ -217,5 +175,5 @@ load_file(char *filename)
 		}
 	}
 
-	load_external_function(filename, (char *) NULL);
+	load_external_function(filename, (char *) NULL, false);
 }
diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c
index 5287615eea0..d4353a48246 100644
--- a/src/backend/utils/fmgr/fmgr.c
+++ b/src/backend/utils/fmgr/fmgr.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.47 2000/11/16 22:30:34 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.48 2000/11/20 20:36:49 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,6 +20,7 @@
 #include "executor/functions.h"
 #include "utils/builtins.h"
 #include "utils/fmgrtab.h"
+#include "utils/lsyscache.h"
 #include "utils/syscache.h"
 
 /*
@@ -42,7 +43,19 @@ typedef int32 ((*func_ptr) ());
 typedef char *((*func_ptr) ());
 #endif
 
+/*
+ * For an oldstyle function, fn_extra points to a record like this:
+ */
+typedef struct
+{
+	func_ptr	func;			/* Address of the oldstyle function */
+	bool		arg_toastable[FUNC_MAX_ARGS]; /* is n'th arg of a toastable
+											   * datatype? */
+} Oldstyle_fnextra;
 
+
+static void fmgr_info_C_lang(FmgrInfo *finfo, HeapTuple procedureTuple);
+static void fmgr_info_other_lang(FmgrInfo *finfo, HeapTuple procedureTuple);
 static Datum fmgr_oldstyle(PG_FUNCTION_ARGS);
 static Datum fmgr_untrusted(PG_FUNCTION_ARGS);
 
@@ -104,9 +117,6 @@ 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;
@@ -120,16 +130,8 @@ fmgr_info(Oid functionId, FmgrInfo *finfo)
 		 */
 		finfo->fn_nargs = fbp->nargs;
 		finfo->fn_strict = fbp->strict;
-		finfo->fn_retset = false; /* assume no builtins return sets! */
-		if (fbp->oldstyle)
-		{
-			finfo->fn_addr = fmgr_oldstyle;
-			finfo->fn_extra = (void *) fbp->func;
-		}
-		else
-		{
-			finfo->fn_addr = fbp->func;
-		}
+		finfo->fn_retset = fbp->retset;
+		finfo->fn_addr = fbp->func;
 		return;
 	}
 
@@ -148,16 +150,15 @@ fmgr_info(Oid functionId, FmgrInfo *finfo)
 
 	if (!procedureStruct->proistrusted)
 	{
+		/* This isn't really supported anymore... */
 		finfo->fn_addr = fmgr_untrusted;
 		ReleaseSysCache(procedureTuple);
 		return;
 	}
 
-	language = procedureStruct->prolang;
-	switch (language)
+	switch (procedureStruct->prolang)
 	{
 		case INTERNALlanguageId:
-		case NEWINTERNALlanguageId:
 			/*
 			 * For an ordinary builtin function, we should never get
 			 * here because the isbuiltin() search above will have
@@ -175,24 +176,12 @@ fmgr_info(Oid functionId, FmgrInfo *finfo)
 				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;
-			}
+			/* Should we check that nargs, strict, retset match the table? */
+			finfo->fn_addr = fbp->func;
 			break;
 
 		case ClanguageId:
-			finfo->fn_addr = fmgr_oldstyle;
-			finfo->fn_extra = (void *) fmgr_dynamic(functionId);
-			break;
-
-		case NEWClanguageId:
-			finfo->fn_addr = fmgr_dynamic(functionId);
+			fmgr_info_C_lang(finfo, procedureTuple);
 			break;
 
 		case SQLlanguageId:
@@ -200,92 +189,234 @@ fmgr_info(Oid functionId, FmgrInfo *finfo)
 			break;
 
 		default:
-			/*
-			 * Might be a created procedural language; try to look it up.
-			 */
-			languageTuple = SearchSysCache(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
+			fmgr_info_other_lang(finfo, procedureTuple);
+			break;
+	}
+
+	ReleaseSysCache(procedureTuple);
+}
+
+/*
+ * Special fmgr_info processing for C-language functions
+ */
+static void
+fmgr_info_C_lang(FmgrInfo *finfo, HeapTuple procedureTuple)
+{
+	Form_pg_proc procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);
+	Datum		prosrcattr,
+				probinattr;
+	char	   *prosrcstring,
+			   *probinstring;
+	PGFunction	user_fn;
+	Pg_finfo_record *inforec;
+	Oldstyle_fnextra *fnextra;
+	bool		isnull;
+	int			i;
+
+	/* Get prosrc and probin strings (link symbol and library filename) */
+	prosrcattr = SysCacheGetAttr(PROCOID, procedureTuple,
+								 Anum_pg_proc_prosrc, &isnull);
+	if (isnull)
+		elog(ERROR, "fmgr: Could not extract prosrc for %u from pg_proc",
+			 finfo->fn_oid);
+	prosrcstring = DatumGetCString(DirectFunctionCall1(textout, prosrcattr));
+
+	probinattr = SysCacheGetAttr(PROCOID, procedureTuple,
+								 Anum_pg_proc_probin, &isnull);
+	if (isnull)
+		elog(ERROR, "fmgr: Could not extract probin for %u from pg_proc",
+			 finfo->fn_oid);
+	probinstring = DatumGetCString(DirectFunctionCall1(textout, probinattr));
+
+	/* Look up the function itself */
+	user_fn = load_external_function(probinstring, prosrcstring, true);
+
+	/* Get the function information record (real or default) */
+	inforec = fetch_finfo_record(probinstring, prosrcstring);
+
+	switch (inforec->api_version)
+	{
+		case 0:
+			/* Old style: need to use a handler */
+			finfo->fn_addr = fmgr_oldstyle;
+			/* OK to use palloc here because fn_mcxt is CurrentMemoryContext */
+			fnextra = (Oldstyle_fnextra *) palloc(sizeof(Oldstyle_fnextra));
+			finfo->fn_extra = (void *) fnextra;
+			MemSet(fnextra, 0, sizeof(Oldstyle_fnextra));
+			fnextra->func = (func_ptr) user_fn;
+			for (i = 0; i < procedureStruct->pronargs; i++)
 			{
-				elog(ERROR, "fmgr_info: function %u: unsupported language %u",
-					 functionId, language);
+				fnextra->arg_toastable[i] =
+					TypeIsToastable(procedureStruct->proargtypes[i]);
 			}
-			ReleaseSysCache(languageTuple);
+			break;
+		case 1:
+			/* New style: call directly */
+			finfo->fn_addr = user_fn;
+			break;
+		default:
+			/* Shouldn't get here if fetch_finfo_record did its job */
+			elog(ERROR, "Unknown function API version %d",
+				 inforec->api_version);
 			break;
 	}
 
-	ReleaseSysCache(procedureTuple);
+	pfree(prosrcstring);
+	pfree(probinstring);
 }
 
+/*
+ * Special fmgr_info processing for other-language functions
+ */
+static void
+fmgr_info_other_lang(FmgrInfo *finfo, HeapTuple procedureTuple)
+{
+	Form_pg_proc procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);
+	Oid			language = procedureStruct->prolang;
+	HeapTuple	languageTuple;
+	Form_pg_language languageStruct;
+
+	languageTuple = SearchSysCache(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",
+			 finfo->fn_oid, language);
+	}
+	ReleaseSysCache(languageTuple);
+}
 
 /*
- * 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.
+ * Fetch and validate the information record for the given external function.
+ *
+ * If no info function exists for the given name, it is not an error.
+ * Instead we return a default info record for a version-0 function.
+ * We want to raise an error here only if the info function returns
+ * something bogus.
+ *
+ * This function is broken out of fmgr_info_C_lang() so that ProcedureCreate()
+ * can validate the information record for a function not yet entered into
+ * pg_proc.
+ */
+Pg_finfo_record *
+fetch_finfo_record(char *filename, char *funcname)
+{
+	char	   *infofuncname;
+	PGFInfoFunction infofunc;
+	Pg_finfo_record *inforec;
+	static Pg_finfo_record default_inforec = { 0 };
+
+	/* Compute name of info func */
+	infofuncname = (char *) palloc(strlen(funcname) + 10);
+	sprintf(infofuncname, "pg_finfo_%s", funcname);
+
+	/* Try to look up the info function */
+	infofunc = (PGFInfoFunction) load_external_function(filename,
+														infofuncname,
+														false);
+	if (infofunc == (PGFInfoFunction) NULL)
+	{
+		/* Not found --- assume version 0 */
+		pfree(infofuncname);
+		return &default_inforec;
+	}
+
+	/* Found, so call it */
+	inforec = (*infofunc)();
+
+	/* Validate result as best we can */
+	if (inforec == NULL)
+		elog(ERROR, "Null result from %s", infofuncname);
+	switch (inforec->api_version)
+	{
+		case 0:
+		case 1:
+			/* OK, no additional fields to validate */
+			break;
+		default:
+			elog(ERROR, "Unknown version %d reported by %s",
+				 inforec->api_version, infofuncname);
+			break;
+	}
+
+	pfree(infofuncname);
+	return inforec;
+}
+
+
+/*
+ * Specialized lookup routine for ProcedureCreate(): given the alleged name
+ * of an internal function, return the OID of the function.
+ * If the name is not recognized, return InvalidOid.
  */
 Oid
-fmgr_internal_language(const char *proname)
+fmgr_internal_function(const char *proname)
 {
 	const FmgrBuiltin *fbp = fmgr_lookupByName(proname);
 
 	if (fbp == NULL)
 		return InvalidOid;
-	return fbp->oldstyle ? INTERNALlanguageId : NEWINTERNALlanguageId;
+	return fbp->foid;
 }
 
 
 /*
- * 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...
+ * Handler for old-style "C" language functions
  */
 static Datum
 fmgr_oldstyle(PG_FUNCTION_ARGS)
 {
-	char	   *returnValue = NULL;
+	Oldstyle_fnextra *fnextra;
 	int			n_arguments = fcinfo->nargs;
 	int			i;
 	bool		isnull;
 	func_ptr	user_fn;
+	char	   *returnValue;
 
 	if (fcinfo->flinfo == NULL || fcinfo->flinfo->fn_extra == NULL)
-		elog(ERROR, "Internal error: fmgr_oldstyle received NULL function pointer");
+		elog(ERROR, "Internal error: fmgr_oldstyle received NULL pointer");
+	fnextra = (Oldstyle_fnextra *) fcinfo->flinfo->fn_extra;
 
 	/*
 	 * 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.
+	 *
+	 * We also need to detoast any TOAST-ed inputs, since it's unlikely that
+	 * an old-style function knows about TOASTing.
 	 */
 	isnull = false;
 	for (i = 0; i < n_arguments; i++)
-		isnull |= PG_ARGISNULL(i);
+	{
+		if (PG_ARGISNULL(i))
+			isnull = true;
+		else if (fnextra->arg_toastable[i])
+			fcinfo->arg[i] = PointerGetDatum(PG_DETOAST_DATUM(fcinfo->arg[i]));
+	}
 	fcinfo->isnull = isnull;
 
-	user_fn = (func_ptr) fcinfo->flinfo->fn_extra;
+	user_fn = fnextra->func;
 
 	switch (n_arguments)
 	{
@@ -411,6 +542,7 @@ fmgr_oldstyle(PG_FUNCTION_ARGS)
 			 */
 			elog(ERROR, "fmgr_oldstyle: function %u: too many arguments (%d > %d)",
 				 fcinfo->flinfo->fn_oid, n_arguments, 16);
+			returnValue = NULL;	/* keep compiler quiet */
 			break;
 	}
 
diff --git a/src/bin/scripts/createlang.sh b/src/bin/scripts/createlang.sh
index 3fc0a1b02fa..02c27aaf90b 100644
--- a/src/bin/scripts/createlang.sh
+++ b/src/bin/scripts/createlang.sh
@@ -8,7 +8,7 @@
 #
 #
 # IDENTIFICATION
-#    $Header: /cvsroot/pgsql/src/bin/scripts/Attic/createlang.sh,v 1.19 2000/11/13 23:37:53 momjian Exp $
+#    $Header: /cvsroot/pgsql/src/bin/scripts/Attic/createlang.sh,v 1.20 2000/11/20 20:36:50 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -259,7 +259,7 @@ fi
 # ----------
 # Create the call handler and the language
 # ----------
-$PSQL "CREATE FUNCTION $handler () RETURNS OPAQUE AS '$PGLIB/${object}$DLSUFFIX' LANGUAGE 'newC'"
+$PSQL "CREATE FUNCTION $handler () RETURNS OPAQUE AS '$PGLIB/${object}$DLSUFFIX' LANGUAGE 'C'"
 if [ $? -ne 0 ]; then
 	echo "$CMDNAME: language installation failed" 1>&2
 	exit 1
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index e3f4c6ff899..558feef575b 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: catversion.h,v 1.61 2000/11/20 05:18:40 vadim Exp $
+ * $Id: catversion.h,v 1.62 2000/11/20 20:36:50 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*                        	yyyymmddN */
-#define CATALOG_VERSION_NO	200011191
+#define CATALOG_VERSION_NO	200011201
 
 #endif
diff --git a/src/include/catalog/pg_language.h b/src/include/catalog/pg_language.h
index 0d597d8c4da..423f2e94700 100644
--- a/src/include/catalog/pg_language.h
+++ b/src/include/catalog/pg_language.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_language.h,v 1.11 2000/05/28 17:56:16 tgl Exp $
+ * $Id: pg_language.h,v 1.12 2000/11/20 20:36:50 tgl Exp $
  *
  * NOTES
  *	  the genbki.sh script reads this file and generates .bki
@@ -63,18 +63,12 @@ typedef FormData_pg_language *Form_pg_language;
  * ----------------
  */
 
-DATA(insert OID = 11 ( internal f f 0 "n/a" ));
-DESCR("old-style built-in functions");
-#define INTERNALlanguageId 11
-DATA(insert OID = 12 ( newinternal f f 0 "n/a" ));
-DESCR("new-style built-in functions");
-#define NEWINTERNALlanguageId 12
+DATA(insert OID = 12 ( internal f f 0 "n/a" ));
+DESCR("Built-in functions");
+#define INTERNALlanguageId 12
 DATA(insert OID = 13 ( "C" f f 0 "/bin/cc" ));
-DESCR("Dynamically-loaded old-style C functions");
+DESCR("Dynamically-loaded C functions");
 #define ClanguageId 13
-DATA(insert OID = 10 ( "newC" f f 0 "/bin/cc" ));
-DESCR("Dynamically-loaded new-style C functions");
-#define NEWClanguageId 10
 DATA(insert OID = 14 ( "sql" f f 0 "postgres"));
 DESCR("SQL-language functions");
 #define SQLlanguageId 14
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index 28634262bcc..08faf956299 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -11,7 +11,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: fmgr.h,v 1.10 2000/08/24 03:29:11 tgl Exp $
+ * $Id: fmgr.h,v 1.11 2000/11/20 20:36:50 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -208,6 +208,43 @@ extern struct varlena * pg_detoast_datum_copy(struct varlena * datum);
 #define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)
 
 
+/*-------------------------------------------------------------------------
+ *		Support for detecting call convention of dynamically-loaded functions
+ *
+ * Dynamically loaded functions may use either the version-1 ("new style")
+ * or version-0 ("old style") calling convention.  Version 1 is the call
+ * convention defined in this header file; version 0 is the old "plain C"
+ * convention.  A version-1 function must be accompanied by the macro call
+ *
+ *		PG_FUNCTION_INFO_V1(function_name);
+ *
+ * Note that internal functions do not need this decoration since they are
+ * assumed to be version-1.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+typedef struct
+{
+	int			api_version;	/* specifies call convention version number */
+	/* More fields may be added later, for version numbers > 1. */
+} Pg_finfo_record;
+
+/* Expected signature of an info function */
+typedef Pg_finfo_record * (*PGFInfoFunction) (void);
+
+/* Macro to build an info function associated with the given function name */
+
+#define PG_FUNCTION_INFO_V1(funcname) \
+extern Pg_finfo_record * CppConcat(pg_finfo_,funcname) (void); \
+Pg_finfo_record * \
+CppConcat(pg_finfo_,funcname) (void) \
+{ \
+	static Pg_finfo_record my_finfo = { 1 }; \
+	return &my_finfo; \
+}
+
+
 /*-------------------------------------------------------------------------
  *		Support routines and macros for callers of fmgr-compatible functions
  *-------------------------------------------------------------------------
@@ -297,13 +334,14 @@ extern Datum OidFunctionCall9(Oid functionId, Datum arg1, Datum arg2,
 /*
  * Routines in fmgr.c
  */
-extern Oid fmgr_internal_language(const char *proname);
+extern Pg_finfo_record *fetch_finfo_record(char *filename, char *funcname);
+extern Oid fmgr_internal_function(const char *proname);
 
 /*
  * Routines in dfmgr.c
  */
-extern PGFunction fmgr_dynamic(Oid functionId);
-extern PGFunction load_external_function(char *filename, char *funcname);
+extern PGFunction load_external_function(char *filename, char *funcname,
+										 bool signalNotFound);
 extern void load_file(char *filename);
 
 
diff --git a/src/include/utils/fmgrtab.h b/src/include/utils/fmgrtab.h
index e6cfe519650..9d46aeae694 100644
--- a/src/include/utils/fmgrtab.h
+++ b/src/include/utils/fmgrtab.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: fmgrtab.h,v 1.13 2000/05/28 17:56:20 tgl Exp $
+ * $Id: fmgrtab.h,v 1.14 2000/11/20 20:36:51 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -28,7 +28,7 @@ typedef struct
 	const char *funcName;		/* C name of the function */
     short       nargs;			/* 0..FUNC_MAX_ARGS, or -1 if variable count */
     bool        strict;			/* T if function is "strict" */
-	bool		oldstyle;		/* T if function uses old fmgr interface */
+	bool		retset;			/* T if function returns a set */
     PGFunction  func;			/* pointer to compiled function */
 } FmgrBuiltin;
 
diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h
index f8547baa884..903e09aaf9c 100644
--- a/src/include/utils/lsyscache.h
+++ b/src/include/utils/lsyscache.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: lsyscache.h,v 1.27 2000/11/16 22:30:49 tgl Exp $
+ * $Id: lsyscache.h,v 1.28 2000/11/20 20:36:51 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -39,6 +39,9 @@ extern char *get_rel_name(Oid relid);
 extern int16 get_typlen(Oid typid);
 extern bool get_typbyval(Oid typid);
 extern void get_typlenbyval(Oid typid, int16 *typlen, bool *typbyval);
+extern char get_typstorage(Oid typid);
 extern Datum get_typdefault(Oid typid);
 
+#define TypeIsToastable(typid)  (get_typstorage(typid) != 'p')
+
 #endif	 /* LSYSCACHE_H */
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 81a4cd75d4b..0b2d7d4e425 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -33,7 +33,7 @@
  *	  ENHANCEMENTS, OR MODIFICATIONS.
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/pl/plperl/plperl.c,v 1.15 2000/11/16 22:30:49 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/pl/plperl/plperl.c,v 1.16 2000/11/20 20:36:51 tgl Exp $
  *
  **********************************************************************/
 
@@ -258,6 +258,7 @@ plperl_init_safe_interp(void)
  *				  call this function for execution of
  *				  perl procedures.
  **********************************************************************/
+PG_FUNCTION_INFO_V1(plperl_call_handler);
 
 /* keep non-static */
 Datum
diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c
index 31788b07061..d9e208ee98b 100644
--- a/src/pl/plpgsql/src/pl_handler.c
+++ b/src/pl/plpgsql/src/pl_handler.c
@@ -3,7 +3,7 @@
  *			  procedural language
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_handler.c,v 1.5 2000/05/29 01:59:14 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_handler.c,v 1.6 2000/11/20 20:36:52 tgl Exp $
  *
  *	  This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -66,6 +66,8 @@ static PLpgSQL_function *compiled_functions = NULL;
  * call this function for execution of PL/pgSQL procedures.
  * ----------
  */
+PG_FUNCTION_INFO_V1(plpgsql_call_handler);
+
 Datum
 plpgsql_call_handler(PG_FUNCTION_ARGS)
 {
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index 8658cac3065..94a67ef0433 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -31,7 +31,7 @@
  *	  ENHANCEMENTS, OR MODIFICATIONS.
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/pl/tcl/pltcl.c,v 1.29 2000/11/16 22:30:52 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/pl/tcl/pltcl.c,v 1.30 2000/11/20 20:36:52 tgl Exp $
  *
  **********************************************************************/
 
@@ -325,6 +325,7 @@ pltcl_init_load_unknown(void)
  *				  call this function for execution of
  *				  PL/Tcl procedures.
  **********************************************************************/
+PG_FUNCTION_INFO_V1(pltcl_call_handler);
 
 /* keep non-static */
 Datum
@@ -371,6 +372,12 @@ pltcl_call_handler(PG_FUNCTION_ARGS)
 	return retval;
 }
 
+
+/*
+ * Alternate handler for unsafe functions
+ */
+PG_FUNCTION_INFO_V1(pltclu_call_handler);
+
 /* keep non-static */
 Datum
 pltclu_call_handler(PG_FUNCTION_ARGS)
diff --git a/src/test/regress/input/create_function_1.source b/src/test/regress/input/create_function_1.source
index 0f82a3bea40..6d91674cd56 100644
--- a/src/test/regress/input/create_function_1.source
+++ b/src/test/regress/input/create_function_1.source
@@ -15,30 +15,30 @@ CREATE FUNCTION widget_out(opaque)
 CREATE FUNCTION check_primary_key ()
 	RETURNS opaque
 	AS '@abs_builddir@/../../../contrib/spi/refint@DLSUFFIX@'
-	LANGUAGE 'newC';
+	LANGUAGE 'C';
 
 CREATE FUNCTION check_foreign_key ()
 	RETURNS opaque
 	AS '@abs_builddir@/../../../contrib/spi/refint@DLSUFFIX@'
-	LANGUAGE 'newC';
+	LANGUAGE 'C';
 
 CREATE FUNCTION autoinc ()
 	RETURNS opaque
 	AS '@abs_builddir@/../../../contrib/spi/autoinc@DLSUFFIX@'
-	LANGUAGE 'newC';
+	LANGUAGE 'C';
 
 CREATE FUNCTION funny_dup17 ()
         RETURNS opaque
         AS '@abs_builddir@/regress@DLSUFFIX@'
-        LANGUAGE 'newC';
+        LANGUAGE 'C';
 
 CREATE FUNCTION ttdummy ()
         RETURNS opaque
         AS '@abs_builddir@/regress@DLSUFFIX@'
-        LANGUAGE 'newC';
+        LANGUAGE 'C';
 
 CREATE FUNCTION set_ttdummy (int4)
         RETURNS int4
         AS '@abs_builddir@/regress@DLSUFFIX@'
-        LANGUAGE 'newC';
+        LANGUAGE 'C';
 
diff --git a/src/test/regress/input/create_function_2.source b/src/test/regress/input/create_function_2.source
index af6695764ac..b1c0eab1386 100644
--- a/src/test/regress/input/create_function_2.source
+++ b/src/test/regress/input/create_function_2.source
@@ -30,28 +30,33 @@ CREATE FUNCTION user_relns()
 CREATE FUNCTION pt_in_widget(point, widget)
    RETURNS bool
    AS '@abs_builddir@/regress@DLSUFFIX@'
-   LANGUAGE 'newC';
+   LANGUAGE 'C';
 
 CREATE FUNCTION overpaid(emp)
    RETURNS bool
    AS '@abs_builddir@/regress@DLSUFFIX@'
-   LANGUAGE 'newC';
+   LANGUAGE 'C';
 
 CREATE FUNCTION boxarea(box)
    RETURNS float8
    AS '@abs_builddir@/regress@DLSUFFIX@'
-   LANGUAGE 'newC';
+   LANGUAGE 'C';
 
 CREATE FUNCTION interpt_pp(path, path)
    RETURNS point
    AS '@abs_builddir@/regress@DLSUFFIX@'
-   LANGUAGE 'newC';
+   LANGUAGE 'C';
 
 CREATE FUNCTION reverse_name(name)
    RETURNS name
    AS '@abs_builddir@/regress@DLSUFFIX@'
    LANGUAGE 'c';
 
+CREATE FUNCTION oldstyle_length(int4, text)
+   RETURNS int4
+   AS '@abs_builddir@/regress@DLSUFFIX@'
+   LANGUAGE 'c';
+
 --
 -- Function dynamic loading
 --
diff --git a/src/test/regress/input/misc.source b/src/test/regress/input/misc.source
index 9e9ebdb75bc..dbb8df84709 100644
--- a/src/test/regress/input/misc.source
+++ b/src/test/regress/input/misc.source
@@ -215,6 +215,19 @@ SELECT user_relns() AS user_relns
 --SELECT name(equipment(hobby_construct(text 'skywalking', text 'mer'))) AS equip_name;
 
 
+--
+-- check that old-style C functions work properly with TOASTed values
+--
+create table oldstyle_test(i int4, t text);
+insert into oldstyle_test values(null,null);
+insert into oldstyle_test values(0,'12');
+insert into oldstyle_test values(1000,'12');
+insert into oldstyle_test values(0, repeat('x', 50000));
+
+select i, length(t), octet_length(t), oldstyle_length(i,t) from oldstyle_test;
+
+drop table oldstyle_test;
+
 --
 -- functional joins
 --
diff --git a/src/test/regress/output/create_function_1.source b/src/test/regress/output/create_function_1.source
index d3815a9aadd..d075a61eb8a 100644
--- a/src/test/regress/output/create_function_1.source
+++ b/src/test/regress/output/create_function_1.source
@@ -13,24 +13,24 @@ CREATE FUNCTION widget_out(opaque)
 CREATE FUNCTION check_primary_key ()
 	RETURNS opaque
 	AS '@abs_builddir@/../../../contrib/spi/refint@DLSUFFIX@'
-	LANGUAGE 'newC';
+	LANGUAGE 'C';
 CREATE FUNCTION check_foreign_key ()
 	RETURNS opaque
 	AS '@abs_builddir@/../../../contrib/spi/refint@DLSUFFIX@'
-	LANGUAGE 'newC';
+	LANGUAGE 'C';
 CREATE FUNCTION autoinc ()
 	RETURNS opaque
 	AS '@abs_builddir@/../../../contrib/spi/autoinc@DLSUFFIX@'
-	LANGUAGE 'newC';
+	LANGUAGE 'C';
 CREATE FUNCTION funny_dup17 ()
         RETURNS opaque
         AS '@abs_builddir@/regress@DLSUFFIX@'
-        LANGUAGE 'newC';
+        LANGUAGE 'C';
 CREATE FUNCTION ttdummy ()
         RETURNS opaque
         AS '@abs_builddir@/regress@DLSUFFIX@'
-        LANGUAGE 'newC';
+        LANGUAGE 'C';
 CREATE FUNCTION set_ttdummy (int4)
         RETURNS int4
         AS '@abs_builddir@/regress@DLSUFFIX@'
-        LANGUAGE 'newC';
+        LANGUAGE 'C';
diff --git a/src/test/regress/output/create_function_2.source b/src/test/regress/output/create_function_2.source
index def359de90f..a5f39a00bb0 100644
--- a/src/test/regress/output/create_function_2.source
+++ b/src/test/regress/output/create_function_2.source
@@ -23,23 +23,27 @@ CREATE FUNCTION user_relns()
 CREATE FUNCTION pt_in_widget(point, widget)
    RETURNS bool
    AS '@abs_builddir@/regress@DLSUFFIX@'
-   LANGUAGE 'newC';
+   LANGUAGE 'C';
 CREATE FUNCTION overpaid(emp)
    RETURNS bool
    AS '@abs_builddir@/regress@DLSUFFIX@'
-   LANGUAGE 'newC';
+   LANGUAGE 'C';
 CREATE FUNCTION boxarea(box)
    RETURNS float8
    AS '@abs_builddir@/regress@DLSUFFIX@'
-   LANGUAGE 'newC';
+   LANGUAGE 'C';
 CREATE FUNCTION interpt_pp(path, path)
    RETURNS point
    AS '@abs_builddir@/regress@DLSUFFIX@'
-   LANGUAGE 'newC';
+   LANGUAGE 'C';
 CREATE FUNCTION reverse_name(name)
    RETURNS name
    AS '@abs_builddir@/regress@DLSUFFIX@'
    LANGUAGE 'c';
+CREATE FUNCTION oldstyle_length(int4, text)
+   RETURNS int4
+   AS '@abs_builddir@/regress@DLSUFFIX@'
+   LANGUAGE 'c';
 --
 -- Function dynamic loading
 --
diff --git a/src/test/regress/output/misc.source b/src/test/regress/output/misc.source
index 144ad33f242..768dba5c3c7 100644
--- a/src/test/regress/output/misc.source
+++ b/src/test/regress/output/misc.source
@@ -657,6 +657,24 @@ SELECT user_relns() AS user_relns
 
 --SELECT name(equipment(hobby_construct(text 'skywalking', text 'mer'))) AS equip_name;
 --
+-- check that old-style C functions work properly with TOASTed values
+--
+create table oldstyle_test(i int4, t text);
+insert into oldstyle_test values(null,null);
+insert into oldstyle_test values(0,'12');
+insert into oldstyle_test values(1000,'12');
+insert into oldstyle_test values(0, repeat('x', 50000));
+select i, length(t), octet_length(t), oldstyle_length(i,t) from oldstyle_test;
+  i   | length | octet_length | oldstyle_length 
+------+--------+--------------+-----------------
+      |        |              |                
+    0 |      2 |            2 |               2
+ 1000 |      2 |            2 |            1002
+    0 |  50000 |          581 |           50000
+(4 rows)
+
+drop table oldstyle_test;
+--
 -- functional joins
 --
 --
diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c
index 479527fc3fc..bd65c4233da 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -1,5 +1,5 @@
 /*
- * $Header: /cvsroot/pgsql/src/test/regress/regress.c,v 1.44 2000/08/24 23:34:11 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/test/regress/regress.c,v 1.45 2000/11/20 20:36:53 tgl Exp $
  */
 
 #include <float.h>				/* faked on sunos */
@@ -25,10 +25,13 @@ extern void regress_lseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
 extern Datum overpaid(PG_FUNCTION_ARGS);
 extern Datum boxarea(PG_FUNCTION_ARGS);
 extern char *reverse_name(char *string);
+extern int oldstyle_length(int n, text *t);
 
 /*
 ** Distance from a point to a path
 */
+PG_FUNCTION_INFO_V1(regress_dist_ptpath);
+
 Datum
 regress_dist_ptpath(PG_FUNCTION_ARGS)
 {
@@ -69,6 +72,8 @@ regress_dist_ptpath(PG_FUNCTION_ARGS)
 
 /* this essentially does a cartesian product of the lsegs in the
    two paths, and finds the min distance between any two lsegs */
+PG_FUNCTION_INFO_V1(regress_path_dist);
+
 Datum
 regress_path_dist(PG_FUNCTION_ARGS)
 {
@@ -129,6 +134,8 @@ POLYGON    *poly;
 }
 
 /* return the point where two paths intersect, or NULL if no intersection. */
+PG_FUNCTION_INFO_V1(interpt_pp);
+
 Datum
 interpt_pp(PG_FUNCTION_ARGS)
 {
@@ -182,6 +189,8 @@ Point	   *pt2;
 	lseg->m = point_sl(pt1, pt2);
 }
 
+PG_FUNCTION_INFO_V1(overpaid);
+
 Datum
 overpaid(PG_FUNCTION_ARGS)
 {
@@ -254,6 +263,8 @@ WIDGET	   *widget;
 	return result;
 }
 
+PG_FUNCTION_INFO_V1(pt_in_widget);
+
 Datum
 pt_in_widget(PG_FUNCTION_ARGS)
 {
@@ -265,6 +276,8 @@ pt_in_widget(PG_FUNCTION_ARGS)
 
 #define ABS(X) ((X) >= 0 ? (X) : -(X))
 
+PG_FUNCTION_INFO_V1(boxarea);
+
 Datum
 boxarea(PG_FUNCTION_ARGS)
 {
@@ -278,8 +291,7 @@ boxarea(PG_FUNCTION_ARGS)
 }
 
 char *
-reverse_name(string)
-char	   *string;
+reverse_name(char *string)
 {
 	int			i;
 	int			len;
@@ -301,6 +313,20 @@ char	   *string;
 	return new_string;
 }
 
+/* This rather silly function is just to test that oldstyle functions
+ * work correctly on toast-able inputs.
+ */
+int
+oldstyle_length(int n, text *t)
+{
+	int		len = 0;
+
+	if (t)
+		len = VARSIZE(t) - VARHDRSZ;
+
+	return n + len;
+}
+
 #include "executor/spi.h"		/* this is what you need to work with SPI */
 #include "commands/trigger.h"	/* -"- and triggers */
 
@@ -312,6 +338,8 @@ static bool fd17b_recursion = true;
 static bool fd17a_recursion = true;
 extern Datum funny_dup17(PG_FUNCTION_ARGS);
 
+PG_FUNCTION_INFO_V1(funny_dup17);
+
 Datum
 funny_dup17(PG_FUNCTION_ARGS)
 {
@@ -428,6 +456,8 @@ extern Datum set_ttdummy(PG_FUNCTION_ARGS);
 static void *splan = NULL;
 static bool ttoff = false;
 
+PG_FUNCTION_INFO_V1(ttdummy);
+
 Datum
 ttdummy(PG_FUNCTION_ARGS)
 {
@@ -625,6 +655,8 @@ ttdummy(PG_FUNCTION_ARGS)
 	return PointerGetDatum(rettuple);
 }
 
+PG_FUNCTION_INFO_V1(set_ttdummy);
+
 Datum
 set_ttdummy(PG_FUNCTION_ARGS)
 {
diff --git a/src/test/regress/sql/drop.sql b/src/test/regress/sql/drop.sql
index 254c62100dc..fc89483208e 100644
--- a/src/test/regress/sql/drop.sql
+++ b/src/test/regress/sql/drop.sql
@@ -38,6 +38,7 @@ DROP FUNCTION interpt_pp(path,path);
 
 DROP FUNCTION reverse_name(name);
 
+DROP FUNCTION oldstyle_length(int4, text);
 
 --
 -- OPERATOR REMOVAL
diff --git a/src/tutorial/funcs_new.c b/src/tutorial/funcs_new.c
index 0734e67a113..20f609d5d2d 100644
--- a/src/tutorial/funcs_new.c
+++ b/src/tutorial/funcs_new.c
@@ -30,6 +30,8 @@ Datum   c_overpaid(PG_FUNCTION_ARGS);
 
 /* By Value */
          
+PG_FUNCTION_INFO_V1(add_one);
+
 Datum
 add_one(PG_FUNCTION_ARGS)
 {
@@ -40,6 +42,8 @@ add_one(PG_FUNCTION_ARGS)
 
 /* By Reference, Fixed Length */
 
+PG_FUNCTION_INFO_V1(add_one_float8);
+
 Datum
 add_one_float8(PG_FUNCTION_ARGS)
 {
@@ -49,6 +53,8 @@ add_one_float8(PG_FUNCTION_ARGS)
     PG_RETURN_FLOAT8(arg + 1.0);
 }
 
+PG_FUNCTION_INFO_V1(makepoint);
+
 Datum
 makepoint(PG_FUNCTION_ARGS)
 {
@@ -64,6 +70,8 @@ makepoint(PG_FUNCTION_ARGS)
 
 /* By Reference, Variable Length */
 
+PG_FUNCTION_INFO_V1(copytext);
+
 Datum
 copytext(PG_FUNCTION_ARGS)
 {
@@ -82,6 +90,8 @@ copytext(PG_FUNCTION_ARGS)
     PG_RETURN_TEXT_P(new_t);
 }
 
+PG_FUNCTION_INFO_V1(concat_text);
+
 Datum
 concat_text(PG_FUNCTION_ARGS)
 {
@@ -99,6 +109,8 @@ concat_text(PG_FUNCTION_ARGS)
 
 /* Composite types */
 
+PG_FUNCTION_INFO_V1(c_overpaid);
+
 Datum
 c_overpaid(PG_FUNCTION_ARGS)
 {
-- 
GitLab