On 2016-12-08 13:34:41 -0800, Andres Freund wrote:
> Hi,
> 
> I'm wondering if it's not time for $subject:
> - V0 causes confusion / weird crashes when PG_FUNCTION_INFO_V1 was
>   forgotten
> - They have us keep weird hacks around just for the sake of testing V0
> - they actually cost performance, because we have to zero initialize Datums, 
> even if
>   the corresponding isnull marker is set.
> - they allow to call arbitrary functions pretty easily
> 
> I don't see any reason to keep them around. If seriously doubt anybody
> is using them seriously in anything but error.

Patches attached.
>From dc6de0b47e1013c165c1026df65bda62cba8d8b7 Mon Sep 17 00:00:00 2001
From: Andres Freund <and...@anarazel.de>
Date: Tue, 28 Feb 2017 23:14:58 -0800
Subject: [PATCH 1/2] Move contrib/seg to only use V1 calling conventions.

A later commit will remove V0 support.

Author: Andres Freund
Discussion: https://postgr.es/m/20161208213441.k3mbno4twhg2q...@alap3.anarazel.de
---
 contrib/seg/seg.c | 453 +++++++++++++++++++++++++++++-------------------------
 1 file changed, 244 insertions(+), 209 deletions(-)

diff --git a/contrib/seg/seg.c b/contrib/seg/seg.c
index 895d879498..ab6b017282 100644
--- a/contrib/seg/seg.c
+++ b/contrib/seg/seg.c
@@ -47,60 +47,53 @@ PG_FUNCTION_INFO_V1(seg_center);
 /*
 ** GiST support methods
 */
-bool gseg_consistent(GISTENTRY *entry,
-				SEG *query,
-				StrategyNumber strategy,
-				Oid subtype,
-				bool *recheck);
-GISTENTRY  *gseg_compress(GISTENTRY *entry);
-GISTENTRY  *gseg_decompress(GISTENTRY *entry);
-float	   *gseg_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result);
-GIST_SPLITVEC *gseg_picksplit(GistEntryVector *entryvec, GIST_SPLITVEC *v);
-bool		gseg_leaf_consistent(SEG *key, SEG *query, StrategyNumber strategy);
-bool		gseg_internal_consistent(SEG *key, SEG *query, StrategyNumber strategy);
-SEG		   *gseg_union(GistEntryVector *entryvec, int *sizep);
-SEG		   *gseg_binary_union(SEG *r1, SEG *r2, int *sizep);
-bool	   *gseg_same(SEG *b1, SEG *b2, bool *result);
+PG_FUNCTION_INFO_V1(gseg_consistent);
+PG_FUNCTION_INFO_V1(gseg_compress);
+PG_FUNCTION_INFO_V1(gseg_decompress);
+PG_FUNCTION_INFO_V1(gseg_picksplit);
+PG_FUNCTION_INFO_V1(gseg_penalty);
+PG_FUNCTION_INFO_V1(gseg_union);
+PG_FUNCTION_INFO_V1(gseg_same);
+static Datum gseg_leaf_consistent(Datum key, Datum query, StrategyNumber strategy);
+static Datum gseg_internal_consistent(Datum key, Datum query, StrategyNumber strategy);
+static Datum gseg_binary_union(Datum r1, Datum r2, int *sizep);
 
 
 /*
 ** R-tree support functions
 */
-bool		seg_same(SEG *a, SEG *b);
-bool		seg_contains_int(SEG *a, int *b);
-bool		seg_contains_float4(SEG *a, float4 *b);
-bool		seg_contains_float8(SEG *a, float8 *b);
-bool		seg_contains(SEG *a, SEG *b);
-bool		seg_contained(SEG *a, SEG *b);
-bool		seg_overlap(SEG *a, SEG *b);
-bool		seg_left(SEG *a, SEG *b);
-bool		seg_over_left(SEG *a, SEG *b);
-bool		seg_right(SEG *a, SEG *b);
-bool		seg_over_right(SEG *a, SEG *b);
-SEG		   *seg_union(SEG *a, SEG *b);
-SEG		   *seg_inter(SEG *a, SEG *b);
-void		rt_seg_size(SEG *a, float *sz);
+PG_FUNCTION_INFO_V1(seg_same);
+PG_FUNCTION_INFO_V1(seg_contains);
+PG_FUNCTION_INFO_V1(seg_contained);
+PG_FUNCTION_INFO_V1(seg_overlap);
+PG_FUNCTION_INFO_V1(seg_left);
+PG_FUNCTION_INFO_V1(seg_over_left);
+PG_FUNCTION_INFO_V1(seg_right);
+PG_FUNCTION_INFO_V1(seg_over_right);
+PG_FUNCTION_INFO_V1(seg_union);
+PG_FUNCTION_INFO_V1(seg_inter);
+static void rt_seg_size(SEG *a, float *size);
 
 /*
 ** Various operators
 */
-int32		seg_cmp(SEG *a, SEG *b);
-bool		seg_lt(SEG *a, SEG *b);
-bool		seg_le(SEG *a, SEG *b);
-bool		seg_gt(SEG *a, SEG *b);
-bool		seg_ge(SEG *a, SEG *b);
-bool		seg_different(SEG *a, SEG *b);
+PG_FUNCTION_INFO_V1(seg_cmp);
+PG_FUNCTION_INFO_V1(seg_lt);
+PG_FUNCTION_INFO_V1(seg_le);
+PG_FUNCTION_INFO_V1(seg_gt);
+PG_FUNCTION_INFO_V1(seg_ge);
+PG_FUNCTION_INFO_V1(seg_different);
 
 /*
 ** Auxiliary funxtions
 */
 static int	restore(char *s, float val, int n);
 
-
 /*****************************************************************************
  * Input/Output functions
  *****************************************************************************/
 
+
 Datum
 seg_in(PG_FUNCTION_ARGS)
 {
@@ -193,13 +186,17 @@ seg_upper(PG_FUNCTION_ARGS)
 ** the predicate x op query == FALSE, where op is the oper
 ** corresponding to strategy in the pg_amop table.
 */
-bool
-gseg_consistent(GISTENTRY *entry,
-				SEG *query,
-				StrategyNumber strategy,
-				Oid subtype,
-				bool *recheck)
+Datum
+gseg_consistent(PG_FUNCTION_ARGS)
 {
+	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+	Datum		query = PG_GETARG_DATUM(1);
+	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
+
+	/* Oid		subtype = PG_GETARG_OID(3); */
+	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
+
+
 	/* All cases served by this function are exact */
 	*recheck = false;
 
@@ -208,71 +205,74 @@ gseg_consistent(GISTENTRY *entry,
 	 * gseg_leaf_consistent
 	 */
 	if (GIST_LEAF(entry))
-		return (gseg_leaf_consistent((SEG *) DatumGetPointer(entry->key), query, strategy));
+		return gseg_leaf_consistent(entry->key, query, strategy);
 	else
-		return (gseg_internal_consistent((SEG *) DatumGetPointer(entry->key), query, strategy));
+		return gseg_internal_consistent(entry->key, query, strategy);
 }
 
 /*
 ** The GiST Union method for segments
 ** returns the minimal bounding seg that encloses all the entries in entryvec
 */
-SEG *
-gseg_union(GistEntryVector *entryvec, int *sizep)
+Datum
+gseg_union(PG_FUNCTION_ARGS)
 {
+	GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
+	int		   *sizep = (int *) PG_GETARG_POINTER(0);
 	int			numranges,
 				i;
-	SEG		   *out = (SEG *) NULL;
-	SEG		   *tmp;
+	Datum		out = 0;
+	Datum		tmp;
 
 #ifdef GIST_DEBUG
 	fprintf(stderr, "union\n");
 #endif
 
 	numranges = entryvec->n;
-	tmp = (SEG *) DatumGetPointer(entryvec->vector[0].key);
+	tmp = entryvec->vector[0].key;
 	*sizep = sizeof(SEG);
 
 	for (i = 1; i < numranges; i++)
 	{
-		out = gseg_binary_union(tmp, (SEG *)
-								DatumGetPointer(entryvec->vector[i].key),
-								sizep);
+		out = gseg_binary_union(tmp, entryvec->vector[i].key, sizep);
 		tmp = out;
 	}
 
-	return (out);
+	PG_RETURN_DATUM(out);
 }
 
 /*
 ** GiST Compress and Decompress methods for segments
 ** do not do anything.
 */
-GISTENTRY *
-gseg_compress(GISTENTRY *entry)
+Datum
+gseg_compress(PG_FUNCTION_ARGS)
 {
-	return (entry);
+	PG_RETURN_POINTER(PG_GETARG_POINTER(0));
 }
 
-GISTENTRY *
-gseg_decompress(GISTENTRY *entry)
+Datum
+gseg_decompress(PG_FUNCTION_ARGS)
 {
-	return (entry);
+	PG_RETURN_POINTER(PG_GETARG_POINTER(0));
 }
 
 /*
 ** The GiST Penalty method for segments
 ** As in the R-tree paper, we use change in area as our penalty metric
 */
-float *
-gseg_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result)
+Datum
+gseg_penalty(PG_FUNCTION_ARGS)
 {
+	GISTENTRY  *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
+	GISTENTRY  *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
+	float	   *result = (float *) PG_GETARG_POINTER(2);
 	SEG		   *ud;
 	float		tmp1,
 				tmp2;
 
-	ud = seg_union((SEG *) DatumGetPointer(origentry->key),
-				   (SEG *) DatumGetPointer(newentry->key));
+	ud = (SEG *) DatumGetPointer(
+			  DirectFunctionCall2(seg_union, origentry->key, newentry->key));
 	rt_seg_size(ud, &tmp1);
 	rt_seg_size((SEG *) DatumGetPointer(origentry->key), &tmp2);
 	*result = tmp1 - tmp2;
@@ -282,7 +282,7 @@ gseg_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result)
 	fprintf(stderr, "\t%g\n", *result);
 #endif
 
-	return (result);
+	PG_RETURN_POINTER(result);
 }
 
 /*
@@ -309,14 +309,15 @@ gseg_picksplit_item_cmp(const void *a, const void *b)
  * it's easier and more robust to just sort the segments by center-point and
  * split at the middle.
  */
