1
0
mirror of https://github.com/postgres/postgres.git synced 2025-12-01 12:18:01 +03:00

Allow float8, int8, and related datatypes to be passed by value on machines

where Datum is 8 bytes wide.  Since this will break old-style C functions
(those still using version 0 calling convention) that have arguments or
results of these types, provide a configure option to disable it and retain
the old pass-by-reference behavior.  Likewise, provide a configure option
to disable the recently-committed float4 pass-by-value change.

Zoltan Boszormenyi, plus configurability stuff by me.
This commit is contained in:
Tom Lane
2008-04-21 00:26:47 +00:00
parent be939544a6
commit 8472bf7a73
36 changed files with 661 additions and 243 deletions

View File

@@ -13,7 +13,7 @@
* this version handles 64 bit numbers and so can hold values up to
* $92,233,720,368,547,758.07.
*
* $PostgreSQL: pgsql/src/backend/utils/adt/cash.c,v 1.78 2008/03/25 22:42:43 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/cash.c,v 1.79 2008/04/21 00:26:45 tgl Exp $
*/
#include "postgres.h"
@@ -34,14 +34,6 @@
#define LAST_PAREN (TERMINATOR - 1)
#define LAST_DIGIT (LAST_PAREN - 1)
/*
* Cash is a pass-by-ref SQL type, so we must pass and return pointers.
* These macros and support routine hide the pass-by-refness.
*/
#define PG_GETARG_CASH(n) (* ((Cash *) PG_GETARG_POINTER(n)))
#define PG_RETURN_CASH(x) return CashGetDatum(x)
/*************************************************************************
* Private routines
@@ -99,15 +91,6 @@ num_word(Cash value)
return buf;
} /* num_word() */
static Datum
CashGetDatum(Cash value)
{
Cash *result = (Cash *) palloc(sizeof(Cash));
*result = value;
return PointerGetDatum(result);
}
/* cash_in()
* Convert a string to a cash data type.

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/float.c,v 1.154 2008/03/10 12:39:22 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/float.c,v 1.155 2008/04/21 00:26:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1780,7 +1780,7 @@ float8_accum(PG_FUNCTION_ARGS)
result = construct_array(transdatums, 3,
FLOAT8OID,
sizeof(float8), false /* float8 byval */ , 'd');
sizeof(float8), FLOAT8PASSBYVAL, 'd');
PG_RETURN_ARRAYTYPE_P(result);
}
@@ -1833,7 +1833,7 @@ float4_accum(PG_FUNCTION_ARGS)
result = construct_array(transdatums, 3,
FLOAT8OID,
sizeof(float8), false /* float8 byval */ , 'd');
sizeof(float8), FLOAT8PASSBYVAL, 'd');
PG_RETURN_ARRAYTYPE_P(result);
}
@@ -2056,8 +2056,7 @@ float8_regr_accum(PG_FUNCTION_ARGS)
result = construct_array(transdatums, 6,
FLOAT8OID,
sizeof(float8),
false /* float8 byval */ , 'd');
sizeof(float8), FLOAT8PASSBYVAL, 'd');
PG_RETURN_ARRAYTYPE_P(result);
}

View File

