mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	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.
This commit is contained in:
		@@ -3902,6 +3902,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 *
 | 
			
		||||
@@ -3915,7 +3918,8 @@ get_last_relevant_decnum(char *num)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	if (!p)
 | 
			
		||||
		p = num;
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	result = p;
 | 
			
		||||
 | 
			
		||||
	while (*(++p))
 | 
			
		||||
@@ -4452,13 +4456,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)
 | 
			
		||||
 
 | 
			
		||||
@@ -1154,6 +1154,24 @@ SELECT '' AS to_char_23, to_char(val, '9.999EEEE')				FROM num_data;
 | 
			
		||||
            | -2.493e+07
 | 
			
		||||
(10 rows)
 | 
			
		||||
 | 
			
		||||
SELECT '' AS to_char_24, to_char('100'::numeric, 'FM999.9');
 | 
			
		||||
 to_char_24 | to_char 
 | 
			
		||||
------------+---------
 | 
			
		||||
            | 100.
 | 
			
		||||
(1 row)
 | 
			
		||||
 | 
			
		||||
SELECT '' AS to_char_25, to_char('100'::numeric, 'FM999.');
 | 
			
		||||
 to_char_25 | to_char 
 | 
			
		||||
------------+---------
 | 
			
		||||
            | 100
 | 
			
		||||
(1 row)
 | 
			
		||||
 | 
			
		||||
SELECT '' AS to_char_26, to_char('100'::numeric, 'FM999');
 | 
			
		||||
 to_char_26 | to_char 
 | 
			
		||||
------------+---------
 | 
			
		||||
            | 100
 | 
			
		||||
(1 row)
 | 
			
		||||
 | 
			
		||||
-- TO_NUMBER()
 | 
			
		||||
--
 | 
			
		||||
SELECT '' AS to_number_1,  to_number('-34,338,492', '99G999G999');
 | 
			
		||||
 
 | 
			
		||||
@@ -764,6 +764,10 @@ SELECT '' AS to_char_21, to_char(val, '999999SG9999999999')			FROM num_data;
 | 
			
		||||
SELECT '' AS to_char_22, to_char(val, 'FM9999999999999999.999999999999999')	FROM num_data;
 | 
			
		||||
SELECT '' AS to_char_23, to_char(val, '9.999EEEE')				FROM num_data;
 | 
			
		||||
 | 
			
		||||
SELECT '' AS to_char_24, to_char('100'::numeric, 'FM999.9');
 | 
			
		||||
SELECT '' AS to_char_25, to_char('100'::numeric, 'FM999.');
 | 
			
		||||
SELECT '' AS to_char_26, to_char('100'::numeric, 'FM999');
 | 
			
		||||
 | 
			
		||||
-- TO_NUMBER()
 | 
			
		||||
--
 | 
			
		||||
SELECT '' AS to_number_1,  to_number('-34,338,492', '99G999G999');
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user