OSDN Git Service

Adjust DatumGetBool macro so that it isn't fooled by garbage in the Datum
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 23 Mar 2007 20:24:41 +0000 (20:24 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 23 Mar 2007 20:24:41 +0000 (20:24 +0000)
to the left of the actual bool value.  While in most cases there won't be
any, our support for old-style user-defined functions violates the C spec
to the extent of calling functions that might return char or short through
a function pointer declared to return "char *", which we then coerce to
Datum.  It is not surprising that the result might contain garbage
high-order bits ... what is surprising is that we didn't see such cases
long ago.  Per report from Magnus.

src/include/postgres.h

index c063335..5234c34 100644 (file)
@@ -10,7 +10,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1995, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/postgres.h,v 1.77 2007/02/27 23:48:09 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/postgres.h,v 1.78 2007/03/23 20:24:41 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -125,13 +125,18 @@ typedef struct varattrib
  *
  *     sizeof(short) == 2
  *
- *     If your machine meets these requirements, Datums should also be checked
- *     to see if the positioning is correct.
+ * When a type narrower than Datum is stored in a Datum, we place it in the
+ * low-order bits and are careful that the DatumGetXXX macro for it discards
+ * the unused high-order bits (as opposed to, say, assuming they are zero).
+ * This is needed to support old-style user-defined functions, since depending
+ * on architecture and compiler, the return value of a function returning char
+ * or short may contain garbage when called as if it returned Datum.
  */
 
 typedef unsigned long Datum;   /* XXX sizeof(long) >= sizeof(void *) */
 
 #define SIZEOF_DATUM SIZEOF_UNSIGNED_LONG
+
 typedef Datum *DatumPtr;
 
 #define GET_1_BYTE(datum)      (((Datum) (datum)) & 0x000000ff)
@@ -145,10 +150,11 @@ typedef Datum *DatumPtr;
  * DatumGetBool
  *             Returns boolean value of a datum.
  *
- * Note: any nonzero value will be considered TRUE.
+ * Note: any nonzero value will be considered TRUE, but we ignore bits to
+ * the left of the width of bool, per comment above.
  */
 
-#define DatumGetBool(X) ((bool) (((Datum) (X)) != 0))
+#define DatumGetBool(X) ((bool) (((bool) (X)) != 0))
 
 /*
  * BoolGetDatum