@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/int8.c,v 1.68 2008/01/01 19:45:52 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/int8.c,v 1.69 2008/04/21 00:26:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -657,17 +657,16 @@ int8mod(PG_FUNCTION_ARGS)
Datum
int8inc(PG_FUNCTION_ARGS)
{
/*
* When int8 is pass-by-reference, we provide this special case to avoid
* palloc overhead for COUNT(): when called from nodeAgg, we know that the
* argument is modifiable local storage, so just update it in-place.
* (If int8 is pass-by-value, then of course this is useless as well
* as incorrect, so just ifdef it out.)
*/
#ifndef USE_FLOAT8_BYVAL /* controls int8 too */
if (fcinfo->context && IsA(fcinfo->context, AggState))
{
/*
* Special case to avoid palloc overhead for COUNT(): when called from
* nodeAgg, we know that the argument is modifiable local storage, so
* just update it in-place.
*
* Note: this assumes int8 is a pass-by-ref type; if we ever support
* pass-by-val int8, this should be ifdef'd out when int8 is
* pass-by-val.
*/
int64 *arg = (int64 *) PG_GETARG_POINTER(0);
int64 result;
@@ -682,6 +681,7 @@ int8inc(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(arg);
}
else
#endif
{
/* Not called by nodeAgg, so just do it the dumb way */
int64 arg = PG_GETARG_INT64(0);

View File

@@ -14,7 +14,7 @@
* Copyright (c) 1998-2008, PostgreSQL Global Development Group
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.109 2008/04/04 18:45:36 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.110 2008/04/21 00:26:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2599,10 +2599,13 @@ int2_sum(PG_FUNCTION_ARGS)
}
/*
* If we're invoked by nodeAgg, we can cheat and modify out first
* If we're invoked by nodeAgg, we can cheat and modify our first
* parameter in-place to avoid palloc overhead. If not, we need to return
* the new value of the transition variable.
* (If int8 is pass-by-value, then of course this is useless as well
* as incorrect, so just ifdef it out.)
*/
#ifndef USE_FLOAT8_BYVAL /* controls int8 too */
if (fcinfo->context && IsA(fcinfo->context, AggState))
{
int64 *oldsum = (int64 *) PG_GETARG_POINTER(0);
@@ -2614,6 +2617,7 @@ int2_sum(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(oldsum);
}
else
#endif
{
int64 oldsum = PG_GETARG_INT64(0);
@@ -2644,10 +2648,13 @@ int4_sum(PG_FUNCTION_ARGS)
}
/*
* If we're invoked by nodeAgg, we can cheat and modify out first
* If we're invoked by nodeAgg, we can cheat and modify our first
* parameter in-place to avoid palloc overhead. If not, we need to return
* the new value of the transition variable.
* (If int8 is pass-by-value, then of course this is useless as well
* as incorrect, so just ifdef it out.)
*/
#ifndef USE_FLOAT8_BYVAL /* controls int8 too */
if (fcinfo->context && IsA(fcinfo->context, AggState))
{
int64 *oldsum = (int64 *) PG_GETARG_POINTER(0);
@@ -2659,6 +2666,7 @@ int4_sum(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(oldsum);
}
else
#endif
{
int64 oldsum = PG_GETARG_INT64(0);

View File

@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/tsquery_gist.c,v 1.6 2008/04/20 09:17:57 teodor Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/tsquery_gist.c,v 1.7 2008/04/21 00:26:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -19,7 +19,8 @@
#include "tsearch/ts_type.h"
#include "tsearch/ts_utils.h"
#define GETENTRY(vec,pos) ((TSQuerySign *) DatumGetPointer((vec)->vector[(pos)].key))
#define GETENTRY(vec,pos) DatumGetTSQuerySign((vec)->vector[pos].key)
Datum
gtsquery_compress(PG_FUNCTION_ARGS)
@@ -29,12 +30,12 @@ gtsquery_compress(PG_FUNCTION_ARGS)
if (entry->leafkey)
{
TSQuerySign *sign = (TSQuerySign *) palloc(sizeof(TSQuerySign));
TSQuerySign sign;
retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
*sign = makeTSQuerySign(DatumGetTSQuery(entry->key));
sign = makeTSQuerySign(DatumGetTSQuery(entry->key));
gistentryinit(*retval, PointerGetDatum(sign),
gistentryinit(*retval, TSQuerySignGetDatum(sign),
entry->rel, entry->page,
entry->offset, FALSE);
}
@@ -56,7 +57,7 @@ gtsquery_consistent(PG_FUNCTION_ARGS)
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
/* Oid subtype = PG_GETARG_OID(3); */
bool *recheck = (bool *) PG_GETARG_POINTER(4);
TSQuerySign *key = (TSQuerySign *) DatumGetPointer(entry->key);
TSQuerySign key = DatumGetTSQuerySign(entry->key);
TSQuerySign sq = makeTSQuerySign(query);
bool retval;
@@ -67,15 +68,15 @@ gtsquery_consistent(PG_FUNCTION_ARGS)
{
case RTContainsStrategyNumber:
if (GIST_LEAF(entry))
retval = (*key & sq) == sq;
retval = (key & sq) == sq;
else
retval = (*key & sq) != 0;
retval = (key & sq) != 0;
break;
case RTContainedByStrategyNumber:
if (GIST_LEAF(entry))
retval = (*key & sq) == *key;
retval = (key & sq) == key;
else
retval = (*key & sq) != 0;
retval = (key & sq) != 0;
break;
default:
retval = FALSE;
@@ -88,27 +89,27 @@ gtsquery_union(PG_FUNCTION_ARGS)
{
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
int *size = (int *) PG_GETARG_POINTER(1);
TSQuerySign *sign = (TSQuerySign *) palloc(sizeof(TSQuerySign));
TSQuerySign sign;
int i;
memset(sign, 0, sizeof(TSQuerySign));
sign = 0;
for (i = 0; i < entryvec->n; i++)
*sign |= *GETENTRY(entryvec, i);
sign |= GETENTRY(entryvec, i);
*size = sizeof(TSQuerySign);
PG_RETURN_POINTER(sign);
PG_RETURN_TSQUERYSIGN(sign);
}
Datum
gtsquery_same(PG_FUNCTION_ARGS)
{
TSQuerySign *a = (TSQuerySign *) PG_GETARG_POINTER(0);
TSQuerySign *b = (TSQuerySign *) PG_GETARG_POINTER(1);
bool *result = (bool *) PG_GETARG_POINTER(2);
TSQuerySign a = PG_GETARG_TSQUERYSIGN(0);
TSQuerySign b = PG_GETARG_TSQUERYSIGN(1);
bool *result = (bool *) PG_GETARG_POINTER(2);
*result = (*a == *b) ? true : false;
*result = (a == b) ? true : false;
PG_RETURN_POINTER(result);
}
@@ -136,11 +137,11 @@ hemdist(TSQuerySign a, TSQuerySign b)
Datum
gtsquery_penalty(PG_FUNCTION_ARGS)
{
TSQuerySign *origval = (TSQuerySign *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
TSQuerySign *newval = (TSQuerySign *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
TSQuerySign origval = DatumGetTSQuerySign(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
TSQuerySign newval = DatumGetTSQuerySign(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
float *penalty = (float *) PG_GETARG_POINTER(2);
*penalty = hemdist(*origval, *newval);
*penalty = hemdist(origval, newval);
PG_RETURN_POINTER(penalty);
}
@@ -171,9 +172,8 @@ gtsquery_picksplit(PG_FUNCTION_ARGS)
OffsetNumber maxoff = entryvec->n - 2;
OffsetNumber k,
j;
TSQuerySign *datum_l,
*datum_r;
TSQuerySign datum_l,
datum_r;
int4 size_alpha,
size_beta;
int4 size_waste,
@@ -194,7 +194,7 @@ gtsquery_picksplit(PG_FUNCTION_ARGS)
for (k = FirstOffsetNumber; k < maxoff; k = OffsetNumberNext(k))
for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j))
{
size_waste = hemdist(*GETENTRY(entryvec, j), *GETENTRY(entryvec, k));
size_waste = hemdist(GETENTRY(entryvec, j), GETENTRY(entryvec, k));
if (size_waste > waste)
{
waste = size_waste;
@@ -210,19 +210,16 @@ gtsquery_picksplit(PG_FUNCTION_ARGS)
seed_2 = 2;
}
datum_l = (TSQuerySign *) palloc(sizeof(TSQuerySign));
*datum_l = *GETENTRY(entryvec, seed_1);
datum_r = (TSQuerySign *) palloc(sizeof(TSQuerySign));
*datum_r = *GETENTRY(entryvec, seed_2);
datum_l = GETENTRY(entryvec, seed_1);
datum_r = GETENTRY(entryvec, seed_2);
maxoff = OffsetNumberNext(maxoff);
costvector = (SPLITCOST *) palloc(sizeof(SPLITCOST) * maxoff);
for (j = FirstOffsetNumber; j <= maxoff; j = OffsetNumberNext(j))
{
costvector[j - 1].pos = j;
size_alpha = hemdist(*GETENTRY(entryvec, seed_1), *GETENTRY(entryvec, j));
size_beta = hemdist(*GETENTRY(entryvec, seed_2), *GETENTRY(entryvec, j));
size_alpha = hemdist(GETENTRY(entryvec, seed_1), GETENTRY(entryvec, j));
size_beta = hemdist(GETENTRY(entryvec, seed_2), GETENTRY(entryvec, j));
costvector[j - 1].cost = abs(size_alpha - size_beta);
}
qsort((void *) costvector, maxoff, sizeof(SPLITCOST), comparecost);
@@ -242,26 +239,26 @@ gtsquery_picksplit(PG_FUNCTION_ARGS)
v->spl_nright++;
continue;
}
size_alpha = hemdist(*datum_l, *GETENTRY(entryvec, j));
size_beta = hemdist(*datum_r, *GETENTRY(entryvec, j));
size_alpha = hemdist(datum_l, GETENTRY(entryvec, j));
size_beta = hemdist(datum_r, GETENTRY(entryvec, j));
if (size_alpha < size_beta + WISH_F(v->spl_nleft, v->spl_nright, 0.05))
{
*datum_l |= *GETENTRY(entryvec, j);
datum_l |= GETENTRY(entryvec, j);
*left++ = j;
v->spl_nleft++;
}
else
{
*datum_r |= *GETENTRY(entryvec, j);
datum_r |= GETENTRY(entryvec, j);
*right++ = j;
v->spl_nright++;
}
}
*right = *left = FirstOffsetNumber;
v->spl_ldatum = PointerGetDatum(datum_l);
v->spl_rdatum = PointerGetDatum(datum_r);
v->spl_ldatum = TSQuerySignGetDatum(datum_l);
v->spl_rdatum = TSQuerySignGetDatum(datum_r);
PG_RETURN_POINTER(v);
}

View File

@@ -1,4 +1,4 @@
$PostgreSQL: pgsql/src/backend/utils/fmgr/README,v 1.11 2008/04/18 18:43:09 alvherre Exp $
$PostgreSQL: pgsql/src/backend/utils/fmgr/README,v 1.12 2008/04/21 00:26:45 tgl Exp $
Function Manager
================
@@ -211,13 +211,11 @@ also amenable to machine processing --- for example, we could probably
write a script that scans code like this and extracts argument and result
type info for comparison to the pg_proc table.
For the standard data types float8 and int8, these macros should
hide the indirection and space allocation involved, so that the function's
code is not explicitly aware that these types are pass-by-reference. This
will offer a considerable gain in readability, and it also opens up the
opportunity to make these types be pass-by-value on machines where it's
feasible to do so. (For example, on an Alpha it's pretty silly to make int8
be pass-by-ref, since Datum is going to be 64 bits anyway.)
For the standard data types float4, float8, and int8, these macros should hide
whether the types are pass-by-value or pass-by reference, by incorporating
indirection and space allocation if needed. This will offer a considerable
gain in readability, and it also opens up the opportunity to make these types
be pass-by-value on machines where it's feasible to do so.
Here are the proposed macros and coding conventions:
@@ -247,20 +245,22 @@ which expands to
Argument values are ordinarily fetched using code like
int32 name = PG_GETARG_INT32(number);
For float8 and int8, the PG_GETARG macros will hide the pass-by-reference
nature of the data types; for example PG_GETARG_FLOAT8 expands to
For float4, float8, and int8, the PG_GETARG macros will hide whether the
types are pass-by-value or pass-by-reference. For example, if float8 is
pass-by-reference then PG_GETARG_FLOAT8 expands to
(* (float8 *) DatumGetPointer(fcinfo->arg[number]))
and would typically be called like this:
float8 arg = PG_GETARG_FLOAT8(0);
Note that "float8" is the recommended typedef to use, not "float64data", and
the macros are named accordingly. But 64-bit ints should be declared as
"int64".
For what are now historical reasons, the float-related typedefs and macros
express the type width in bytes (4 or 8), whereas we prefer to label the
widths of integer types in bits.
Non-null values are returned with a PG_RETURN_XXX macro of the appropriate
type. For example, PG_RETURN_INT32 expands to
return Int32GetDatum(x)
PG_RETURN_FLOAT8 and PG_RETURN_INT64 hide the pass-by-reference nature of
their datatypes.
PG_RETURN_FLOAT4, PG_RETURN_FLOAT8, and PG_RETURN_INT64 hide whether their
data types are pass-by-value or pass-by-reference, by doing a palloc if
needed.
fmgr.h will provide PG_GETARG and PG_RETURN macros for all the basic data
types. Modules or header files that define specialized SQL datatypes
@@ -333,9 +333,8 @@ Again, this style of coding does not allow for expressing NULL inputs
or receiving a NULL result.
As with the callee-side situation, I propose adding argument conversion
macros that hide the pass-by-reference nature of int8, and
float8, with an eye to making those types relatively painless to convert
to pass-by-value.
macros that hide whether int8, float4, and float8 are pass-by-value or
pass-by-reference.
The existing helper functions fmgr(), fmgr_c(), etc will be left in
place until all uses of them are gone. Of course their internals will

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.116 2008/04/18 18:43:09 alvherre Exp $
* $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.117 2008/04/21 00:26:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2023,17 +2023,23 @@ fmgr(Oid procedureId,...)
/*-------------------------------------------------------------------------
* Support routines for standard pass-by-reference datatypes
* Support routines for standard maybe-pass-by-reference datatypes
*
* Note: at some point, at least on some platforms, these might become
* pass-by-value types. Obviously Datum must be >= 8 bytes to allow
* int64 or float8 to be pass-by-value. I think that Float4GetDatum
* and Float8GetDatum will need to be out-of-line routines anyway,
* since just casting from float to Datum will not do the right thing;
* some kind of trick with pointer-casting or a union will be needed.
* int8, float4, and float8 can be passed by value if Datum is wide enough.
* (For backwards-compatibility reasons, we allow pass-by-ref to be chosen
* at compile time even if pass-by-val is possible.) For the float types,
* we need a support routine even if we are passing by value, because many
* machines pass int and float function parameters/results differently;
* so we need to play weird games with unions.
*
* Note: there is only one switch controlling the pass-by-value option for
* both int8 and float8; this is to avoid making things unduly complicated
* for the timestamp types, which might have either representation.
*-------------------------------------------------------------------------
*/
#ifndef USE_FLOAT8_BYVAL /* controls int8 too */
Datum
Int64GetDatum(int64 X)
{
@@ -2057,9 +2063,12 @@ Int64GetDatum(int64 X)
#endif /* INT64_IS_BUSTED */
}
#endif /* USE_FLOAT8_BYVAL */
Datum
Float4GetDatum(float4 X)
{
#ifdef USE_FLOAT4_BYVAL
union {
float4 value;
int32 retval;
@@ -2067,8 +2076,16 @@ Float4GetDatum(float4 X)
myunion.value = X;
return SET_4_BYTES(myunion.retval);
#else
float4 *retval = (float4 *) palloc(sizeof(float4));
*retval = X;
return PointerGetDatum(retval);
#endif
}
#ifdef USE_FLOAT4_BYVAL
float4
DatumGetFloat4(Datum X)
{
@@ -2081,15 +2098,44 @@ DatumGetFloat4(Datum X)
return myunion.retval;
}
#endif /* USE_FLOAT4_BYVAL */
Datum
Float8GetDatum(float8 X)
{
#ifdef USE_FLOAT8_BYVAL
union {
float8 value;
int64 retval;
} myunion;
myunion.value = X;
return SET_8_BYTES(myunion.retval);
#else
float8 *retval = (float8 *) palloc(sizeof(float8));
*retval = X;
return PointerGetDatum(retval);
#endif
}
#ifdef USE_FLOAT8_BYVAL
float8
DatumGetFloat8(Datum X)
{
union {
int64 value;
float8 retval;
} myunion;
myunion.value = GET_8_BYTES(X);
return myunion.retval;
}
#endif /* USE_FLOAT8_BYVAL */
/*-------------------------------------------------------------------------
* Support routines for toastable datatypes
*-------------------------------------------------------------------------

View File

@@ -23,7 +23,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/backend/utils/init/flatfiles.c,v 1.32 2008/03/26 21:10:39 alvherre Exp $
* $PostgreSQL: pgsql/src/backend/utils/init/flatfiles.c,v 1.33 2008/04/21 00:26:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -483,13 +483,14 @@ write_auth_file(Relation rel_authid, Relation rel_authmem)
}
else
{
/*
* rolvaliduntil is timestamptz, which we assume is double
* alignment and pass-by-reference.
*/
TimestampTz *rvup;
/* Assume timestamptz has double alignment */
off = att_align_nominal(off, 'd');
datum = PointerGetDatum(tp + off);
auth_info[curr_role].rolvaliduntil = DatumGetCString(DirectFunctionCall1(timestamptz_out, datum));
rvup = (TimestampTz *) (tp + off);
auth_info[curr_role].rolvaliduntil =
DatumGetCString(DirectFunctionCall1(timestamptz_out,
TimestampTzGetDatum(*rvup)));
}
/*