-
-
Notifications
You must be signed in to change notification settings - Fork 6.2k
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: enable explicitly inserting IDENTITY values into mssql #6199
fix: enable explicitly inserting IDENTITY values into mssql #6199
Conversation
@pleerock Any opinion on this? Currently the behavior differs between database engines (i.e. Oracle DB, MySQL and Sqllite will update auto increment values, MSSQL will not). This is a step towards homogenizing this behavior. |
shouldn't this be set on a connection-level or configuration level? I found it weird having it here. |
I agree that this is rather weird, but that weirdness is a result of the way Microsoft implemented enabling manual insertion of values into identity columns. You can only enable Lastly you are not allowed to set |
a14b9d9
to
972092b
Compare
.filter((column) => this.expressionMap.insertColumns.length > 0 ? this.expressionMap.insertColumns.indexOf(column.propertyPath) !== -1 : column.isInsert) | ||
.some((column) => this.isOverridingAutoIncrementBehavior(column)) | ||
) { | ||
query = `SET IDENTITY_INSERT ${tableName} ON; ${query}; SET IDENTITY_INSERT ${tableName} OFF`; |
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.
Are you able to escape the path for the table name here? (this.escapePath
)
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.
Have a look at line 304. Either the table name is already escaped, or there is an issue with injection already.
&& column.generationStrategy === "increment" | ||
&& this.getValueSets().some((valueSet) => | ||
column.getEntityValue(valueSet) !== undefined | ||
&& column.getEntityValue(valueSet) !== null |
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.
If it is null isn't that technically a valid value that we'd want to count as a "supplied" value
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.
In general, null
is not a valid value for a primary key (because that is a clustered index that determines on-disk ordering of entries). Most databases (including mssql) prevent you from doing this.
Now, one could argue that this should fail instead of falling back to auto increment. However, that would be inconsistent with common SQL behavior, as databases cannot distinguish between undefined and null, and as such would insert a auto generated primary key if you supply null in a query.
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.
What if it is '0'. I want to use the 'save()' method which can update and insert and when I want to insert then I set the data of identity column is 0. And it really insert 0 into the identity column. So I can not insert more data because it only update this row.
I'm making a change now to loosen up that insert test. |
ACTUALLY, I'm confused - why is it running it for that code? The DDL for the table that's in the test that failed is:
It's not an But it should be - 🤔 This isn't a problem with your changes. |
.filter((column) => this.expressionMap.insertColumns.length > 0 ? this.expressionMap.insertColumns.indexOf(column.propertyPath) !== -1 : column.isInsert) | ||
.some((column) => this.isOverridingAutoIncrementBehavior(column)) | ||
) { | ||
query = `SET IDENTITY_INSERT ${tableName} ON; ${query}; SET IDENTITY_INSERT ${tableName} OFF`; |
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.
Also, Instead of doing this as part of building the query itself, how would it look as part of the execute
function?
That way it's not muddying up the SQL we've generated - and we already do something similar to that for @OutputTable
. That way it's more for the session than the query itself we're generating.
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.
I thought about that. However, i think its more appropriate to have it here. Otherwise, the query generation method will generate a query which cannot be run, unless you execute it with the execute function. In other words, this method would build an invalid query, without additional context provided by execute. There is also a lot of driver dependent code in this method anyways.
The OutputTable handling in the execute method on the other hand has nothing to do with the insert query, but the way we retrieve results. In other words, without the OutputTable handling, the query would still work, it just could not retrieve the results correctly (which is a concern with regard to the return value of the execute function).
It is an entity type. Look at the related entity/test.ts in that folder
|
The DDL it generates is not an identity, though. It should be. Not sure why - I think there's a bug elsewhere in typeorm. Unrelated to this PR. |
I'm pretty sure you are looking at the wrong DDL. Where does that description field come from? |
From sql server studio - I also confirmed by inspecting the table manually. But not related to this PR so we're good :) |
Allow explicit insertion of preset values for mssql IDENTITY columns. These are the equivalent to auto-incrementing primary keys in MySQL, but require special conditional treatment. Closes: typeorm#2199 for mssql
081091c
to
30c43ad
Compare
Is there anything required from my side to get this merged? I'll happily discuss and make changes. |
I am having the exact issue that seems to be solved with this PR. Is there a plan to merge this in the near future? |
I usually prefer not to have these kind of changes (because of additional complexities it brings, and many "why"-s on many "if"-s. But you did a great job on investigation on how it works in sql server and I can't simply ignore these amount of efforts. Thank you for contribution! |
Debatable if this should be considered as a breaking change since the behaviour is changed and can suddenly cause issues. At the very least it is a new feature and I would like to see this reflected in the version number. Only the patch portion was updated giving me no indication of new features, let alone breaking changes. Should only be incremented for backwards compatible fixes. Of course, this is due to the Updated to this version recently and a lot of tests started failing on the CI server. Turned out we had some code which was generating a value of Perhaps it is time to drop the "anything can change at any time" leading |
So how you reslove this issue? I face the same issue with you and I did not find the early version which don`t have this function. Thanks |
@EatingJoey Browsing through the GIT history I see version IIRC we fixed it by making sure we do not specify an explicit value for the identity based column. That was a bug on our part. |
@geersch Thank you for your information. |
Is there a way to disable |
Do you have a test case for the broken behavior you are seeing? |
Seems only first call of |
I found the problem. |
Allow explicit insertion of preset values for mssql IDENTITY columns. These are the equivalent to
auto-incrementing primary keys in MySQL, but require special conditional treatment.
Closes: #2199 for mssql