1 /**
2 * UGENE - Integrated Bioinformatics Tools.
3 * Copyright (C) 2008-2021 UniPro <ugene@unipro.ru>
4 * http://ugene.net
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301, USA.
20 */
21
22 #include "SQLiteMsaDbi.h"
23
24 #include <U2Core/U2DbiPackUtils.h>
25 #include <U2Core/U2SafePoints.h>
26 #include <U2Core/U2SqlHelpers.h>
27
28 #include "SQLiteModDbi.h"
29 #include "SQLiteSequenceDbi.h"
30
31 namespace U2 {
32
SQLiteMsaDbi(SQLiteDbi * dbi)33 SQLiteMsaDbi::SQLiteMsaDbi(SQLiteDbi *dbi)
34 : U2MsaDbi(dbi), SQLiteChildDBICommon(dbi) {
35 }
36
initSqlSchema(U2OpStatus & os)37 void SQLiteMsaDbi::initSqlSchema(U2OpStatus &os) {
38 if (os.hasError()) {
39 return;
40 }
41
42 // MSA object
43 SQLiteWriteQuery("CREATE TABLE Msa (object INTEGER PRIMARY KEY, length INTEGER NOT NULL, "
44 "alphabet TEXT NOT NULL, numOfRows INTEGER NOT NULL, "
45 "FOREIGN KEY(object) REFERENCES Object(id) ON DELETE CASCADE)",
46 db,
47 os)
48 .execute();
49
50 // MSA object row
51 // msa - msa object id
52 // rowId - id of the row in the msa
53 // sequence - sequence object id
54 // pos - positional number of a row in the msa (initially, equals 'id', but can be changed, e.g. in GUI by moving rows)
55 // gstart - offset of the first element in the sequence
56 // gend - offset of the last element in the sequence (non-inclusive)
57 // length - sequence and gaps length (trailing gap are not taken into account)
58 SQLiteWriteQuery("CREATE TABLE MsaRow (msa INTEGER NOT NULL, rowId INTEGER NOT NULL, sequence INTEGER NOT NULL,"
59 " pos INTEGER NOT NULL, gstart INTEGER NOT NULL, gend INTEGER NOT NULL, length INTEGER NOT NULL,"
60 " PRIMARY KEY(msa, rowId),"
61 " FOREIGN KEY(msa) REFERENCES Msa(object) ON DELETE CASCADE, "
62 " FOREIGN KEY(sequence) REFERENCES Sequence(object) ON DELETE CASCADE)",
63 db,
64 os)
65 .execute();
66 SQLiteWriteQuery("CREATE INDEX MsaRow_msa_rowId ON MsaRow(msa, rowId)", db, os).execute();
67 SQLiteWriteQuery("CREATE INDEX MsaRow_length ON MsaRow(length)", db, os).execute();
68 SQLiteWriteQuery("CREATE INDEX MsaRow_sequence ON MsaRow(sequence)", db, os).execute();
69
70 // Gap info for a MSA row:
71 // msa - msa object id
72 // rowId - id of the row in the msa
73 // gapStart - start of the gap, the coordinate is relative to the gstart coordinate of the row
74 // gapEnd - end of the gap, the coordinate is relative to the gstart coordinate of the row (non-inclusive)
75 // Note! there is invariant: gend - gstart (of the row) == gapEnd - gapStart
76 SQLiteWriteQuery("CREATE TABLE MsaRowGap (msa INTEGER NOT NULL, rowId INTEGER NOT NULL, "
77 "gapStart INTEGER NOT NULL, gapEnd INTEGER NOT NULL, "
78 "FOREIGN KEY(msa, rowId) REFERENCES MsaRow(msa, rowId) ON DELETE CASCADE)",
79 db,
80 os)
81 .execute();
82 SQLiteWriteQuery("CREATE INDEX MsaRowGap_msa_rowId ON MsaRowGap(msa, rowId)", db, os).execute();
83 }
84
createMsaObject(const QString & folder,const QString & name,const U2AlphabetId & alphabet,U2OpStatus & os)85 U2DataId SQLiteMsaDbi::createMsaObject(const QString &folder, const QString &name, const U2AlphabetId &alphabet, U2OpStatus &os) {
86 return createMsaObject(folder, name, alphabet, 0, os);
87 }
88
createMsaObject(const QString & folder,const QString & name,const U2AlphabetId & alphabet,int length,U2OpStatus & os)89 U2DataId SQLiteMsaDbi::createMsaObject(const QString &folder, const QString &name, const U2AlphabetId &alphabet, int length, U2OpStatus &os) {
90 SQLiteTransaction t(db, os);
91 U2Msa msa;
92 msa.visualName = name;
93 msa.alphabet = alphabet;
94 msa.length = length;
95
96 // Create the object
97 dbi->getSQLiteObjectDbi()->createObject(msa, folder, U2DbiObjectRank_TopLevel, os);
98 CHECK_OP(os, U2DataId());
99
100 // Create a record in the Msa table
101 SQLiteWriteQuery q("INSERT INTO Msa(object, length, alphabet, numOfRows) VALUES(?1, ?2, ?3, ?4)", db, os);
102 CHECK_OP(os, U2DataId());
103
104 q.bindDataId(1, msa.id);
105 q.bindInt64(2, msa.length);
106 q.bindString(3, msa.alphabet.id);
107 q.bindInt64(4, 0); // no rows
108 q.insert();
109
110 return msa.id;
111 }
112
updateMsaName(const U2DataId & msaId,const QString & name,U2OpStatus & os)113 void SQLiteMsaDbi::updateMsaName(const U2DataId &msaId, const QString &name, U2OpStatus &os) {
114 SQLiteTransaction t(db, os);
115 U2Object msaObj;
116 dbi->getSQLiteObjectDbi()->getObject(msaObj, msaId, os);
117 CHECK_OP(os, );
118
119 SQLiteObjectDbiUtils::renameObject(dbi, msaObj, name, os);
120 }
121
updateMsaAlphabet(const U2DataId & msaId,const U2AlphabetId & alphabet,U2OpStatus & os)122 void SQLiteMsaDbi::updateMsaAlphabet(const U2DataId &msaId, const U2AlphabetId &alphabet, U2OpStatus &os) {
123 SQLiteTransaction t(db, os);
124 SQLiteModificationAction updateAction(dbi, msaId);
125 U2TrackModType trackMod = updateAction.prepare(os);
126 CHECK_OP(os, );
127
128 // Get modDetails, if required
129 QByteArray modDetails;
130 if (TrackOnUpdate == trackMod) {
131 U2Msa msaObj = getMsaObject(msaId, os);
132 CHECK_OP(os, );
133 modDetails = U2DbiPackUtils::packAlphabetDetails(msaObj.alphabet, alphabet);
134 }
135
136 // Update the alphabet
137 SQLiteWriteQuery q("UPDATE Msa SET alphabet = ?1 WHERE object = ?2", db, os);
138 CHECK_OP(os, );
139
140 q.bindString(1, alphabet.id);
141 q.bindDataId(2, msaId);
142 q.update(1);
143
144 // Increment version; track the modification, if required
145 updateAction.addModification(msaId, U2ModType::msaUpdatedAlphabet, modDetails, os);
146 SAFE_POINT_OP(os, );
147
148 updateAction.complete(os);
149 SAFE_POINT_OP(os, );
150 }
151
createMsaRow(const U2DataId & msaId,qint64 posInMsa,U2MsaRow & msaRow,U2OpStatus & os)152 void SQLiteMsaDbi::createMsaRow(const U2DataId &msaId, qint64 posInMsa, U2MsaRow &msaRow, U2OpStatus &os) {
153 assert(posInMsa >= 0);
154
155 // Calculate the row length
156 qint64 rowLength = calculateRowLength(msaRow.gend - msaRow.gstart, msaRow.gaps);
157
158 // Insert the data
159 SQLiteWriteQuery q("INSERT INTO MsaRow(msa, rowId, sequence, pos, gstart, gend, length)"
160 " VALUES(?1, ?2, ?3, ?4, ?5, ?6, ?7)",
161 db,
162 os);
163 CHECK_OP(os, );
164
165 q.bindDataId(1, msaId);
166 q.bindInt64(2, msaRow.rowId);
167 q.bindDataId(3, msaRow.sequenceId);
168 q.bindInt64(4, posInMsa);
169 q.bindInt64(5, msaRow.gstart);
170 q.bindInt64(6, msaRow.gend);
171 q.bindInt64(7, rowLength);
172 q.insert();
173 }
174
createMsaRowGap(const U2DataId & msaId,qint64 msaRowId,const U2MsaGap & msaGap,U2OpStatus & os)175 void SQLiteMsaDbi::createMsaRowGap(const U2DataId &msaId, qint64 msaRowId, const U2MsaGap &msaGap, U2OpStatus &os) {
176 SQLiteTransaction t(db, os);
177
178 static const QString queryString("INSERT INTO MsaRowGap(msa, rowId, gapStart, gapEnd) VALUES(?1, ?2, ?3, ?4)");
179 QSharedPointer<SQLiteQuery> q = t.getPreparedQuery(queryString, db, os);
180 CHECK_OP(os, );
181
182 q->bindDataId(1, msaId);
183 q->bindInt64(2, msaRowId);
184 q->bindInt64(3, msaGap.offset);
185 q->bindInt64(4, msaGap.offset + msaGap.gap);
186 q->insert();
187 }
188
addMsaRowAndGaps(const U2DataId & msaId,qint64 posInMsa,U2MsaRow & row,U2OpStatus & os)189 void SQLiteMsaDbi::addMsaRowAndGaps(const U2DataId &msaId, qint64 posInMsa, U2MsaRow &row, U2OpStatus &os) {
190 createMsaRow(msaId, posInMsa, row, os);
191 CHECK_OP(os, );
192
193 foreach (const U2MsaGap &gap, row.gaps) {
194 createMsaRowGap(msaId, row.rowId, gap, os);
195 CHECK_OP(os, );
196 }
197
198 dbi->getSQLiteObjectDbi()->setParent(msaId, row.sequenceId, os);
199 }
200
addRow(const U2DataId & msaId,int insertRowIndex,U2MsaRow & row,U2OpStatus & os)201 void SQLiteMsaDbi::addRow(const U2DataId &msaId, int insertRowIndex, U2MsaRow &row, U2OpStatus &os) {
202 SQLiteModificationAction updateAction(dbi, msaId);
203 U2TrackModType trackMod = updateAction.prepare(os);
204 CHECK_OP(os, );
205
206 row.rowId = getMaximumRowId(msaId, os) + 1;
207 CHECK_OP(os, );
208
209 // TODO: allow core method to change insertRowIndex value to store the correct value on tracking
210 addRowCore(msaId, insertRowIndex, row, os);
211 CHECK_OP(os, );
212
213 QByteArray modDetails;
214 if (trackMod == TrackOnUpdate) {
215 modDetails = U2DbiPackUtils::packRow(insertRowIndex, row);
216 }
217 if (row.length > getMsaLength(msaId, os)) {
218 updateMsaLength(updateAction, msaId, row.length, os);
219 }
220
221 // Update track mod type for child sequence object
222 if (trackMod == TrackOnUpdate) {
223 dbi->getObjectDbi()->setTrackModType(row.sequenceId, TrackOnUpdate, os);
224 CHECK_OP(os, );
225 }
226
227 // Increment version; track the modification, if required
228 updateAction.addModification(msaId, U2ModType::msaAddedRow, modDetails, os);
229 SAFE_POINT_OP(os, );
230
231 updateAction.complete(os);
232 SAFE_POINT_OP(os, );
233 }
234
addRows(const U2DataId & msaId,QList<U2MsaRow> & rows,int insertRowIndex,U2OpStatus & os)235 void SQLiteMsaDbi::addRows(const U2DataId &msaId, QList<U2MsaRow> &rows, int insertRowIndex, U2OpStatus &os) {
236 SQLiteTransaction t(db, os);
237
238 SQLiteModificationAction updateAction(dbi, msaId);
239 U2TrackModType trackMod = updateAction.prepare(os);
240 CHECK_OP(os, );
241
242 // Add the rows
243 qint64 numOfRows = getNumOfRows(msaId, os);
244 CHECK_OP(os, );
245
246 qint64 insertStartIndex = insertRowIndex < 0 || insertRowIndex >= numOfRows ? numOfRows : insertRowIndex;
247 QList<int> insertRowIndexes;
248 for (int i = 0; i < rows.count(); i++) {
249 insertRowIndexes << i + insertStartIndex;
250 }
251
252 qint64 maxRowId = getMaximumRowId(msaId, os);
253 for (int i = 0; i < rows.count(); ++i) {
254 rows[i].rowId = maxRowId + i + 1;
255 }
256
257 QByteArray modDetails;
258 if (trackMod == TrackOnUpdate) {
259 modDetails = U2DbiPackUtils::packRows(insertRowIndexes, rows);
260 }
261
262 addRowsCore(msaId, insertRowIndexes, rows, os);
263 CHECK_OP(os, );
264
265 // Update msa length
266 qint64 maxLength = 0;
267 foreach (const U2MsaRow &row, rows) {
268 maxLength = qMax(maxLength, row.length);
269 }
270 qint64 currentMsaLength = getMsaLength(msaId, os);
271 if (maxLength > currentMsaLength) {
272 updateMsaLength(updateAction, msaId, maxLength, os);
273 CHECK_OP(os, );
274 }
275
276 // Update track mod type for child sequence object
277 if (trackMod == TrackOnUpdate) {
278 foreach (const U2MsaRow &row, rows) {
279 dbi->getObjectDbi()->setTrackModType(row.sequenceId, TrackOnUpdate, os);
280 CHECK_OP(os, );
281 }
282 }
283
284 // Increment version; track the modification, if required
285 updateAction.addModification(msaId, U2ModType::msaAddedRows, modDetails, os);
286 SAFE_POINT_OP(os, );
287
288 updateAction.complete(os);
289 SAFE_POINT_OP(os, );
290 }
291
updateRowName(const U2DataId & msaId,qint64 rowId,const QString & newName,U2OpStatus & os)292 void SQLiteMsaDbi::updateRowName(const U2DataId &msaId, qint64 rowId, const QString &newName, U2OpStatus &os) {
293 SQLiteTransaction t(db, os);
294
295 SQLiteModificationAction updateAction(dbi, msaId);
296 updateAction.prepare(os);
297 SAFE_POINT_OP(os, );
298
299 U2DataId sequenceId = getSequenceIdByRowId(msaId, rowId, os);
300 SAFE_POINT_OP(os, );
301
302 U2Sequence seqObject = dbi->getSequenceDbi()->getSequenceObject(sequenceId, os);
303 SAFE_POINT_OP(os, );
304
305 SQLiteObjectDbiUtils::renameObject(updateAction, dbi, seqObject, newName, os);
306 SAFE_POINT_OP(os, );
307
308 updateAction.complete(os);
309 SAFE_POINT_OP(os, );
310 }
311
updateRowContent(const U2DataId & msaId,qint64 rowId,const QByteArray & seqBytes,const QList<U2MsaGap> & gaps,U2OpStatus & os)312 void SQLiteMsaDbi::updateRowContent(const U2DataId &msaId, qint64 rowId, const QByteArray &seqBytes, const QList<U2MsaGap> &gaps, U2OpStatus &os) {
313 SQLiteTransaction t(db, os);
314
315 SQLiteModificationAction updateAction(dbi, msaId);
316 U2TrackModType trackMod = updateAction.prepare(os);
317 SAFE_POINT_OP(os, );
318 Q_UNUSED(trackMod);
319
320 // Get the row object
321 U2MsaRow row = getRow(msaId, rowId, os);
322 SAFE_POINT_OP(os, );
323
324 // Update the sequence data
325 QVariantMap hints;
326 dbi->getSQLiteSequenceDbi()->updateSequenceData(updateAction,
327 row.sequenceId,
328 U2_REGION_MAX,
329 seqBytes,
330 hints,
331 os);
332 SAFE_POINT_OP(os, );
333
334 // Update the row object
335 U2MsaRow newRow(row);
336 qint64 seqLength = seqBytes.length();
337 newRow.gstart = 0;
338 newRow.gend = seqLength;
339 newRow.length = calculateRowLength(seqLength, gaps);
340 updateRowInfo(updateAction, msaId, newRow, os);
341 SAFE_POINT_OP(os, );
342
343 // Update the gap model
344 // WARNING: this update must go after the row info update to recalculate the msa length properly
345 updateGapModel(updateAction, msaId, rowId, gaps, os);
346 SAFE_POINT_OP(os, );
347
348 // Save tracks, if required; increment versions
349 updateAction.complete(os);
350 SAFE_POINT_OP(os, );
351 }
352
updateRowInfo(SQLiteModificationAction & updateAction,const U2DataId & msaId,const U2MsaRow & row,U2OpStatus & os)353 void SQLiteMsaDbi::updateRowInfo(SQLiteModificationAction &updateAction, const U2DataId &msaId, const U2MsaRow &row, U2OpStatus &os) {
354 QByteArray modDetails;
355 if (TrackOnUpdate == updateAction.getTrackModType()) {
356 U2MsaRow oldRow = getRow(msaId, row.rowId, os);
357 SAFE_POINT_OP(os, );
358
359 modDetails = U2DbiPackUtils::packRowInfoDetails(oldRow, row);
360 }
361
362 updateRowInfoCore(msaId, row, os);
363 SAFE_POINT_OP(os, );
364
365 // Track the modification, if required; add the object to the list (versions of the objects will be incremented on the updateAction completion)
366 updateAction.addModification(msaId, U2ModType::msaUpdatedRowInfo, modDetails, os);
367 SAFE_POINT_OP(os, );
368 }
369
getOrderedRowIds(const U2DataId & msaId,U2OpStatus & os)370 QList<qint64> SQLiteMsaDbi::getOrderedRowIds(const U2DataId &msaId, U2OpStatus &os) {
371 QList<qint64> res;
372 SQLiteReadQuery q("SELECT rowId FROM MsaRow WHERE msa = ?1 ORDER BY pos", db, os);
373 q.bindDataId(1, msaId);
374 qint64 rowId;
375 while (q.step()) {
376 rowId = q.getInt64(0);
377 res.append(rowId);
378 }
379 return res;
380 }
381
getMsaAlphabet(const U2DataId & msaId,U2OpStatus & os)382 U2AlphabetId SQLiteMsaDbi::getMsaAlphabet(const U2DataId &msaId, U2OpStatus &os) {
383 QString alphabetName;
384 SQLiteReadQuery q("SELECT alphabet FROM Msa WHERE object = ?1", db, os);
385 q.bindDataId(1, msaId);
386 if (q.step()) {
387 alphabetName = q.getString(0);
388 q.ensureDone();
389 } else if (!os.hasError()) {
390 os.setError(U2DbiL10n::tr("Msa object not found"));
391 }
392
393 return U2AlphabetId(alphabetName);
394 }
395
setNewRowsOrder(const U2DataId & msaId,const QList<qint64> & rowIds,U2OpStatus & os)396 void SQLiteMsaDbi::setNewRowsOrder(const U2DataId &msaId, const QList<qint64> &rowIds, U2OpStatus &os) {
397 // Init track info
398 SQLiteTransaction t(db, os);
399 SQLiteModificationAction updateAction(dbi, msaId);
400 U2TrackModType trackMod = updateAction.prepare(os);
401 CHECK_OP(os, );
402
403 QByteArray modDetails;
404 if (trackMod == TrackOnUpdate) {
405 QList<qint64> oldOrder = getOrderedRowIds(msaId, os);
406 CHECK_OP(os, );
407 modDetails = U2DbiPackUtils::packRowOrderDetails(oldOrder, rowIds);
408 }
409
410 // Check that row IDs number is correct (if required, can be later removed for efficiency)
411 qint64 numOfRows = getNumOfRows(msaId, os);
412 CHECK_OP(os, );
413 SAFE_POINT(numOfRows == rowIds.count(), "Incorrect number of row IDs!", );
414
415 // Set the new order
416 setNewRowsOrderCore(msaId, rowIds, os);
417 CHECK_OP(os, );
418
419 // Increment version; track the modification, if required
420 updateAction.addModification(msaId, U2ModType::msaSetNewRowsOrder, modDetails, os);
421 SAFE_POINT_OP(os, );
422
423 updateAction.complete(os);
424 SAFE_POINT_OP(os, );
425 }
426
removeRecordFromMsaRow(const U2DataId & msaId,qint64 rowId,U2OpStatus & os)427 void SQLiteMsaDbi::removeRecordFromMsaRow(const U2DataId &msaId, qint64 rowId, U2OpStatus &os) {
428 SQLiteTransaction t(db, os);
429 static const QString queryString("DELETE FROM MsaRow WHERE msa = ?1 AND rowId = ?2");
430 QSharedPointer<SQLiteQuery> q = t.getPreparedQuery(queryString, db, os);
431 CHECK_OP(os, );
432
433 q->bindDataId(1, msaId);
434 q->bindInt64(2, rowId);
435 q->update(1);
436 }
437
removeRecordsFromMsaRowGap(const U2DataId & msaId,qint64 rowId,U2OpStatus & os)438 void SQLiteMsaDbi::removeRecordsFromMsaRowGap(const U2DataId &msaId, qint64 rowId, U2OpStatus &os) {
439 SQLiteTransaction t(db, os);
440 static const QString queryString("DELETE FROM MsaRowGap WHERE msa = ?1 AND rowId = ?2");
441 QSharedPointer<SQLiteQuery> q = t.getPreparedQuery(queryString, db, os);
442 CHECK_OP(os, );
443
444 q->bindDataId(1, msaId);
445 q->bindInt64(2, rowId);
446 q->update();
447 }
448
removeRow(const U2DataId & msaId,qint64 rowId,U2OpStatus & os)449 void SQLiteMsaDbi::removeRow(const U2DataId &msaId, qint64 rowId, U2OpStatus &os) {
450 SQLiteTransaction t(db, os);
451 SQLiteModificationAction updateAction(dbi, msaId);
452 U2TrackModType trackMod = updateAction.prepare(os);
453 CHECK_OP(os, );
454
455 QByteArray modDetails;
456 if (TrackOnUpdate == trackMod) {
457 U2MsaRow removedRow = getRow(msaId, rowId, os);
458 CHECK_OP(os, );
459 qint64 posInMsa = getPosInMsa(msaId, rowId, os);
460 CHECK_OP(os, );
461 modDetails = U2DbiPackUtils::packRow(posInMsa, removedRow);
462 }
463
464 bool removeSequence = (TrackOnUpdate != trackMod);
465 removeRowCore(msaId, rowId, removeSequence, os);
466 CHECK_OP(os, );
467
468 // Increment version; track the modification, if required
469 updateAction.addModification(msaId, U2ModType::msaRemovedRow, modDetails, os);
470 SAFE_POINT_OP(os, );
471
472 updateAction.complete(os);
473 SAFE_POINT_OP(os, );
474 }
475
removeRows(const U2DataId & msaId,const QList<qint64> & rowIds,U2OpStatus & os)476 void SQLiteMsaDbi::removeRows(const U2DataId &msaId, const QList<qint64> &rowIds, U2OpStatus &os) {
477 SQLiteTransaction t(db, os);
478
479 SQLiteModificationAction updateAction(dbi, msaId);
480 U2TrackModType trackMod = updateAction.prepare(os);
481 CHECK_OP(os, );
482
483 QByteArray modDetails;
484 int numOfRows = getNumOfRows(msaId, os);
485 if (trackMod == TrackOnUpdate) {
486 QList<int> rowIndexes;
487 QList<U2MsaRow> rows;
488 for (qint64 rowId : qAsConst(rowIds)) {
489 rowIndexes << getPosInMsa(msaId, rowId, os);
490 CHECK_OP(os, );
491 rows << getRow(msaId, rowId, os);
492 CHECK_OP(os, );
493 }
494 modDetails = U2DbiPackUtils::packRows(rowIndexes, rows);
495 }
496
497 bool removeSequence = trackMod != TrackOnUpdate;
498 removeRowsCore(msaId, rowIds, removeSequence, os);
499
500 if (numOfRows == rowIds.count()) {
501 updateMsaLength(updateAction, msaId, 0, os);
502 }
503
504 // Increment version; track the modification, if required
505 updateAction.addModification(msaId, U2ModType::msaRemovedRows, modDetails, os);
506 SAFE_POINT_OP(os, );
507
508 updateAction.complete(os);
509 SAFE_POINT_OP(os, );
510 }
511
removeMsaRowAndGaps(const U2DataId & msaId,qint64 rowId,bool removeSequence,U2OpStatus & os)512 void SQLiteMsaDbi::removeMsaRowAndGaps(const U2DataId &msaId, qint64 rowId, bool removeSequence, U2OpStatus &os) {
513 U2DataId sequenceId = getSequenceIdByRowId(msaId, rowId, os);
514 CHECK_OP(os, );
515
516 removeRecordsFromMsaRowGap(msaId, rowId, os);
517 removeRecordFromMsaRow(msaId, rowId, os);
518
519 dbi->getSQLiteObjectDbi()->removeParent(msaId, sequenceId, removeSequence, os);
520 }
521
deleteRowsData(const U2DataId & msaId,U2OpStatus & os)522 void SQLiteMsaDbi::deleteRowsData(const U2DataId &msaId, U2OpStatus &os) {
523 static const QString deleteObjStr = "DELETE FROM Object WHERE id IN (SELECT sequence FROM MsaRow WHERE msa = ?1)";
524 SQLiteWriteQuery deleteObjQeury(deleteObjStr, db, os);
525 deleteObjQeury.bindDataId(1, msaId);
526 deleteObjQeury.execute();
527 }
528
getMsaObject(const U2DataId & msaId,U2OpStatus & os)529 U2Msa SQLiteMsaDbi::getMsaObject(const U2DataId &msaId, U2OpStatus &os) {
530 U2Msa res;
531 dbi->getSQLiteObjectDbi()->getObject(res, msaId, os);
532
533 SAFE_POINT_OP(os, res);
534
535 SQLiteReadQuery q("SELECT length, alphabet FROM Msa WHERE object = ?1", db, os);
536 q.bindDataId(1, msaId);
537 if (q.step()) {
538 res.length = q.getInt64(0);
539 res.alphabet = q.getString(1);
540 q.ensureDone();
541 } else if (!os.hasError()) {
542 os.setError(U2DbiL10n::tr("Msa object not found!"));
543 }
544 return res;
545 }
546
getNumOfRows(const U2DataId & msaId,U2OpStatus & os)547 int SQLiteMsaDbi::getNumOfRows(const U2DataId &msaId, U2OpStatus &os) {
548 int res = 0;
549 SQLiteReadQuery q("SELECT numOfRows FROM Msa WHERE object = ?1", db, os);
550 CHECK_OP(os, res);
551
552 q.bindDataId(1, msaId);
553 if (q.step()) {
554 res = q.getInt32(0);
555 q.ensureDone();
556 } else if (!os.hasError()) {
557 os.setError(U2DbiL10n::tr("Msa object not found!"));
558 }
559 return res;
560 }
561
recalculateRowsPositions(const U2DataId & msaId,U2OpStatus & os)562 void SQLiteMsaDbi::recalculateRowsPositions(const U2DataId &msaId, U2OpStatus &os) {
563 QList<U2MsaRow> rows = getRows(msaId, os);
564 CHECK_OP(os, );
565
566 SQLiteTransaction t(db, os);
567 SQLiteWriteQuery q("UPDATE MsaRow SET pos = ?1 WHERE msa = ?2 AND rowId = ?3", db, os);
568 CHECK_OP(os, );
569
570 for (int i = 0, n = rows.count(); i < n; ++i) {
571 qint64 rowId = rows[i].rowId;
572 q.reset();
573 q.bindInt64(1, i);
574 q.bindDataId(2, msaId);
575 q.bindInt64(3, rowId);
576 q.execute();
577 }
578 }
579
getMaximumRowId(const U2DataId & msaId,U2OpStatus & os)580 qint64 SQLiteMsaDbi::getMaximumRowId(const U2DataId &msaId, U2OpStatus &os) {
581 qint64 maxRowId = 0;
582 SQLiteReadQuery q("SELECT MAX(rowId) FROM MsaRow WHERE msa = ?1", db, os);
583 SAFE_POINT_OP(os, 0);
584
585 q.bindDataId(1, msaId);
586 q.getInt64(1);
587 if (q.step()) {
588 maxRowId = q.getInt64(0);
589 }
590
591 return maxRowId;
592 }
593
getRows(const U2DataId & msaId,U2OpStatus & os)594 QList<U2MsaRow> SQLiteMsaDbi::getRows(const U2DataId &msaId, U2OpStatus &os) {
595 QList<U2MsaRow> res;
596 SQLiteReadQuery q("SELECT rowId, sequence, gstart, gend, length FROM MsaRow WHERE msa = ?1 ORDER BY pos", db, os);
597 q.bindDataId(1, msaId);
598
599 SQLiteReadQuery gapQ("SELECT gapStart, gapEnd FROM MsaRowGap WHERE msa = ?1 AND rowId = ?2 ORDER BY gapStart", db, os);
600 while (q.step()) {
601 U2MsaRow row;
602 row.rowId = q.getInt64(0);
603 row.sequenceId = q.getDataId(1, U2Type::Sequence);
604 row.gstart = q.getInt64(2);
605 row.gend = q.getInt64(3);
606 row.length = q.getInt64(4);
607
608 gapQ.reset();
609 gapQ.bindDataId(1, msaId);
610 gapQ.bindInt64(2, row.rowId);
611 while (gapQ.step()) {
612 U2MsaGap gap;
613 gap.offset = gapQ.getInt64(0);
614 gap.gap = gapQ.getInt64(1) - gap.offset;
615 SAFE_POINT_EXT(gap.isValid(), os.setError("An invalid gap is stored in the database"), res);
616 row.gaps.append(gap);
617 }
618
619 SAFE_POINT_OP(os, res);
620 res.append(row);
621 }
622 return res;
623 }
624
getRow(const U2DataId & msaId,qint64 rowId,U2OpStatus & os)625 U2MsaRow SQLiteMsaDbi::getRow(const U2DataId &msaId, qint64 rowId, U2OpStatus &os) {
626 U2MsaRow res;
627 SQLiteReadQuery q("SELECT sequence, gstart, gend, length FROM MsaRow WHERE msa = ?1 AND rowId = ?2", db, os);
628 SAFE_POINT_OP(os, res);
629
630 q.bindDataId(1, msaId);
631 q.bindInt64(2, rowId);
632 if (q.step()) {
633 res.rowId = rowId;
634 res.sequenceId = q.getDataId(0, U2Type::Sequence);
635 res.gstart = q.getInt64(1);
636 res.gend = q.getInt64(2);
637 res.length = q.getInt64(3);
638 q.ensureDone();
639 } else if (!os.hasError()) {
640 os.setError(U2DbiL10n::tr("Msa row not found!"));
641 SAFE_POINT_OP(os, res);
642 }
643
644 SQLiteReadQuery gapQ("SELECT gapStart, gapEnd FROM MsaRowGap WHERE msa = ?1 AND rowId = ?2 ORDER BY gapStart", db, os);
645 SAFE_POINT_OP(os, res);
646
647 gapQ.bindDataId(1, msaId);
648 gapQ.bindInt64(2, rowId);
649 while (gapQ.step()) {
650 U2MsaGap gap;
651 gap.offset = gapQ.getInt64(0);
652 gap.gap = gapQ.getInt64(1) - gap.offset;
653 res.gaps.append(gap);
654 }
655
656 return res;
657 }
658
updateNumOfRows(const U2DataId & msaId,qint64 numOfRows,U2OpStatus & os)659 void SQLiteMsaDbi::updateNumOfRows(const U2DataId &msaId, qint64 numOfRows, U2OpStatus &os) {
660 SQLiteWriteQuery q("UPDATE Msa SET numOfRows = ?1 WHERE object = ?2", db, os);
661 SAFE_POINT_OP(os, );
662
663 q.bindInt64(1, numOfRows);
664 q.bindDataId(2, msaId);
665 q.update(1);
666 }
667
updateGapModel(const U2DataId & msaId,qint64 msaRowId,const QList<U2MsaGap> & gapModel,U2OpStatus & os)668 void SQLiteMsaDbi::updateGapModel(const U2DataId &msaId, qint64 msaRowId, const QList<U2MsaGap> &gapModel, U2OpStatus &os) {
669 SQLiteTransaction t(db, os);
670
671 SQLiteModificationAction updateAction(dbi, msaId);
672 updateAction.prepare(os);
673 SAFE_POINT_OP(os, );
674
675 updateGapModel(updateAction, msaId, msaRowId, gapModel, os);
676 SAFE_POINT_OP(os, );
677
678 updateAction.complete(os);
679 SAFE_POINT_OP(os, );
680 }
681
updateGapModel(SQLiteModificationAction & updateAction,const U2DataId & msaId,qint64 msaRowId,const QList<U2MsaGap> & gapModel,U2OpStatus & os)682 void SQLiteMsaDbi::updateGapModel(SQLiteModificationAction &updateAction, const U2DataId &msaId, qint64 msaRowId, const QList<U2MsaGap> &gapModel, U2OpStatus &os) {
683 QByteArray gapsDetails;
684 if (TrackOnUpdate == updateAction.getTrackModType()) {
685 U2MsaRow row = getRow(msaId, msaRowId, os);
686 SAFE_POINT_OP(os, );
687 gapsDetails = U2DbiPackUtils::packGapDetails(msaRowId, row.gaps, gapModel);
688 }
689
690 updateGapModelCore(msaId, msaRowId, gapModel, os);
691 SAFE_POINT_OP(os, );
692
693 qint64 len = 0;
694 foreach (const U2MsaGap &gap, gapModel) {
695 len += gap.gap;
696 }
697 len += getRowSequenceLength(msaId, msaRowId, os);
698 SAFE_POINT_OP(os, );
699 if (len > getMsaLength(msaId, os)) {
700 updateMsaLength(updateAction, msaId, len, os);
701 }
702 SAFE_POINT_OP(os, );
703
704 // Track the modification, if required; add the object to the list (versions of the objects will be incremented on the updateAction completion)
705 updateAction.addModification(msaId, U2ModType::msaUpdatedGapModel, gapsDetails, os);
706 SAFE_POINT_OP(os, );
707 }
708
updateMsaLength(const U2DataId & msaId,qint64 length,U2OpStatus & os)709 void SQLiteMsaDbi::updateMsaLength(const U2DataId &msaId, qint64 length, U2OpStatus &os) {
710 SQLiteTransaction t(db, os);
711
712 SQLiteModificationAction updateAction(dbi, msaId);
713 updateAction.prepare(os);
714 SAFE_POINT_OP(os, );
715
716 updateMsaLength(updateAction, msaId, length, os);
717
718 updateAction.complete(os);
719 SAFE_POINT_OP(os, );
720 }
721
updateMsaLength(SQLiteModificationAction & updateAction,const U2DataId & msaId,qint64 length,U2OpStatus & os)722 void SQLiteMsaDbi::updateMsaLength(SQLiteModificationAction &updateAction, const U2DataId &msaId, qint64 length, U2OpStatus &os) {
723 QByteArray modDetails;
724 if (TrackOnUpdate == updateAction.getTrackModType()) {
725 qint64 oldMsaLen = getMsaLength(msaId, os);
726 CHECK_OP(os, );
727 modDetails = U2DbiPackUtils::packAlignmentLength(oldMsaLen, length);
728 }
729
730 updateMsaLengthCore(msaId, length, os);
731 SAFE_POINT_OP(os, )
732
733 updateAction.addModification(msaId, U2ModType::msaLengthChanged, modDetails, os);
734 SAFE_POINT_OP(os, );
735 }
736
getMsaLength(const U2DataId & msaId,U2OpStatus & os)737 qint64 SQLiteMsaDbi::getMsaLength(const U2DataId &msaId, U2OpStatus &os) {
738 qint64 res = 0;
739 SQLiteReadQuery q("SELECT length FROM Msa WHERE object = ?1", db, os);
740 CHECK_OP(os, res);
741
742 q.bindDataId(1, msaId);
743 if (q.step()) {
744 res = q.getInt64(0);
745 q.ensureDone();
746 } else if (!os.hasError()) {
747 os.setError(U2DbiL10n::tr("Msa object not found!"));
748 }
749
750 return res;
751 }
752
createMcaObject(const QString & folder,const QString & name,const U2AlphabetId & alphabet,U2OpStatus & os)753 U2DataId SQLiteMsaDbi::createMcaObject(const QString &folder, const QString &name, const U2AlphabetId &alphabet, U2OpStatus &os) {
754 return createMcaObject(folder, name, alphabet, 0, os);
755 }
756
createMcaObject(const QString & folder,const QString & name,const U2AlphabetId & alphabet,int length,U2OpStatus & os)757 U2DataId SQLiteMsaDbi::createMcaObject(const QString &folder, const QString &name, const U2AlphabetId &alphabet, int length, U2OpStatus &os) {
758 SQLiteTransaction t(db, os);
759
760 U2Mca mca;
761 mca.visualName = name;
762 mca.alphabet = alphabet;
763 mca.length = length;
764
765 // Create the object
766 dbi->getSQLiteObjectDbi()->createObject(mca, folder, U2DbiObjectRank_TopLevel, os);
767 CHECK_OP(os, U2DataId());
768
769 // Create a record in the Msa table
770 SQLiteWriteQuery q("INSERT INTO Msa(object, length, alphabet, numOfRows) VALUES(?1, ?2, ?3, ?4)", db, os);
771 CHECK_OP(os, U2DataId());
772
773 q.bindDataId(1, mca.id);
774 q.bindInt64(2, mca.length);
775 q.bindString(3, mca.alphabet.id);
776 q.bindInt64(4, 0); // no rows
777 q.insert();
778
779 return mca.id;
780 }
781
calculateRowLength(qint64 seqLength,const QList<U2MsaGap> & gaps)782 qint64 SQLiteMsaDbi::calculateRowLength(qint64 seqLength, const QList<U2MsaGap> &gaps) {
783 qint64 res = seqLength;
784 foreach (const U2MsaGap &gap, gaps) {
785 if (gap.offset < res) { // ignore trailing gaps
786 res += gap.gap;
787 }
788 }
789 return res;
790 }
791
getRowSequenceLength(const U2DataId & msaId,qint64 rowId,U2OpStatus & os)792 qint64 SQLiteMsaDbi::getRowSequenceLength(const U2DataId &msaId, qint64 rowId, U2OpStatus &os) {
793 qint64 res = 0;
794 SQLiteReadQuery q("SELECT gstart, gend FROM MsaRow WHERE msa = ?1 AND rowId = ?2", db, os);
795 CHECK_OP(os, res);
796
797 q.bindDataId(1, msaId);
798 q.bindInt64(2, rowId);
799 if (q.step()) {
800 qint64 startInSeq = q.getInt64(0);
801 qint64 endInSeq = q.getInt64(1);
802 res = endInSeq - startInSeq;
803 q.ensureDone();
804 } else if (!os.hasError()) {
805 os.setError(U2DbiL10n::tr("Msa row not found!"));
806 }
807
808 return res;
809 }
810
updateRowLength(const U2DataId & msaId,qint64 rowId,qint64 newLength,U2OpStatus & os)811 void SQLiteMsaDbi::updateRowLength(const U2DataId &msaId, qint64 rowId, qint64 newLength, U2OpStatus &os) {
812 SQLiteWriteQuery q("UPDATE MsaRow SET length = ?1 WHERE msa = ?2 AND rowId = ?3", db, os);
813 CHECK_OP(os, );
814
815 q.bindInt64(1, newLength);
816 q.bindDataId(2, msaId);
817 q.bindInt64(3, rowId);
818 q.update(1);
819 }
820
updateMsaLengthCore(const U2DataId & msaId,qint64 length,U2OpStatus & os)821 void SQLiteMsaDbi::updateMsaLengthCore(const U2DataId &msaId, qint64 length, U2OpStatus &os) {
822 SQLiteTransaction t(db, os);
823 SQLiteWriteQuery q("UPDATE Msa SET length = ?1 WHERE object = ?2", db, os);
824 CHECK_OP(os, );
825
826 q.bindInt64(1, length);
827 q.bindDataId(2, msaId);
828 q.execute();
829 }
830
getSequenceIdByRowId(const U2DataId & msaId,qint64 rowId,U2OpStatus & os)831 U2DataId SQLiteMsaDbi::getSequenceIdByRowId(const U2DataId &msaId, qint64 rowId, U2OpStatus &os) {
832 U2DataId res;
833 SQLiteReadQuery q("SELECT sequence FROM MsaRow WHERE msa = ?1 AND rowId = ?2", db, os);
834 CHECK_OP(os, res);
835
836 q.bindDataId(1, msaId);
837 q.bindInt64(2, rowId);
838 if (q.step()) {
839 res = q.getDataId(0, U2Type::Sequence);
840 q.ensureDone();
841 } else if (!os.hasError()) {
842 os.setError(U2DbiL10n::tr("Msa row not found!"));
843 }
844
845 return res;
846 }
847
getRemovedRowDetails(const U2MsaRow & row)848 QByteArray SQLiteMsaDbi::getRemovedRowDetails(const U2MsaRow &row) {
849 QByteArray res;
850
851 // Info about gaps
852 QByteArray gapsInfo;
853 for (int i = 0, n = row.gaps.count(); i < n; ++i) {
854 const U2MsaGap &gap = row.gaps[i];
855 gapsInfo += "offset=";
856 gapsInfo += QByteArray::number(gap.offset);
857 gapsInfo += "&gap=";
858 gapsInfo += QByteArray::number(gap.gap);
859
860 if (i > 0 && i < n - 1) {
861 gapsInfo += "&";
862 }
863 }
864
865 res = QByteArray("rowId=") + QByteArray::number(row.rowId) +
866 QByteArray("&sequenceId=") + row.sequenceId.toHex() +
867 QByteArray("&gstart=") + QByteArray::number(row.gstart) +
868 QByteArray("&gend=") + QByteArray::number(row.gend) +
869 QByteArray("&gaps=\"") + gapsInfo + QByteArray("\"") +
870 QByteArray("&length=") + QByteArray::number(row.length);
871
872 return res;
873 }
874
getPosInMsa(const U2DataId & msaId,qint64 rowId,U2OpStatus & os)875 qint64 SQLiteMsaDbi::getPosInMsa(const U2DataId &msaId, qint64 rowId, U2OpStatus &os) {
876 SQLiteReadQuery q("SELECT pos FROM MsaRow WHERE msa = ?1 AND rowId = ?2", db, os);
877 CHECK_OP(os, -1);
878 q.bindDataId(1, msaId);
879 q.bindInt64(2, rowId);
880 if (q.step()) {
881 qint64 result = q.getInt64(0);
882 q.ensureDone();
883 return result;
884 }
885 os.setError(QString("No row with id '%1' in msa '%2'").arg(QString::number(rowId)).arg(msaId.data()));
886 return -1;
887 }
888
undo(const U2DataId & msaId,qint64 modType,const QByteArray & modDetails,U2OpStatus & os)889 void SQLiteMsaDbi::undo(const U2DataId &msaId, qint64 modType, const QByteArray &modDetails, U2OpStatus &os) {
890 if (U2ModType::msaUpdatedAlphabet == modType) {
891 undoUpdateMsaAlphabet(msaId, modDetails, os);
892 } else if (U2ModType::msaAddedRows == modType) {
893 undoAddRows(msaId, modDetails, os);
894 } else if (U2ModType::msaAddedRow == modType) {
895 undoAddRow(msaId, modDetails, os);
896 } else if (U2ModType::msaRemovedRows == modType) {
897 undoRemoveRows(msaId, modDetails, os);
898 } else if (U2ModType::msaRemovedRow == modType) {
899 undoRemoveRow(msaId, modDetails, os);
900 } else if (U2ModType::msaUpdatedRowInfo == modType) {
901 undoUpdateRowInfo(msaId, modDetails, os);
902 } else if (U2ModType::msaUpdatedGapModel == modType) {
903 undoUpdateGapModel(msaId, modDetails, os);
904 } else if (U2ModType::msaSetNewRowsOrder == modType) {
905 undoSetNewRowsOrder(msaId, modDetails, os);
906 } else if (U2ModType::msaLengthChanged == modType) {
907 undoMsaLengthChange(msaId, modDetails, os);
908 } else {
909 os.setError(QString("Unexpected modification type '%1'!").arg(QString::number(modType)));
910 return;
911 }
912 }
913
redo(const U2DataId & msaId,qint64 modType,const QByteArray & modDetails,U2OpStatus & os)914 void SQLiteMsaDbi::redo(const U2DataId &msaId, qint64 modType, const QByteArray &modDetails, U2OpStatus &os) {
915 if (U2ModType::msaUpdatedAlphabet == modType) {
916 redoUpdateMsaAlphabet(msaId, modDetails, os);
917 } else if (U2ModType::msaAddedRows == modType) {
918 redoAddRows(msaId, modDetails, os);
919 } else if (U2ModType::msaAddedRow == modType) {
920 redoAddRow(msaId, modDetails, os);
921 } else if (U2ModType::msaRemovedRows == modType) {
922 redoRemoveRows(msaId, modDetails, os);
923 } else if (U2ModType::msaRemovedRow == modType) {
924 redoRemoveRow(msaId, modDetails, os);
925 } else if (U2ModType::msaUpdatedRowInfo == modType) {
926 redoUpdateRowInfo(msaId, modDetails, os);
927 } else if (U2ModType::msaUpdatedGapModel == modType) {
928 redoUpdateGapModel(msaId, modDetails, os);
929 } else if (U2ModType::msaSetNewRowsOrder == modType) {
930 redoSetNewRowsOrder(msaId, modDetails, os);
931 } else if (U2ModType::msaLengthChanged == modType) {
932 redoMsaLengthChange(msaId, modDetails, os);
933 } else {
934 os.setError(QString("Unexpected modification type '%1'!").arg(QString::number(modType)));
935 return;
936 }
937 }
938
939 /************************************************************************/
940 /* Core methods */
941 /************************************************************************/
updateGapModelCore(const U2DataId & msaId,qint64 msaRowId,const QList<U2MsaGap> & gapModel,U2OpStatus & os)942 void SQLiteMsaDbi::updateGapModelCore(const U2DataId &msaId, qint64 msaRowId, const QList<U2MsaGap> &gapModel, U2OpStatus &os) {
943 SQLiteTransaction t(db, os);
944 // Remove obsolete gaps of the row
945 removeRecordsFromMsaRowGap(msaId, msaRowId, os);
946 CHECK_OP(os, );
947
948 // Store the new gap model
949 foreach (const U2MsaGap &gap, gapModel) {
950 createMsaRowGap(msaId, msaRowId, gap, os);
951 CHECK_OP(os, );
952 }
953
954 // Update the row length (without trailing gaps)
955 qint64 rowSequenceLength = getRowSequenceLength(msaId, msaRowId, os);
956 CHECK_OP(os, );
957
958 qint64 newRowLength = calculateRowLength(rowSequenceLength, gapModel);
959 updateRowLength(msaId, msaRowId, newRowLength, os);
960 CHECK_OP(os, );
961 }
962
addRowSubcore(const U2DataId & msaId,qint64 numOfRows,const QList<qint64> & rowsOrder,U2OpStatus & os)963 void SQLiteMsaDbi::addRowSubcore(const U2DataId &msaId, qint64 numOfRows, const QList<qint64> &rowsOrder, U2OpStatus &os) {
964 // Re-calculate position, if needed
965 setNewRowsOrderCore(msaId, rowsOrder, os);
966 CHECK_OP(os, );
967
968 // Update the number of rows of the MSA
969 updateNumOfRows(msaId, numOfRows, os);
970 }
971
addRowCore(const U2DataId & msaId,int insertRowIndex,U2MsaRow & row,U2OpStatus & os)972 void SQLiteMsaDbi::addRowCore(const U2DataId &msaId, int insertRowIndex, U2MsaRow &row, U2OpStatus &os) {
973 SQLiteTransaction t(db, os);
974
975 // Append the row to the end, if "-1"
976 qint64 numOfRows = getNumOfRows(msaId, os);
977 CHECK_OP(os, );
978
979 QList<qint64> orderedRowIds;
980 if (insertRowIndex == -1) {
981 insertRowIndex = numOfRows;
982 } else {
983 orderedRowIds = getOrderedRowIds(msaId, os);
984 CHECK_OP(os, );
985 SAFE_POINT(orderedRowIds.count() == numOfRows, "Incorrect number of rows!", );
986 }
987 SAFE_POINT(insertRowIndex >= 0 && insertRowIndex <= numOfRows, "Incorrect input position!", );
988
989 // Create the row
990 addMsaRowAndGaps(msaId, insertRowIndex, row, os);
991 CHECK_OP(os, );
992
993 // Update the alignment length
994 row.length = calculateRowLength(row.gend - row.gstart, row.gaps);
995 if (insertRowIndex != numOfRows) {
996 orderedRowIds.insert(insertRowIndex, row.rowId);
997 }
998 addRowSubcore(msaId, numOfRows + 1, orderedRowIds, os);
999 }
1000
addRowsCore(const U2DataId & msaId,const QList<int> & insertRowIndexes,QList<U2MsaRow> & rows,U2OpStatus & os)1001 void SQLiteMsaDbi::addRowsCore(const U2DataId &msaId, const QList<int> &insertRowIndexes, QList<U2MsaRow> &rows, U2OpStatus &os) {
1002 SQLiteTransaction t(db, os);
1003
1004 int numOfRows = getNumOfRows(msaId, os);
1005 CHECK_OP(os, );
1006
1007 QList<qint64> orderedRowIds = getOrderedRowIds(msaId, os);
1008 CHECK_OP(os, );
1009 SAFE_POINT(numOfRows == orderedRowIds.count(), "Incorrect number of rows!", );
1010
1011 // Add new rows
1012 QList<int>::ConstIterator insertIndexIt = insertRowIndexes.begin();
1013 QList<U2MsaRow>::Iterator rowIt = rows.begin();
1014 for (; rowIt != rows.end(); rowIt++, insertIndexIt++) {
1015 int insertRowIndex = *insertIndexIt;
1016 if (insertRowIndex < 0 || insertRowIndex > numOfRows) {
1017 insertRowIndex = numOfRows;
1018 }
1019 addMsaRowAndGaps(msaId, insertRowIndex, *rowIt, os);
1020 CHECK_OP(os, );
1021
1022 rowIt->length = calculateRowLength(rowIt->gend - rowIt->gstart, rowIt->gaps);
1023 numOfRows++;
1024 orderedRowIds.insert(insertRowIndex, rowIt->rowId);
1025 }
1026
1027 addRowSubcore(msaId, numOfRows, orderedRowIds, os);
1028 }
1029
removeRowSubcore(const U2DataId & msaId,qint64 numOfRows,U2OpStatus & os)1030 void SQLiteMsaDbi::removeRowSubcore(const U2DataId &msaId, qint64 numOfRows, U2OpStatus &os) {
1031 // Update the number of rows
1032 updateNumOfRows(msaId, numOfRows, os);
1033 CHECK_OP(os, );
1034
1035 // Re-calculate the rows positions
1036 recalculateRowsPositions(msaId, os);
1037 }
1038
removeRowCore(const U2DataId & msaId,qint64 rowId,bool removeSequence,U2OpStatus & os)1039 void SQLiteMsaDbi::removeRowCore(const U2DataId &msaId, qint64 rowId, bool removeSequence, U2OpStatus &os) {
1040 SQLiteTransaction t(db, os);
1041 // Get and verify the number of rows
1042 qint64 numOfRows = getNumOfRows(msaId, os);
1043 CHECK_OP(os, );
1044 SAFE_POINT(numOfRows > 0, "Empty MSA!", );
1045
1046 // Remove the row
1047 removeMsaRowAndGaps(msaId, rowId, removeSequence, os);
1048 CHECK_OP(os, );
1049
1050 removeRowSubcore(msaId, numOfRows - 1, os);
1051 }
1052
removeRowsCore(const U2DataId & msaId,const QList<qint64> & rowIds,bool removeSequence,U2OpStatus & os)1053 void SQLiteMsaDbi::removeRowsCore(const U2DataId &msaId, const QList<qint64> &rowIds, bool removeSequence, U2OpStatus &os) {
1054 SQLiteTransaction t(db, os);
1055 qint64 numOfRows = getNumOfRows(msaId, os);
1056 CHECK_OP(os, );
1057 SAFE_POINT(numOfRows >= rowIds.count(), "Incorrect rows to remove!", );
1058
1059 for (int i = 0; i < rowIds.count(); ++i) {
1060 removeMsaRowAndGaps(msaId, rowIds[i], removeSequence, os);
1061 CHECK_OP(os, );
1062 }
1063
1064 removeRowSubcore(msaId, numOfRows - rowIds.size(), os);
1065 }
1066
setNewRowsOrderCore(const U2DataId & msaId,const QList<qint64> rowIds,U2OpStatus & os)1067 void SQLiteMsaDbi::setNewRowsOrderCore(const U2DataId &msaId, const QList<qint64> rowIds, U2OpStatus &os) {
1068 SQLiteTransaction t(db, os);
1069 SQLiteWriteQuery q("UPDATE MsaRow SET pos = ?1 WHERE msa = ?2 AND rowId = ?3", db, os);
1070 CHECK_OP(os, );
1071
1072 for (int i = 0, n = rowIds.count(); i < n; ++i) {
1073 qint64 rowId = rowIds[i];
1074 q.reset();
1075 q.bindInt64(1, i);
1076 q.bindDataId(2, msaId);
1077 q.bindInt64(3, rowId);
1078 q.execute();
1079 }
1080 }
1081
updateRowInfoCore(const U2DataId & msaId,const U2MsaRow & row,U2OpStatus & os)1082 void SQLiteMsaDbi::updateRowInfoCore(const U2DataId &msaId, const U2MsaRow &row, U2OpStatus &os) {
1083 SQLiteWriteQuery q("UPDATE MsaRow SET sequence = ?1, gstart = ?2, gend = ?3 WHERE msa = ?4 AND rowId = ?5", db, os);
1084 SAFE_POINT_OP(os, );
1085
1086 q.bindDataId(1, row.sequenceId);
1087 q.bindInt64(2, row.gstart);
1088 q.bindInt64(3, row.gend);
1089 q.bindDataId(4, msaId);
1090 q.bindInt64(5, row.rowId);
1091 q.update(1);
1092 }
1093
1094 /************************************************************************/
1095 /* Undo/redo methods */
1096 /************************************************************************/
undoUpdateMsaAlphabet(const U2DataId & msaId,const QByteArray & modDetails,U2OpStatus & os)1097 void SQLiteMsaDbi::undoUpdateMsaAlphabet(const U2DataId &msaId, const QByteArray &modDetails, U2OpStatus &os) {
1098 U2AlphabetId oldAlphabet;
1099 U2AlphabetId newAlphabet;
1100 bool ok = U2DbiPackUtils::unpackAlphabetDetails(modDetails, oldAlphabet, newAlphabet);
1101 if (!ok) {
1102 os.setError("An error occurred during updating an alignment alphabet!");
1103 return;
1104 }
1105
1106 // Update the value
1107 SQLiteWriteQuery q("UPDATE Msa SET alphabet = ?1 WHERE object = ?2", db, os);
1108 CHECK_OP(os, );
1109
1110 q.bindString(1, oldAlphabet.id);
1111 q.bindDataId(2, msaId);
1112 q.update(1);
1113 }
1114
redoUpdateMsaAlphabet(const U2DataId & msaId,const QByteArray & modDetails,U2OpStatus & os)1115 void SQLiteMsaDbi::redoUpdateMsaAlphabet(const U2DataId &msaId, const QByteArray &modDetails, U2OpStatus &os) {
1116 U2AlphabetId oldAlphabet;
1117 U2AlphabetId newAlphabet;
1118 bool ok = U2DbiPackUtils::unpackAlphabetDetails(modDetails, oldAlphabet, newAlphabet);
1119 if (!ok) {
1120 os.setError("An error occurred during updating an alignment alphabet!");
1121 return;
1122 }
1123
1124 // Redo the updating
1125 SQLiteWriteQuery q("UPDATE Msa SET alphabet = ?1 WHERE object = ?2", db, os);
1126 CHECK_OP(os, );
1127
1128 q.bindString(1, newAlphabet.id);
1129 q.bindDataId(2, msaId);
1130 q.update(1);
1131 }
1132
undoAddRows(const U2DataId & msaId,const QByteArray & modDetails,U2OpStatus & os)1133 void SQLiteMsaDbi::undoAddRows(const U2DataId &msaId, const QByteArray &modDetails, U2OpStatus &os) {
1134 QList<int> rowIndexes;
1135 QList<U2MsaRow> rows;
1136 bool ok = U2DbiPackUtils::unpackRows(modDetails, rowIndexes, rows);
1137 if (!ok) {
1138 os.setError("An error occurred during reverting adding of rows!");
1139 return;
1140 }
1141 QList<qint64> rowIds;
1142 for (const U2MsaRow &row : qAsConst(rows)) {
1143 rowIds << row.rowId;
1144 }
1145 removeRowsCore(msaId, rowIds, false, os);
1146 }
1147
redoAddRows(const U2DataId & msaId,const QByteArray & modDetails,U2OpStatus & os)1148 void SQLiteMsaDbi::redoAddRows(const U2DataId &msaId, const QByteArray &modDetails, U2OpStatus &os) {
1149 QList<int> rowIndexes;
1150 QList<U2MsaRow> rows;
1151 bool ok = U2DbiPackUtils::unpackRows(modDetails, rowIndexes, rows);
1152 if (!ok) {
1153 os.setError("An error occurred during reverting adding of rows!");
1154 return;
1155 }
1156
1157 addRowsCore(msaId, rowIndexes, rows, os);
1158 }
1159
undoAddRow(const U2DataId & msaId,const QByteArray & modDetails,U2OpStatus & os)1160 void SQLiteMsaDbi::undoAddRow(const U2DataId &msaId, const QByteArray &modDetails, U2OpStatus &os) {
1161 U2MsaRow row;
1162 int rowIndex;
1163 bool ok = U2DbiPackUtils::unpackRow(modDetails, rowIndex, row);
1164 if (!ok) {
1165 os.setError("An error occurred during reverting addition of a row!");
1166 return;
1167 }
1168
1169 removeRowCore(msaId, row.rowId, false, os);
1170 }
1171
redoAddRow(const U2DataId & msaId,const QByteArray & modDetails,U2OpStatus & os)1172 void SQLiteMsaDbi::redoAddRow(const U2DataId &msaId, const QByteArray &modDetails, U2OpStatus &os) {
1173 U2MsaRow row;
1174 int rowIndex;
1175 bool ok = U2DbiPackUtils::unpackRow(modDetails, rowIndex, row);
1176 if (!ok) {
1177 os.setError("An error occurred during addition of a row!");
1178 return;
1179 }
1180
1181 addRowCore(msaId, rowIndex, row, os);
1182 }
1183
undoRemoveRows(const U2DataId & msaId,const QByteArray & modDetails,U2OpStatus & os)1184 void SQLiteMsaDbi::undoRemoveRows(const U2DataId &msaId, const QByteArray &modDetails, U2OpStatus &os) {
1185 QList<int> rowIndexes;
1186 QList<U2MsaRow> rows;
1187 bool ok = U2DbiPackUtils::unpackRows(modDetails, rowIndexes, rows);
1188 if (!ok) {
1189 os.setError("An error occurred during reverting removing of rows!");
1190 return;
1191 }
1192
1193 addRowsCore(msaId, rowIndexes, rows, os);
1194 }
1195
redoRemoveRows(const U2DataId & msaId,const QByteArray & modDetails,U2OpStatus & os)1196 void SQLiteMsaDbi::redoRemoveRows(const U2DataId &msaId, const QByteArray &modDetails, U2OpStatus &os) {
1197 QList<int> rowIndexes;
1198 QList<U2MsaRow> rows;
1199 bool ok = U2DbiPackUtils::unpackRows(modDetails, rowIndexes, rows);
1200 if (!ok) {
1201 os.setError("An error occurred during reverting removing of rows!");
1202 return;
1203 }
1204 QList<qint64> rowIds;
1205 for (const U2MsaRow &row : qAsConst(rows)) {
1206 rowIds << row.rowId;
1207 }
1208 removeRowsCore(msaId, rowIds, false, os);
1209 }
1210
undoRemoveRow(const U2DataId & msaId,const QByteArray & modDetails,U2OpStatus & os)1211 void SQLiteMsaDbi::undoRemoveRow(const U2DataId &msaId, const QByteArray &modDetails, U2OpStatus &os) {
1212 U2MsaRow row;
1213 int rowIndex;
1214 bool ok = U2DbiPackUtils::unpackRow(modDetails, rowIndex, row);
1215 if (!ok) {
1216 os.setError("An error occurred during reverting removing of a row!");
1217 return;
1218 }
1219
1220 addRowCore(msaId, rowIndex, row, os);
1221 }
1222
redoRemoveRow(const U2DataId & msaId,const QByteArray & modDetails,U2OpStatus & os)1223 void SQLiteMsaDbi::redoRemoveRow(const U2DataId &msaId, const QByteArray &modDetails, U2OpStatus &os) {
1224 U2MsaRow row;
1225 int rowIndex;
1226 bool ok = U2DbiPackUtils::unpackRow(modDetails, rowIndex, row);
1227 if (!ok) {
1228 os.setError("An error occurred during reverting removing of a row!");
1229 return;
1230 }
1231
1232 removeRowCore(msaId, row.rowId, false, os);
1233 }
1234
undoUpdateGapModel(const U2DataId & msaId,const QByteArray & modDetails,U2OpStatus & os)1235 void SQLiteMsaDbi::undoUpdateGapModel(const U2DataId &msaId, const QByteArray &modDetails, U2OpStatus &os) {
1236 qint64 rowId = 0;
1237 QList<U2MsaGap> oldGaps;
1238 QList<U2MsaGap> newGaps;
1239 bool ok = U2DbiPackUtils::unpackGapDetails(modDetails, rowId, oldGaps, newGaps);
1240 if (!ok) {
1241 os.setError("An error occurred during updating an alignment gaps!");
1242 return;
1243 }
1244
1245 updateGapModelCore(msaId, rowId, oldGaps, os);
1246 }
1247
redoUpdateGapModel(const U2DataId & msaId,const QByteArray & modDetails,U2OpStatus & os)1248 void SQLiteMsaDbi::redoUpdateGapModel(const U2DataId &msaId, const QByteArray &modDetails, U2OpStatus &os) {
1249 qint64 rowId = 0;
1250 QList<U2MsaGap> oldGaps;
1251 QList<U2MsaGap> newGaps;
1252 bool ok = U2DbiPackUtils::unpackGapDetails(modDetails, rowId, oldGaps, newGaps);
1253 if (!ok) {
1254 os.setError("An error occurred during updating an alignment gaps!");
1255 return;
1256 }
1257
1258 updateGapModelCore(msaId, rowId, newGaps, os);
1259 }
1260
undoSetNewRowsOrder(const U2DataId & msaId,const QByteArray & modDetails,U2OpStatus & os)1261 void SQLiteMsaDbi::undoSetNewRowsOrder(const U2DataId &msaId, const QByteArray &modDetails, U2OpStatus &os) {
1262 QList<qint64> oldOrder;
1263 QList<qint64> newOrder;
1264 bool ok = U2DbiPackUtils::unpackRowOrderDetails(modDetails, oldOrder, newOrder);
1265 if (!ok) {
1266 os.setError("An error occurred during updating an alignment row order!");
1267 return;
1268 }
1269
1270 // Set the old order
1271 setNewRowsOrderCore(msaId, oldOrder, os);
1272 }
1273
redoSetNewRowsOrder(const U2DataId & msaId,const QByteArray & modDetails,U2OpStatus & os)1274 void SQLiteMsaDbi::redoSetNewRowsOrder(const U2DataId &msaId, const QByteArray &modDetails, U2OpStatus &os) {
1275 QList<qint64> oldOrder;
1276 QList<qint64> newOrder;
1277 bool ok = U2DbiPackUtils::unpackRowOrderDetails(modDetails, oldOrder, newOrder);
1278 if (!ok) {
1279 os.setError("An error occurred during updating an alignment row order!");
1280 return;
1281 }
1282
1283 setNewRowsOrderCore(msaId, newOrder, os);
1284 }
1285
undoUpdateRowInfo(const U2DataId & msaId,const QByteArray & modDetails,U2OpStatus & os)1286 void SQLiteMsaDbi::undoUpdateRowInfo(const U2DataId &msaId, const QByteArray &modDetails, U2OpStatus &os) {
1287 U2MsaRow oldRow;
1288 U2MsaRow newRow;
1289 bool ok = U2DbiPackUtils::unpackRowInfoDetails(modDetails, oldRow, newRow);
1290 if (!ok) {
1291 os.setError("An error occurred during updating a row info!");
1292 return;
1293 }
1294 SAFE_POINT(oldRow.rowId == newRow.rowId, "Incorrect rowId!", );
1295 SAFE_POINT(oldRow.sequenceId == newRow.sequenceId, "Incorrect sequenceId!", );
1296
1297 updateRowInfoCore(msaId, oldRow, os);
1298 }
1299
redoUpdateRowInfo(const U2DataId & msaId,const QByteArray & modDetails,U2OpStatus & os)1300 void SQLiteMsaDbi::redoUpdateRowInfo(const U2DataId &msaId, const QByteArray &modDetails, U2OpStatus &os) {
1301 U2MsaRow oldRow;
1302 U2MsaRow newRow;
1303 bool ok = U2DbiPackUtils::unpackRowInfoDetails(modDetails, oldRow, newRow);
1304 if (!ok) {
1305 os.setError("An error occurred during updating a row info!");
1306 return;
1307 }
1308 SAFE_POINT(oldRow.rowId == newRow.rowId, "Incorrect rowId!", );
1309 SAFE_POINT(oldRow.sequenceId == newRow.sequenceId, "Incorrect sequenceId!", );
1310
1311 updateRowInfoCore(msaId, newRow, os);
1312 }
1313
undoMsaLengthChange(const U2DataId & msaId,const QByteArray & modDetails,U2OpStatus & os)1314 void SQLiteMsaDbi::undoMsaLengthChange(const U2DataId &msaId, const QByteArray &modDetails, U2OpStatus &os) {
1315 qint64 oldLen;
1316 qint64 newLen;
1317
1318 bool ok = U2DbiPackUtils::unpackAlignmentLength(modDetails, oldLen, newLen);
1319 CHECK_EXT(ok, os.setError(U2DbiL10n::tr("An error occurred during updating an msa length")), );
1320
1321 updateMsaLengthCore(msaId, oldLen, os);
1322 }
1323
redoMsaLengthChange(const U2DataId & msaId,const QByteArray & modDetails,U2OpStatus & os)1324 void SQLiteMsaDbi::redoMsaLengthChange(const U2DataId &msaId, const QByteArray &modDetails, U2OpStatus &os) {
1325 qint64 oldLen;
1326 qint64 newLen;
1327
1328 bool ok = U2DbiPackUtils::unpackAlignmentLength(modDetails, oldLen, newLen);
1329 CHECK_EXT(ok, os.setError(U2DbiL10n::tr("An error occurred during updating an msa length")), );
1330
1331 updateMsaLengthCore(msaId, newLen, os);
1332 }
1333
1334 } // namespace U2
1335