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

Commitb2d4792

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 parent2010d8b commitb2d4792

File tree

1 file changed

+46
-27
lines changed

1 file changed

+46
-27
lines changed

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

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4235,67 +4235,86 @@ int64_to_numeric(int64 val)
42354235
}
42364236

42374237
/*
4238-
* Convert val1/(10**val2) to numeric. This is much faster than normal
4238+
* Convert val1/(10**log10val2) to numeric. This is much faster than normal
42394239
* numeric division.
42404240
*/
42414241
Numeric
42424242
int64_div_fast_to_numeric(int64val1,intlog10val2)
42434243
{
42444244
Numericres;
42454245
NumericVarresult;
4246-
int64saved_val1=val1;
4246+
intrscale;
42474247
intw;
42484248
intm;
42494249

4250+
init_var(&result);
4251+
4252+
/* result scale */
4253+
rscale=log10val2<0 ?0 :log10val2;
4254+
42504255
/* how much to decrease the weight by */
42514256
w=log10val2 /DEC_DIGITS;
4252-
/* how much is left */
4257+
/* how much is leftto divide by*/
42534258
m=log10val2 %DEC_DIGITS;
4259+
if (m<0)
4260+
{
4261+
m+=DEC_DIGITS;
4262+
w--;
4263+
}
42544264

42554265
/*
4256-
* If there is anything left, multiply the dividend by what's left, then
4257-
* shift the weight by one more.
4266+
* If there is anything left to divide by (10^m with 0 < m < DEC_DIGITS),
4267+
* multiply the dividend by 10^(DEC_DIGITS - m), and shift the weight by
4268+
* one more.
42584269
*/
42594270
if (m>0)
42604271
{
42614272
#ifDEC_DIGITS==4
4262-
staticintpow10[]= {1,10,100,1000};
4273+
staticconstintpow10[]= {1,10,100,1000};
42634274
#elifDEC_DIGITS==2
4264-
staticintpow10[]= {1,10};
4275+
staticconstintpow10[]= {1,10};
42654276
#elifDEC_DIGITS==1
4266-
staticintpow10[]= {1};
4277+
staticconstintpow10[]= {1};
42674278
#else
42684279
#error unsupported NBASE
42694280
#endif
4281+
int64factor=pow10[DEC_DIGITS-m];
4282+
int64new_val1;
42704283

42714284
StaticAssertDecl(lengthof(pow10)==DEC_DIGITS,"mismatch with DEC_DIGITS");
42724285

4273-
if (unlikely(pg_mul_s64_overflow(val1,pow10[DEC_DIGITS-m],&val1)))
4286+
if (unlikely(pg_mul_s64_overflow(val1,factor,&new_val1)))
42744287
{
4275-
/*
4276-
* If it doesn't fit, do the whole computation in numeric the slow
4277-
* way. Note that va1l may have been overwritten, so use
4278-
* saved_val1 instead.
4279-
*/
4280-
intval2=1;
4288+
#ifdefHAVE_INT128
4289+
/* do the multiplication using 128-bit integers */
4290+
int128tmp;
42814291

4282-
for (inti=0;i<log10val2;i++)
4283-
val2 *=10;
4284-
res=numeric_div_opt_error(int64_to_numeric(saved_val1),int64_to_numeric(val2),NULL);
4285-
res=DatumGetNumeric(DirectFunctionCall2(numeric_round,
4286-
NumericGetDatum(res),
4287-
Int32GetDatum(log10val2)));
4288-
returnres;
4292+
tmp= (int128)val1* (int128)factor;
4293+
4294+
int128_to_numericvar(tmp,&result);
4295+
#else
4296+
/* do the multiplication using numerics */
4297+
NumericVartmp;
4298+
4299+
init_var(&tmp);
4300+
4301+
int64_to_numericvar(val1,&result);
4302+
int64_to_numericvar(factor,&tmp);
4303+
mul_var(&result,&tmp,&result,0);
4304+
4305+
free_var(&tmp);
4306+
#endif
42894307
}
4308+
else
4309+
int64_to_numericvar(new_val1,&result);
4310+
42904311
w++;
42914312
}
4292-
4293-
init_var(&result);
4294-
4295-
int64_to_numericvar(val1,&result);
4313+
else
4314+
int64_to_numericvar(val1,&result);
42964315

42974316
result.weight-=w;
4298-
result.dscale+=w*DEC_DIGITS- (DEC_DIGITS-m);
4317+
result.dscale=rscale;
42994318

43004319
res=make_result(&result);
43014320

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp