diff --git a/lib/dialects/mysql/query.js b/lib/dialects/mysql/query.js index bc4cd06b..f6a26515 100644 --- a/lib/dialects/mysql/query.js +++ b/lib/dialects/mysql/query.js @@ -75,9 +75,16 @@ QueryCompiler_MySQL.prototype.columnInfo = function() { }; }; +QueryCompiler_MySQL.prototype.limit = function() { + if (!this.single.limit && !this.single.offset) return ''; + + // Workaround for offset only, see http://stackoverflow.com/questions/255517/mysql-offset-infinite-rows + return 'limit ' + ((this.single.offset && !this.single.limit) ? '18446744073709551615' : this.formatter.parameter(this.single.limit)); +}; + // Set the QueryBuilder & QueryCompiler on the client object, // incase anyone wants to modify things to suit their own purposes. client.QueryBuilder = QueryBuilder_MySQL; client.QueryCompiler = QueryCompiler_MySQL; -}; \ No newline at end of file +}; diff --git a/lib/dialects/sqlite3/query.js b/lib/dialects/sqlite3/query.js index cf0c8d99..41178338 100644 --- a/lib/dialects/sqlite3/query.js +++ b/lib/dialects/sqlite3/query.js @@ -110,6 +110,13 @@ QueryCompiler_SQLite3.prototype.columnInfo = function() { }; }; +QueryCompiler_SQLite3.prototype.limit = function() { + if (!this.single.limit && !this.single.offset) return ''; + + // Workaround for offset only, see http://stackoverflow.com/questions/10491492/sqllite-with-skip-offset-only-not-limit + return 'limit ' + this.formatter.parameter((this.single.offset && !this.single.limit) ? -1 : this.single.limit); +}; + client.QueryBuilder = QueryBuilder_SQLite3; client.QueryCompiler = QueryCompiler_SQLite3; diff --git a/test/integration/builder/selects.js b/test/integration/builder/selects.js index 3fb12ea8..ea697fd4 100644 --- a/test/integration/builder/selects.js +++ b/test/integration/builder/selects.js @@ -40,6 +40,36 @@ module.exports = function(knex) { }); }); + it('starts selecting at offset', function () { + return knex.pluck('id').orderBy('id').from('accounts').offset(2) + .testSql(function (tester) { + tester( + 'mysql', + 'select `id` from `accounts` order by `id` asc limit 18446744073709551615 offset ?', + [2], + [3, 4, 5, 7] + ); + tester( + 'postgresql', + 'select "id" from "accounts" order by "id" asc offset ?', + [2], + ['3', '4', '5', '7'] + ); + tester( + 'sqlite3', + 'select "id" from "accounts" order by "id" asc limit ? offset ?', + [-1, 2], + [3, 4, 5, 6] + ); + tester( + 'oracle', + "select * from (select row_.*, ROWNUM rownum_ from (select \"id\" from \"accounts\" order by \"id\" asc) row_ where rownum <= ?) where rownum_ > ?", + [10000000000002, 2], + [3, 4, 5, 7] + ); + }); + }); + it('returns a single entry with first', function() { return knex.first('id', 'first_name').orderBy('id').from('accounts') .testSql(function(tester) { diff --git a/test/unit/query/builder.js b/test/unit/query/builder.js index 5fe7520c..3a41f5cc 100644 --- a/test/unit/query/builder.js +++ b/test/unit/query/builder.js @@ -729,7 +729,7 @@ module.exports = function(qb, clientName, aliasName) { }); }); - it("Oracle first", function() { + it("first", function() { testsql(qb().first('*').from('users'), { mysql: { sql: 'select * from `users` limit ?', @@ -749,15 +749,15 @@ module.exports = function(qb, clientName, aliasName) { it("offsets only", function() { testsql(qb().select('*').from('users').offset(5), { mysql: { - sql: 'select * from `users` offset ?', // TODO: This is wrong + sql: 'select * from `users` limit 18446744073709551615 offset ?', bindings: [5] }, sqlite3: { - sql: 'select * from "users" offset ?', // TODO: This is wrong - bindings: [5] + sql: 'select * from "users" limit ? offset ?', + bindings: [-1, 5] }, postgres: { - sql: 'select * from "users" offset ?', // TODO: This is wrong + sql: 'select * from "users" offset ?', bindings: [5] }, oracle: {