不要怂,就是干,撸起袖子干!

Commit be30a5e7 by Harshith Kashyap Committed by Jan Aagaard Meier

Fixes MSSQL Limit in update query, closes #6636 (#6918)

* Fixes MSSQL Limit in update query, closes #6636

* Fixes failing unit test

* Moved unit test to test/unit/sql folder

* Added sqlite case to unit test

* Added MSSQL dialect specific updateQuery

* Removed .call from super.updateQuery
1 parent a1bf8b02
# Future # Future
- [FIXED] MSSQL LIMIT IN UPDATE [#6636](https://github.com/sequelize/sequelize/issues/6636)
- [FIXED] Custom error message not used for `notNull` validation [#6531](https://github.com/sequelize/sequelize/issues/6531) - [FIXED] Custom error message not used for `notNull` validation [#6531](https://github.com/sequelize/sequelize/issues/6531)
- [FIXED] N:M `through` option naming collisions [#4597](https://github.com/sequelize/sequelize/issues/4597) - [FIXED] N:M `through` option naming collisions [#4597](https://github.com/sequelize/sequelize/issues/4597)
[#6444](https://github.com/sequelize/sequelize/issues/6444) [#6444](https://github.com/sequelize/sequelize/issues/6444)
......
...@@ -292,7 +292,9 @@ const QueryGenerator = { ...@@ -292,7 +292,9 @@ const QueryGenerator = {
let selectFromTmp = ''; // Select statement for trigger let selectFromTmp = ''; // Select statement for trigger
if (this._dialect.supports['LIMIT ON UPDATE'] && options.limit) { if (this._dialect.supports['LIMIT ON UPDATE'] && options.limit) {
query += ' LIMIT ' + this.escape(options.limit) + ' '; if (this.dialect !== 'mssql') {
query += ' LIMIT ' + this.escape(options.limit) + ' ';
}
} }
if (this._dialect.supports.returnValues) { if (this._dialect.supports.returnValues) {
......
...@@ -302,6 +302,15 @@ var QueryGenerator = { ...@@ -302,6 +302,15 @@ var QueryGenerator = {
return generatedQuery; return generatedQuery;
}, },
updateQuery(tableName, attrValueHash, where, options, attributes) {
let sql = super.updateQuery(tableName, attrValueHash, where, options, attributes);
if (options.limit) {
const updateArgs = `UPDATE TOP(${this.escape(options.limit)})`;
sql = sql.replace('UPDATE', updateArgs);
}
return sql;
},
upsertQuery(tableName, insertValues, updateValues, where, rawAttributes, options) { upsertQuery(tableName, insertValues, updateValues, where, rawAttributes, options) {
const targetTableAlias = this.quoteTable(`${tableName}_target`); const targetTableAlias = this.quoteTable(`${tableName}_target`);
const sourceTableAlias = this.quoteTable(`${tableName}_source`); const sourceTableAlias = this.quoteTable(`${tableName}_source`);
......
...@@ -2487,7 +2487,7 @@ class Model { ...@@ -2487,7 +2487,7 @@ class Model {
* @param {Boolean} [options.sideEffects=true] Whether or not to update the side effects of any virtual setters. * @param {Boolean} [options.sideEffects=true] Whether or not to update the side effects of any virtual setters.
* @param {Boolean} [options.individualHooks=false] Run before / after update hooks?. If true, this will execute a SELECT followed by individual UPDATEs. A select is needed, because the row data needs to be passed to the hooks * @param {Boolean} [options.individualHooks=false] Run before / after update hooks?. If true, this will execute a SELECT followed by individual UPDATEs. A select is needed, because the row data needs to be passed to the hooks
* @param {Boolean} [options.returning=false] Return the affected rows (only for postgres) * @param {Boolean} [options.returning=false] Return the affected rows (only for postgres)
* @param {Number} [options.limit] How many rows to update (only for mysql and mariadb) * @param {Number} [options.limit] How many rows to update (only for mysql and mariadb, implemented as TOP(n) for MSSQL)
* @param {Function} [options.logging=false] A function that gets executed while running the query to log the sql. * @param {Function} [options.logging=false] A function that gets executed while running the query to log the sql.
* @param {Boolean} [options.benchmark=false] Pass query execution time in milliseconds as second argument to logging function (options.logging). * @param {Boolean} [options.benchmark=false] Pass query execution time in milliseconds as second argument to logging function (options.logging).
* @param {Transaction} [options.transaction] Transaction to run query under * @param {Transaction} [options.transaction] Transaction to run query under
......
...@@ -64,5 +64,38 @@ describe(Support.getTestDialectTeaser('Model'), function() { ...@@ -64,5 +64,38 @@ describe(Support.getTestDialectTeaser('Model'), function() {
}); });
} }
if (current.dialect.supports['LIMIT ON UPDATE']) {
it('Should only update one row', function () {
return Account.create({
ownerId: 2,
name: 'Account Name 1'
})
.then(() => {
return Account.create({
ownerId: 2,
name: 'Account Name 2'
});
})
.then(() => {
return Account.create({
ownerId: 2,
name: 'Account Name 3'
});
})
.then(() => {
const options = {
where: {
ownerId: 2
},
limit: 1
};
return Account.update({ name: 'New Name' }, options);
})
.then(account => {
expect(account[0]).to.equal(1);
});
});
}
}); });
}); });
...@@ -30,9 +30,28 @@ describe(Support.getTestDialectTeaser('SQL'), function() { ...@@ -30,9 +30,28 @@ describe(Support.getTestDialectTeaser('SQL'), function() {
{ {
mssql: 'declare @tmp table ([id] INTEGER,[user_name] NVARCHAR(255));UPDATE [users] SET [user_name]=N\'triggertest\' OUTPUT INSERTED.[id],INSERTED.[user_name] into @tmp WHERE [id] = 2;select * from @tmp', mssql: 'declare @tmp table ([id] INTEGER,[user_name] NVARCHAR(255));UPDATE [users] SET [user_name]=N\'triggertest\' OUTPUT INSERTED.[id],INSERTED.[user_name] into @tmp WHERE [id] = 2;select * from @tmp',
postgres:'UPDATE "users" SET "user_name"=\'triggertest\' WHERE "id" = 2 RETURNING *', postgres:'UPDATE "users" SET "user_name"=\'triggertest\' WHERE "id" = 2 RETURNING *',
default: "UPDATE `users` SET `user_name`=\'triggertest\' WHERE `id` = 2", default: "UPDATE `users` SET `user_name`=\'triggertest\' WHERE `id` = 2"
}); });
}); });
it('Works with limit', function () {
const User = Support.sequelize.define('User', {
username: {
type: DataTypes.STRING
},
userId: {
type: DataTypes.INTEGER
}
}, {
timestamps: false
});
expectsql(sql.updateQuery(User.tableName, { username: 'new.username' }, { username: 'username' }, { limit: 1 }), {
mssql: "UPDATE TOP(1) [Users] SET [username]=N'new.username' OUTPUT INSERTED.* WHERE [username] = N'username'",
mysql: "UPDATE `Users` SET `username`='new.username' WHERE `username` = 'username' LIMIT 1",
default: "UPDATE [Users] SET [username]='new.username' WHERE [username] = 'username'"
});
});
}); });
}); });
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!