diff --git a/src/tutorial/funcs.c b/src/tutorial/funcs.c
index 5cb8d95c7368560dcac79461663415975cdafb1d..621503a421c785a246ccb3569b7fd7b88b873fcc 100644
--- a/src/tutorial/funcs.c
+++ b/src/tutorial/funcs.c
@@ -4,75 +4,104 @@
 
   The calling format for these functions is defined by the CREATE FUNCTION
   SQL statement that binds them to the backend.
+
+  NOTE: this file shows examples of "old style" function call conventions.
+  See funcs_new.c for examples of "new style".
 *****************************************************************************/
 
-#include "postgres.h"			/* for variable length type */
+#include <string.h>
+
+#include "postgres.h"			/* general Postgres declarations */
+
 #include "executor/executor.h"	/* for GetAttributeByName() */
 #include "utils/geo_decls.h"	/* for point type */
 
-/* The following prototypes declare what we assume the user declares to
-   Postgres in his CREATE FUNCTION statement.
-*/
+
+/* These prototypes just prevent possible warnings from gcc. */
 
 int			add_one(int arg);
+float8     *add_one_float8(float8 *arg);
 Point	   *makepoint(Point *pointx, Point *pointy);
 text	   *copytext(text *t);
-
+text       *concat_text(text *arg1, text *arg2);
 bool c_overpaid(TupleTableSlot *t,	/* the current instance of EMP */
-		   int4 limit);
-
+		   int32 limit);
 
 
+/* By Value */
+         
 int
 add_one(int arg)
 {
-	return arg + 1;
+    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));
+    Point     *new_point = (Point *) palloc(sizeof(Point));
 
-	new_point->x = pointx->x;
-	new_point->y = pointy->y;
-
-	return new_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));
+    VARATT_SIZEP(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;
+}
 
-	/*
-	 * VARSIZE is the total size of the struct in bytes.
-	 */
-	text	   *new_t = (text *) palloc(VARSIZE(t));
-
-	MemSet(new_t, 0, VARSIZE(t));
-
-	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);
+
+    memset((void *) new_text, 0, new_text_size);
+    VARATT_SIZEP(new_text) = new_text_size;
+    strncpy(VARDATA(new_text), VARDATA(arg1), VARSIZE(arg1)-VARHDRSZ);
+    strncat(VARDATA(new_text), VARDATA(arg2), VARSIZE(arg2)-VARHDRSZ);
+    return new_text;
 }
 
+/* Composite types */
+
 bool
 c_overpaid(TupleTableSlot *t,	/* the current instance of EMP */
-		   int4 limit)
+		   int32 limit)
 {
-	bool		isnull = false;
-	int4		salary;
-
-	salary = (int4) GetAttributeByName(t, "salary", &isnull);
+    bool isnull;
+    int32 salary;
 
-	if (isnull)
-		return false;
-	return salary > limit;
+    salary = DatumGetInt32(GetAttributeByName(t, "salary", &isnull));
+    if (isnull)
+        return (false);
+    return salary > limit;
 }
diff --git a/src/tutorial/funcs_new.c b/src/tutorial/funcs_new.c
new file mode 100644
index 0000000000000000000000000000000000000000..0734e67a113d9b06c25ba5a325baeb9cec8013ff
--- /dev/null
+++ b/src/tutorial/funcs_new.c
@@ -0,0 +1,116 @@
+/******************************************************************************
+  These are user-defined functions that can be bound to a Postgres backend
+  and called by Postgres to execute SQL functions of the same name.
+
+  The calling format for these functions is defined by the CREATE FUNCTION
+  SQL statement that binds them to the backend.
+
+  NOTE: this file shows examples of "new style" function call conventions.
+  See funcs.c for examples of "old style".
+*****************************************************************************/
+
+#include <string.h>
+
+#include "postgres.h"			/* general Postgres declarations */
+
+#include "fmgr.h"               /* for argument/result macros */
+#include "executor/executor.h"	/* for GetAttributeByName() */
+#include "utils/geo_decls.h"	/* for point type */
+
+
+/* These prototypes just prevent possible warnings from gcc. */
+
+Datum	add_one(PG_FUNCTION_ARGS);
+Datum	add_one_float8(PG_FUNCTION_ARGS);
+Datum	makepoint(PG_FUNCTION_ARGS);
+Datum	copytext(PG_FUNCTION_ARGS);
+Datum	concat_text(PG_FUNCTION_ARGS);
+Datum   c_overpaid(PG_FUNCTION_ARGS);
+
+
+/* By Value */
+         
+Datum
+add_one(PG_FUNCTION_ARGS)
+{
+    int32   arg = PG_GETARG_INT32(0);
+
+    PG_RETURN_INT32(arg + 1);
+}
+
+/* By Reference, Fixed Length */
+
+Datum
+add_one_float8(PG_FUNCTION_ARGS)
+{
+    /* The macros for FLOAT8 hide its pass-by-reference nature */
+    float8   arg = PG_GETARG_FLOAT8(0);
+
+    PG_RETURN_FLOAT8(arg + 1.0);
+}
+
+Datum
+makepoint(PG_FUNCTION_ARGS)
+{
+    Point     *pointx = PG_GETARG_POINT_P(0);
+    Point     *pointy = PG_GETARG_POINT_P(1);
+    Point     *new_point = (Point *) palloc(sizeof(Point));
+
+    new_point->x = pointx->x;
+    new_point->y = pointy->y;
+       
+    PG_RETURN_POINT_P(new_point);
+}
+
+/* By Reference, Variable Length */
+
+Datum
+copytext(PG_FUNCTION_ARGS)
+{
+    text     *t = PG_GETARG_TEXT_P(0);
+    /*
+     * VARSIZE is the total size of the struct in bytes.
+     */
+    text     *new_t = (text *) palloc(VARSIZE(t));
+    VARATT_SIZEP(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 */
+    PG_RETURN_TEXT_P(new_t);
+}
+
+Datum
+concat_text(PG_FUNCTION_ARGS)
+{
+    text  *arg1 = PG_GETARG_TEXT_P(0);
+    text  *arg2 = PG_GETARG_TEXT_P(1);
+    int32 new_text_size = VARSIZE(arg1) + VARSIZE(arg2) - VARHDRSZ;
+    text *new_text = (text *) palloc(new_text_size);
+
+    memset((void *) new_text, 0, new_text_size);
+    VARATT_SIZEP(new_text) = new_text_size;
+    strncpy(VARDATA(new_text), VARDATA(arg1), VARSIZE(arg1)-VARHDRSZ);
+    strncat(VARDATA(new_text), VARDATA(arg2), VARSIZE(arg2)-VARHDRSZ);
+    PG_RETURN_TEXT_P(new_text);
+}
+
+/* Composite types */
+
+Datum
+c_overpaid(PG_FUNCTION_ARGS)
+{
+    TupleTableSlot  *t = (TupleTableSlot *) PG_GETARG_POINTER(0);
+    int32            limit = PG_GETARG_INT32(1);
+    bool isnull;
+    int32 salary;
+
+    salary = DatumGetInt32(GetAttributeByName(t, "salary", &isnull));
+    if (isnull)
+        PG_RETURN_BOOL(false);
+    /* Alternatively, we might prefer to do PG_RETURN_NULL() for null salary */
+
+    PG_RETURN_BOOL(salary > limit);
+}