-<!-- $PostgreSQL: pgsql/doc/src/sgml/xfunc.sgml,v 1.113 2006/05/30 14:09:32 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/xfunc.sgml,v 1.114 2006/05/30 21:21:29 tgl Exp $ -->
<sect1 id="xfunc">
<title>User-Defined Functions</title>
that fails as well, the load will fail.
</para>
- <para>
- After the module has been found, PostgreSQL looks for its magic block.
- This block contains information about the environment a module was
- compiled in. The server uses this to verify the module was compiled
- under the same assumptions and environment as the backend.
- </para>
-
<para>
The user ID the <productname>PostgreSQL</productname> server runs
as must be able to traverse the path to the file you intend to
<listitem>
<para>
- To ensure your module is not loaded into an incompatible backend, it
- is recommended to include a magic block. To do this you must include
- the header <filename>pgmagic.h</filename> and declare the block as
- follows:
+ Symbol names defined within object files must not conflict
+ with each other or with symbols defined in the
+ <productname>PostgreSQL</productname> server executable. You
+ will have to rename your functions or variables if you get
+ error messages to this effect.
</para>
+ </listitem>
-<programlisting>
-#include "pgmagic.h"
+ <listitem>
+ <para>
+ To ensure your module is not loaded into an incompatible server, it
+ is recommended to include a <quote>magic block</>. This allows
+ the server to detect obvious incompatibilities, such as a module
+ compiled for a different major version of
+ <productname>PostgreSQL</productname>. It is likely that magic
+ blocks will be required in future releases. To include a magic
+ block, write this in one (and only one) of your module source files,
+ after having included the header <filename>fmgr.h</>:
+ </para>
+<programlisting>
+#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
+#endif
</programlisting>
<para>
- If the module consists of multiple source files, this only needs to
- be done in one of them.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Symbol names defined within object files must not conflict
- with each other or with symbols defined in the
- <productname>PostgreSQL</productname> server executable. You
- will have to rename your functions or variables if you get
- error messages to this effect.
+ The <literal>#ifdef</> test can be omitted if your code doesn't
+ need to compile against pre-8.2 <productname>PostgreSQL</productname>
+ releases.
</para>
</listitem>
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.83 2006/05/30 14:09:32 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.84 2006/05/30 21:21:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
-#include <errno.h>
#include <sys/stat.h>
#include "dynloader.h"
#include "miscadmin.h"
#include "utils/dynamic_loader.h"
-#include "pgmagic.h"
+
/*
* List of dynamically loaded files (kept in malloc'd memory).
static char *substitute_libpath_macro(const char *name);
/* Magic structure that module needs to match to be accepted */
-static Pg_magic_struct magic_data = PG_MODULE_MAGIC_DATA;
+static const Pg_magic_struct magic_data = PG_MODULE_MAGIC_DATA;
+
/*
* Load the specified dynamic-link library file, and look for a function
{
DynamicFileList *file_scanner;
PGFunction retval;
+ PGModuleMagicFunction magic_func;
char *load_error;
struct stat stat_buf;
char *fullname;
if (file_scanner == NULL)
{
- PGModuleMagicFunction magic_func;
/*
* File not loaded yet.
*/
fullname, load_error)));
}
- /* Check the magic function to determine compatability */
- magic_func = pg_dlsym( file_scanner->handle, PG_MAGIC_FUNCTION_NAME_STRING );
- if( magic_func )
+ /* Check the magic function to determine compatibility */
+ magic_func = (PGModuleMagicFunction)
+ pg_dlsym(file_scanner->handle, PG_MAGIC_FUNCTION_NAME_STRING);
+ if (magic_func)
{
- Pg_magic_struct *module_magic_data = magic_func();
- if( module_magic_data->len != magic_data.len ||
- memcmp( module_magic_data, &magic_data, magic_data.len ) != 0 )
+ const Pg_magic_struct *magic_data_ptr = (*magic_func) ();
+
+ if (magic_data_ptr->len != magic_data.len ||
+ memcmp(magic_data_ptr, &magic_data, magic_data.len) != 0)
{
- pg_dlclose( file_scanner->handle );
-
- if( module_magic_data->len != magic_data.len )
+ /* copy data block before unlinking library */
+ Pg_magic_struct module_magic_data = *magic_data_ptr;
+
+ /* try to unlink library */
+ 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\": Magic block length mismatch",
- fullname)));
- if( module_magic_data->version != magic_data.version )
- ereport(ERROR,
- (errmsg("incompatible library \"%s\": Version mismatch",
- fullname),
- errdetail("Expected %d.%d, got %d.%d",
- magic_data.version/100, magic_data.version % 100,
- module_magic_data->version/100, module_magic_data->version % 100)));
-
- if( module_magic_data->magic != magic_data.magic )
- ereport(ERROR,
- (errmsg("incompatible library \"%s\": Magic constant mismatch",
- fullname),
- errdetail("Expected 0x%08X, got 0x%08X",
- magic_data.magic, magic_data.magic)));
- /* Should never get here */
- ereport(ERROR,(errmsg("incompatible library \"%s\": Reason unknown",
+ (errmsg("incompatible library \"%s\": version mismatch",
+ fullname),
+ 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",
fullname)));
}
}
else
- /* Currently we do not penalize modules for not having a
- magic block, it would break every external module in
- existance. At some point though... */
- ereport(LOG, (errmsg("external library \"%s\" did not have magic block", fullname )));
+ {
+ /*
+ * Currently we do not reject modules for not having a
+ * magic block, it would break every external module in
+ * existence. At some point though, this will become an ERROR.
+ */
+ ereport(LOG,
+ (errmsg("library \"%s\" does not have a magic block",
+ fullname)));
+ }
/* OK to link it into list */
if (file_list == NULL)
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.100 2006/04/04 19:35:36 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.101 2006/05/30 21:21:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
TransactionId fn_xmin; /* for checking up-to-dateness */
CommandId fn_cmin;
PGFunction user_fn; /* the function's address */
- Pg_finfo_record *inforec; /* address of its info record */
+ const Pg_finfo_record *inforec; /* address of its info record */
} CFuncHashTabEntry;
static HTAB *CFuncHash = NULL;
static void fmgr_info_other_lang(Oid functionId, FmgrInfo *finfo, HeapTuple procedureTuple);
static CFuncHashTabEntry *lookup_C_func(HeapTuple procedureTuple);
static void record_C_func(HeapTuple procedureTuple,
- PGFunction user_fn, Pg_finfo_record *inforec);
+ PGFunction user_fn, const Pg_finfo_record *inforec);
static Datum fmgr_oldstyle(PG_FUNCTION_ARGS);
static Datum fmgr_security_definer(PG_FUNCTION_ARGS);
Form_pg_proc procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);
CFuncHashTabEntry *hashentry;
PGFunction user_fn;
- Pg_finfo_record *inforec;
+ const Pg_finfo_record *inforec;
Oldstyle_fnextra *fnextra;
bool isnull;
int i;
* can validate the information record for a function not yet entered into
* pg_proc.
*/
-Pg_finfo_record *
+const Pg_finfo_record *
fetch_finfo_record(void *filehandle, char *funcname)
{
char *infofuncname;
PGFInfoFunction infofunc;
- Pg_finfo_record *inforec;
+ const Pg_finfo_record *inforec;
static Pg_finfo_record default_inforec = {0};
/* Compute name of info func */
*/
static void
record_C_func(HeapTuple procedureTuple,
- PGFunction user_fn, Pg_finfo_record *inforec)
+ PGFunction user_fn, const Pg_finfo_record *inforec)
{
Oid fn_oid = HeapTupleGetOid(procedureTuple);
CFuncHashTabEntry *entry;
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/fmgr.h,v 1.43 2006/04/04 19:35:37 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/fmgr.h,v 1.44 2006/05/30 21:21:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
} Pg_finfo_record;
/* Expected signature of an info function */
-typedef Pg_finfo_record *(*PGFInfoFunction) (void);
+typedef const Pg_finfo_record *(*PGFInfoFunction) (void);
/*
* Macro to build an info function associated with the given function name.
* doesn't hurt to add DLLIMPORT in case they don't.
*/
#define PG_FUNCTION_INFO_V1(funcname) \
-extern DLLIMPORT Pg_finfo_record * CppConcat(pg_finfo_,funcname) (void); \
-Pg_finfo_record * \
+extern DLLIMPORT const Pg_finfo_record * CppConcat(pg_finfo_,funcname)(void); \
+const Pg_finfo_record * \
CppConcat(pg_finfo_,funcname) (void) \
{ \
- static Pg_finfo_record my_finfo = { 1 }; \
+ static const Pg_finfo_record my_finfo = { 1 }; \
return &my_finfo; \
} \
extern int no_such_variable
+/*-------------------------------------------------------------------------
+ * Support for verifying backend compatibility of loaded modules
+ *
+ * If a loaded module includes the macro call
+ * PG_MODULE_MAGIC;
+ * (put this in only one source file), then we can check for obvious
+ * incompatibility, such as being compiled for a different major PostgreSQL
+ * version.
+ *
+ * To compile with versions of PostgreSQL that do not support this,
+ * you may put an #ifdef/#endif test around it.
+ *
+ * The specific items included in the magic block are intended to be ones that
+ * are custom-configurable and especially likely to break dynamically loaded
+ * modules if they were compiled with other values. Also, the length field
+ * can be used to detect definition changes.
+ *-------------------------------------------------------------------------
+ */
+
+/* Definition of the magic block structure */
+typedef struct
+{
+ int len; /* sizeof(this struct) */
+ int version; /* PostgreSQL major version */
+ int funcmaxargs; /* FUNC_MAX_ARGS */
+ int indexmaxkeys; /* INDEX_MAX_KEYS */
+ int namedatalen; /* NAMEDATALEN */
+} Pg_magic_struct;
+
+/* The actual data block contents */
+#define PG_MODULE_MAGIC_DATA \
+{ \
+ sizeof(Pg_magic_struct), \
+ PG_VERSION_NUM / 100, \
+ FUNC_MAX_ARGS, \
+ INDEX_MAX_KEYS, \
+ NAMEDATALEN \
+}
+
+/*
+ * Declare the module magic function. It needs to be a function as the dlsym
+ * in the backend is only guaranteed to work on functions, not data
+ */
+typedef const Pg_magic_struct *(*PGModuleMagicFunction) (void);
+
+#define PG_MAGIC_FUNCTION_NAME Pg_magic_func
+#define PG_MAGIC_FUNCTION_NAME_STRING "Pg_magic_func"
+
+#define PG_MODULE_MAGIC \
+extern DLLIMPORT const Pg_magic_struct *PG_MAGIC_FUNCTION_NAME(void); \
+const Pg_magic_struct * \
+PG_MAGIC_FUNCTION_NAME(void) \
+{ \
+ static const Pg_magic_struct Pg_magic_data = PG_MODULE_MAGIC_DATA; \
+ return &Pg_magic_data; \
+} \
+extern int no_such_variable
+
+
/*-------------------------------------------------------------------------
* Support routines and macros for callers of fmgr-compatible functions
*-------------------------------------------------------------------------
/*
* Routines in fmgr.c
*/
-extern Pg_finfo_record *fetch_finfo_record(void *filehandle, char *funcname);
+extern const Pg_finfo_record *fetch_finfo_record(void *filehandle, char *funcname);
extern void clear_external_function_hash(void *filehandle);
extern Oid fmgr_internal_function(const char *proname);
extern Oid get_fn_expr_rettype(FmgrInfo *flinfo);
+++ /dev/null
-/*-------------------------------------------------------------------------
- *
- * pgmagic.h
- * Defines a magic block that can mark a module in a way so show that
- * it is compatible with the server it is being loaded into.
- *
- * This file is intended to be included into modules that wish to load
- * themselves into the backend. All they need to do is include this header
- * into one of the source files and include the line:
- *
- * PG_MODULE_MAGIC;
- *
- * The trailing semi-colon is optional. To work with versions of PostgreSQL
- * that do not support this, you may put an #ifdef/endif block around it.
- *
- * Note, there is space available, particularly in the bitfield part. If it
- * turns out that a change has happened within a major release that would
- * require all modules to be recompiled, just setting one unused bit there
- * will do the trick.
- *
- * Originally written by Martijn van Oosterhout <kleptog@svana.org>
- *
- * $PostgreSQL: pgsql/src/include/pgmagic.h,v 1.1 2006/05/30 14:09:32 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
-
-#ifndef PGMAGIC_H
-#define PGMAGIC_H
-
-#include "c.h"
-
-/* The main structure in which the magic is stored. the length field is used
- * to detect major changes */
-
-typedef struct {
- int len;
- int version;
- int magic;
-} Pg_magic_struct;
-
-/* Declare the module magic function. It needs to be a function as the dlsym
- * in the backend is only guarenteed to work on functions, not data */
-
-typedef Pg_magic_struct *(*PGModuleMagicFunction) (void);
-
-#define PG_MAGIC_FUNCTION_NAME Pg_magic_func
-#define PG_MAGIC_FUNCTION_NAME_STRING "Pg_magic_func"
-
-#define PG_MODULE_MAGIC \
-extern DLLIMPORT Pg_magic_struct *PG_MAGIC_FUNCTION_NAME(void); \
-Pg_magic_struct * \
-PG_MAGIC_FUNCTION_NAME(void) \
-{ \
- static Pg_magic_struct Pg_magic_data = PG_MODULE_MAGIC_DATA; \
- return &Pg_magic_data; \
-}
-
- /* Common user adjustable constants */
-#define PG_MODULE_MAGIC_CONST \
- ((INDEX_MAX_KEYS << 0) + \
- (FUNC_MAX_ARGS << 8) + \
- (NAMEDATALEN << 16))
-
-/* Finally, the actual data block */
-#define PG_MODULE_MAGIC_DATA \
-{ \
- sizeof(Pg_magic_struct), \
- PG_VERSION_NUM / 100, /* Major version of postgres */ \
- PG_MODULE_MAGIC_CONST, /* Constants users can configure */ \
-}
-
-#endif /* PGMAGIC_H */
/*
- * $PostgreSQL: pgsql/src/test/regress/regress.c,v 1.66 2006/05/30 14:09:32 momjian Exp $
+ * $PostgreSQL: pgsql/src/test/regress/regress.c,v 1.67 2006/05/30 21:21:30 tgl Exp $
*/
#include "postgres.h"
#include "utils/geo_decls.h" /* includes <math.h> */
#include "executor/executor.h" /* For GetAttributeByName */
#include "commands/sequence.h" /* for nextval() */
-#include "pgmagic.h"
#define P_MAXDIG 12
#define LDELIM '('
extern Datum int44in(PG_FUNCTION_ARGS);
extern Datum int44out(PG_FUNCTION_ARGS);
+#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
+#endif
+
+
/*
* Distance from a point to a path
*/