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

Commit86bfbea

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 parent89d28f9 commit86bfbea

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
@@ -4089,58 +4089,86 @@ int64_to_numeric(int64 val)
40894089
}
40904090

40914091
/*
4092-
* Convert val1/(10**val2) to numeric. This is much faster than normal
4092+
* Convert val1/(10**log10val2) to numeric. This is much faster than normal
40934093
* numeric division.
40944094
*/
40954095
Numeric
40964096
int64_div_fast_to_numeric(int64val1,intlog10val2)
40974097
{
40984098
Numericres;
40994099
NumericVarresult;
4100-
int64saved_val1=val1;
4100+
intrscale;
41014101
intw;
41024102
intm;
41034103

4104+
init_var(&result);
4105+
4106+
/* result scale */
4107+
rscale=log10val2<0 ?0 :log10val2;
4108+
41044109
/* how much to decrease the weight by */
41054110
w=log10val2 /DEC_DIGITS;
4106-
/* how much is left */
4111+
/* how much is leftto divide by*/
41074112
m=log10val2 %DEC_DIGITS;
4113+
if (m<0)
4114+
{
4115+
m+=DEC_DIGITS;
4116+
w--;
4117+
}
41084118

41094119
/*
4110-
* If there is anything left, multiply the dividend by what's left, then
4111-
* shift the weight by one more.
4120+
* If there is anything left to divide by (10^m with 0 < m < DEC_DIGITS),
4121+
* multiply the dividend by 10^(DEC_DIGITS - m), and shift the weight by
4122+
* one more.
41124123
*/
41134124
if (m>0)
41144125
{
4115-
staticintpow10[]= {1,10,100,1000};
4126+
#ifDEC_DIGITS==4
4127+
staticconstintpow10[]= {1,10,100,1000};
4128+
#elifDEC_DIGITS==2
4129+
staticconstintpow10[]= {1,10};
4130+
#elifDEC_DIGITS==1
4131+
staticconstintpow10[]= {1};
4132+
#else
4133+
#error unsupported NBASE
4134+
#endif
4135+
int64factor=pow10[DEC_DIGITS-m];
4136+
int64new_val1;
41164137

41174138
StaticAssertStmt(lengthof(pow10)==DEC_DIGITS,"mismatch with DEC_DIGITS");
4118-
if (unlikely(pg_mul_s64_overflow(val1,pow10[DEC_DIGITS-m],&val1)))
4139+
4140+
if (unlikely(pg_mul_s64_overflow(val1,factor,&new_val1)))
41194141
{
4120-
/*
4121-
* If it doesn't fit, do the whole computation in numeric the slow
4122-
* way. Note that va1l may have been overwritten, so use
4123-
* saved_val1 instead.
4124-
*/
4125-
intval2=1;
4126-
4127-
for (inti=0;i<log10val2;i++)
4128-
val2 *=10;
4129-
res=numeric_div_opt_error(int64_to_numeric(saved_val1),int64_to_numeric(val2),NULL);
4130-
res=DatumGetNumeric(DirectFunctionCall2(numeric_round,
4131-
NumericGetDatum(res),
4132-
Int32GetDatum(log10val2)));
4133-
returnres;
4142+
#ifdefHAVE_INT128
4143+
/* do the multiplication using 128-bit integers */
4144+
int128tmp;
4145+
4146+
tmp= (int128)val1* (int128)factor;
4147+
4148+
int128_to_numericvar(tmp,&result);
4149+
#else
4150+
/* do the multiplication using numerics */
4151+
NumericVartmp;
4152+
4153+
init_var(&tmp);
4154+
4155+
int64_to_numericvar(val1,&result);
4156+
int64_to_numericvar(factor,&tmp);
4157+
mul_var(&result,&tmp,&result,0);
4158+
4159+
free_var(&tmp);
4160+
#endif
41344161
}
4162+
else
4163+
int64_to_numericvar(new_val1,&result);
4164+
41354165
w++;
41364166
}
4137-
4138-
init_var(&result);
4139-
4140-
int64_to_numericvar(val1,&result);
4167+
else
4168+
int64_to_numericvar(val1,&result);
41414169

41424170
result.weight-=w;
4143-
result.dscale+=w*DEC_DIGITS- (DEC_DIGITS-m);
4171+
result.dscale=rscale;
41444172

41454173
res=make_result(&result);
41464174

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp