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 <cmath>
23
24 #include <QBitArray>
25 #include <QFile>
26
27 #include <U2Core/AppContext.h>
28 #include <U2Core/U2DbiRegistry.h>
29 #include <U2Core/U2ObjectDbi.h>
30 #include <U2Core/U2OpStatus.h>
31 #include <U2Core/U2OpStatusUtils.h>
32 #include <U2Core/U2SafePoints.h>
33 #include <U2Core/Version.h>
34
35 #include "U2DbiUtils.h"
36
37 namespace U2 {
38
39 #define DB_ID_OFFSET 0
40 #define TYPE_OFFSET 8
41 #define DB_EXTRA_OFFSET 10
42 #define DATAID_MIN_LEN 10
43
44 static U2DataId emptyId;
45
46 const QString U2DbiUtils::PUBLIC_DATABASE_NAME = "UGENE public database";
47 const QString U2DbiUtils::PUBLIC_DATABASE_LOGIN = "public";
48 const QString U2DbiUtils::PUBLIC_DATABASE_PASSWORD = "public";
49 const QString U2DbiUtils::PUBLIC_DATABASE_URL = U2DbiUtils::createFullDbiUrl(PUBLIC_DATABASE_LOGIN, "db.ugene.net", 3306, "public_ugene_1_25");
50
logNotSupported(U2DbiFeature f,U2Dbi * dbi,U2OpStatus & os)51 void U2DbiUtils::logNotSupported(U2DbiFeature f, U2Dbi *dbi, U2OpStatus &os) {
52 QString msg = tr("Feature is not supported: %1, dbi: %2").arg(int(f)).arg(dbi == nullptr ? QString("<unknown>") : dbi->getDbiId());
53 coreLog.error(msg);
54 if (!os.hasError()) {
55 os.setError(msg);
56 }
57
58 #ifdef _DEBUG
59 if (dbi->getFeatures().contains(f)) {
60 coreLog.error("Calling not-supported method while features is listed in supported features list!");
61 }
62 assert(0);
63 #endif
64 }
65
toRef(U2Dbi * dbi)66 U2DbiRef U2DbiUtils::toRef(U2Dbi *dbi) {
67 if (dbi == nullptr) {
68 return U2DbiRef();
69 }
70 return U2DbiRef(dbi->getFactoryId(), dbi->getDbiId());
71 }
72
addLimit(QString & sql,qint64 offset,qint64 count)73 void U2DbiUtils::addLimit(QString &sql, qint64 offset, qint64 count) {
74 if (count == -1) {
75 return;
76 }
77 sql = sql + QString(" LIMIT %1, %2").arg(offset).arg(count).toLatin1();
78 }
79
toU2DataId(qint64 id,U2DataType type,const QByteArray & dbExtra)80 U2DataId U2DbiUtils::toU2DataId(qint64 id, U2DataType type, const QByteArray &dbExtra) {
81 assert(sizeof(U2DataType) == 2);
82
83 if (0 == id) {
84 return emptyId;
85 }
86
87 int extraLen = dbExtra.size();
88 int len = DATAID_MIN_LEN + extraLen;
89 QByteArray res(len, Qt::Uninitialized);
90 char *data = res.data();
91 ((qint64 *)(data + DB_ID_OFFSET))[0] = id;
92 ((U2DataType *)(data + TYPE_OFFSET))[0] = type;
93 if (extraLen > 0) {
94 memcpy(data + DB_EXTRA_OFFSET, dbExtra.constData(), dbExtra.size());
95 }
96
97 return res;
98 }
99
toDbiId(const U2DataId & id)100 quint64 U2DbiUtils::toDbiId(const U2DataId &id) {
101 if (id.size() < DATAID_MIN_LEN) {
102 return 0;
103 }
104 return *(qint64 *)(id.constData() + DB_ID_OFFSET);
105 }
106
toType(const U2DataId & id)107 U2DataType U2DbiUtils::toType(const U2DataId &id) {
108 if (id.size() < DATAID_MIN_LEN) {
109 return 0;
110 }
111 return *(U2DataType *)(id.constData() + TYPE_OFFSET);
112 }
113
toDbExtra(const U2DataId & id)114 QByteArray U2DbiUtils::toDbExtra(const U2DataId &id) {
115 if (id.size() < DATAID_MIN_LEN) {
116 return emptyId;
117 }
118 return QByteArray(id.constData() + DB_EXTRA_OFFSET, id.length() - DB_EXTRA_OFFSET);
119 }
120
text(const U2DataId & id)121 QString U2DbiUtils::text(const U2DataId &id) {
122 QString res = QString("[Id: %1, Type: %2, Extra: %3]").arg(toDbiId(id)).arg(int(toType(id))).arg(toDbExtra(id).constData());
123 return res;
124 }
125
ref2Url(const U2DbiRef & dbiRef)126 QString U2DbiUtils::ref2Url(const U2DbiRef &dbiRef) {
127 U2DbiFactory *dbiFactory = AppContext::getDbiRegistry()->getDbiFactoryById(dbiRef.dbiFactoryId);
128 SAFE_POINT(nullptr != dbiFactory, QString("Invalid database type: %1").arg(dbiRef.dbiFactoryId), "");
129 return dbiFactory->id2Url(dbiRef.dbiId).getURLString();
130 }
131
createDbiUrl(const QString & host,int port,const QString & dbName)132 QString U2DbiUtils::createDbiUrl(const QString &host, int port, const QString &dbName) {
133 QString portString = (port >= 0 ? QString::number(port) : "");
134 return host + ":" + portString + "/" + dbName;
135 }
136
createFullDbiUrl(const QString & userName,const QString & host,int port,const QString & dbName)137 QString U2DbiUtils::createFullDbiUrl(const QString &userName, const QString &host, int port, const QString &dbName) {
138 return createFullDbiUrl(userName, createDbiUrl(host, port, dbName));
139 }
140
createFullDbiUrl(const QString & userName,const QString & dbiUrl)141 QString U2DbiUtils::createFullDbiUrl(const QString &userName, const QString &dbiUrl) {
142 return userName + "@" + dbiUrl;
143 }
144
parseDbiUrl(const QString & dbiUrl,QString & host,int & port,QString & dbName)145 bool U2DbiUtils::parseDbiUrl(const QString &dbiUrl, QString &host, int &port, QString &dbName) {
146 int sepIndex = dbiUrl.indexOf(":");
147 if (sepIndex < 0) {
148 return false;
149 }
150
151 host = dbiUrl.left(sepIndex);
152
153 sepIndex = dbiUrl.indexOf("/", sepIndex);
154 if (sepIndex < 0) {
155 return false;
156 }
157
158 QString portString = dbiUrl.mid(host.length() + 1, sepIndex - host.length() - 1);
159 if (portString.isEmpty()) {
160 port = -1;
161 } else {
162 bool ok = false;
163 port = portString.toInt(&ok);
164 if (!ok) {
165 return false;
166 }
167 }
168
169 dbName = dbiUrl.right(dbiUrl.length() - sepIndex - 1);
170
171 return true;
172 }
173
parseFullDbiUrl(const QString & dbiUrl,QString & userName,QString & host,int & port,QString & dbName)174 bool U2DbiUtils::parseFullDbiUrl(const QString &dbiUrl, QString &userName, QString &host, int &port, QString &dbName) {
175 return parseDbiUrl(full2shortDbiUrl(dbiUrl, userName), host, port, dbName);
176 }
177
full2shortDbiUrl(const QString & fullDbiUrl)178 QString U2DbiUtils::full2shortDbiUrl(const QString &fullDbiUrl) {
179 QString unusedUserName;
180 return full2shortDbiUrl(fullDbiUrl, unusedUserName);
181 }
182
full2shortDbiUrl(const QString & fullDbiUrl,QString & userName)183 QString U2DbiUtils::full2shortDbiUrl(const QString &fullDbiUrl, QString &userName) {
184 int sepIndex = fullDbiUrl.indexOf("@");
185 if (-1 == sepIndex) {
186 return fullDbiUrl;
187 }
188
189 userName = fullDbiUrl.left(sepIndex);
190 return fullDbiUrl.right(fullDbiUrl.length() - sepIndex - 1);
191 }
192
isFullDbiUrl(const QString & dbiUrl)193 bool U2DbiUtils::isFullDbiUrl(const QString &dbiUrl) {
194 return dbiUrl.contains('@');
195 }
196
makeFolderCanonical(const QString & folder)197 QString U2DbiUtils::makeFolderCanonical(const QString &folder) {
198 if (U2ObjectDbi::ROOT_FOLDER == folder) {
199 return folder;
200 }
201
202 QString result = folder.startsWith(U2ObjectDbi::ROOT_FOLDER + U2ObjectDbi::PATH_SEP) ? folder : U2ObjectDbi::ROOT_FOLDER + U2ObjectDbi::PATH_SEP + folder;
203 result.replace(QRegExp(U2ObjectDbi::PATH_SEP + "+"), U2ObjectDbi::PATH_SEP);
204
205 if (U2ObjectDbi::ROOT_FOLDER != result &&
206 result.endsWith(U2ObjectDbi::ROOT_FOLDER)) {
207 result.chop(U2ObjectDbi::ROOT_FOLDER.size());
208 }
209
210 return result;
211 }
212
isDbiReadOnly(const U2DbiRef & dbiRef)213 bool U2DbiUtils::isDbiReadOnly(const U2DbiRef &dbiRef) {
214 U2OpStatusImpl os;
215 DbiConnection con(dbiRef, os);
216 CHECK_OP(os, true);
217
218 return con.dbi->isReadOnly();
219 }
220
getDbMinRequiredVersion(const U2DbiRef & dbiRef,U2OpStatus & os)221 Version U2DbiUtils::getDbMinRequiredVersion(const U2DbiRef &dbiRef, U2OpStatus &os) {
222 DbiConnection con(dbiRef, os);
223 CHECK_OP(os, Version());
224 return Version::parseVersion(con.dbi->getProperty(U2DbiOptions::APP_MIN_COMPATIBLE_VERSION, "", os));
225 }
226
isDatabaseTooNew(const U2DbiRef & dbiRef,const Version & ugeneVersion,QString & minRequiredVersionString,U2OpStatus & os)227 bool U2DbiUtils::isDatabaseTooNew(const U2DbiRef &dbiRef, const Version &ugeneVersion, QString &minRequiredVersionString, U2OpStatus &os) {
228 const Version minRequiredVersion = getDbMinRequiredVersion(dbiRef, os);
229 CHECK_OP(os, false);
230 minRequiredVersionString = minRequiredVersion.text;
231 return minRequiredVersion > ugeneVersion;
232 }
233
isDatabaseTooOld(const U2DbiRef & dbiRef,const Version & ugeneVersion,U2OpStatus & os)234 bool U2DbiUtils::isDatabaseTooOld(const U2DbiRef &dbiRef, const Version &ugeneVersion, U2OpStatus &os) {
235 const Version minRequiredVersion = getDbMinRequiredVersion(dbiRef, os);
236 CHECK_OP(os, false);
237 return minRequiredVersion < ugeneVersion;
238 }
239
240 //////////////////////////////////////////////////////////////////////////
241 // TmpDbiHandle
242
TmpDbiHandle()243 TmpDbiHandle::TmpDbiHandle() {
244 }
245
TmpDbiHandle(const QString & _alias,U2OpStatus & os,const U2DbiFactoryId & factoryId)246 TmpDbiHandle::TmpDbiHandle(const QString &_alias, U2OpStatus &os, const U2DbiFactoryId &factoryId)
247 : alias(_alias) {
248 dbiRef = AppContext::getDbiRegistry()->attachTmpDbi(alias, os, factoryId);
249 }
250
TmpDbiHandle(const TmpDbiHandle & dbiHandle)251 TmpDbiHandle::TmpDbiHandle(const TmpDbiHandle &dbiHandle) {
252 if (dbiHandle.isValid()) {
253 alias = dbiHandle.getAlias();
254 dbiRef = dbiHandle.getDbiRef();
255
256 U2OpStatus2Log os;
257 AppContext::getDbiRegistry()->attachTmpDbi(dbiHandle.getAlias(), os, dbiRef.dbiFactoryId);
258 }
259 }
260
operator =(const TmpDbiHandle & dbiHandle)261 TmpDbiHandle &TmpDbiHandle::operator=(const TmpDbiHandle &dbiHandle) {
262 if (this != &dbiHandle) {
263 if (dbiHandle.isValid()) {
264 alias = dbiHandle.getAlias();
265 dbiRef = dbiHandle.getDbiRef();
266
267 U2OpStatus2Log os;
268 AppContext::getDbiRegistry()->attachTmpDbi(dbiHandle.getAlias(), os, dbiRef.dbiFactoryId);
269 }
270 }
271
272 return *this;
273 }
274
~TmpDbiHandle()275 TmpDbiHandle::~TmpDbiHandle() {
276 if (isValid()) {
277 U2OpStatus2Log os;
278 AppContext::getDbiRegistry()->detachTmpDbi(alias, os);
279 }
280 }
281
282 //////////////////////////////////////////////////////////////////////////
283 // TmpDbiObjects
~TmpDbiObjects()284 TmpDbiObjects::~TmpDbiObjects() {
285 if (os.isCoR()) {
286 foreach (const U2DataId &id, objects) {
287 if (!id.isEmpty()) {
288 U2OpStatus2Log os2log;
289 DbiConnection con(dbiRef, os2log);
290 con.dbi->getObjectDbi()->removeObject(id, os2log);
291 }
292 }
293 }
294 }
295
DbiOperationsBlock(const U2DbiRef & _dbiRef,U2OpStatus & os)296 DbiOperationsBlock::DbiOperationsBlock(const U2DbiRef &_dbiRef, U2OpStatus &os)
297 : dbiRef(_dbiRef),
298 os(os) {
299 connection = new DbiConnection(dbiRef, os);
300 CHECK_OP(os, );
301 connection->dbi->startOperationsBlock(os);
302 }
303
~DbiOperationsBlock()304 DbiOperationsBlock::~DbiOperationsBlock() {
305 if (nullptr != connection->dbi) {
306 connection->dbi->stopOperationBlock(os);
307 }
308 delete connection;
309 }
310
311 } // namespace U2
312