This commit is contained in:
zadam 2023-03-16 13:29:11 +01:00
parent b6efc954bd
commit 515fb4e5db
2 changed files with 108 additions and 96 deletions

4
.idea/dataSources.xml generated
View File

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true"> <component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="SQLite - document.db" uuid="30cef30d-e704-484d-a4ca-5d3bfc2ece63"> <data-source source="LOCAL" name="document.db" uuid="2a4ac1e6-b828-4a2a-8e4a-3f59f10aff26">
<driver-ref>sqlite.xerial</driver-ref> <driver-ref>sqlite.xerial</driver-ref>
<synchronize>true</synchronize> <synchronize>true</synchronize>
<jdbc-driver>org.sqlite.JDBC</jdbc-driver> <jdbc-driver>org.sqlite.JDBC</jdbc-driver>
<jdbc-url>jdbc:sqlite:$PROJECT_DIR$/../trilium-data/document.db</jdbc-url> <jdbc-url>jdbc:sqlite:$PROJECT_DIR$/data/document.db</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir> <working-dir>$ProjectFileDir$</working-dir>
</data-source> </data-source>
</component> </component>

View File

@ -13,6 +13,7 @@ const noteRevisionService = require('./note_revisions');
const becca = require("../becca/becca"); const becca = require("../becca/becca");
const utils = require("../services/utils"); const utils = require("../services/utils");
const {sanitizeAttributeName} = require("./sanitize_attribute_name"); const {sanitizeAttributeName} = require("./sanitize_attribute_name");
const {note} = require("../../spec/search/becca_mocking.js");
const noteTypes = require("../services/note_types").getNoteTypeNames(); const noteTypes = require("../services/note_types").getNoteTypeNames();
class ConsistencyChecks { class ConsistencyChecks {
@ -214,25 +215,27 @@ class ConsistencyChecks {
} }
}); });
// FIXME this.findAndFixIssues(`
// this.findAndFixIssues(` SELECT attachmentId, attachments.parentId AS noteId
// SELECT attachmentId, attachments.parentId AS noteId FROM attachments
// FROM attachments WHERE attachments.parentId NOT IN (
// LEFT JOIN notes ON notes.noteId = attachments.parentId SELECT noteId FROM notes
// WHERE notes.noteId IS NULL UNION ALL
// AND attachments.isDeleted = 0`, SELECT noteRevisionId FROM note_revisions
// ({attachmentId, noteId}) => { )
// if (this.autoFix) { AND attachments.isDeleted = 0`,
// const attachment = becca.getAttachment(attachmentId); ({attachmentId, parentId}) => {
// attachment.markAsDeleted(); if (this.autoFix) {
// const attachment = becca.getAttachment(attachmentId);
// this.reloadNeeded = false; attachment.markAsDeleted();
//
// logFix(`Note attachment '${attachmentId}' has been deleted since it references missing note '${noteId}'`); this.reloadNeeded = false;
// } else {
// logError(`Note attachment '${attachmentId}' references missing note '${noteId}'`); logFix(`Note attachment '${attachmentId}' has been deleted since it references missing note/revision '${parentId}'`);
// } } else {
// }); logError(`Note attachment '${attachmentId}' references missing note/revision '${parentId}'`);
}
});
} }
findExistencyIssues() { findExistencyIssues() {
@ -384,86 +387,95 @@ class ConsistencyChecks {
} }
}); });
// this.findAndFixIssues(` this.findAndFixIssues(`
// SELECT notes.noteId, notes.isProtected, notes.type, notes.mime SELECT notes.noteId, notes.isProtected, notes.type, notes.mime
// FROM notes FROM notes
// LEFT JOIN note_contents USING (noteId) LEFT JOIN blobs USING (blobId)
// WHERE note_contents.noteId IS NULL`, WHERE blobs.blobId IS NULL
// ({noteId, isProtected, type, mime}) => { AND notes.isDeleted = 0`,
// if (this.autoFix) { ({noteId, isProtected, type, mime}) => {
// // it might be possible that the note_content is not available only because of the interrupted if (this.autoFix) {
// // sync, and it will come later. It's therefore important to guarantee that this artifical // it might be possible that the blob is not available only because of the interrupted
// // record won't overwrite the real one coming from the sync. // sync, and it will come later. It's therefore important to guarantee that this artifical
// const fakeDate = "2000-01-01 00:00:00Z"; // record won't overwrite the real one coming from the sync.
// const fakeDate = "2000-01-01 00:00:00Z";
// // manually creating row since this can also affect deleted notes
// sql.upsert("note_contents", "noteId", { const blankContent = getBlankContent(isProtected, type, mime);
// noteId: noteId, const blobId = utils.hashedBlobId(blankContent);
// content: getBlankContent(isProtected, type, mime), const blobAlreadyExists = !!sql.getValue("SELECT 1 FROM blobs WHERE blobId = ?", [blobId]);
// utcDateModified: fakeDate,
// dateModified: fakeDate if (!blobAlreadyExists) {
// }); // manually creating row since this can also affect deleted notes
// sql.upsert("blobs", "blobId", {
// const hash = utils.hash(utils.randomString(10)); noteId: noteId,
// content: blankContent,
// entityChangesService.addEntityChange({ utcDateModified: fakeDate,
// entityName: 'note_contents', dateModified: fakeDate
// entityId: noteId, });
// hash: hash,
// isErased: false, const hash = utils.hash(utils.randomString(10));
// utcDateChanged: fakeDate,
// isSynced: true entityChangesService.addEntityChange({
// }); entityName: 'blobs',
// entityId: blobId,
// this.reloadNeeded = true; hash: hash,
// isErased: false,
// logFix(`Note '${noteId}' content was set to empty string since there was no corresponding row`); utcDateChanged: fakeDate,
// } else { isSynced: true
// logError(`Note '${noteId}' content row does not exist`); });
// } }
// });
sql.execute("UPDATE notes SET blobId = ? WHERE noteId = ?", [blobId, noteId]);
this.reloadNeeded = true;
logFix(`Note '${noteId}' content was set to empty string since there was no corresponding row`);
} else {
logError(`Note '${noteId}' content row does not exist`);
}
});
if (sqlInit.getDbSize() < 500000) { if (sqlInit.getDbSize() < 500000) {
// querying for "content IS NULL" is expensive since content is not indexed. See e.g. https://github.com/zadam/trilium/issues/2887 // querying for "content IS NULL" is expensive since content is not indexed. See e.g. https://github.com/zadam/trilium/issues/2887
// this.findAndFixIssues(` this.findAndFixIssues(`
// SELECT notes.noteId, notes.type, notes.mime SELECT notes.noteId, notes.type, notes.mime
// FROM notes FROM notes
// JOIN note_contents USING (noteId) JOIN blobs USING (blobId)
// WHERE isDeleted = 0 WHERE isDeleted = 0
// AND isProtected = 0 AND isProtected = 0
// AND content IS NULL`, AND content IS NULL`,
// ({noteId, type, mime}) => { ({noteId, type, mime}) => {
// if (this.autoFix) { if (this.autoFix) {
// const note = becca.getNote(noteId); const note = becca.getNote(noteId);
// const blankContent = getBlankContent(false, type, mime); const blankContent = getBlankContent(false, type, mime);
// note.setContent(blankContent); note.setContent(blankContent);
//
// this.reloadNeeded = true; this.reloadNeeded = true;
//
// logFix(`Note '${noteId}' content was set to '${blankContent}' since it was null even though it is not deleted`); logFix(`Note '${noteId}' content was set to '${blankContent}' since it was null even though it is not deleted`);
// } else { } else {
// logError(`Note '${noteId}' content is null even though it is not deleted`); logError(`Note '${noteId}' content is null even though it is not deleted`);
// } }
// }); });
} }
// this.findAndFixIssues(` this.findAndFixIssues(`
// SELECT note_revisions.noteRevisionId SELECT note_revisions.noteRevisionId
// FROM note_revisions FROM note_revisions
// LEFT JOIN note_revision_contents USING (noteRevisionId) LEFT JOIN blobs USING (blobId)
// WHERE note_revision_contents.noteRevisionId IS NULL`, WHERE blobs.blobId IS NULL`,
// ({noteRevisionId}) => { ({noteRevisionId}) => {
// if (this.autoFix) { if (this.autoFix) {
// noteRevisionService.eraseNoteRevisions([noteRevisionId]); noteRevisionService.eraseNoteRevisions([noteRevisionId]);
//
// this.reloadNeeded = true; this.reloadNeeded = true;
//
// logFix(`Note revision content '${noteRevisionId}' was set to erased since it did not exist.`); logFix(`Note revision content '${noteRevisionId}' was set to erased since its content did not exist.`);
// } else { } else {
// logError(`Note revision content '${noteRevisionId}' does not exist`); logError(`Note revision content '${noteRevisionId}' does not exist`);
// } }
// }); });
this.findAndFixIssues(` this.findAndFixIssues(`
SELECT parentNoteId SELECT parentNoteId
@ -487,7 +499,7 @@ class ConsistencyChecks {
branch.markAsDeleted("parent-is-search"); branch.markAsDeleted("parent-is-search");
// create a replacement branch in root parent // create a replacement branch in root parent
new Branch({ new BBranch({
parentNoteId: 'root', parentNoteId: 'root',
noteId: branch.noteId, noteId: branch.noteId,
prefix: 'recovered' prefix: 'recovered'