Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit4778a0b

Browse files
committed
Fix psql's code for locale-aware formatting of numeric output.
This code did the wrong thing entirely for numbers with an exponentbut no decimal point (e.g., '1e6'), as reported by Jeff Janes inbug #13636. More generally, it made lots of unverified assumptionsabout what the input string could possibly look like. Rearrange sothat it only fools with leading digits that it's directly verifiedare there, and an immediately adjacent decimal point. While at it,get rid of some useless inefficiencies, like converting the groupingcount string to integer over and over (and over).This has been broken for a long time, so back-patch to all supportedbranches.
1 parent39df0f1 commit4778a0b

File tree

1 file changed

+47
-56
lines changed

1 file changed

+47
-56
lines changed

‎src/bin/psql/print.c

Lines changed: 47 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,9 @@
3939
*/
4040
volatileboolcancel_pressed= false;
4141

42+
/* info for locale-aware numeric formatting; set up by setDecimalLocale() */
4243
staticchar*decimal_point;
43-
staticchar*grouping;
44+
staticintgroupdigits;
4445
staticchar*thousands_sep;
4546

4647
staticchardefault_footer[100];
@@ -196,98 +197,87 @@ static void IsPagerNeeded(const printTableContent *cont, const int extra_lines,
196197
staticvoidprint_aligned_vertical(constprintTableContent*cont,FILE*fout);
197198

198199

200+
/* Count number of digits in integral part of number */
199201
staticint
200202
integer_digits(constchar*my_str)
201203
{
202-
intfrac_len;
203-
204-
if (my_str[0]=='-')
204+
/* ignoring any sign ... */
205+
if (my_str[0]=='-'||my_str[0]=='+')
205206
my_str++;
206-
207-
frac_len=strchr(my_str,'.') ?strlen(strchr(my_str,'.')) :0;
208-
209-
returnstrlen(my_str)-frac_len;
207+
/* ... count initial integral digits */
208+
returnstrspn(my_str,"0123456789");
210209
}
211210

212-
/*Return additional length required for locale-aware numeric output */
211+
/*Compute additional length required for locale-aware numeric output */
213212
staticint
214213
additional_numeric_locale_len(constchar*my_str)
215214
{
216215
intint_len=integer_digits(my_str),
217216
len=0;
218-
intgroupdigits=atoi(grouping);
219217

220-
if (int_len>0)
221-
/* Don't count a leading separator */
222-
len= (int_len /groupdigits- (int_len %groupdigits==0))*
223-
strlen(thousands_sep);
218+
/* Account for added thousands_sep instances */
219+
if (int_len>groupdigits)
220+
len+= ((int_len-1) /groupdigits)*strlen(thousands_sep);
224221

222+
/* Account for possible additional length of decimal_point */
225223
if (strchr(my_str,'.')!=NULL)
226-
len+=strlen(decimal_point)-strlen(".");
224+
len+=strlen(decimal_point)-1;
227225

228226
returnlen;
229227
}
230228

231-
staticint
232-
strlen_with_numeric_locale(constchar*my_str)
233-
{
234-
returnstrlen(my_str)+additional_numeric_locale_len(my_str);
235-
}
236-
237229
/*
238230
* Returns the appropriately formatted string in a new allocated block,
239231
* caller must free
240232
*/
241233
staticchar*
242234
format_numeric_locale(constchar*my_str)
243235
{
236+
intnew_len=strlen(my_str)+additional_numeric_locale_len(my_str);
237+
char*new_str=pg_malloc(new_len+1);
238+
intint_len=integer_digits(my_str);
244239
inti,
245-
j,
246-
int_len=integer_digits(my_str),
247240
leading_digits;
248-
intgroupdigits=atoi(grouping);
249-
intnew_str_start=0;
250-
char*new_str=pg_malloc(strlen_with_numeric_locale(my_str)+1);
241+
intnew_str_pos=0;
251242

252-
leading_digits= (int_len %groupdigits!=0) ?
253-
int_len %groupdigits :groupdigits;
243+
/* number of digits in first thousands group */
244+
leading_digits=int_len %groupdigits;
245+
if (leading_digits==0)
246+
leading_digits=groupdigits;
254247

255-
if (my_str[0]=='-')/*skip oversign, affects grouping
256-
* calculations */
248+
/*processsign */
249+
if (my_str[0]=='-'||my_str[0]=='+')
257250
{
258-
new_str[0]=my_str[0];
251+
new_str[new_str_pos++]=my_str[0];
259252
my_str++;
260-
new_str_start=1;
261253
}
262254

263-
for (i=0,j=new_str_start;;i++,j++)
255+
/* process integer part of number */
256+
for (i=0;i<int_len;i++)
264257
{
265-
/*Hit decimal point? */
266-
if (my_str[i]=='.')
258+
/*Time to insert separator? */
259+
if (i>0&&--leading_digits==0)
267260
{
268-
strcpy(&new_str[j],decimal_point);
269-
j+=strlen(decimal_point);
270-
/* add fractional part */
271-
strcpy(&new_str[j],&my_str[i]+1);
272-
break;
261+
strcpy(&new_str[new_str_pos],thousands_sep);
262+
new_str_pos+=strlen(thousands_sep);
263+
leading_digits=groupdigits;
273264
}
265+
new_str[new_str_pos++]=my_str[i];
266+
}
274267

275-
/* End of string? */
276-
if (my_str[i]=='\0')
277-
{
278-
new_str[j]='\0';
279-
break;
280-
}
268+
/* handle decimal point if any */
269+
if (my_str[i]=='.')
270+
{
271+
strcpy(&new_str[new_str_pos],decimal_point);
272+
new_str_pos+=strlen(decimal_point);
273+
i++;
274+
}
281275

282-
/* Add separator? */
283-
if (i!=0&& (i-leading_digits) %groupdigits==0)
284-
{
285-
strcpy(&new_str[j],thousands_sep);
286-
j+=strlen(thousands_sep);
287-
}
276+
/* copy the rest (fractional digits and/or exponent, and \0 terminator) */
277+
strcpy(&new_str[new_str_pos],&my_str[i]);
288278

289-
new_str[j]=my_str[i];
290-
}
279+
/* assert we didn't underestimate new_len (an overestimate is OK) */
280+
Assert(strlen(new_str) <=new_len);
291281

292282
returnnew_str;
293283
}
@@ -3241,10 +3231,11 @@ setDecimalLocale(void)
32413231
decimal_point=pg_strdup(extlconv->decimal_point);
32423232
else
32433233
decimal_point=".";/* SQL output standard */
3234+
32443235
if (*extlconv->grouping&&atoi(extlconv->grouping)>0)
3245-
grouping=pg_strdup(extlconv->grouping);
3236+
groupdigits=atoi(extlconv->grouping);
32463237
else
3247-
grouping="3";/* most common */
3238+
groupdigits=3;/* most common */
32483239

32493240
/* similar code exists in formatting.c */
32503241
if (*extlconv->thousands_sep)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp