-
Notifications
You must be signed in to change notification settings - Fork 314
Fix | Allow SqlBulkCopy to operate on hidden columns #3590
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 | Allow SqlBulkCopy to operate on hidden columns #3590
Conversation
SQL Server won't allow them to be updated, but it'll provide a descriptive error when data is flowing rather than refuse to believe that the column exists.
These tables have columns which cannot be selected explicitly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After working on sqltoolsservice and DSCT, I learned how it's pretty much always frowned upon to use * for "official" queries. So, I'm kinda surprised we were using * to discover the columns in a table.
A few changes that could be made, but I won't hold up the PR over them.
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs
Outdated
Show resolved
Hide resolved
src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/HiddenTargetColumn.cs
Show resolved
Hide resolved
src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/SqlGraphTables.cs
Show resolved
Hide resolved
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs
Outdated
Show resolved
Hide resolved
/azp run |
Azure Pipelines successfully started running 2 pipeline(s). |
Correct casing and escaping of query. Factor new tests into their own classes, allow them to run against Azure SQL.
/azp run |
Azure Pipelines successfully started running 2 pipeline(s). |
@edwardneal so looking at the failures, I think the issue is because in main we've dropped DataTestUtility.GetUniqueNameForSqlServer and split it into GetShortName and GetLongName. Even though it's not a conflict, I guess we're doing the merge before running the CI builds? Anyways, take a look at the notes for those methods, and we'll get the PR going. |
Thanks @benrr101, I've just merged to main. |
/azp run |
Azure Pipelines successfully started running 2 pipeline(s). |
@edwardneal looks like there's a test related to hidden columns failing :(
|
That's frustrating, but thanks. Our test case is covered by the SqlException.Number assertion on the previous line, so I've simplified the comparison. It's odd to see this fail though - I've tested against SQL 2022, 2025 and Azure... |
/azp run |
Azure Pipelines successfully started running 2 pipeline(s). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me! Thanks for hanging in there on the test failures!
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3590 +/- ##
==========================================
- Coverage 66.13% 0 -66.14%
==========================================
Files 276 0 -276
Lines 60765 0 -60765
==========================================
- Hits 40184 0 -40184
+ Misses 20581 0 -20581
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Description
This deals with an older bug: if we try to use
SqlBulkCopy
to import data into a SQL Server table with hidden columns, we can't use those hidden columns as destinations - SqlBulkCopy won't acknowledge that the column exists.The root cause of this is that we discover the columns in the target table by running the command below and looking at the TDS-level metadata:
Hidden columns don't appear when we run a
SELECT *
query. This PR overcomes the problem by queryingsys.all_columns
for the column list, building aSELECT
query dynamically.It's worth noting that this PR doesn't result in a successful bulk copy. As far as I can tell, the only way to create a hidden column is to create a temporal table - specific columns can be marked
GENERATED ALWAYS AS ROW START HIDDEN
. Trying to insert data into these columns will result in a SqlException containing error 13536 from SQL Server:This is a better failure mode than the existing behaviour (an InvalidOperationException) though - it makes it clear that SqlBulkCopy found the column and that SQL Server is rejecting it.
Issues
Fixes #1854.
Testing
New unit test added, all SqlBulkCopy unit tests pass.
The original issue mentioned that running DROP PERIOD FOR SYSTEM_TIME would disable versioning and leave the columns hidden. I wasn't able to reproduce this - once the table has been altered, the columns are no longer hidden.