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

Commit4f74741

Browse files
committed
Make int64_div_fast_to_numeric() more robust.
The prior coding of int64_div_fast_to_numeric() had a number of bugsthat would cause it to fail under different circumstances, such aswith log10val2 <= 0, or log10val2 a multiple of 4, or in the "slow"numeric path with log10val2 >= 10.None of those could be triggered by any of our current code, whichonly uses log10val2 = 3 or 6. However, they made it a hazard for anyfuture code that might use it. Also, since this is exported bynumeric.c, users writing their own C code might choose to use it.Therefore fix, and back-patch to v14, where it was introduced.Dean Rasheed, reviewed by Tom Lane.Discussion:https://postgr.es/m/CAEZATCW8gXgW0tgPxPgHDPhVX71%2BSWFRkhnXy%2BTfGDsKLepu2g%40mail.gmail.com
1 parente7c2e02 commit4f74741

File tree

1 file changed

+54
-26
lines changed

1 file changed

+54
-26
lines changed

‎src/backend/utils/adt/numeric.c

Lines changed: 54 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4151,58 +4151,86 @@ int64_to_numeric(int64 val)
41514151
}
41524152

41534153
/*
4154-
* Convert val1/(10**val2) to numeric. This is much faster than normal
4154+
* Convert val1/(10**log10val2) to numeric. This is much faster than normal
41554155
* numeric division.
41564156
*/
41574157
Numeric
41584158
int64_div_fast_to_numeric(int64val1,intlog10val2)
41594159
{
41604160
Numericres;
41614161
NumericVarresult;
4162-
int64saved_val1=val1;
4162+
intrscale;
41634163
intw;
41644164
intm;
41654165

4166+
init_var(&result);
4167+
4168+
/* result scale */
4169+
rscale=log10val2<0 ?0 :log10val2;
4170+
41664171
/* how much to decrease the weight by */
41674172
w=log10val2 /DEC_DIGITS;
4168-
/* how much is left */
4173+
/* how much is leftto divide by*/
41694174
m=log10val2 %DEC_DIGITS;
4175+
if (m<0)
4176+
{
4177+
m+=DEC_DIGITS;
4178+
w--;
4179+
}
41704180

41714181
/*
4172-
* If there is anything left, multiply the dividend by what's left, then
4173-
* shift the weight by one more.
4182+
* If there is anything left to divide by (10^m with 0 < m < DEC_DIGITS),
4183+
* multiply the dividend by 10^(DEC_DIGITS - m), and shift the weight by
4184+
* one more.
41744185
*/
41754186
if (m>0)
41764187
{
4177-
staticintpow10[]= {1,10,100,1000};
4188+
#ifDEC_DIGITS==4
4189+
staticconstintpow10[]= {1,10,100,1000};
4190+
#elifDEC_DIGITS==2
4191+
staticconstintpow10[]= {1,10};
4192+
#elifDEC_DIGITS==1
4193+
staticconstintpow10[]= {1};
4194+
#else
4195+
#error unsupported NBASE
4196+
#endif
4197+
int64factor=pow10[DEC_DIGITS-m];
4198+
int64new_val1;
41784199

41794200
StaticAssertStmt(lengthof(pow10)==DEC_DIGITS,"mismatch with DEC_DIGITS");
4180-
if (unlikely(pg_mul_s64_overflow(val1,pow10[DEC_DIGITS-m],&val1)))
4201+
4202+
if (unlikely(pg_mul_s64_overflow(val1,factor,&new_val1)))
41814203
{
4182-
/*
4183-
* If it doesn't fit, do the whole computation in numeric the slow
4184-
* way. Note that va1l may have been overwritten, so use
4185-
* saved_val1 instead.
4186-
*/
4187-
intval2=1;
4188-
4189-
for (inti=0;i<log10val2;i++)
4190-
val2 *=10;
4191-
res=numeric_div_opt_error(int64_to_numeric(saved_val1),int64_to_numeric(val2),NULL);
4192-
res=DatumGetNumeric(DirectFunctionCall2(numeric_round,
4193-
NumericGetDatum(res),
4194-
Int32GetDatum(log10val2)));
4195-
returnres;
4204+
#ifdefHAVE_INT128
4205+
/* do the multiplication using 128-bit integers */
4206+
int128tmp;
4207+
4208+
tmp= (int128)val1* (int128)factor;
4209+
4210+
int128_to_numericvar(tmp,&result);
4211+
#else
4212+
/* do the multiplication using numerics */
4213+
NumericVartmp;
4214+
4215+
init_var(&tmp);
4216+
4217+
int64_to_numericvar(val1,&result);
4218+
int64_to_numericvar(factor,&tmp);
4219+
mul_var(&result,&tmp,&result,0);
4220+
4221+
free_var(&tmp);
4222+
#endif
41964223
}
4224+
else
4225+
int64_to_numericvar(new_val1,&result);
4226+
41974227
w++;
41984228
}
4199-
4200-
init_var(&result);
4201-
4202-
int64_to_numericvar(val1,&result);
4229+
else
4230+
int64_to_numericvar(val1,&result);
42034231

42044232
result.weight-=w;
4205-
result.dscale+=w*DEC_DIGITS- (DEC_DIGITS-m);
4233+
result.dscale=rscale;
42064234

42074235
res=make_result(&result);
42084236

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp