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

Fix type casting to Decimal from Float with large precision #16333

Conversation

joker1007
Copy link
Contributor

When I define large precision column at RDBMS,
I assign float value, raises ArgumentError (precision too large).

Cause of this probrem:

  • precision is derived from database column definition.
  • If precision is larger than Float::DIG + 1, BigDecimal.new raises ArgumentError

I think it is inconvenient.

this commit fixes it.

@senny
Copy link
Member

senny commented Jul 29, 2014

@joker1007 won't this patch lead to problems when reading data from the database, which actually make use of the precision specified on the column?

@joker1007
Copy link
Contributor Author

@senny
I think this commit is no probrem.

cast_value method is used only when writing to database.
database column cannot have value of larger precision than its definition,
whatever value of Float, the value is rounded to column precision.
Because of it, BigDecimal does not need more precision than column definition.

But, precision larger than Float::DIG + 1 raises ArgumentError.
Because of it, this commit use less than either column definition or Float::DIG + 1

@senny
Copy link
Member

senny commented Jul 29, 2014

@joker1007 right thank you for clarifying.

/cc @sgrif

@@ -14,7 +14,9 @@ def type_cast_for_schema(value)
private

def cast_value(value)
if value.is_a?(::Numeric) || value.is_a?(::String)
if value.is_a?(::Float)
BigDecimal(value, [precision.to_i, ::Float::DIG + 1].min)
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 do this in the constructor instead?

def initialize(*)
  super

  if precision > ::Float::DIG + 1
    @precision = ::Float::DIG + 1
  end

Copy link
Contributor

Choose a reason for hiding this comment

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

Never mind I just realized how stupid that is. Let's at least pull this out to a method. My preference would still be for an if statement, but I don't feel super strongly about it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Only When the value is Float, it is necessary to limit precision.
If value is other type, precision value has reason.
limitation by constructor seems not good.

@sgrif
Copy link
Contributor

sgrif commented Jul 29, 2014

I was hoping to remove precision from the types at some point in the nearish future, but it's seeming more and more likely that we need to keep it where it is. I had a few minor comments, but this seems fine overall.

@@ -14,7 +14,9 @@ def type_cast_for_schema(value)
private

def cast_value(value)
if value.is_a?(::Numeric) || value.is_a?(::String)
if value.is_a?(::Float)
Copy link
Contributor

Choose a reason for hiding this comment

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

Once we have 3 cases we usually use a case statement instead.

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 followed the style of base code.
I prefer to case statement too.

Thanks!

@matthewd
Copy link
Member

Do we really want to do this?

It's raising an exception for a reason.

Edit: Yes, yes we do.

BigDecimal(value, precision.to_i)
elsif value.respond_to?(:to_d)
when ->(v) { v.respond_to?(:to_d) }
Copy link
Contributor

Choose a reason for hiding this comment

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

This proc feels wrong to me. I think I'd prefer this to be an if statement inside of the else case.

@joker1007
Copy link
Contributor Author

@sgrif
Thanks for your comments!
I fixed it.

@senny
Copy link
Member

senny commented Jul 31, 2014

@joker1007 looks good, can you squash your commits and add an entry to the CHANGELOG?

When I defines large precision column at RDBMS,
I assigns float value, raise ArgumentError (precision too large).
@joker1007
Copy link
Contributor Author

@senny OK, I'm done.

@senny senny merged commit 1d6a877 into rails:master Aug 4, 2014
senny added a commit that referenced this pull request Aug 4, 2014
…with_large_precision

Fix type casting to Decimal from Float with large precision

Conflicts:
	activerecord/CHANGELOG.md
@senny
Copy link
Member

senny commented Aug 4, 2014

@joker1007 thank you 💛

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants