mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-24 10:27:10 +02:00
Server: Prevent crash when returning too many rows using SQLite
This commit is contained in:
parent
9b27b3b1fb
commit
1efe3d3c6a
@ -16,6 +16,11 @@ require('pg').types.setTypeParser(20, function(val: any) {
|
||||
|
||||
const logger = Logger.create('db');
|
||||
|
||||
// To prevent error "SQLITE_ERROR: too many SQL variables", SQL statements with
|
||||
// "IN" clauses shouldn't contain more than the number of variables below.s
|
||||
// https://www.sqlite.org/limits.html#max_variable_number
|
||||
export const SqliteMaxVariableNum = 999;
|
||||
|
||||
const migrationDir = `${__dirname}/migrations`;
|
||||
export const sqliteDefaultDir = pathUtils.dirname(__dirname);
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { createUserAndSession, beforeAllDb, afterAllTests, beforeEachDb, models, expectThrow, createFolder, createItemTree3 } from '../utils/testing/testUtils';
|
||||
import { ChangeType, Item, Uuid } from '../db';
|
||||
import { createUserAndSession, beforeAllDb, afterAllTests, beforeEachDb, models, expectThrow, createFolder, createItemTree3, expectNotThrow } from '../utils/testing/testUtils';
|
||||
import { ChangeType, Item, SqliteMaxVariableNum, Uuid } from '../db';
|
||||
import { msleep } from '../utils/time';
|
||||
import { ChangePagination } from './ChangeModel';
|
||||
|
||||
async function makeTestItem(userId: Uuid, num: number): Promise<Item> {
|
||||
return models().item().saveForUser(userId, {
|
||||
name: `0000000000000000000000000000000${num}.md`,
|
||||
name: `${num.toString().padStart(32, '0')}.md`,
|
||||
});
|
||||
}
|
||||
|
||||
@ -164,4 +164,25 @@ describe('ChangeModel', function() {
|
||||
expect(allFromIds3.has_more).toBe(false);
|
||||
});
|
||||
|
||||
test('should not fail when retrieving many changes', async function() {
|
||||
// Create many changes and verify that, by default, the SQL query that
|
||||
// returns change doesn't fail. Before the max number of items was set
|
||||
// to 1000 and it would fail with "SQLITE_ERROR: too many SQL variables"
|
||||
// with SQLite. So now it's set to 999.
|
||||
|
||||
const { user } = await createUserAndSession(1, true);
|
||||
|
||||
for (let i = 0; i < 1010; i++) {
|
||||
await makeTestItem(user.id, i);
|
||||
}
|
||||
|
||||
let changeCount = 0;
|
||||
await expectNotThrow(async () => {
|
||||
const changes = await models().change().allFromId('');
|
||||
changeCount = changes.items.length;
|
||||
});
|
||||
|
||||
expect(changeCount).toBe(SqliteMaxVariableNum);
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Knex } from 'knex';
|
||||
import { Change, ChangeType, Item, Uuid } from '../db';
|
||||
import { Change, ChangeType, Item, SqliteMaxVariableNum, Uuid } from '../db';
|
||||
import { md5 } from '../utils/crypto';
|
||||
import { ErrorResyncRequired } from '../utils/errors';
|
||||
import BaseModel, { SaveOptions } from './BaseModel';
|
||||
@ -59,7 +59,7 @@ export default class ChangeModel extends BaseModel<Change> {
|
||||
return `${this.baseUrl}/changes`;
|
||||
}
|
||||
|
||||
public async allFromId(id: string, limit: number = 1000): Promise<PaginatedChanges> {
|
||||
public async allFromId(id: string, limit: number = SqliteMaxVariableNum): Promise<PaginatedChanges> {
|
||||
const startChange: Change = id ? await this.load(id) : null;
|
||||
const query = this.db(this.tableName).select(...this.defaultFields);
|
||||
if (startChange) void query.where('counter', '>', startChange.counter);
|
||||
|
Loading…
Reference in New Issue
Block a user