diff options
| author | Tom Lane <tgl@sss.pgh.pa.us> | 2011-09-07 17:06:26 -0400 | 
|---|---|---|
| committer | Tom Lane <tgl@sss.pgh.pa.us> | 2011-09-07 17:06:26 -0400 | 
| commit | 6e7a3c364bf5df266bb7000ead399e779410962c (patch) | |
| tree | 7d8587c8798bebccfc9c4844e45daa2597e4398b /src/backend/utils/adt/formatting.c | |
| parent | c3106a340f3177105b80a0a6e878eba1986ae9fe (diff) | |
Fix corner case bug in numeric to_char().
Trailing-zero stripping applied by the FM specifier could strip zeroes
to the left of the decimal point, for a format with no digit positions
after the decimal point (such as "FM999.").
Reported and diagnosed by Marti Raudsepp, though I didn't use his patch.
Diffstat (limited to 'src/backend/utils/adt/formatting.c')
| -rw-r--r-- | src/backend/utils/adt/formatting.c | 27 | 
1 files changed, 20 insertions, 7 deletions
| diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c index 08ddab214d3..d86e1140ce7 100644 --- a/src/backend/utils/adt/formatting.c +++ b/src/backend/utils/adt/formatting.c @@ -3673,6 +3673,9 @@ NUM_prepare_locale(NUMProc *Np)  /* ----------   * Return pointer of last relevant number after decimal point   *	12.0500 --> last relevant is '5' + *	12.0000 --> last relevant is '.' + * If there is no decimal point, return NULL (which will result in same + * behavior as if FM hadn't been specified).   * ----------   */  static char * @@ -3686,7 +3689,8 @@ get_last_relevant_decnum(char *num)  #endif  	if (!p) -		p = num; +		return NULL; +  	result = p;  	while (*(++p)) @@ -4223,13 +4227,22 @@ NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number,  	{  		Np->num_pre = plen; -		if (IS_FILLMODE(Np->Num)) +		if (IS_FILLMODE(Np->Num) && IS_DECIMAL(Np->Num))  		{ -			if (IS_DECIMAL(Np->Num)) -				Np->last_relevant = get_last_relevant_decnum( -															 Np->number + -									 ((Np->Num->zero_end - Np->num_pre > 0) ? -									  Np->Num->zero_end - Np->num_pre : 0)); +			Np->last_relevant = get_last_relevant_decnum(Np->number); + +			/* +			 * If any '0' specifiers are present, make sure we don't strip +			 * those digits. +			 */ +			if (Np->last_relevant && Np->Num->zero_end > Np->num_pre) +			{ +				char   *last_zero; + +				last_zero = Np->number + (Np->Num->zero_end - Np->num_pre); +				if (Np->last_relevant < last_zero) +					Np->last_relevant = last_zero; +			}  		}  		if (Np->sign_wrote == FALSE && Np->num_pre == 0) | 
