From ba9f37f066cffbc327936fe35d08778c23be6e16 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Wed, 3 Sep 2008 22:34:50 +0000
Subject: [PATCH] If a loadable module has wrong values in its magic block,
 spell out exactly what they are in the complaint message.  Marko Kreen, some
 editorialization by me.

---
 src/backend/utils/fmgr/dfmgr.c | 111 +++++++++++++++++++++++++++------
 src/include/fmgr.h             |   5 +-
 2 files changed, 97 insertions(+), 19 deletions(-)

diff --git a/src/backend/utils/fmgr/dfmgr.c b/src/backend/utils/fmgr/dfmgr.c
index 743df3a916e..eedab5f30b6 100644
--- a/src/backend/utils/fmgr/dfmgr.c
+++ b/src/backend/utils/fmgr/dfmgr.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.96 2008/01/01 19:45:53 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.97 2008/09/03 22:34:50 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,6 +21,7 @@
 #else
 #include "port/dynloader/win32.h"
 #endif
+#include "lib/stringinfo.h"
 #include "miscadmin.h"
 #include "utils/dynamic_loader.h"
 #include "utils/hsearch.h"
@@ -71,6 +72,8 @@ static DynamicFileList *file_tail = NULL;
 char	   *Dynamic_library_path;
 
 static void *internal_load_library(const char *libname);
+static void incompatible_module_error(const char *libname,
+									const Pg_magic_struct *module_magic_data);
 static void internal_unload_library(const char *libname);
 static bool file_exists(const char *name);
 static char *expand_dynamic_library_name(const char *name);
@@ -257,23 +260,8 @@ internal_load_library(const char *libname)
 				pg_dlclose(file_scanner->handle);
 				free((char *) file_scanner);
 
-				/*
-				 * Report suitable error.  It's probably not worth writing a
-				 * separate error message for each field; only the most common
-				 * case of wrong major version gets its own message.
-				 */
-				if (module_magic_data.version != magic_data.version)
-					ereport(ERROR,
-					 (errmsg("incompatible library \"%s\": version mismatch",
-							 libname),
-					  errdetail("Server is version %d.%d, library is version %d.%d.",
-								magic_data.version / 100,
-								magic_data.version % 100,
-								module_magic_data.version / 100,
-								module_magic_data.version % 100)));
-				ereport(ERROR,
-				 (errmsg("incompatible library \"%s\": magic block mismatch",
-						 libname)));
+				/* issue suitable complaint */
+				incompatible_module_error(libname, &module_magic_data);
 			}
 		}
 		else
@@ -306,6 +294,93 @@ internal_load_library(const char *libname)
 	return file_scanner->handle;
 }
 
+/*
+ * Report a suitable error for an incompatible magic block.
+ */
+static void
+incompatible_module_error(const char *libname,
+						  const Pg_magic_struct *module_magic_data)
+{
+	StringInfoData	details;
+
+	/*
+	 * If the version doesn't match, just report that, because the rest of the
+	 * block might not even have the fields we expect.
+	 */
+	if (magic_data.version != module_magic_data->version)
+		ereport(ERROR,
+				(errmsg("incompatible library \"%s\": version mismatch",
+						libname),
+				 errdetail("Server is version %d.%d, library is version %d.%d.",
+						   magic_data.version / 100,
+						   magic_data.version % 100,
+						   module_magic_data->version / 100,
+						   module_magic_data->version % 100)));
+
+	/*
+	 * Otherwise, spell out which fields don't agree.
+	 *
+	 * XXX this code has to be adjusted any time the set of fields in a magic
+	 * block change!
+	 */
+	initStringInfo(&details);
+
+	if (module_magic_data->funcmaxargs != magic_data.funcmaxargs)
+	{
+		if (details.len)
+			appendStringInfoChar(&details, '\n');
+		appendStringInfo(&details,
+						 _("Server has FUNC_MAX_ARGS = %d, library has %d."),
+						 magic_data.funcmaxargs,
+						 module_magic_data->funcmaxargs);
+	}
+	if (module_magic_data->indexmaxkeys != magic_data.indexmaxkeys)
+	{
+		if (details.len)
+			appendStringInfoChar(&details, '\n');
+		appendStringInfo(&details,
+						 _("Server has INDEX_MAX_KEYS = %d, library has %d."),
+						 magic_data.indexmaxkeys,
+						 module_magic_data->indexmaxkeys);
+	}
+	if (module_magic_data->namedatalen != magic_data.namedatalen)
+	{
+		if (details.len)
+			appendStringInfoChar(&details, '\n');
+		appendStringInfo(&details,
+						 _("Server has NAMEDATALEN = %d, library has %d."),
+						 magic_data.namedatalen,
+						 module_magic_data->namedatalen);
+	}
+	if (module_magic_data->float4byval != magic_data.float4byval)
+	{
+		if (details.len)
+			appendStringInfoChar(&details, '\n');
+		appendStringInfo(&details,
+						 _("Server has FLOAT4PASSBYVAL = %s, library has %s."),
+						 magic_data.float4byval ? "true" : "false",
+						 module_magic_data->float4byval ? "true" : "false");
+	}
+	if (module_magic_data->float8byval != magic_data.float8byval)
+	{
+		if (details.len)
+			appendStringInfoChar(&details, '\n');
+		appendStringInfo(&details,
+						 _("Server has FLOAT8PASSBYVAL = %s, library has %s."),
+						 magic_data.float8byval ? "true" : "false",
+						 module_magic_data->float8byval ? "true" : "false");
+	}
+
+	if (details.len == 0)
+		appendStringInfo(&details,
+						 _("Magic block has unexpected length or padding difference."));
+
+	ereport(ERROR,
+			(errmsg("incompatible library \"%s\": magic block mismatch",
+					libname),
+			 errdetail("%s", details.data)));
+}
+
 /*
  * Unload the specified dynamic-link library file, if it is loaded.
  *
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index f0cc26f5311..c348086fbc8 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -11,7 +11,7 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/fmgr.h,v 1.59 2008/05/15 00:17:41 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/fmgr.h,v 1.60 2008/09/03 22:34:50 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -357,6 +357,9 @@ extern int no_such_variable
  *
  * Note: we compare magic blocks with memcmp(), so there had better not be
  * any alignment pad bytes in them.
+ *
+ * Note: when changing the contents of magic blocks, be sure to adjust the
+ * incompatible_module_error() function in dfmgr.c.
  *-------------------------------------------------------------------------
  */