-GIST_SPLITVEC *
-gseg_picksplit(GistEntryVector *entryvec,
-			   GIST_SPLITVEC *v)
+Datum
+gseg_picksplit(PG_FUNCTION_ARGS)
 {
+	GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
+	GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
 	int			i;
-	SEG		   *datum_l,
-			   *datum_r,
-			   *seg;
+	Datum		datum_l,
+				datum_r;
+	SEG		   *seg;
 	gseg_picksplit_item *sort_items;
 	OffsetNumber *left,
 			   *right;
@@ -359,13 +360,14 @@ gseg_picksplit(GistEntryVector *entryvec,
 	/*
 	 * Emit segments to the left output page, and compute its bounding box.
 	 */
-	datum_l = (SEG *) palloc(sizeof(SEG));
-	memcpy(datum_l, sort_items[0].data, sizeof(SEG));
+	datum_l = PointerGetDatum(palloc(sizeof(SEG)));
+	memcpy(DatumGetPointer(datum_l), sort_items[0].data, sizeof(SEG));
 	*left++ = sort_items[0].index;
 	v->spl_nleft++;
 	for (i = 1; i < firstright; i++)
 	{
-		datum_l = seg_union(datum_l, sort_items[i].data);
+		datum_l = DirectFunctionCall2(seg_union, datum_l,
+									  PointerGetDatum(sort_items[i].data));
 		*left++ = sort_items[i].index;
 		v->spl_nleft++;
 	}
@@ -373,13 +375,14 @@ gseg_picksplit(GistEntryVector *entryvec,
 	/*
 	 * Likewise for the right page.
 	 */
-	datum_r = (SEG *) palloc(sizeof(SEG));
-	memcpy(datum_r, sort_items[firstright].data, sizeof(SEG));
+	datum_r = PointerGetDatum(palloc(sizeof(SEG)));
+	memcpy(DatumGetPointer(datum_r), sort_items[firstright].data, sizeof(SEG));
 	*right++ = sort_items[firstright].index;
 	v->spl_nright++;
 	for (i = firstright + 1; i < maxoff; i++)
 	{
-		datum_r = seg_union(datum_r, sort_items[i].data);
+		datum_r = DirectFunctionCall2(seg_union, datum_r,
+									  PointerGetDatum(sort_items[i].data));
 		*right++ = sort_items[i].index;
 		v->spl_nright++;
 	}
@@ -387,16 +390,18 @@ gseg_picksplit(GistEntryVector *entryvec,
 	v->spl_ldatum = PointerGetDatum(datum_l);
 	v->spl_rdatum = PointerGetDatum(datum_r);
 
-	return v;
+	PG_RETURN_POINTER(v);
 }
 
 /*
 ** Equality methods
 */
-bool *
-gseg_same(SEG *b1, SEG *b2, bool *result)
+Datum
+gseg_same(PG_FUNCTION_ARGS)
 {
-	if (seg_same(b1, b2))
+	bool	   *result = (bool *) PG_GETARG_POINTER(2);
+
+	if (DirectFunctionCall2(seg_same, PG_GETARG_DATUM(0), PG_GETARG_DATUM(2)))
 		*result = TRUE;
 	else
 		*result = FALSE;
@@ -405,18 +410,16 @@ gseg_same(SEG *b1, SEG *b2, bool *result)
 	fprintf(stderr, "same: %s\n", (*result ? "TRUE" : "FALSE"));
 #endif
 
-	return (result);
+	PG_RETURN_POINTER(result);
 }
 
 /*
 ** SUPPORT ROUTINES
 */
-bool
-gseg_leaf_consistent(SEG *key,
-					 SEG *query,
-					 StrategyNumber strategy)
+Datum
+gseg_leaf_consistent(Datum key, Datum query, StrategyNumber strategy)
 {
-	bool		retval;
+	Datum		retval;
 
 #ifdef GIST_QUERY_DEBUG
 	fprintf(stderr, "leaf_consistent, %d\n", strategy);
@@ -425,41 +428,41 @@ gseg_leaf_consistent(SEG *key,
 	switch (strategy)
 	{
 		case RTLeftStrategyNumber:
-			retval = (bool) seg_left(key, query);
+			retval = DirectFunctionCall2(seg_left, key, query);
 			break;
 		case RTOverLeftStrategyNumber:
-			retval = (bool) seg_over_left(key, query);
+			retval = DirectFunctionCall2(seg_over_left, key, query);
 			break;
 		case RTOverlapStrategyNumber:
-			retval = (bool) seg_overlap(key, query);
+			retval = DirectFunctionCall2(seg_overlap, key, query);
 			break;
 		case RTOverRightStrategyNumber:
-			retval = (bool) seg_over_right(key, query);
+			retval = DirectFunctionCall2(seg_over_right, key, query);
 			break;
 		case RTRightStrategyNumber:
-			retval = (bool) seg_right(key, query);
+			retval = DirectFunctionCall2(seg_right, key, query);
 			break;
 		case RTSameStrategyNumber:
-			retval = (bool) seg_same(key, query);
+			retval = DirectFunctionCall2(seg_same, key, query);
 			break;
 		case RTContainsStrategyNumber:
 		case RTOldContainsStrategyNumber:
-			retval = (bool) seg_contains(key, query);
+			retval = DirectFunctionCall2(seg_contains, key, query);
+
 			break;
 		case RTContainedByStrategyNumber:
 		case RTOldContainedByStrategyNumber:
-			retval = (bool) seg_contained(key, query);
+			retval = DirectFunctionCall2(seg_contained, key, query);
 			break;
 		default:
 			retval = FALSE;
 	}
-	return (retval);
+
+	PG_RETURN_DATUM(retval);
 }
 
-bool
-gseg_internal_consistent(SEG *key,
-						 SEG *query,
-						 StrategyNumber strategy)
+static Datum
+gseg_internal_consistent(Datum key, Datum query, StrategyNumber strategy)
 {
 	bool		retval;
 
@@ -470,117 +473,147 @@ gseg_internal_consistent(SEG *key,
 	switch (strategy)
 	{
 		case RTLeftStrategyNumber:
-			retval = (bool) !seg_over_right(key, query);
+			retval =
+				!DatumGetBool(DirectFunctionCall2(seg_over_right, key, query));
 			break;
 		case RTOverLeftStrategyNumber:
-			retval = (bool) !seg_right(key, query);
+			retval =
+				!DatumGetBool(DirectFunctionCall2(seg_right, key, query));
 			break;
 		case RTOverlapStrategyNumber:
-			retval = (bool) seg_overlap(key, query);
+			retval =
+				!DatumGetBool(DirectFunctionCall2(seg_overlap, key, query));
 			break;
 		case RTOverRightStrategyNumber:
-			retval = (bool) !seg_left(key, query);
+			retval =
+				!DatumGetBool(DirectFunctionCall2(seg_left, key, query));
 			break;
 		case RTRightStrategyNumber:
-			retval = (bool) !seg_over_left(key, query);
+			retval =
+				!DatumGetBool(DirectFunctionCall2(seg_over_left, key, query));
 			break;
 		case RTSameStrategyNumber:
 		case RTContainsStrategyNumber:
 		case RTOldContainsStrategyNumber:
-			retval = (bool) seg_contains(key, query);
+			retval =
+				DatumGetBool(DirectFunctionCall2(seg_contains, key, query));
 			break;
 		case RTContainedByStrategyNumber:
 		case RTOldContainedByStrategyNumber:
-			retval = (bool) seg_overlap(key, query);
+			retval =
+				DatumGetBool(DirectFunctionCall2(seg_overlap, key, query));
 			break;
 		default:
 			retval = FALSE;
 	}
-	return (retval);
+
+	PG_RETURN_BOOL(retval);
 }
 
-SEG *
-gseg_binary_union(SEG *r1, SEG *r2, int *sizep)
+static Datum
+gseg_binary_union(Datum r1, Datum r2, int *sizep)
 {
-	SEG		   *retval;
+	Datum		retval;
 
-	retval = seg_union(r1, r2);
+	retval = DirectFunctionCall2(seg_union, r1, r2);
 	*sizep = sizeof(SEG);
 
 	return (retval);
 }
 
 
-bool
-seg_contains(SEG *a, SEG *b)
+Datum
+seg_contains(PG_FUNCTION_ARGS)
 {
-	return ((a->lower <= b->lower) && (a->upper >= b->upper));
+	SEG		   *a = (SEG *) PG_GETARG_POINTER(0);
+	SEG		   *b = (SEG *) PG_GETARG_POINTER(1);
+
+	PG_RETURN_BOOL((a->lower <= b->lower) && (a->upper >= b->upper));
 }
 
-bool
-seg_contained(SEG *a, SEG *b)
+Datum
+seg_contained(PG_FUNCTION_ARGS)
 {
-	return (seg_contains(b, a));
+	PG_RETURN_DATUM(
+					DirectFunctionCall2(seg_contains,
+										PG_GETARG_DATUM(1),
+										PG_GETARG_DATUM(0)));
 }
 
 /*****************************************************************************
  * Operator class for R-tree indexing
  *****************************************************************************/
 
-bool
-seg_same(SEG *a, SEG *b)
+Datum
+seg_same(PG_FUNCTION_ARGS)
 {
-	return seg_cmp(a, b) == 0;
+	Datum		cmp =
+	DirectFunctionCall2(seg_cmp, PG_GETARG_DATUM(0), PG_GETARG_DATUM(1));
+
+	PG_RETURN_BOOL(DatumGetInt32(cmp) == 0);
 }
 
 /*	seg_overlap -- does a overlap b?
  */
-bool
-seg_overlap(SEG *a, SEG *b)
+Datum
+seg_overlap(PG_FUNCTION_ARGS)
 {
-	return (
-			((a->upper >= b->upper) && (a->lower <= b->upper))
-			||
-			((b->upper >= a->upper) && (b->lower <= a->upper))
-		);
+	SEG		   *a = (SEG *) PG_GETARG_POINTER(0);
+	SEG		   *b = (SEG *) PG_GETARG_POINTER(1);
+
+	PG_RETURN_BOOL(((a->upper >= b->upper) && (a->lower <= b->upper)) ||
+				   ((b->upper >= a->upper) && (b->lower <= a->upper)));
 }
 
-/*	seg_overleft -- is the right edge of (a) located at or left of the right edge of (b)?
+/*	seg_over_left -- is the right edge of (a) located at or left of the right edge of (b)?
  */
-bool
-seg_over_left(SEG *a, SEG *b)
+Datum
+seg_over_left(PG_FUNCTION_ARGS)
 {
-	return (a->upper <= b->upper);
+	SEG		   *a = (SEG *) PG_GETARG_POINTER(0);
+	SEG		   *b = (SEG *) PG_GETARG_POINTER(1);
+
+	PG_RETURN_BOOL(a->upper <= b->upper);
 }
 
 /*	seg_left -- is (a) entirely on the left of (b)?
  */
-bool
-seg_left(SEG *a, SEG *b)
+Datum
+seg_left(PG_FUNCTION_ARGS)
 {
-	return (a->upper < b->lower);
+	SEG		   *a = (SEG *) PG_GETARG_POINTER(0);
+	SEG		   *b = (SEG *) PG_GETARG_POINTER(1);
+
+	PG_RETURN_BOOL(a->upper < b->lower);
 }
 
 /*	seg_right -- is (a) entirely on the right of (b)?
  */
-bool
-seg_right(SEG *a, SEG *b)
+Datum
+seg_right(PG_FUNCTION_ARGS)
 {
-	return (a->lower > b->upper);
+	SEG		   *a = (SEG *) PG_GETARG_POINTER(0);
+	SEG		   *b = (SEG *) PG_GETARG_POINTER(1);
+
+	PG_RETURN_BOOL(a->lower > b->upper);
 }
 
-/*	seg_overright -- is the left edge of (a) located at or right of the left edge of (b)?
+/*	seg_over_right -- is the left edge of (a) located at or right of the left edge of (b)?
  */
-bool
-seg_over_right(SEG *a, SEG *b)
+Datum
+seg_over_right(PG_FUNCTION_ARGS)
 {
-	return (a->lower >= b->lower);
+	SEG		   *a = (SEG *) PG_GETARG_POINTER(0);
+	SEG		   *b = (SEG *) PG_GETARG_POINTER(1);
+
+	PG_RETURN_BOOL(a->lower >= b->lower);
 }
 
-
-SEG *
-seg_union(SEG *a, SEG *b)
+Datum
+seg_union(PG_FUNCTION_ARGS)
 {
+	SEG		   *a = (SEG *) PG_GETARG_POINTER(0);
+	SEG		   *b = (SEG *) PG_GETARG_POINTER(1);
 	SEG		   *n;
 
 	n = (SEG *) palloc(sizeof(*n));
@@ -613,13 +646,14 @@ seg_union(SEG *a, SEG *b)
 		n->l_ext = b->l_ext;
 	}
 
-	return (n);
+	PG_RETURN_POINTER(n);
 }
 
-
-SEG *
-seg_inter(SEG *a, SEG *b)
+Datum
+seg_inter(PG_FUNCTION_ARGS)
 {
+	SEG		   *a = (SEG *) PG_GETARG_POINTER(0);
+	SEG		   *b = (SEG *) PG_GETARG_POINTER(1);
 	SEG		   *n;
 
 	n = (SEG *) palloc(sizeof(*n));
@@ -652,10 +686,10 @@ seg_inter(SEG *a, SEG *b)
 		n->l_ext = b->l_ext;
 	}
 
-	return (n);
+	PG_RETURN_POINTER(n);
 }
 
-void
+static void
 rt_seg_size(SEG *a, float *size)
 {
 	if (a == (SEG *) NULL || a->upper <= a->lower)
@@ -678,16 +712,19 @@ seg_size(PG_FUNCTION_ARGS)
 /*****************************************************************************
  *				   Miscellaneous operators
  *****************************************************************************/
-int32
-seg_cmp(SEG *a, SEG *b)
+Datum
+seg_cmp(PG_FUNCTION_ARGS)
 {
+	SEG		   *a = (SEG *) PG_GETARG_POINTER(0);
+	SEG		   *b = (SEG *) PG_GETARG_POINTER(1);
+
 	/*
 	 * First compare on lower boundary position
 	 */
 	if (a->lower < b->lower)
-		return -1;
+		PG_RETURN_INT32(-1);
 	if (a->lower > b->lower)
-		return 1;
+		PG_RETURN_INT32(1);
 
 	/*
 	 * a->lower == b->lower, so consider type of boundary.
@@ -699,27 +736,27 @@ seg_cmp(SEG *a, SEG *b)
 	if (a->l_ext != b->l_ext)
 	{
 		if (a->l_ext == '-')
-			return -1;
+			PG_RETURN_INT32(-1);
 		if (b->l_ext == '-')
-			return 1;
+			PG_RETURN_INT32(1);
 		if (a->l_ext == '<')
-			return -1;
+			PG_RETURN_INT32(-1);
 		if (b->l_ext == '<')
-			return 1;
+			PG_RETURN_INT32(1);
 		if (a->l_ext == '>')
-			return 1;
+			PG_RETURN_INT32(1);
 		if (b->l_ext == '>')
-			return -1;
+			PG_RETURN_INT32(-1);
 	}
 
 	/*
 	 * For other boundary types, consider # of significant digits first.
 	 */
 	if (a->l_sigd < b->l_sigd)	/* (a) is blurred and is likely to include (b) */
-		return -1;
+		PG_RETURN_INT32(-1);
 	if (a->l_sigd > b->l_sigd)	/* (a) is less blurred and is likely to be
 								 * included in (b) */
-		return 1;
+		PG_RETURN_INT32(1);
 
 	/*
 	 * For same # of digits, an approximate boundary is more blurred than
@@ -728,9 +765,9 @@ seg_cmp(SEG *a, SEG *b)
 	if (a->l_ext != b->l_ext)
 	{
 		if (a->l_ext == '~')	/* (a) is approximate, while (b) is exact */
-			return -1;
+			PG_RETURN_INT32(-1);
 		if (b->l_ext == '~')
-			return 1;
+			PG_RETURN_INT32(1);
 		/* can't get here unless data is corrupt */
 		elog(ERROR, "bogus lower boundary types %d %d",
 			 (int) a->l_ext, (int) b->l_ext);
@@ -742,9 +779,9 @@ seg_cmp(SEG *a, SEG *b)
 	 * First compare on upper boundary position
 	 */
 	if (a->upper < b->upper)
-		return -1;
+		PG_RETURN_INT32(-1);
 	if (a->upper > b->upper)
-		return 1;
+		PG_RETURN_INT32(1);
 
 	/*
 	 * a->upper == b->upper, so consider type of boundary.
@@ -756,17 +793,17 @@ seg_cmp(SEG *a, SEG *b)
 	if (a->u_ext != b->u_ext)
 	{
 		if (a->u_ext == '-')
-			return 1;
+			PG_RETURN_INT32(1);
 		if (b->u_ext == '-')
-			return -1;
+			PG_RETURN_INT32(-1);
 		if (a->u_ext == '<')
-			return -1;
+			PG_RETURN_INT32(-1);
 		if (b->u_ext == '<')
-			return 1;
+			PG_RETURN_INT32(1);
 		if (a->u_ext == '>')
-			return 1;
+			PG_RETURN_INT32(1);
 		if (b->u_ext == '>')
-			return -1;
+			PG_RETURN_INT32(-1);
 	}
 
 	/*
@@ -774,10 +811,10 @@ seg_cmp(SEG *a, SEG *b)
 	 * result here is converse of the lower-boundary case.
 	 */
 	if (a->u_sigd < b->u_sigd)	/* (a) is blurred and is likely to include (b) */
-		return 1;
+		PG_RETURN_INT32(1);
 	if (a->u_sigd > b->u_sigd)	/* (a) is less blurred and is likely to be
 								 * included in (b) */
-		return -1;
+		PG_RETURN_INT32(-1);
 
 	/*
 	 * For same # of digits, an approximate boundary is more blurred than
@@ -786,45 +823,61 @@ seg_cmp(SEG *a, SEG *b)
 	if (a->u_ext != b->u_ext)
 	{
 		if (a->u_ext == '~')	/* (a) is approximate, while (b) is exact */
-			return 1;
+			PG_RETURN_INT32(1);
 		if (b->u_ext == '~')
-			return -1;
+			PG_RETURN_INT32(-1);
 		/* can't get here unless data is corrupt */
 		elog(ERROR, "bogus upper boundary types %d %d",
 			 (int) a->u_ext, (int) b->u_ext);
 	}
 
-	return 0;
+	PG_RETURN_INT32(0);
 }
 
-bool
-seg_lt(SEG *a, SEG *b)
+Datum
+seg_lt(PG_FUNCTION_ARGS)
 {
-	return seg_cmp(a, b) < 0;
+	int			cmp = DatumGetInt32(
+	   DirectFunctionCall2(seg_cmp, PG_GETARG_DATUM(0), PG_GETARG_DATUM(1)));
+
+	PG_RETURN_BOOL(cmp < 0);
 }
 
-bool
-seg_le(SEG *a, SEG *b)
+Datum
+seg_le(PG_FUNCTION_ARGS)
 {
-	return seg_cmp(a, b) <= 0;
+	int			cmp = DatumGetInt32(
+	   DirectFunctionCall2(seg_cmp, PG_GETARG_DATUM(0), PG_GETARG_DATUM(1)));
+
+	PG_RETURN_BOOL(cmp <= 0);
 }
 
-bool
-seg_gt(SEG *a, SEG *b)
+Datum
+seg_gt(PG_FUNCTION_ARGS)
 {
-	return seg_cmp(a, b) > 0;
+	int			cmp = DatumGetInt32(
+	   DirectFunctionCall2(seg_cmp, PG_GETARG_DATUM(0), PG_GETARG_DATUM(1)));
+
+	PG_RETURN_BOOL(cmp > 0);
 }
 
-bool
-seg_ge(SEG *a, SEG *b)
+Datum
+seg_ge(PG_FUNCTION_ARGS)
 {
-	return seg_cmp(a, b) >= 0;
+	int			cmp = DatumGetInt32(
+	   DirectFunctionCall2(seg_cmp, PG_GETARG_DATUM(0), PG_GETARG_DATUM(1)));
+
+	PG_RETURN_BOOL(cmp >= 0);
 }
 
-bool
-seg_different(SEG *a, SEG *b)
+
+Datum
+seg_different(PG_FUNCTION_ARGS)
 {
-	return seg_cmp(a, b) != 0;
+	int			cmp = DatumGetInt32(
+	   DirectFunctionCall2(seg_cmp, PG_GETARG_DATUM(0), PG_GETARG_DATUM(1)));
+
+	PG_RETURN_BOOL(cmp != 0);
 }
 
 
@@ -985,24 +1038,6 @@ restore(char *result, float val, int n)
 ** Miscellany
 */
 
-bool
-seg_contains_int(SEG *a, int *b)
-{
-	return ((a->lower <= *b) && (a->upper >= *b));
-}
-
-bool
-seg_contains_float4(SEG *a, float4 *b)
-{
-	return ((a->lower <= *b) && (a->upper >= *b));
-}
-
-bool
-seg_contains_float8(SEG *a, float8 *b)
-{
-	return ((a->lower <= *b) && (a->upper >= *b));
-}
-
 /* find out the number of significant digits in a string representing
  * a floating point number
  */
-- 
2.11.0.22.g8d7a455.dirty

>From 6a61db32b4d52fee02157d6a93593a8cceab9fff Mon Sep 17 00:00:00 2001
From: Andres Freund <and...@anarazel.de>
Date: Tue, 28 Feb 2017 23:14:58 -0800
Subject: [PATCH 2/2] Remove support for version-0 calling conventions.

The V0 convention is failure prone because we've so far assumed that a
function is V0 if PG_FUNCTION_INFO_V1 is missing, leading to crashes
if a function was coded against the V1 interface.  V0 doesn't allow
proper NULL, SRF and toast handling.  V0 doesn't offer features that
V1 doesn't.

Thus remove V0 support.

Author: Andres Freund
Discussion: https://postgr.es/m/20161208213441.k3mbno4twhg2q...@alap3.anarazel.de
---
 contrib/earthdistance/earthdistance.c            |  22 --
 doc/src/sgml/xfunc.sgml                          | 288 +++++------------
 src/backend/utils/fmgr/fmgr.c                    | 377 +----------------------
 src/include/fmgr.h                               |   8 +-
 src/test/regress/input/create_function_2.source  |   5 -
 src/test/regress/input/misc.source               |  13 -
 src/test/regress/output/create_function_2.source |   4 -
 src/test/regress/output/misc.source              |  18 --
 src/test/regress/regress.c                       |  47 ++-
 9 files changed, 103 insertions(+), 679 deletions(-)

diff --git a/contrib/earthdistance/earthdistance.c b/contrib/earthdistance/earthdistance.c
index 861b166373..6ad6d87ce8 100644
--- a/contrib/earthdistance/earthdistance.c
+++ b/contrib/earthdistance/earthdistance.c
@@ -88,16 +88,8 @@ geo_distance_internal(Point *pt1, Point *pt2)
  *
  * returns: float8
  *	 distance between the points in miles on earth's surface
- *
- * If float8 is passed-by-value, the oldstyle version-0 calling convention
- * is unportable, so we use version-1.  However, if it's passed-by-reference,
- * continue to use oldstyle.  This is just because we'd like earthdistance
- * to serve as a canary for any unintentional breakage of version-0 functions
- * with float8 results.
  ******************************************************/
 
-#ifdef USE_FLOAT8_BYVAL
-
 PG_FUNCTION_INFO_V1(geo_distance);
 
 Datum
@@ -110,17 +102,3 @@ geo_distance(PG_FUNCTION_ARGS)
 	result = geo_distance_internal(pt1, pt2);
 	PG_RETURN_FLOAT8(result);
 }
-#else							/* !USE_FLOAT8_BYVAL */
-
-double	   *geo_distance(Point *pt1, Point *pt2);
-
-double *
-geo_distance(Point *pt1, Point *pt2)
-{
-	double	   *resultp = palloc(sizeof(double));
-
-	*resultp = geo_distance_internal(pt1, pt2);
-	return resultp;
-}
-
-#endif   /* USE_FLOAT8_BYVAL */
diff --git a/doc/src/sgml/xfunc.sgml b/doc/src/sgml/xfunc.sgml
index 255bfddad7..cd41b89136 100644
--- a/doc/src/sgml/xfunc.sgml
+++ b/doc/src/sgml/xfunc.sgml
@@ -675,7 +675,7 @@ CREATE FUNCTION mleast(VARIADIC arr numeric[]) RETURNS numeric AS $$
 $$ LANGUAGE SQL;
 
 SELECT mleast(10, -1, 5, 4.4);
- mleast 
+ mleast
 --------
      -1
 (1 row)
@@ -775,19 +775,19 @@ AS $$
 $$;
 
 SELECT foo(10, 20, 30);
- foo 
+ foo
 -----
   60
 (1 row)
 
 SELECT foo(10, 20);
- foo 
+ foo
 -----
   33
 (1 row)
 
 SELECT foo(10);
- foo 
+ foo
 -----
   15
 (1 row)
@@ -1209,13 +1209,13 @@ CREATE FUNCTION anyleast (VARIADIC anyarray) RETURNS anyelement AS $$
 $$ LANGUAGE SQL;
 
 SELECT anyleast(10, -1, 5, 4);
- anyleast 
+ anyleast
 ----------
        -1
 (1 row)
 
 SELECT anyleast('abc'::text, 'def');
- anyleast 
+ anyleast
 ----------
  abc
 (1 row)
@@ -1225,7 +1225,7 @@ CREATE FUNCTION concat_values(text, VARIADIC anyarray) RETURNS text AS $$
 $$ LANGUAGE SQL;
 
 SELECT concat_values('|', 1, 4, 2);
- concat_values 
+ concat_values
 ---------------
  1|4|2
 (1 row)
@@ -1610,14 +1610,11 @@ CREATE FUNCTION square_root(double precision) RETURNS double precision
    </para>
 
    <para>
-    Two different calling conventions are currently used for C functions.
-    The newer <quote>version 1</quote> 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
-    (<quote>version 0</quote>) function.  The language name specified in <command>CREATE FUNCTION</command>
-    is <literal>C</literal> 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.
+
+    Currently only one calling convention is used for C functions
+    (<quote>version 1</quote>). Support for that calling convention is
+    indicated by writing a <literal>PG_FUNCTION_INFO_V1()</literal> macro
+    call for the function, as illustrated below.
    </para>
 
   <sect2 id="xfunc-c-dynload">
@@ -1655,8 +1652,8 @@ CREATE FUNCTION square_root(double precision) RETURNS double precision
       <para>
        If the name starts with the string <literal>$libdir</literal>,
        that part is replaced by the <productname>PostgreSQL</> package
-        library directory
-       name, which is determined at build time.<indexterm><primary>$libdir</></>
+       library directory name, which is determined at build time.
+       <indexterm><primary>$libdir</></>
       </para>
      </listitem>
 
@@ -2138,160 +2135,6 @@ memcpy(destination->data, buffer, 40);
    </sect2>
 
    <sect2>
-    <title>Version 0 Calling Conventions</title>
-
-    <para>
-     We present the <quote>old style</quote> calling convention first &mdash; although
-     this approach is now deprecated, it's easier to get a handle on
-     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.
-    </para>
-
-    <para>
-     Here are some examples:
-
-<programlisting><![CDATA[
-#include "postgres.h"
-#include <string.h>
-#include "utils/geo_decls.h"
-
-#ifdef PG_MODULE_MAGIC
-PG_MODULE_MAGIC;
-#endif
-
-/* by value */
-
-int
-add_one(int arg)
-{
-    return arg + 1;
-}
-
-/* by reference, fixed length */
-
-float8 *
-add_one_float8(float8 *arg)
-{
-    float8    *result = (float8 *) palloc(sizeof(float8));
-
-    *result = *arg + 1.0;
-
-    return result;
-}
-
-Point *
-makepoint(Point *pointx, Point *pointy)
-{
-    Point     *new_point = (Point *) palloc(sizeof(Point));
-
-    new_point->x = pointx->x;
-    new_point->y = pointy->y;
-
-    return new_point;
-}
-
-/* by reference, variable length */
-
-text *
-copytext(text *t)
-{
-    /*
-     * VARSIZE is the total size of the struct in bytes.
-     */
-    text *new_t = (text *) palloc(VARSIZE(t));
-    SET_VARSIZE(new_t, VARSIZE(t));
-    /*
-     * VARDATA is a pointer to the data region of the struct.
-     */
-    memcpy((void *) VARDATA(new_t), /* destination */
-           (void *) VARDATA(t),     /* source */
-           VARSIZE(t) - VARHDRSZ);  /* how many bytes */
-    return new_t;
-}
-
-text *
-concat_text(text *arg1, text *arg2)
-{
-    int32 new_text_size = VARSIZE(arg1) + VARSIZE(arg2) - VARHDRSZ;
-    text *new_text = (text *) palloc(new_text_size);
-
-    SET_VARSIZE(new_text, new_text_size);
-    memcpy(VARDATA(new_text), VARDATA(arg1), VARSIZE(arg1) - VARHDRSZ);
-    memcpy(VARDATA(new_text) + (VARSIZE(arg1) - VARHDRSZ),
-           VARDATA(arg2), VARSIZE(arg2) - VARHDRSZ);
-    return new_text;
-}
-]]>
-</programlisting>
-    </para>
-
-    <para>
-     Supposing that the above code has been prepared in file
-     <filename>funcs.c</filename> and compiled into a shared object,
-     we could define the functions to <productname>PostgreSQL</productname>
-     with commands like this:
-
-<programlisting>
-CREATE FUNCTION add_one(integer) RETURNS integer
-     AS '<replaceable>DIRECTORY</replaceable>/funcs', 'add_one'
-     LANGUAGE C STRICT;
-
--- note overloading of SQL function name "add_one"
-CREATE FUNCTION add_one(double precision) RETURNS double precision
-     AS '<replaceable>DIRECTORY</replaceable>/funcs', 'add_one_float8'
-     LANGUAGE C STRICT;
-
-CREATE FUNCTION makepoint(point, point) RETURNS point
-     AS '<replaceable>DIRECTORY</replaceable>/funcs', 'makepoint'
-     LANGUAGE C STRICT;
-
-CREATE FUNCTION copytext(text) RETURNS text
-     AS '<replaceable>DIRECTORY</replaceable>/funcs', 'copytext'
-     LANGUAGE C STRICT;
-
-CREATE FUNCTION concat_text(text, text) RETURNS text
-     AS '<replaceable>DIRECTORY</replaceable>/funcs', 'concat_text'
-     LANGUAGE C STRICT;
-</programlisting>
-    </para>
-
-    <para>
-     Here, <replaceable>DIRECTORY</replaceable> stands for the
-     directory of the shared library file (for instance the
-     <productname>PostgreSQL</productname> tutorial directory, which
-     contains the code for the examples used in this section).
-     (Better style would be to use just <literal>'funcs'</> in the
-     <literal>AS</> clause, after having added
-     <replaceable>DIRECTORY</replaceable> to the search path.  In any
-     case, we can omit the system-specific extension for a shared
-     library, commonly <literal>.so</literal> or
-     <literal>.sl</literal>.)
-    </para>
-
-    <para>
-     Notice that we have specified the functions as <quote>strict</quote>,
-     meaning that
-     the system should automatically assume a null result if any input
-     value is null.  By doing this, we avoid having to check for null inputs
-     in the function code.  Without this, we'd have to check for null values
-     explicitly, by checking for a null pointer for each
-     pass-by-reference argument.  (For pass-by-value arguments, we don't
-     even have a way to check!)
-    </para>
-
-    <para>
-     Although this calling convention is simple to use,
-     it is not very portable; on some architectures there are problems
-     with passing data types that are smaller than <type>int</type> 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 version-1
-     convention, presented next, overcomes these objections.
-    </para>
-   </sect2>
-
-   <sect2>
     <title>Version 1 Calling Conventions</title>
 
     <para>
@@ -2316,8 +2159,10 @@ PG_FUNCTION_INFO_V1(funcname);
     <para>
      In a version-1 function, each actual argument is fetched using a
      <function>PG_GETARG_<replaceable>xxx</replaceable>()</function>
-     macro that corresponds to the argument's data type, and the
-     result is returned using a
+     macro that corresponds to the argument's data type.  In non-strict
+     functions there needs to be a previous check about argument null-ness
+     using <function>PG_ARGNULL_<replaceable>xxx</replaceable>()</function>.
+     The result is returned using a
      <function>PG_RETURN_<replaceable>xxx</replaceable>()</function>
      macro for the return type.
      <function>PG_GETARG_<replaceable>xxx</replaceable>()</function>
@@ -2328,7 +2173,7 @@ PG_FUNCTION_INFO_V1(funcname);
     </para>
 
     <para>
-     Here we show the same functions as above, coded in version-1 style:
+     Here are some examples using the version-1 calling convention:
 
 <programlisting><![CDATA[
 #include "postgres.h"
@@ -2421,27 +2266,67 @@ concat_text(PG_FUNCTION_ARGS)
 }
 ]]>
 </programlisting>
+
+    <para>
+     Supposing that the above code has been prepared in file
+     <filename>funcs.c</filename> and compiled into a shared object,
+     we could define the functions to <productname>PostgreSQL</productname>
+     with commands like this:
+
+<programlisting>
+CREATE FUNCTION add_one(integer) RETURNS integer
+     AS '<replaceable>DIRECTORY</replaceable>/funcs', 'add_one'
+     LANGUAGE C STRICT;
+
+-- note overloading of SQL function name "add_one"
+CREATE FUNCTION add_one(double precision) RETURNS double precision
+     AS '<replaceable>DIRECTORY</replaceable>/funcs', 'add_one_float8'
+     LANGUAGE C STRICT;
+
+CREATE FUNCTION makepoint(point, point) RETURNS point
+     AS '<replaceable>DIRECTORY</replaceable>/funcs', 'makepoint'
+     LANGUAGE C STRICT;
+
+CREATE FUNCTION copytext(text) RETURNS text
+     AS '<replaceable>DIRECTORY</replaceable>/funcs', 'copytext'
+     LANGUAGE C STRICT;
+
+CREATE FUNCTION concat_text(text, text) RETURNS text
+     AS '<replaceable>DIRECTORY</replaceable>/funcs', 'concat_text'
+     LANGUAGE C STRICT;
+</programlisting>
+
+    <para>
+     Here, <replaceable>DIRECTORY</replaceable> stands for the
+     directory of the shared library file (for instance the
+     <productname>PostgreSQL</productname> tutorial directory, which
+     contains the code for the examples used in this section).
+     (Better style would be to use just <literal>'funcs'</> in the
+     <literal>AS</> clause, after having added
+     <replaceable>DIRECTORY</replaceable> to the search path.  In any
+     case, we can omit the system-specific extension for a shared
+     library, commonly <literal>.so</literal>.)
     </para>
 
     <para>
-     The <command>CREATE FUNCTION</command> commands are the same as
-     for the version-0 equivalents.
+     Notice that we have specified the functions as <quote>strict</quote>,
+     meaning that
+     the system should automatically assume a null result if any input
+     value is null.  By doing this, we avoid having to check for null inputs
+     in the function code.  Without this, we'd have to check for null values
+     explicitly, using PG_ARGISNULL().
     </para>
 
     <para>
-     At first glance, the version-1 coding conventions might appear to
-     be just pointless obscurantism.  They do, however, offer a number
-     of improvements, because the macros can hide unnecessary detail.
-     An example is that in coding <function>add_one_float8</>, we no longer need to
-     be aware that <type>float8</type> is a pass-by-reference type.  Another
-     example is that the <literal>GETARG</> macros for variable-length types allow
-     for more efficient fetching of <quote>toasted</quote> (compressed or
+     At first glance, the version-1 coding conventions might appear to be just
+     pointless obscurantism, over using plain <literal>C</> calling
+     conventions.  They do however allow to deal with <literal>NULL</>able
+     arguments/return values, and <quote>toasted</quote> (compressed or
      out-of-line) values.
     </para>
 
     <para>
-     One big improvement in version-1 functions is better handling of null
-     inputs and results.  The macro <function>PG_ARGISNULL(<replaceable>n</>)</function>
+     The macro <function>PG_ARGISNULL(<replaceable>n</>)</function>
      allows a function to test whether each input is null.  (Of course, doing
      this is only necessary in functions not declared <quote>strict</>.)
      As with the
@@ -2455,7 +2340,7 @@ concat_text(PG_FUNCTION_ARGS)
     </para>
 
     <para>
-     Other options provided in the new-style interface are two
+     Other options provided by the version-1 interface are two
      variants of the
      <function>PG_GETARG_<replaceable>xxx</replaceable>()</function>
      macros. The first of these,
@@ -2487,9 +2372,7 @@ concat_text(PG_FUNCTION_ARGS)
      to return set results (<xref linkend="xfunc-c-return-set">) and
      implement trigger functions (<xref linkend="triggers">) and
      procedural-language call handlers (<xref
-     linkend="plhandler">).  Version-1 code is also more
-     portable than version-0, because it does not break restrictions
-     on function call protocol in the C standard.  For more details
+     linkend="plhandler">).  For more details
      see <filename>src/backend/utils/fmgr/README</filename> in the
      source distribution.
     </para>
@@ -2624,7 +2507,7 @@ SELECT name, c_overpaid(emp, 1500) AS overpaid
     WHERE name = 'Bill' OR name = 'Sam';
 </programlisting>
 
-     Using call conventions version 0, we can define
+     Using the version-1 calling conventions, we can define
      <function>c_overpaid</> as:
 
 <programlisting><![CDATA[
@@ -2635,31 +2518,6 @@ SELECT name, c_overpaid(emp, 1500) AS overpaid
 PG_MODULE_MAGIC;
 #endif
 
-bool
-c_overpaid(HeapTupleHeader t, /* the current row of emp */
-           int32 limit)
-{
-    bool isnull;
-    int32 salary;
-
-    salary = DatumGetInt32(GetAttributeByName(t, "salary", &isnull));
-    if (isnull)
-        return false;
-    return salary > limit;
-}
-]]>
-</programlisting>
-
-     In version-1 coding, the above would look like this:
-
-<programlisting><![CDATA[
-#include "postgres.h"
-#include "executor/executor.h"  /* for GetAttributeByName() */
-
-#ifdef PG_MODULE_MAGIC
-PG_MODULE_MAGIC;
-#endif
-
 PG_FUNCTION_INFO_V1(c_overpaid);
 
 Datum
diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c
index 3976496aef..7d95fb7cdb 100644
--- a/src/backend/utils/fmgr/fmgr.c
+++ b/src/backend/utils/fmgr/fmgr.c
@@ -37,37 +37,6 @@ PGDLLIMPORT needs_fmgr_hook_type needs_fmgr_hook = NULL;
 PGDLLIMPORT fmgr_hook_type fmgr_hook = NULL;
 
 /*
- * Declaration for old-style function pointer type.  This is now used only
- * in fmgr_oldstyle() and is no longer exported.
- *
- * The m68k SVR4 ABI defines that pointers are returned in %a0 instead of
- * %d0. So if a function pointer is declared to return a pointer, the
- * compiler may look only into %a0, but if the called function was declared
- * to return an integer type, it puts its value only into %d0. So the
- * caller doesn't pick up the correct return value. The solution is to
- * declare the function pointer to return int, so the compiler picks up the
- * return value from %d0. (Functions returning pointers put their value
- * *additionally* into %d0 for compatibility.) The price is that there are
- * some warnings about int->pointer conversions ... which we can suppress
- * with suitably ugly casts in fmgr_oldstyle().
- */
-#if (defined(__mc68000__) || (defined(__m68k__))) && defined(__ELF__)
-typedef int32 (*func_ptr) ();
-#else
-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;
-
-/*
  * Hashtable for fast lookup of external C functions
  */
 typedef struct
@@ -90,7 +59,6 @@ static void fmgr_info_other_lang(Oid functionId, FmgrInfo *finfo, HeapTuple proc
 static CFuncHashTabEntry *lookup_C_func(HeapTuple procedureTuple);
 static void record_C_func(HeapTuple procedureTuple,
 			  PGFunction user_fn, const Pg_finfo_record *inforec);
-static Datum fmgr_oldstyle(PG_FUNCTION_ARGS);
 static Datum fmgr_security_definer(PG_FUNCTION_ARGS);
 
 
@@ -304,13 +272,10 @@ fmgr_info_cxt_security(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt,
 static void
 fmgr_info_C_lang(Oid functionId, FmgrInfo *finfo, HeapTuple procedureTuple)
 {
-	Form_pg_proc procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);
 	CFuncHashTabEntry *hashentry;
 	PGFunction	user_fn;
 	const Pg_finfo_record *inforec;
-	Oldstyle_fnextra *fnextra;
 	bool		isnull;
-	int			i;
 
 	/*
 	 * See if we have the function address cached already
@@ -362,20 +327,6 @@ fmgr_info_C_lang(Oid functionId, FmgrInfo *finfo, HeapTuple procedureTuple)
 
 	switch (inforec->api_version)
 	{
-		case 0:
-			/* Old style: need to use a handler */
-			finfo->fn_addr = fmgr_oldstyle;
-			fnextra = (Oldstyle_fnextra *)
-				MemoryContextAllocZero(finfo->fn_mcxt,
-									   sizeof(Oldstyle_fnextra));
-			finfo->fn_extra = (void *) fnextra;
-			fnextra->func = (func_ptr) user_fn;
-			for (i = 0; i < procedureStruct->pronargs; i++)
-			{
-				fnextra->arg_toastable[i] =
-					TypeIsToastable(procedureStruct->proargtypes.values[i]);
-			}
-			break;
 		case 1:
 			/* New style: call directly */
 			finfo->fn_addr = user_fn;
@@ -415,14 +366,6 @@ fmgr_info_other_lang(Oid functionId, FmgrInfo *finfo, HeapTuple procedureTuple)
 						   CurrentMemoryContext, true);
 	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, "language %u has old-style handler", language);
-
 	ReleaseSysCache(languageTuple);
 }
 
@@ -431,10 +374,7 @@ fmgr_info_other_lang(Oid functionId, FmgrInfo *finfo, HeapTuple procedureTuple)
  * The function is specified by a handle for the containing library
  * (obtained from load_external_function) as well as the function name.
  *
- * 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.
+ * If no info function exists for the given name an error is raised.
  *
  * This function is broken out of fmgr_info_C_lang so that fmgr_c_validator
  * can validate the information record for a function not yet entered into
@@ -446,7 +386,6 @@ fetch_finfo_record(void *filehandle, char *funcname)
 	char	   *infofuncname;
 	PGFInfoFunction infofunc;
 	const Pg_finfo_record *inforec;
-	static Pg_finfo_record default_inforec = {0};
 
 	infofuncname = psprintf("pg_finfo_%s", funcname);
 
@@ -455,9 +394,12 @@ fetch_finfo_record(void *filehandle, char *funcname)
 														  infofuncname);
 	if (infofunc == NULL)
 	{
-		/* Not found --- assume version 0 */
-		pfree(infofuncname);
-		return &default_inforec;
+		ereport(ERROR,
+				(errcode(ERRCODE_UNDEFINED_FUNCTION),
+				 errmsg("could not find function information for function \"%s\"",
+						funcname),
+				 errhint("SQL-callable functions need an accompanying PG_FUNCTION_INFO_V1(funcname).")));
+		return NULL; /* silence compiler */
 	}
 
 	/* Found, so call it */
@@ -468,7 +410,6 @@ fetch_finfo_record(void *filehandle, char *funcname)
 		elog(ERROR, "null result from info function \"%s\"", infofuncname);
 	switch (inforec->api_version)
 	{
-		case 0:
 		case 1:
 			/* OK, no additional fields to validate */
 			break;
@@ -585,18 +526,7 @@ fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo,
 {
 	memcpy(dstinfo, srcinfo, sizeof(FmgrInfo));
 	dstinfo->fn_mcxt = destcxt;
-	if (dstinfo->fn_addr == fmgr_oldstyle)
-	{
-		/* For oldstyle functions we must copy fn_extra */
-		Oldstyle_fnextra *fnextra;
-
-		fnextra = (Oldstyle_fnextra *)
-			MemoryContextAlloc(destcxt, sizeof(Oldstyle_fnextra));
-		memcpy(fnextra, srcinfo->fn_extra, sizeof(Oldstyle_fnextra));
-		dstinfo->fn_extra = (void *) fnextra;
-	}
-	else
-		dstinfo->fn_extra = NULL;
+	dstinfo->fn_extra = NULL;
 }
 
 
@@ -617,245 +547,6 @@ fmgr_internal_function(const char *proname)
 
 
 /*
- * Handler for old-style "C" language functions
- */
-static Datum
-fmgr_oldstyle(PG_FUNCTION_ARGS)
-{
-	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, "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++)
-	{
-		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 = fnextra->func;
-
-	switch (n_arguments)
-	{
-		case 0:
-			returnValue = (char *) (*user_fn) ();
-			break;
-		case 1:
-
-			/*
-			 * 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 = (char *) (*user_fn) (fcinfo->arg[0],
-											   &fcinfo->isnull);
-			break;
-		case 2:
-			returnValue = (char *) (*user_fn) (fcinfo->arg[0],
-											   fcinfo->arg[1]);
-			break;
-		case 3:
-			returnValue = (char *) (*user_fn) (fcinfo->arg[0],
-											   fcinfo->arg[1],
-											   fcinfo->arg[2]);
-			break;
-		case 4:
-			returnValue = (char *) (*user_fn) (fcinfo->arg[0],
-											   fcinfo->arg[1],
-											   fcinfo->arg[2],
-											   fcinfo->arg[3]);
-			break;
-		case 5:
-			returnValue = (char *) (*user_fn) (fcinfo->arg[0],
-											   fcinfo->arg[1],
-											   fcinfo->arg[2],
-											   fcinfo->arg[3],
-											   fcinfo->arg[4]);
-			break;
-		case 6:
-			returnValue = (char *) (*user_fn) (fcinfo->arg[0],
-											   fcinfo->arg[1],
-											   fcinfo->arg[2],
-											   fcinfo->arg[3],
-											   fcinfo->arg[4],
-											   fcinfo->arg[5]);
-			break;
-		case 7:
-			returnValue = (char *) (*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 = (char *) (*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 = (char *) (*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;
-		case 10:
-			returnValue = (char *) (*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;
-		case 11:
-			returnValue = (char *) (*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;
-		case 12:
-			returnValue = (char *) (*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;
-		case 13:
-			returnValue = (char *) (*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;
-		case 14:
-			returnValue = (char *) (*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;
-		case 15:
-			returnValue = (char *) (*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;
-		case 16:
-			returnValue = (char *) (*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;
-		default:
-
-			/*
-			 * Increasing FUNC_MAX_ARGS doesn't automatically add cases to the
-			 * above code, so mention 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.
-			 */
-			ereport(ERROR,
-					(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
-			 errmsg("function %u has too many arguments (%d, maximum is %d)",
-					fcinfo->flinfo->fn_oid, n_arguments, 16)));
-			returnValue = NULL; /* keep compiler quiet */
-			break;
-	}
-
-	return PointerGetDatum(returnValue);
-}
-
-
-/*
  * Support for security-definer and proconfig-using functions.  We support
  * both of these features using the same call handler, because they are
  * often used together and it would be inefficient (as well as notationally
@@ -2031,58 +1722,6 @@ OidSendFunctionCall(Oid functionId, Datum val)
 }
 
 
-/*
- * !!! OLD INTERFACE !!!
- *
- * fmgr() is the only remaining vestige of the old-style caller support
- * functions.  It's no longer used anywhere in the Postgres distribution,
- * but we should leave it around for a release or two to ease the transition
- * for user-supplied C functions.  OidFunctionCallN() replaces it for new
- * code.
- *
- * DEPRECATED, DO NOT USE IN NEW CODE
- */
-char *
-fmgr(Oid procedureId,...)
-{
-	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;
-
-		if (n_arguments > FUNC_MAX_ARGS)
-			ereport(ERROR,
-					(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
-			 errmsg("function %u has too many arguments (%d, maximum is %d)",
-					flinfo.fn_oid, n_arguments, FUNC_MAX_ARGS)));
-		va_start(pvar, procedureId);
-		for (i = 0; i < n_arguments; i++)
-			fcinfo.arg[i] = PointerGetDatum(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, "function %u returned NULL", flinfo.fn_oid);
-
-	return DatumGetPointer(result);
-}
-
-
 /*-------------------------------------------------------------------------
  *		Support routines for standard maybe-pass-by-reference datatypes
  *
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index a671480004..87b23f9731 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -320,10 +320,10 @@ extern struct varlena *pg_detoast_datum_packed(struct varlena * datum);
 /*-------------------------------------------------------------------------
  *		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
+ * Dynamically loaded functions currently can only use the version-1 ("new
+ * style") calling convention.  Version-0 ("old style") is not supported
+ * anymore.  Version 1 is the call convention defined in this header file, and
+ * must be accompanied by the macro call
  *
  *		PG_FUNCTION_INFO_V1(function_name);
  *
diff --git a/src/test/regress/input/create_function_2.source b/src/test/regress/input/create_function_2.source
index 3c26b2fec6..b167c8ac6d 100644
--- a/src/test/regress/input/create_function_2.source
+++ b/src/test/regress/input/create_function_2.source
@@ -87,11 +87,6 @@ CREATE FUNCTION reverse_name(name)
    AS '@libdir@/regress@DLSUFFIX@'
    LANGUAGE C STRICT;
 
-CREATE FUNCTION oldstyle_length(int4, text)
-   RETURNS int4
-   AS '@libdir@/regress@DLSUFFIX@'
-   LANGUAGE C;  -- intentionally not strict
-
 --
 -- Function dynamic loading
 --
diff --git a/src/test/regress/input/misc.source b/src/test/regress/input/misc.source
index dd2d1b2033..b1dbc573c9 100644
--- a/src/test/regress/input/misc.source
+++ b/src/test/regress/input/misc.source
@@ -250,19 +250,6 @@ SELECT *, name(equipment(h.*)) FROM hobbies_r h;
 SELECT *, (equipment(CAST((h.*) AS hobbies_r))).name FROM hobbies_r h;
 
 --
--- 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_2.source b/src/test/regress/output/create_function_2.source
index bdd1b1bec5..8f28bff298 100644
--- a/src/test/regress/output/create_function_2.source
+++ b/src/test/regress/output/create_function_2.source
@@ -67,10 +67,6 @@ CREATE FUNCTION reverse_name(name)
    RETURNS name
    AS '@libdir@/regress@DLSUFFIX@'
    LANGUAGE C STRICT;
-CREATE FUNCTION oldstyle_length(int4, text)
-   RETURNS int4
-   AS '@libdir@/regress@DLSUFFIX@'
-   LANGUAGE C;  -- intentionally not strict
 --
 -- Function dynamic loading
 --
diff --git a/src/test/regress/output/misc.source b/src/test/regress/output/misc.source
index 574ef0d2e3..b9595cc239 100644
--- a/src/test/regress/output/misc.source
+++ b/src/test/regress/output/misc.source
@@ -682,24 +682,6 @@ SELECT *, (equipment(CAST((h.*) AS hobbies_r))).name FROM hobbies_r h;
 (7 rows)
 
 --
--- 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 |        50000 |           50000
-(4 rows)
-
-drop table oldstyle_test;
---
 -- functional joins
 --
 --
diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c
index 986d54ce2f..da02696b93 100644
--- a/src/test/regress/regress.c
+++ b/src/test/regress/regress.c
@@ -45,8 +45,6 @@
 
 extern PATH *poly2path(POLYGON *poly);
 extern void regress_lseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
-extern char *reverse_name(char *string);
-extern int	oldstyle_length(int n, text *t);
 
 #ifdef PG_MODULE_MAGIC
 PG_MODULE_MAGIC;
@@ -240,14 +238,15 @@ typedef struct
 	double		radius;
 } WIDGET;
 
-WIDGET	   *widget_in(char *str);
-char	   *widget_out(WIDGET *widget);
+PG_FUNCTION_INFO_V1(widget_in);
+PG_FUNCTION_INFO_V1(widget_out);
 
 #define NARGS	3
 
-WIDGET *
-widget_in(char *str)
+Datum
+widget_in(PG_FUNCTION_ARGS)
 {
+	char	   *str = PG_GETARG_CSTRING(0);
 	char	   *p,
 			   *coord[NARGS];
 	int			i;
@@ -270,14 +269,16 @@ widget_in(char *str)
 	result->center.y = atof(coord[1]);
 	result->radius = atof(coord[2]);
 
-	return result;
+	PG_RETURN_DATUM(PointerGetDatum(result));
 }
 
-char *
-widget_out(WIDGET *widget)
+Datum
+widget_out(PG_FUNCTION_ARGS)
 {
-	return psprintf("(%g,%g,%g)",
-					widget->center.x, widget->center.y, widget->radius);
+	WIDGET *widget = (WIDGET *) PG_GETARG_POINTER(0);
+	char *str =  psprintf("(%g,%g,%g)",
+						  widget->center.x, widget->center.y, widget->radius);
+	PG_RETURN_CSTRING(str);
 }
 
 PG_FUNCTION_INFO_V1(pt_in_widget);
@@ -305,9 +306,12 @@ boxarea(PG_FUNCTION_ARGS)
 	PG_RETURN_FLOAT8(width * height);
 }
 
-char *
-reverse_name(char *string)
+PG_FUNCTION_INFO_V1(reverse_name);
+
+Datum
+reverse_name(PG_FUNCTION_ARGS)
 {
+	char	   *string = PG_GETARG_CSTRING(0);
 	int			i;
 	int			len;
 	char	   *new_string;
@@ -320,22 +324,7 @@ reverse_name(char *string)
 	len = i;
 	for (; i >= 0; --i)
 		new_string[len - i] = string[i];
-	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;
+	PG_RETURN_CSTRING(new_string);
 }
 
 
-- 
2.11.0.22.g8d7a455.dirty

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to