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

Commit348dd28

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 parent0da864c commit348dd28

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];
@@ -130,98 +131,87 @@ static void IsPagerNeeded(const printTableContent *cont, const int extra_lines,
130131
staticvoidprint_aligned_vertical(constprintTableContent*cont,FILE*fout);
131132

132133

134+
/* Count number of digits in integral part of number */
133135
staticint
134136
integer_digits(constchar*my_str)
135137
{
136-
intfrac_len;
137-
138-
if (my_str[0]=='-')
138+
/* ignoring any sign ... */
139+
if (my_str[0]=='-'||my_str[0]=='+')
139140
my_str++;
140-
141-
frac_len=strchr(my_str,'.') ?strlen(strchr(my_str,'.')) :0;
142-
143-
returnstrlen(my_str)-frac_len;
141+
/* ... count initial integral digits */
142+
returnstrspn(my_str,"0123456789");
144143
}
145144

146-
/*Return additional length required for locale-aware numeric output */
145+
/*Compute additional length required for locale-aware numeric output */
147146
staticint
148147
additional_numeric_locale_len(constchar*my_str)
149148
{
150149
intint_len=integer_digits(my_str),
151150
len=0;
152-
intgroupdigits=atoi(grouping);
153151

154-
if (int_len>0)
155-
/* Don't count a leading separator */
156-
len= (int_len /groupdigits- (int_len %groupdigits==0))*
157-
strlen(thousands_sep);
152+
/* Account for added thousands_sep instances */
153+
if (int_len>groupdigits)
154+
len+= ((int_len-1) /groupdigits)*strlen(thousands_sep);
158155

156+
/* Account for possible additional length of decimal_point */
159157
if (strchr(my_str,'.')!=NULL)
160-
len+=strlen(decimal_point)-strlen(".");
158+
len+=strlen(decimal_point)-1;
161159

162160
returnlen;
163161
}
164162

165-
staticint
166-
strlen_with_numeric_locale(constchar*my_str)
167-
{
168-
returnstrlen(my_str)+additional_numeric_locale_len(my_str);
169-
}
170-
171163
/*
172164
* Returns the appropriately formatted string in a new allocated block,
173165
* caller must free
174166
*/
175167
staticchar*
176168
format_numeric_locale(constchar*my_str)
177169
{
170+
intnew_len=strlen(my_str)+additional_numeric_locale_len(my_str);
171+
char*new_str=pg_malloc(new_len+1);
172+
intint_len=integer_digits(my_str);
178173
inti,
179-
j,
180-
int_len=integer_digits(my_str),
181174
leading_digits;
182-
intgroupdigits=atoi(grouping);
183-
intnew_str_start=0;
184-
char*new_str=pg_malloc(strlen_with_numeric_locale(my_str)+1);
175+
intnew_str_pos=0;
185176

186-
leading_digits= (int_len %groupdigits!=0) ?
187-
int_len %groupdigits :groupdigits;
177+
/* number of digits in first thousands group */
178+
leading_digits=int_len %groupdigits;
179+
if (leading_digits==0)
180+
leading_digits=groupdigits;
188181

189-
if (my_str[0]=='-')/*skip oversign, affects grouping
190-
* calculations */
182+
/*processsign */
183+
if (my_str[0]=='-'||my_str[0]=='+')
191184
{
192-
new_str[0]=my_str[0];
185+
new_str[new_str_pos++]=my_str[0];
193186
my_str++;
194-
new_str_start=1;
195187
}
196188

197-
for (i=0,j=new_str_start;;i++,j++)
189+
/* process integer part of number */
190+
for (i=0;i<int_len;i++)
198191
{
199-
/*Hit decimal point? */
200-
if (my_str[i]=='.')
192+
/*Time to insert separator? */
193+
if (i>0&&--leading_digits==0)
201194
{
202-
strcpy(&new_str[j],decimal_point);
203-
j+=strlen(decimal_point);
204-
/* add fractional part */
205-
strcpy(&new_str[j],&my_str[i]+1);
206-
break;
195+
strcpy(&new_str[new_str_pos],thousands_sep);
196+
new_str_pos+=strlen(thousands_sep);
197+
leading_digits=groupdigits;
207198
}
199+
new_str[new_str_pos++]=my_str[i];
200+
}
208201

209-
/* End of string? */
210-
if (my_str[i]=='\0')
211-
{
212-
new_str[j]='\0';
213-
break;
214-
}
202+
/* handle decimal point if any */
203+
if (my_str[i]=='.')
204+
{
205+
strcpy(&new_str[new_str_pos],decimal_point);
206+
new_str_pos+=strlen(decimal_point);
207+
i++;
208+
}
215209

216-
/* Add separator? */
217-
if (i!=0&& (i-leading_digits) %groupdigits==0)
218-
{
219-
strcpy(&new_str[j],thousands_sep);
220-
j+=strlen(thousands_sep);
221-
}
210+
/* copy the rest (fractional digits and/or exponent, and \0 terminator) */
211+
strcpy(&new_str[new_str_pos],&my_str[i]);
222212

223-
new_str[j]=my_str[i];
224-
}
213+
/* assert we didn't underestimate new_len (an overestimate is OK) */
214+
Assert(strlen(new_str) <=new_len);
225215

226216
returnnew_str;
227217
}
@@ -2678,10 +2668,11 @@ setDecimalLocale(void)
26782668
decimal_point=pg_strdup(extlconv->decimal_point);
26792669
else
26802670
decimal_point=".";/* SQL output standard */
2671+
26812672
if (*extlconv->grouping&&atoi(extlconv->grouping)>0)
2682-
grouping=pg_strdup(extlconv->grouping);
2673+
groupdigits=atoi(extlconv->grouping);
26832674
else
2684-
grouping="3";/* most common */
2675+
groupdigits=3;/* most common */
26852676

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

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp