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

Commitc2d6ef1

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 parent078d471 commitc2d6ef1

File tree

1 file changed

+45
-58
lines changed

1 file changed

+45
-58
lines changed

‎src/bin/psql/print.c

Lines changed: 45 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,9 @@
4040
*/
4141
volatileboolcancel_pressed= false;
4242

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

4748
/* Line style control structures */
@@ -154,100 +155,85 @@ pg_local_calloc(int count, size_t size)
154155
returntmp;
155156
}
156157

158+
/* Count number of digits in integral part of number */
157159
staticint
158160
integer_digits(constchar*my_str)
159161
{
160-
intfrac_len;
161-
162-
if (my_str[0]=='-')
162+
/* ignoring any sign ... */
163+
if (my_str[0]=='-'||my_str[0]=='+')
163164
my_str++;
164-
165-
frac_len=strchr(my_str,'.') ?strlen(strchr(my_str,'.')) :0;
166-
167-
returnstrlen(my_str)-frac_len;
165+
/* ... count initial integral digits */
166+
returnstrspn(my_str,"0123456789");
168167
}
169168

170-
/*Return additional length required for locale-aware numeric output */
169+
/*Compute additional length required for locale-aware numeric output */
171170
staticint
172171
additional_numeric_locale_len(constchar*my_str)
173172
{
174173
intint_len=integer_digits(my_str),
175174
len=0;
176-
intgroupdigits=atoi(grouping);
177175

178-
if (int_len>0)
179-
/* Don't count a leading separator */
180-
len= (int_len /groupdigits- (int_len %groupdigits==0))*
181-
strlen(thousands_sep);
176+
/* Account for added thousands_sep instances */
177+
if (int_len>groupdigits)
178+
len+= ((int_len-1) /groupdigits)*strlen(thousands_sep);
182179

180+
/* Account for possible additional length of decimal_point */
183181
if (strchr(my_str,'.')!=NULL)
184-
len+=strlen(decimal_point)-strlen(".");
182+
len+=strlen(decimal_point)-1;
185183

186184
returnlen;
187185
}
188186

189-
staticint
190-
strlen_with_numeric_locale(constchar*my_str)
191-
{
192-
returnstrlen(my_str)+additional_numeric_locale_len(my_str);
193-
}
194-
195187
/*
196188
* Returns the appropriately formatted string in a new allocated block,
197189
* caller must free
198190
*/
199191
staticchar*
200192
format_numeric_locale(constchar*my_str)
201193
{
194+
intnew_len=strlen(my_str)+additional_numeric_locale_len(my_str);
195+
char*new_str=pg_local_malloc(new_len+1);
196+
intint_len=integer_digits(my_str);
202197
inti,
203-
j,
204-
int_len=integer_digits(my_str),
205198
leading_digits;
206-
intgroupdigits=atoi(grouping);
207-
intnew_str_start=0;
208-
char*new_str=new_str=pg_local_malloc(
209-
strlen_with_numeric_locale(my_str)+1);
199+
intnew_str_pos=0;
210200

211-
leading_digits= (int_len %groupdigits!=0) ?
212-
int_len %groupdigits :groupdigits;
201+
/* number of digits in first thousands group */
202+
leading_digits=int_len %groupdigits;
203+
if (leading_digits==0)
204+
leading_digits=groupdigits;
213205

214-
if (my_str[0]=='-')/*skip oversign, affects grouping
215-
* calculations */
206+
/*processsign */
207+
if (my_str[0]=='-'||my_str[0]=='+')
216208
{
217-
new_str[0]=my_str[0];
209+
new_str[new_str_pos++]=my_str[0];
218210
my_str++;
219-
new_str_start=1;
220211
}
221212

222-
for (i=0,j=new_str_start;;i++,j++)
213+
/* process integer part of number */
214+
for (i=0;i<int_len;i++)
223215
{
224-
/*Hit decimal point? */
225-
if (my_str[i]=='.')
216+
/*Time to insert separator? */
217+
if (i>0&&--leading_digits==0)
226218
{
227-
strcpy(&new_str[j],decimal_point);
228-
j+=strlen(decimal_point);
229-
/* add fractional part */
230-
strcpy(&new_str[j],&my_str[i]+1);
231-
break;
232-
}
233-
234-
/* End of string? */
235-
if (my_str[i]=='\0')
236-
{
237-
new_str[j]='\0';
238-
break;
239-
}
240-
241-
/* Add separator? */
242-
if (i!=0&& (i-leading_digits) %groupdigits==0)
243-
{
244-
strcpy(&new_str[j],thousands_sep);
245-
j+=strlen(thousands_sep);
219+
strcpy(&new_str[new_str_pos],thousands_sep);
220+
new_str_pos+=strlen(thousands_sep);
221+
leading_digits=groupdigits;
246222
}
223+
new_str[new_str_pos++]=my_str[i];
224+
}
247225

248-
new_str[j]=my_str[i];
226+
/* handle decimal point if any */
227+
if (my_str[i]=='.')
228+
{
229+
strcpy(&new_str[new_str_pos],decimal_point);
230+
new_str_pos+=strlen(decimal_point);
231+
i++;
249232
}
250233

234+
/* copy the rest (fractional digits and/or exponent, and \0 terminator) */
235+
strcpy(&new_str[new_str_pos],&my_str[i]);
236+
251237
returnnew_str;
252238
}
253239

@@ -2473,10 +2459,11 @@ setDecimalLocale(void)
24732459
decimal_point=pg_strdup(extlconv->decimal_point);
24742460
else
24752461
decimal_point=".";/* SQL output standard */
2462+
24762463
if (*extlconv->grouping&&atoi(extlconv->grouping)>0)
2477-
grouping=pg_strdup(extlconv->grouping);
2464+
groupdigits=atoi(extlconv->grouping);
24782465
else
2479-
grouping="3";/* most common */
2466+
groupdigits=3;/* most common */
24802467

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

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp