Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

type: fix float over flow when converting a decimal to a float and then converting a float to an uint #10405

Merged
merged 10 commits into from
May 15, 2019

Conversation

qw4990
Copy link
Contributor

@qw4990 qw4990 commented May 9, 2019

What problem does this PR solve?

Fix #10181.
When converting 9223372036854775807-0.5 from decimal to uint, we convert it to a float value first and then convert the float value to an uint value.
For float, 9223372036854775807-0.5 is too large to let it keep high precision.

What is changed and how it works?

Introduce ConvertDecimalToUint to convert a decimal to an uint by string instead of float to avoid float overflow.

Check List

Tests

  • Unit test

@qw4990 qw4990 added type/bugfix This PR fixes a bug. component/expression labels May 9, 2019
@codecov
Copy link

codecov bot commented May 9, 2019

Codecov Report

Merging #10405 into master will increase coverage by 0.0169%.
The diff coverage is 86.8852%.

@@               Coverage Diff               @@
##             master    #10405        +/-   ##
===============================================
+ Coverage   77.3061%   77.323%   +0.0169%     
===============================================
  Files           412       412                
  Lines         86715     86718         +3     
===============================================
+ Hits          67036     67053        +17     
+ Misses        14522     14508        -14     
  Partials       5157      5157

@qw4990 qw4990 requested review from XuHuaiyu, alivxxx and zz-jason May 9, 2019 08:52
types/convert.go Outdated Show resolved Hide resolved
@zhouqiang-cl
Copy link
Contributor

/run-all-tests

Copy link
Member

@zz-jason zz-jason left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@zz-jason zz-jason added the status/LGT1 Indicates that a PR has LGTM 1. label May 9, 2019
@zhouqiang-cl
Copy link
Contributor

/run-all-tests

1 similar comment
@zhouqiang-cl
Copy link
Contributor

/run-all-tests

types/convert.go Outdated
@@ -173,6 +173,48 @@ func ConvertFloatToUint(sc *stmtctx.StatementContext, fval float64, upperBound u
return uint64(val), nil
}

// ConvertDecimalToUint converts a decimal to an uint by string instead of float to avoid float overflow (#10181).
func ConvertDecimalToUint(sc *stmtctx.StatementContext, d *MyDecimal, upperBound uint64, tp byte) (uint64, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add UT for this func?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UT is added.

types/convert.go Outdated
@@ -173,6 +173,48 @@ func ConvertFloatToUint(sc *stmtctx.StatementContext, fval float64, upperBound u
return uint64(val), nil
}

// ConvertDecimalToUint converts a decimal to an uint by string instead of float to avoid float overflow (#10181).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ConvertDecimalToUint converts a decimal to a uint by converting it to a string first.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated.

types/convert.go Outdated
intStr = str[:p]
fracStr = str[p+1:]
}
for len(intStr) > 0 && intStr[0] == '0' {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. intSrt = strings.TrimLeft(intStr, "0") ?
  2. When will there have leading "0"s?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right... I will update it.

for len(intStr) > 0 && intStr[0] == '0' {
intStr = intStr[1:]
}
if sc.ShouldClipToZero() && intStr[0] == '-' {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will len(intStr) == 0 be true here ? If so, intStr[0] == '-' will cause a panic?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume that len(intStr) > 0 here because MyDecimal returns a valid decimal string without scientific notation.
But I will let it support scientific notation for safety.

}

val, err := strconv.ParseUint(intStr, 10, 64)
if err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return val, err

types/convert.go Outdated
}

var round uint64
if fracStr != "" {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we just check fracStr[0] >= "5"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.. you are right, I will update it.

types/convert.go Show resolved Hide resolved
@qw4990
Copy link
Contributor Author

qw4990 commented May 15, 2019

/rebuild

1 similar comment
@zhouqiang-cl
Copy link
Contributor

/rebuild

@qw4990
Copy link
Contributor Author

qw4990 commented May 15, 2019

All comments have been addressed, PTAL~

types/convert.go Outdated Show resolved Hide resolved
zz-jason
zz-jason previously approved these changes May 15, 2019
Copy link
Member

@zz-jason zz-jason left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@zz-jason zz-jason dismissed their stale review May 15, 2019 08:49

need another reviewer 😂

@qw4990 qw4990 removed the request for review from alivxxx May 15, 2019 08:59
@qw4990 qw4990 requested a review from alivxxx May 15, 2019 08:59
Copy link
Contributor

@alivxxx alivxxx left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@qw4990
Copy link
Contributor Author

qw4990 commented May 15, 2019

/run-all-tests

@qw4990 qw4990 added status/LGT2 Indicates that a PR has LGTM 2. and removed status/LGT1 Indicates that a PR has LGTM 1. labels May 15, 2019
@qw4990
Copy link
Contributor Author

qw4990 commented May 15, 2019

/run-all-tests

@qw4990 qw4990 merged commit 627bd69 into pingcap:master May 15, 2019
@qw4990 qw4990 changed the title type: fix float over flow when converting a decimal to an uint by float type: fix float over flow when converting a decimal to a float and then converting a float to an uint May 20, 2019
qw4990 added a commit to qw4990/tidb that referenced this pull request Jun 6, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component/expression status/LGT2 Indicates that a PR has LGTM 2. type/bugfix This PR fixes a bug.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Wrong result when using unsigned bigint as primary key and comparing it with float numbers
6 participants