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 bulkcopy of DateTimeOffsets and precise Decimals #404

Merged
merged 6 commits into from Sep 11, 2019

Conversation

jwebb
Copy link
Contributor

@jwebb jwebb commented Aug 3, 2018

  • Converting numeric types via float64 risks losing precision, so add direct conversions for ints and strings
  • DateTimeOffset values were being rejected by the server due to a typo in the code
  • Also support dates/times expressed as strings for consistency with regular inserts, and make the 'invalid type' errors more helpful

@codecov
Copy link

codecov bot commented Aug 3, 2018

Codecov Report

Merging #404 into master will decrease coverage by 0.03%.
The diff coverage is 42.85%.

Impacted file tree graph

@@            Coverage Diff            @@
##           master    #404      +/-   ##
=========================================
- Coverage   68.93%   68.9%   -0.04%     
=========================================
  Files          22      22              
  Lines        5009    5033      +24     
=========================================
+ Hits         3453    3468      +15     
- Misses       1350    1359       +9     
  Partials      206     206
Impacted Files Coverage Δ
bulkcopy.go 57.74% <42.85%> (+0.26%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update dd40567...050b152. Read the comment docs.

Copy link
Collaborator

@kardianos kardianos left a comment

Choose a reason for hiding this comment

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

Overall, I like what you've done here.

The only think I'm unsure of is if we should do something different for decimals altogether, like use github.com/cockroachdb/apd.

Opinion @denisenkom ?

@denisenkom
Copy link
Owner

Looks good to me.

As for decimals, do you think we could use rational type (Rat) from math/big package? Decimal is a subset of rational so conversion from decimal to rational is fine but conversion back may not work if rational is not decimal.

@jwebb
Copy link
Contributor Author

jwebb commented Aug 6, 2018

Agree this could do with a larger rework. The [4]int32 at present is just adding complication with no benefit, as all output conversions go via big.Int anyway. The simplistic float64 conversions also have undesirable properties (e.g. round-tripping 1.3 will become 1.2999999999999999245025280). Go provides Grisu3/Dragon4 implementations for this reason.

Thing is, it's not obvious to me that this library needs any sort of decimal type at all. It's public, but it doesn't look like something a client would ever use? Unless there are future plans? Right now AFAICT it's only used momentarily for conversions, and there's very little sharing of code paths. Given that, it would probably be better to implement each of those conversions as a function using whatever library facilities are most appropriate, and ditch the intermediate representation.

(But I still think this PR should be merged in the meantime, as it fixes observable issues.)

@SQLServerIO
Copy link

I am using github.com/shopspring/decimal to handle all my decimal needs.

@dagss
Copy link
Contributor

dagss commented Dec 8, 2018

Nice work I'd really like this in..

NOTE: When implementing #430 I first tried introducing a dedicated mssql.Money type for the bulk import. However, the golang database/sql package didn't like that -- it seems that arguments has to be converted to primitive types before they hit the driver.

So I think this PR would need to work with string -- any decimal type would need to serialize to string before it is allowed to hit this driver code.

If I am right then all the suggestions here about using decimal packages would not work. At least without a significant change in approach (another bulk insert API). (I hope I am wrong though.)

On tests:

I notice that the strategy used for testing conflicts with the one I did in #430 . I did that what I did so that it would be possible to test for bulk import of NULL values, but I can rewrite the test to follow the pattern here if required.

@john8329
Copy link

john8329 commented Sep 4, 2019

Is it possible to fix at least the datetimeoffset issue? I can see that using datetime2 works when using the bulk insert feature, and I'm currently using it as a workaround.

@denisenkom
Copy link
Owner

Yes, please send PR which contains fix for datetime2 issue. Or provide details about this issue, preferably by opening issue or linking issue, if one already open.

@jwebb
Copy link
Contributor Author

jwebb commented Sep 5, 2019

This PR already contains the fix. As well as another. Can I please understand why you will not merge it?

I'm happy to rebase, if it's going to be merged.

I'm also happy to spend some time on refactoring to remove the Decimal type entirely as I mentioned previously. But I'd first need some feedback from you that this is a direction you want to go in, and I don't think that reworking internals should hold up a fix for a data corruption issue.

In the meantime, we have been using this branch in production for the past year.

@denisenkom
Copy link
Owner

This PR is too big. Maybe you can break it down into individual fixes. Lets start with datetime fix. I still don't know what is wrong with it, but with smaller PR I might be able to understand.
There is no good solution for decimals yet, so lets postpone it. I believe newer golang will have necessary functionality, once it is ready we can revisit.

@john8329
Copy link

john8329 commented Sep 6, 2019

The problem I'm having is that if I use that SQL type for the column definition, the bulk insert operation fails, while if the column uses the datetime2 type everything works.

@jwebb
Copy link
Contributor Author

jwebb commented Sep 6, 2019

Datetimeoffsets are this commit - a trivial typo: bcb7c74

I could PR these separately if necessary, and if it will result in everything going in. But I'm afraid that much as I would prefer to contribute fixes back, I can't reasonably allocate time to work on this further if we're going to have to continue to use our own fork anyway.

I must say I'm a little confused by the position that it is better not to apply a fix for a data corruption bug now (or indeed a year ago!), just because the code might be deleted later if something better comes along. Nothing in this fix would make that work any harder. Easier, in fact, given that it also improves error reporting and test coverage.

@denisenkom
Copy link
Owner

Ok merged datetimeoffsets fix. I will look more into the reset of this PR.
In general it is better when PR contains single fix, especially when it introduces lots of changes. Otherwise it make is much harder to review.

@denisenkom
Copy link
Owner

I reviewed the rest of the changes, and I approve this PR. @jwebb can you re-base it?

@jwebb
Copy link
Contributor Author

jwebb commented Sep 10, 2019

Great, thanks!

Rebasing a branch this old was slightly nontrivial, so I'm going to do some more testing before updating this PR (rebase is at https://github.com/XTXMarkets/go-mssqldb/commits/bulk-insert2 if anyone's curious). Will check back in, in a day or so.

@jwebb
Copy link
Contributor Author

jwebb commented Sep 11, 2019

Seems fine. Updated.

@denisenkom denisenkom merged commit 1ecece8 into denisenkom:master Sep 11, 2019
@denisenkom
Copy link
Owner

Thank you. Merged.

rHermes pushed a commit to vippsas/go-mssqldb that referenced this pull request Mar 30, 2020
* Report type as well as value for bulkcopy type errors

* Support strings for bulkcopied dates and times

* Avoid rounding decimals when bulk copying

* Fix some formatting

* Fix bulk insert of datetimeoffset

* Bulkcopy input decimals need to be scaled to match the column
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants