mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 18:36:30 +01:00 
			
		
		
		
	converted most dynamic SQL queries into prepared statement to avoid excessive statement caching
This commit is contained in:
		| @@ -33,10 +33,12 @@ function getAutocomplete(req) { | |||||||
|  |  | ||||||
| function getRecentNotes(activeNoteId) { | function getRecentNotes(activeNoteId) { | ||||||
|     let extraCondition = ''; |     let extraCondition = ''; | ||||||
|  |     const params = [activeNoteId]; | ||||||
|  |  | ||||||
|     const hoistedNoteId = optionService.getOption('hoistedNoteId'); |     const hoistedNoteId = optionService.getOption('hoistedNoteId'); | ||||||
|     if (hoistedNoteId !== 'root') { |     if (hoistedNoteId !== 'root') { | ||||||
|         extraCondition = `AND recent_notes.notePath LIKE '%${utils.sanitizeSql(hoistedNoteId)}%'`; |         extraCondition = `AND recent_notes.notePath LIKE ?`; | ||||||
|  |         params.push(hoistedNoteId + '%'); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     const recentNotes = repository.getEntities(` |     const recentNotes = repository.getEntities(` | ||||||
| @@ -52,7 +54,7 @@ function getRecentNotes(activeNoteId) { | |||||||
|         ${extraCondition} |         ${extraCondition} | ||||||
|       ORDER BY  |       ORDER BY  | ||||||
|         utcDateCreated DESC |         utcDateCreated DESC | ||||||
|       LIMIT 200`, [activeNoteId]); |       LIMIT 200`, params); | ||||||
|  |  | ||||||
|     return recentNotes.map(rn => { |     return recentNotes.map(rn => { | ||||||
|         const title = noteCacheService.getNoteTitleForPath(rn.notePath.split('/')); |         const title = noteCacheService.getNoteTitleForPath(rn.notePath.split('/')); | ||||||
|   | |||||||
| @@ -119,21 +119,19 @@ function restoreNoteRevision(req) { | |||||||
| } | } | ||||||
|  |  | ||||||
| function getEditedNotesOnDate(req) { | function getEditedNotesOnDate(req) { | ||||||
|     const date = utils.sanitizeSql(req.params.date); |  | ||||||
|  |  | ||||||
|     const notes = repository.getEntities(` |     const notes = repository.getEntities(` | ||||||
|         SELECT notes.* |         SELECT notes.* | ||||||
|         FROM notes |         FROM notes | ||||||
|         WHERE noteId IN ( |         WHERE noteId IN ( | ||||||
|                 SELECT noteId FROM notes  |                 SELECT noteId FROM notes  | ||||||
|                 WHERE notes.dateCreated LIKE '${date}%'  |                 WHERE notes.dateCreated LIKE :date | ||||||
|                    OR notes.dateModified LIKE '${date}%' |                    OR notes.dateModified LIKE :date | ||||||
|             UNION ALL |             UNION ALL | ||||||
|                 SELECT noteId FROM note_revisions |                 SELECT noteId FROM note_revisions | ||||||
|                 WHERE note_revisions.dateLastEdited LIKE '${date}%' |                 WHERE note_revisions.dateLastEdited LIKE :date | ||||||
|         ) |         ) | ||||||
|         ORDER BY isDeleted |         ORDER BY isDeleted | ||||||
|         LIMIT 50`); |         LIMIT 50`, {date: req.params.date + '%'}); | ||||||
|  |  | ||||||
|     for (const note of notes) { |     for (const note of notes) { | ||||||
|         const notePath = noteCacheService.getNotePath(note.noteId); |         const notePath = noteCacheService.getNotePath(note.noteId); | ||||||
|   | |||||||
| @@ -97,7 +97,7 @@ function getAttributeNames(type, nameLike) { | |||||||
|              FROM attributes  |              FROM attributes  | ||||||
|              WHERE isDeleted = 0 |              WHERE isDeleted = 0 | ||||||
|                AND type = ? |                AND type = ? | ||||||
|                AND name LIKE '%${utils.sanitizeSql(nameLike)}%'`, [type]); |                AND name LIKE ?`, [type, '%' + nameLike + '%']); | ||||||
|  |  | ||||||
|     for (const attr of BUILTIN_ATTRIBUTES) { |     for (const attr of BUILTIN_ATTRIBUTES) { | ||||||
|         if (attr.type === type && attr.name.toLowerCase().includes(nameLike) && !names.includes(attr.name)) { |         if (attr.type === type && attr.name.toLowerCase().includes(nameLike) && !names.includes(attr.name)) { | ||||||
|   | |||||||
| @@ -31,8 +31,6 @@ function periodBackup(optionName, fileName, periodInSeconds) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| const COPY_ATTEMPT_COUNT = 50; |  | ||||||
|  |  | ||||||
| async function copyFile(backupFile) { | async function copyFile(backupFile) { | ||||||
|     const sql = require('./sql'); |     const sql = require('./sql'); | ||||||
|  |  | ||||||
| @@ -78,7 +76,7 @@ async function anonymize() { | |||||||
|     // on the other hand builtin/system attrs should not contain any sensitive info |     // on the other hand builtin/system attrs should not contain any sensitive info | ||||||
|     const builtinAttrs = attributeService |     const builtinAttrs = attributeService | ||||||
|         .getBuiltinAttributeNames() |         .getBuiltinAttributeNames() | ||||||
|         .map(name => "'" + utils.sanitizeSql(name) + "'").join(', '); |         .map(name => "'" + name + "'").join(', '); | ||||||
|  |  | ||||||
|     db.prepare(`UPDATE attributes SET name = 'name', value = 'value' WHERE type = 'label' AND name NOT IN(${builtinAttrs})`).run(); |     db.prepare(`UPDATE attributes SET name = 'name', value = 'value' WHERE type = 'label' AND name NOT IN(${builtinAttrs})`).run(); | ||||||
|     db.prepare(`UPDATE attributes SET name = 'name' WHERE type = 'relation' AND name NOT IN (${builtinAttrs})`).run(); |     db.prepare(`UPDATE attributes SET name = 'name' WHERE type = 'relation' AND name NOT IN (${builtinAttrs})`).run(); | ||||||
|   | |||||||
| @@ -127,7 +127,8 @@ function getManyRows(query, params) { | |||||||
|         const questionMarks = curParams.map(() => ":param" + i++).join(","); |         const questionMarks = curParams.map(() => ":param" + i++).join(","); | ||||||
|         const curQuery = query.replace(/\?\?\?/g, questionMarks); |         const curQuery = query.replace(/\?\?\?/g, questionMarks); | ||||||
|  |  | ||||||
|         results = results.concat(getRows(curQuery, curParamsObj)); |         const subResults = dbConnection.prepare(curQuery).all(curParamsObj); | ||||||
|  |         results = results.concat(subResults); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return results; |     return results; | ||||||
| @@ -200,7 +201,7 @@ function wrap(query, func) { | |||||||
|  |  | ||||||
|     const milliseconds = Date.now() - startTimestamp; |     const milliseconds = Date.now() - startTimestamp; | ||||||
|  |  | ||||||
|     if (milliseconds >= 100) { |     if (milliseconds >= 20) { | ||||||
|         if (query.includes("WITH RECURSIVE")) { |         if (query.includes("WITH RECURSIVE")) { | ||||||
|             log.info(`Slow recursive query took ${milliseconds}ms.`); |             log.info(`Slow recursive query took ${milliseconds}ms.`); | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -50,11 +50,6 @@ function isEmptyOrWhitespace(str) { | |||||||
|     return str === null || str.match(/^ *$/) !== null; |     return str === null || str.match(/^ *$/) !== null; | ||||||
| } | } | ||||||
|  |  | ||||||
| function sanitizeSql(str) { |  | ||||||
|     // should be improved or usage eliminated |  | ||||||
|     return str.replace(/'/g, "''"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function sanitizeSqlIdentifier(str) { | function sanitizeSqlIdentifier(str) { | ||||||
|     return str.replace(/[^A-Za-z0-9_]/g, ""); |     return str.replace(/[^A-Za-z0-9_]/g, ""); | ||||||
| } | } | ||||||
| @@ -286,7 +281,6 @@ module.exports = { | |||||||
|     isElectron, |     isElectron, | ||||||
|     hash, |     hash, | ||||||
|     isEmptyOrWhitespace, |     isEmptyOrWhitespace, | ||||||
|     sanitizeSql, |  | ||||||
|     sanitizeSqlIdentifier, |     sanitizeSqlIdentifier, | ||||||
|     prepareSqlForLike, |     prepareSqlForLike, | ||||||
|     stopWatch, |     stopWatch, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user