@ -276,6 +276,16 @@ static NumericDigit const_two_data[1] = {2};
static NumericVar const_two =
{ 1 , 0 , NUMERIC_POS , 0 , NULL , const_two_data } ;
# if DEC_DIGITS == 4 || DEC_DIGITS == 2
static NumericDigit const_ten_data [ 1 ] = { 10 } ;
static NumericVar const_ten =
{ 1 , 0 , NUMERIC_POS , 0 , NULL , const_ten_data } ;
# elif DEC_DIGITS == 1
static NumericDigit const_ten_data [ 1 ] = { 1 } ;
static NumericVar const_ten =
{ 1 , 1 , NUMERIC_POS , 0 , NULL , const_ten_data } ;
# endif
# if DEC_DIGITS == 4
static NumericDigit const_zero_point_five_data [ 1 ] = { 5000 } ;
# elif DEC_DIGITS == 2
@ -367,8 +377,9 @@ static void zero_var(NumericVar *var);
static const char * set_var_from_str ( const char * str , const char * cp ,
NumericVar * dest ) ;
static void set_var_from_num ( Numeric value , NumericVar * dest ) ;
static void init_var_from_num ( Numeric num , NumericVar * dest ) ;
static void set_var_from_var ( NumericVar * value , NumericVar * dest ) ;
static char * get_str_from_var ( NumericVar * var , int dscale ) ;
static char * get_str_from_var ( NumericVar * var ) ;
static char * get_str_from_var_sci ( NumericVar * var , int rscale ) ;
static Numeric make_result ( NumericVar * var ) ;
@ -533,18 +544,10 @@ numeric_out(PG_FUNCTION_ARGS)
/*
* Get the number in the variable format .
*
* Even if we didn ' t need to change format , we ' d still need to copy the
* value to have a modifiable copy for rounding . set_var_from_num ( ) also
* guarantees there is extra digit space in case we produce a carry out
* from rounding .
*/
init_var ( & x ) ;
set_var_from_num ( num , & x ) ;
init_var_from_num ( num , & x ) ;
str = get_str_from_var ( & x , x . dscale ) ;
free_var ( & x ) ;
str = get_str_from_var ( & x ) ;
PG_RETURN_CSTRING ( str ) ;
}
@ -616,12 +619,10 @@ numeric_out_sci(Numeric num, int scale)
if ( NUMERIC_IS_NAN ( num ) )
return pstrdup ( " NaN " ) ;
init_var ( & x ) ;
set_var_from_num ( num , & x ) ;
init_var_from_num ( num , & x ) ;
str = get_str_from_var_sci ( & x , scale ) ;
free_var ( & x ) ;
return str ;
}
@ -695,8 +696,7 @@ numeric_send(PG_FUNCTION_ARGS)
StringInfoData buf ;
int i ;
init_var ( & x ) ;
set_var_from_num ( num , & x ) ;
init_var_from_num ( num , & x ) ;
pq_begintypsend ( & buf ) ;
@ -707,8 +707,6 @@ numeric_send(PG_FUNCTION_ARGS)
for ( i = 0 ; i < x . ndigits ; i + + )
pq_sendint ( & buf , x . digits [ i ] , sizeof ( NumericDigit ) ) ;
free_var ( & x ) ;
PG_RETURN_BYTEA_P ( pq_endtypsend ( & buf ) ) ;
}
@ -1150,9 +1148,7 @@ numeric_ceil(PG_FUNCTION_ARGS)
if ( NUMERIC_IS_NAN ( num ) )
PG_RETURN_NUMERIC ( make_result ( & const_nan ) ) ;
init_var ( & result ) ;
set_var_from_num ( num , & result ) ;
init_var_from_num ( num , & result ) ;
ceil_var ( & result , & result ) ;
res = make_result ( & result ) ;
@ -1177,9 +1173,7 @@ numeric_floor(PG_FUNCTION_ARGS)
if ( NUMERIC_IS_NAN ( num ) )
PG_RETURN_NUMERIC ( make_result ( & const_nan ) ) ;
init_var ( & result ) ;
set_var_from_num ( num , & result ) ;
init_var_from_num ( num , & result ) ;
floor_var ( & result , & result ) ;
res = make_result ( & result ) ;
@ -1282,13 +1276,9 @@ compute_bucket(Numeric operand, Numeric bound1, Numeric bound2,
NumericVar bound2_var ;
NumericVar operand_var ;
init_var ( & bound1_var ) ;
init_var ( & bound2_var ) ;
init_var ( & operand_var ) ;
set_var_from_num ( bound1 , & bound1_var ) ;
set_var_from_num ( bound2 , & bound2_var ) ;
set_var_from_num ( operand , & operand_var ) ;
init_var_from_num ( bound1 , & bound1_var ) ;
init_var_from_num ( bound2 , & bound2_var ) ;
init_var_from_num ( operand , & operand_var ) ;
if ( cmp_var ( & bound1_var , & bound2_var ) < 0 )
{
@ -1573,19 +1563,14 @@ numeric_add(PG_FUNCTION_ARGS)
/*
* Unpack the values , let add_var ( ) compute the result and return it .
*/
init_var ( & arg1 ) ;
init_var ( & arg2 ) ;
init_var ( & result ) ;
set_var_from_num ( num1 , & arg1 ) ;
set_var_from_num ( num2 , & arg2 ) ;
init_var_from_num ( num1 , & arg1 ) ;
init_var_from_num ( num2 , & arg2 ) ;
init_var ( & result ) ;
add_var ( & arg1 , & arg2 , & result ) ;
res = make_result ( & result ) ;
free_var ( & arg1 ) ;
free_var ( & arg2 ) ;
free_var ( & result ) ;
PG_RETURN_NUMERIC ( res ) ;
@ -1616,19 +1601,14 @@ numeric_sub(PG_FUNCTION_ARGS)
/*
* Unpack the values , let sub_var ( ) compute the result and return it .
*/
init_var ( & arg1 ) ;
init_var ( & arg2 ) ;
init_var ( & result ) ;
set_var_from_num ( num1 , & arg1 ) ;
set_var_from_num ( num2 , & arg2 ) ;
init_var_from_num ( num1 , & arg1 ) ;
init_var_from_num ( num2 , & arg2 ) ;
init_var ( & result ) ;
sub_var ( & arg1 , & arg2 , & result ) ;
res = make_result ( & result ) ;
free_var ( & arg1 ) ;
free_var ( & arg2 ) ;
free_var ( & result ) ;
PG_RETURN_NUMERIC ( res ) ;
@ -1663,19 +1643,14 @@ numeric_mul(PG_FUNCTION_ARGS)
* we request exact representation for the product ( rscale = sum ( dscale of
* arg1 , dscale of arg2 ) ) .
*/
init_var ( & arg1 ) ;
init_var ( & arg2 ) ;
init_var ( & result ) ;
set_var_from_num ( num1 , & arg1 ) ;
set_var_from_num ( num2 , & arg2 ) ;
init_var_from_num ( num1 , & arg1 ) ;
init_var_from_num ( num2 , & arg2 ) ;
init_var ( & result ) ;
mul_var ( & arg1 , & arg2 , & result , arg1 . dscale + arg2 . dscale ) ;
res = make_result ( & result ) ;
free_var ( & arg1 ) ;
free_var ( & arg2 ) ;
free_var ( & result ) ;
PG_RETURN_NUMERIC ( res ) ;
@ -1707,12 +1682,10 @@ numeric_div(PG_FUNCTION_ARGS)
/*
* Unpack the arguments
*/
init_var ( & arg1 ) ;
init_var ( & arg2 ) ;
init_var ( & result ) ;
init_var_from_num ( num1 , & arg1 ) ;
init_var_from_num ( num2 , & arg2 ) ;
set_var_from_num ( num1 , & arg1 ) ;
set_var_from_num ( num2 , & arg2 ) ;
init_var ( & result ) ;
/*
* Select scale for division result
@ -1726,8 +1699,6 @@ numeric_div(PG_FUNCTION_ARGS)
res = make_result ( & result ) ;
free_var ( & arg1 ) ;
free_var ( & arg2 ) ;
free_var ( & result ) ;
PG_RETURN_NUMERIC ( res ) ;
@ -1758,12 +1729,10 @@ numeric_div_trunc(PG_FUNCTION_ARGS)
/*
* Unpack the arguments
*/
init_var ( & arg1 ) ;
init_var ( & arg2 ) ;
init_var ( & result ) ;
init_var_from_num ( num1 , & arg1 ) ;
init_var_from_num ( num2 , & arg2 ) ;
set_var_from_num ( num1 , & arg1 ) ;
set_var_from_num ( num2 , & arg2 ) ;
init_var ( & result ) ;
/*
* Do the divide and return the result
@ -1772,8 +1741,6 @@ numeric_div_trunc(PG_FUNCTION_ARGS)
res = make_result ( & result ) ;
free_var ( & arg1 ) ;
free_var ( & arg2 ) ;
free_var ( & result ) ;
PG_RETURN_NUMERIC ( res ) ;
@ -1798,20 +1765,16 @@ numeric_mod(PG_FUNCTION_ARGS)
if ( NUMERIC_IS_NAN ( num1 ) | | NUMERIC_IS_NAN ( num2 ) )
PG_RETURN_NUMERIC ( make_result ( & const_nan ) ) ;
init_var ( & arg1 ) ;
init_var ( & arg2 ) ;
init_var ( & result ) ;
init_var_from_num ( num1 , & arg1 ) ;
init_var_from_num ( num2 , & arg2 ) ;
set_var_from_num ( num1 , & arg1 ) ;
set_var_from_num ( num2 , & arg2 ) ;
init_var ( & result ) ;
mod_var ( & arg1 , & arg2 , & result ) ;
res = make_result ( & result ) ;
free_var ( & result ) ;
free_var ( & arg2 ) ;
free_var ( & arg1 ) ;
PG_RETURN_NUMERIC ( res ) ;
}
@ -1838,9 +1801,7 @@ numeric_inc(PG_FUNCTION_ARGS)
/*
* Compute the result and return it
*/
init_var ( & arg ) ;
set_var_from_num ( num , & arg ) ;
init_var_from_num ( num , & arg ) ;
add_var ( & arg , & const_one , & arg ) ;
@ -1977,10 +1938,9 @@ numeric_sqrt(PG_FUNCTION_ARGS)
* to give at least NUMERIC_MIN_SIG_DIGITS significant digits ; but in any
* case not less than the input ' s dscale .
*/
init_var ( & arg ) ;
init_var ( & result ) ;
init_var_from_num ( num , & arg ) ;
set_var_from_num ( num , & arg ) ;
init_var ( & result ) ;
/* Assume the input was normalized, so arg.weight is accurate */
sweight = ( arg . weight + 1 ) * DEC_DIGITS / 2 - 1 ;
@ -1998,7 +1958,6 @@ numeric_sqrt(PG_FUNCTION_ARGS)
res = make_result ( & result ) ;
free_var ( & result ) ;
free_var ( & arg ) ;
PG_RETURN_NUMERIC ( res ) ;
}
@ -2030,10 +1989,9 @@ numeric_exp(PG_FUNCTION_ARGS)
* to give at least NUMERIC_MIN_SIG_DIGITS significant digits ; but in any
* case not less than the input ' s dscale .
*/
init_var ( & arg ) ;
init_var ( & result ) ;
init_var_from_num ( num , & arg ) ;
set_var_from_num ( num , & arg ) ;
init_var ( & result ) ;
/* convert input to float8, ignoring overflow */
val = numericvar_to_double_no_overflow ( & arg ) ;
@ -2061,7 +2019,6 @@ numeric_exp(PG_FUNCTION_ARGS)
res = make_result ( & result ) ;
free_var ( & result ) ;
free_var ( & arg ) ;
PG_RETURN_NUMERIC ( res ) ;
}
@ -2088,11 +2045,9 @@ numeric_ln(PG_FUNCTION_ARGS)
if ( NUMERIC_IS_NAN ( num ) )
PG_RETURN_NUMERIC ( make_result ( & const_nan ) ) ;
init_var ( & arg ) ;
init_var_from_num ( num , & arg ) ;
init_var ( & result ) ;
set_var_from_num ( num , & arg ) ;
/* Approx decimal digits before decimal point */
dec_digits = ( arg . weight + 1 ) * DEC_DIGITS ;
@ -2112,7 +2067,6 @@ numeric_ln(PG_FUNCTION_ARGS)
res = make_result ( & result ) ;
free_var ( & result ) ;
free_var ( & arg ) ;
PG_RETURN_NUMERIC ( res ) ;
}
@ -2142,13 +2096,10 @@ numeric_log(PG_FUNCTION_ARGS)
/*
* Initialize things
*/
init_var ( & arg1 ) ;
init_var ( & arg2 ) ;
init_var_from_num ( num1 , & arg1 ) ;
init_var_from_num ( num2 , & arg2 ) ;
init_var ( & result ) ;
set_var_from_num ( num1 , & arg1 ) ;
set_var_from_num ( num2 , & arg2 ) ;
/*
* Call log_var ( ) to compute and return the result ; note it handles scale
* selection itself .
@ -2158,8 +2109,6 @@ numeric_log(PG_FUNCTION_ARGS)
res = make_result ( & result ) ;
free_var ( & result ) ;
free_var ( & arg2 ) ;
free_var ( & arg1 ) ;
PG_RETURN_NUMERIC ( res ) ;
}
@ -2190,15 +2139,12 @@ numeric_power(PG_FUNCTION_ARGS)
/*
* Initialize things
*/
init_var ( & arg1 ) ;
init_var ( & arg2 ) ;
init_var ( & arg2_trunc ) ;
init_var ( & result ) ;
init_var_from_num ( num1 , & arg1 ) ;
init_var_from_num ( num2 , & arg2 ) ;
set_var_from_num ( num1 , & arg1 ) ;
set_var_from_num ( num2 , & arg2 ) ;
set_var_from_var ( & arg2 , & arg2_trunc ) ;
trunc_var ( & arg2_trunc , 0 ) ;
/*
@ -2227,9 +2173,7 @@ numeric_power(PG_FUNCTION_ARGS)
res = make_result ( & result ) ;
free_var ( & result ) ;
free_var ( & arg2 ) ;
free_var ( & arg2_trunc ) ;
free_var ( & arg1 ) ;
PG_RETURN_NUMERIC ( res ) ;
}
@ -2276,10 +2220,8 @@ numeric_int4(PG_FUNCTION_ARGS)
errmsg ( " cannot convert NaN to integer " ) ) ) ;
/* Convert to variable format, then convert to int4 */
init_var ( & x ) ;
set_var_from_num ( num , & x ) ;
init_var_from_num ( num , & x ) ;
result = numericvar_to_int4 ( & x ) ;
free_var ( & x ) ;
PG_RETURN_INT32 ( result ) ;
}
@ -2344,16 +2286,13 @@ numeric_int8(PG_FUNCTION_ARGS)
errmsg ( " cannot convert NaN to bigint " ) ) ) ;
/* Convert to variable format and thence to int8 */
init_var ( & x ) ;
set_var_from_num ( num , & x ) ;
init_var_from_num ( num , & x ) ;
if ( ! numericvar_to_int8 ( & x , & result ) )
ereport ( ERROR ,
( errcode ( ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ) ,
errmsg ( " bigint out of range " ) ) ) ;
free_var ( & x ) ;
PG_RETURN_INT64 ( result ) ;
}
@ -2392,16 +2331,13 @@ numeric_int2(PG_FUNCTION_ARGS)
errmsg ( " cannot convert NaN to smallint " ) ) ) ;
/* Convert to variable format and thence to int8 */
init_var ( & x ) ;
set_var_from_num ( num , & x ) ;
init_var_from_num ( num , & x ) ;
if ( ! numericvar_to_int8 ( & x , & val ) )
ereport ( ERROR ,
( errcode ( ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ) ,
errmsg ( " smallint out of range " ) ) ) ;
free_var ( & x ) ;
/* Down-convert to int2 */
result = ( int16 ) val ;
@ -2763,8 +2699,7 @@ numeric_stddev_internal(ArrayType *transarray,
if ( NUMERIC_IS_NAN ( N ) | | NUMERIC_IS_NAN ( sumX ) | | NUMERIC_IS_NAN ( sumX2 ) )
return make_result ( & const_nan ) ;
init_var ( & vN ) ;
set_var_from_num ( N , & vN ) ;
init_var_from_num ( N , & vN ) ;
/*
* Sample stddev and variance are undefined when N < = 1 ; population stddev
@ -2777,7 +2712,6 @@ numeric_stddev_internal(ArrayType *transarray,
if ( cmp_var ( & vN , comp ) < = 0 )
{
free_var ( & vN ) ;
* is_null = true ;
return NULL ;
}
@ -2785,10 +2719,8 @@ numeric_stddev_internal(ArrayType *transarray,
init_var ( & vNminus1 ) ;
sub_var ( & vN , & const_one , & vNminus1 ) ;
init_var ( & vsumX ) ;
set_var_from_num ( sumX , & vsumX ) ;
init_var ( & vsumX2 ) ;
set_var_from_num ( sumX2 , & vsumX2 ) ;
init_var_from_num ( sumX , & vsumX ) ;
init_var_from_num ( sumX2 , & vsumX2 ) ;
/* compute rscale for mul_var calls */
rscale = vsumX . dscale * 2 ;
@ -2816,7 +2748,6 @@ numeric_stddev_internal(ArrayType *transarray,
res = make_result ( & vsumX ) ;
}
free_var ( & vN ) ;
free_var ( & vNminus1 ) ;
free_var ( & vsumX ) ;
free_var ( & vsumX2 ) ;
@ -3449,6 +3380,32 @@ set_var_from_num(Numeric num, NumericVar *dest)
}
/*
* init_var_from_num ( ) -
*
* Initialize a variable from packed db format . The digits array is not
* copied , which saves some cycles when the resulting var is not modified .
* Also , there ' s no need to call free_var ( ) , as long as you don ' t assign any
* other value to it ( with set_var_ * functions , or by using the var as the
* destination of a function like add_var ( ) )
*
* CAUTION : Do not modify the digits buffer of a var initialized with this
* function , e . g by calling round_var ( ) or trunc_var ( ) , as the changes will
* propagate to the original Numeric ! It ' s OK to use it as the destination
* argument of one of the calculational functions , though .
*/
static void
init_var_from_num ( Numeric num , NumericVar * dest )
{
dest - > ndigits = NUMERIC_NDIGITS ( num ) ;
dest - > weight = NUMERIC_WEIGHT ( num ) ;
dest - > sign = NUMERIC_SIGN ( num ) ;
dest - > dscale = NUMERIC_DSCALE ( num ) ;
dest - > digits = NUMERIC_DIGITS ( num ) ;
dest - > buf = NULL ; /* digits array is not palloc'd */
}
/*
* set_var_from_var ( ) -
*
@ -3475,12 +3432,13 @@ set_var_from_var(NumericVar *value, NumericVar *dest)
* get_str_from_var ( ) -
*
* Convert a var to text representation ( guts of numeric_out ) .
* CAUTION : var ' s contents may be modified by rounding !
* The var is displayed to the number of digits indicated by its dscale .
* Returns a palloc ' d string .
*/
static char *
get_str_from_var ( NumericVar * var , int dscale )
get_str_from_var ( NumericVar * var )
{
int dscale ;
char * str ;
char * cp ;
char * endcp ;
@ -3492,13 +3450,7 @@ get_str_from_var(NumericVar *var, int dscale)
NumericDigit d1 ;
# endif
if ( dscale < 0 )
dscale = 0 ;
/*
* Check if we must round up before printing the value and do so .
*/
round_var ( var , dscale ) ;
dscale = var - > dscale ;
/*
* Allocate space for the result .
@ -3634,8 +3586,6 @@ get_str_from_var(NumericVar *var, int dscale)
* rscale is the number of decimal digits desired after the decimal point in
* the output , negative values will be treated as meaning zero .
*
* CAUTION : var ' s contents may be modified by rounding !
*
* Returns a palloc ' d string .
*/
static char *
@ -3694,10 +3644,9 @@ get_str_from_var_sci(NumericVar *var, int rscale)
init_var ( & denominator ) ;
init_var ( & significand ) ;
int8_to_numericvar ( ( int64 ) 10 , & denominator ) ;
power_var_int ( & denominator , exponent , & denominator , denom_scale ) ;
power_var_int ( & const_ten , exponent , & denominator , denom_scale ) ;
div_var ( var , & denominator , & significand , rscale , true ) ;
sig_out = get_str_from_var ( & significand , rscale ) ;
sig_out = get_str_from_var ( & significand ) ;
free_var ( & denominator ) ;
free_var ( & significand ) ;
@ -3886,8 +3835,6 @@ apply_typmod(NumericVar *var, int32 typmod)
* Convert numeric to int8 , rounding if needed .
*
* If overflow , return FALSE ( no error is raised ) . Return TRUE if okay .
*
* CAUTION : var ' s contents may be modified by rounding !
*/
static bool
numericvar_to_int8 ( NumericVar * var , int64 * result )
@ -3899,16 +3846,20 @@ numericvar_to_int8(NumericVar *var, int64 *result)
int64 val ,
oldval ;
bool neg ;
NumericVar rounded ;
/* Round to nearest integer */
round_var ( var , 0 ) ;
init_var ( & rounded ) ;
set_var_from_var ( var , & rounded ) ;
round_var ( & rounded , 0 ) ;
/* Check for zero input */
strip_var ( var ) ;
ndigits = var - > ndigits ;
strip_var ( & rounded ) ;
ndigits = rounded . ndigits ;
if ( ndigits = = 0 )
{
* result = 0 ;
free_var ( & rounded ) ;
return true ;
}
@ -3916,12 +3867,12 @@ numericvar_to_int8(NumericVar *var, int64 *result)
* For input like 10000000000 , we must treat stripped digits as real . So
* the loop assumes there are weight + 1 digits before the decimal point .
*/
weight = var - > weight ;
weight = rounded . weight ;
Assert ( weight > = 0 & & ndigits < = weight + 1 ) ;
/* Construct the result */
digits = var - > digits ;
neg = ( var - > sign = = NUMERIC_NEG ) ;
digits = rounded . digits ;
neg = ( rounded . sign = = NUMERIC_NEG ) ;
val = digits [ 0 ] ;
for ( i = 1 ; i < = weight ; i + + )
{
@ -3940,10 +3891,15 @@ numericvar_to_int8(NumericVar *var, int64 *result)
if ( ( val / NBASE ) ! = oldval ) /* possible overflow? */
{
if ( ! neg | | ( - val ) ! = val | | val = = 0 | | oldval < 0 )
{
free_var ( & rounded ) ;
return false ;
}
}
}
free_var ( & rounded ) ;
* result = neg ? - val : val ;
return true ;
}
@ -4030,7 +3986,7 @@ numericvar_to_double_no_overflow(NumericVar *var)
double val ;
char * endptr ;
tmp = get_str_from_var ( var , var - > dscale ) ;
tmp = get_str_from_var ( var ) ;
/* unlike float8in, we ignore ERANGE from strtod */
val = strtod ( tmp , & endptr ) ;
@ -5597,13 +5553,9 @@ power_var(NumericVar *base, NumericVar *exp, NumericVar *result)
if ( exp - > ndigits = = 0 | | exp - > ndigits < = exp - > weight + 1 )
{
/* exact integer, but does it fit in int? */
NumericVar x ;
int64 expval64 ;
/* must copy because numericvar_to_int8() scribbles on input */
init_var ( & x ) ;
set_var_from_var ( exp , & x ) ;
if ( numericvar_to_int8 ( & x , & expval64 ) )
if ( numericvar_to_int8 ( exp , & expval64 ) )
{
int expval = ( int ) expval64 ;
@ -5617,12 +5569,9 @@ power_var(NumericVar *base, NumericVar *exp, NumericVar *result)
rscale = Min ( rscale , NUMERIC_MAX_DISPLAY_SCALE ) ;
power_var_int ( base , expval , result , rscale ) ;
free_var ( & x ) ;
return ;
}
}
free_var ( & x ) ;
}
/*