玉兔远程控制 0.1.0-bate8
载入中...
搜索中...
未找到
Database.cpp
1// Author: Kang Lin <kl222@126.com>
2
3#include <QSqlDriver>
4#include <QSqlDatabase>
5#include <QSqlQuery>
6#include <QSqlError>
7#include <QLoggingCategory>
8#include <QJsonDocument>
9#include <QJsonArray>
10#include <QJsonObject>
11#include "RabbitCommonDir.h"
12#include "RabbitCommonTools.h"
13#include "IconUtils.h"
14
15#include "Database.h"
16#include "ParameterDatabase.h"
17static Q_LOGGING_CATEGORY(log, "DB")
18CDatabase::CDatabase(QObject *parent)
19 : QObject{parent}
20 , m_MinVersion("0.1.0")
21 , m_pPara(nullptr)
22 , m_bOwner(false)
23{
24 qDebug(log) << Q_FUNC_INFO;
25}
26
27CDatabase::~CDatabase()
28{
29 qDebug(log) << Q_FUNC_INFO;
30 if (m_bOwner)
32}
33
35{
36 return SetDatabase(db->GetDatabase(), db->GetParameter());
37}
38
39bool CDatabase::SetDatabase(const QSqlDatabase db, const CParameterDatabase *pPara)
40{
41 QString szErr = "Only one of OpenDatabase or SetDatabase can be called, and it can only be called once";
42 Q_ASSERT_X(!IsOpen(), "Database", szErr.toStdString().c_str());
43 SetError();
44 m_database = db;
45 m_pPara = pPara;
46 return OnInitializeDatabase();
47}
48
49QSqlDatabase CDatabase::GetDatabase() const
50{
51 return m_database;
52}
53
54const CParameterDatabase *CDatabase::GetParameter() const
55{
56 return m_pPara;
57}
58
59const QString CDatabase::GetError() const
60{
61 return m_szError;
62}
63
64void CDatabase::SetError(const QString &szErr)
65{
66 m_szError = szErr;
67}
68
70 const QString &szConnectName)
71{
72 SetError();
73 bool bRet = false;
74 if(!pPara) {
75 bRet = OpenSQLiteDatabase(pPara, szConnectName);
76 return bRet;
77 }
78
79 m_pPara = pPara;
80 QString szErr = "Only one of OpenDatabase or SetDatabase can be called, and it can only be called once";
81 Q_ASSERT_X(!IsOpen(), "Database", szErr.toStdString().c_str());
82
83 if(pPara->GetType() == "QSQLITE")
84 bRet = OpenSQLiteDatabase(pPara, szConnectName);
85 else if(pPara->GetType() == "QMYSQL")
86 bRet = OpenMySqlDatabase(pPara, szConnectName);
87 else if(pPara->GetType() == "QODBC")
88 bRet = OpenODBCDatabase(pPara, szConnectName);
89 else
90 SetError(tr("Database type not supported:") + " " + pPara->GetType());
91
92 QSqlDriver *driver = GetDatabase().driver();
93 if (driver) {
94 qDebug(log) << "=== Features for" << pPara->GetType() << "===";
95 qDebug(log) << "Transactions:" << driver->hasFeature(QSqlDriver::Transactions);
96 qDebug(log) << "Query size:" << driver->hasFeature(QSqlDriver::QuerySize);
97 qDebug(log) << "BLOB:" << driver->hasFeature(QSqlDriver::BLOB);
98 qDebug(log) << "Unicode:" << driver->hasFeature(QSqlDriver::Unicode);
99 qDebug(log) << "Prepared queries:" << driver->hasFeature(QSqlDriver::PreparedQueries);
100 qDebug(log) << "Named placeholders:" << driver->hasFeature(QSqlDriver::NamedPlaceholders);
101 qDebug(log) << "Positional placeholders:" << driver->hasFeature(QSqlDriver::PositionalPlaceholders);
102 qDebug(log) << "Last insert ID:" << driver->hasFeature(QSqlDriver::LastInsertId);
103 qDebug(log) << "Batch operations:" << driver->hasFeature(QSqlDriver::BatchOperations);
104 qDebug(log) << "Event notifications:" << driver->hasFeature(QSqlDriver::EventNotifications);
105 qDebug(log) << "Finish query:" << driver->hasFeature(QSqlDriver::FinishQuery);
106 qDebug(log) << "Multiple result sets:" << driver->hasFeature(QSqlDriver::MultipleResultSets);
107 qDebug(log) << "Cancel query:" << driver->hasFeature(QSqlDriver::CancelQuery);
108 }
109
110 return bRet;
111}
112
113bool CDatabase::OpenSQLiteDatabase(const CParameterDatabase *pPara,
114 const QString &szConnectionName)
115{
116 QString szFile;
117 if(pPara) {
118 szFile = pPara->GetDatabaseName();
119 }
120 return OpenSQLiteDatabase(szFile, szConnectionName);
121}
122
123bool CDatabase::OpenSQLiteDatabase(
124 const QString& szFile, const QString& szConnectionName)
125{
126 QString databasePath = szFile;
127 if (databasePath.isEmpty()) {
128 // 使用默认路径
129 QString dataDir = RabbitCommon::CDir::Instance()->GetDirUserDatabase();
130 QDir dir(dataDir);
131 if (!dir.exists()) {
132 dir.mkpath(dataDir);
133 }
134#if DEBUG
135 databasePath = dir.filePath("remote_control_dev.db");
136#else
137 databasePath = dir.filePath("remote_control.db");
138#endif
139 }
140
141 if(!szConnectionName.isEmpty())
142 m_szConnectName = szConnectionName;
143
144 // 打开或创建数据库
145 m_database = QSqlDatabase::addDatabase("QSQLITE", m_szConnectName);
146 m_database.setDatabaseName(databasePath);
147
148 if (!m_database.open()) {
149 SetError("Failed to open sqlite database: " + m_database.databaseName()
150 + "; Connect name: " + m_database.connectionName()
151 + "; Error: " + m_database.lastError().text());
152 qCritical(log) << GetError();
153 return false;
154 }
155
156 m_bOwner = true;
157 qInfo(log) << "Open sqlite database:" << m_database.databaseName()
158 << "Connect name:" << m_database.connectionName();
159
160 return OnInitializeDatabase();
161}
162
163bool CDatabase::OpenMySqlDatabase(const CParameterDatabase *pPara,
164 const QString &szConnectName)
165{
166 bool success = false;
167 if(!pPara) return false;
168
169 if(!szConnectName.isEmpty())
170 m_szConnectName = szConnectName;
171
172 // 打开或创建数据库
173 m_database = QSqlDatabase::addDatabase("QMYSQL", m_szConnectName);
174 QString szDbName = pPara->GetDatabaseName();
175 if(szDbName.isEmpty()) {
176#if DEBUG
177 szDbName = "remote_control_dev";
178#else
179 szDbName = "remote_control";
180#endif
181 }
182
183 auto &net = pPara->m_Net;
184 m_database.setHostName(net.GetHost());
185 m_database.setPort(net.GetPort());
186 auto &user = net.m_User;
187 m_database.setUserName(user.GetName());
188 m_database.setPassword(user.GetPassword());
189
190 if (!m_database.open()) {
191 SetError("Failed to open mysql database: " + m_database.databaseName()
192 + "; Connect name: " + m_database.connectionName()
193 + "; Host: " + net.GetHost()
194 + "; Port: " + QString::number(net.GetPort())
195 + "; User: " + user.GetUser()
196 + "; Error: " + m_database.lastError().text()
197 );
198 qCritical(log) << GetError();
199 return false;
200 }
201
202 m_bOwner = true;
203
204 QSqlQuery query(GetDatabase());
205 success = query.exec("CREATE DATABASE IF NOT EXISTS " + szDbName);
206 if (!success) {
207 SetError("Failed to create mysql database: " + szDbName
208 + "; Error: " + query.lastError().text()
209 + "; Sql: " + query.executedQuery());
210 qCritical(log) << GetError();
211 return false;
212 }
213
214 success = query.exec("use " + szDbName);
215 if (!success) {
216 SetError("Failed to use " + szDbName
217 + "; Error: " + query.lastError().text()
218 + "; Sql: " + query.executedQuery());
219 qCritical(log) << GetError();
220 return false;
221 }
222
223 m_database.setDatabaseName(szDbName);
224 qInfo(log) << "Open mysql database:" << m_database.databaseName()
225 << "Connect name:" << m_database.connectionName()
226 << "Host:" << net.GetHost() << "Port:" << net.GetPort()
227 << "User:" << user.GetUser();
228
229 return OnInitializeDatabase();
230}
231
232bool CDatabase::OpenODBCDatabase(const CParameterDatabase *pPara,
233 const QString &szConnectName)
234{
235 if(!pPara) return false;
236
237 if(!szConnectName.isEmpty())
238 m_szConnectName = szConnectName;
239
240 // 打开或创建数据库
241 m_database = QSqlDatabase::addDatabase("QODBC", m_szConnectName);
242 QString szDbName = pPara->GetDatabaseName();
243 if(szDbName.isEmpty()) {
244#if DEBUG
245 szDbName = "remote_control_dev";
246#else
247 szDbName = "remote_control";
248#endif
249 }
250 m_database.setDatabaseName(szDbName);
251
252 if (!m_database.open()) {
253 SetError("Failed to open odbc database: " + m_database.databaseName()
254 + "; Connect name: " + m_database.connectionName()
255 + "; Error: " + m_database.lastError().text()
256 );
257 qCritical(log) << GetError();
258 return false;
259 }
260
261 m_bOwner = true;
262
263 QSqlQuery query(GetDatabase());
264 bool success = query.exec("CREATE DATABASE IF NOT EXISTS " + szDbName);
265 if (!success) {
266 SetError("Failed to create database: " + szDbName
267 + "; Error: " + query.lastError().text()
268 + "; Sql: " + query.executedQuery());
269 qCritical(log) << GetError();
270 return false;
271 }
272
273 success = query.exec("use " + szDbName);
274 if (!success) {
275 SetError("Failed to use " + szDbName
276 + "; Error: " + query.lastError().text()
277 + "; Sql: " + query.executedQuery());
278 qCritical(log) << GetError();
279 return false;
280 }
281
282 qInfo(log) << "Open odbc database:" << m_database.databaseName()
283 << "Connect name:" << m_database.connectionName();
284
285 return OnInitializeDatabase();
286}
287
289{
290 bool bRet = false;
291 if(!m_pPara) {
292 bRet = OnInitializeSqliteDatabase();
293 return bRet;
294 }
295 if(m_pPara->GetType() == "QSQLITE")
296 bRet = OnInitializeSqliteDatabase();
297 else if(m_pPara->GetType() == "QMYSQL" || m_pPara->GetType() == "QODBC") {
298 bRet = OnInitializeMySqlDatabase();
299 } else {
300 SetError("Don't support:" + m_pPara->GetType());
301 qWarning(log) << GetError();
302 }
303 return bRet;
304}
305
306bool CDatabase::OnInitializeSqliteDatabase()
307{
308 return true;
309}
310
311bool CDatabase::OnInitializeMySqlDatabase()
312{
313 return true;
314}
315
316bool CDatabase::IsOpen() const
317{
318 return m_database.isOpen();
319}
320
322{
323 if (!m_bOwner) {
324 QString szErr = "This instance is not the owner of the database, but it is will close the database.";
325 qWarning(log) << szErr;
326 Q_ASSERT_X(m_bOwner, "CDatabase", szErr.toStdString().c_str());
327 }
328 if(m_database.isOpen()) {
329 m_database.close();
330 }
331 QSqlDatabase::removeDatabase(m_szConnectName);
332}
333
334bool CDatabase::ExportToJsonFile(const QString &szFile)
335{
336 SetError();
337 QFile file(szFile);
338 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
339 SetError("Failed to open export JSON file: " + szFile + "; Error: " + file.errorString());
340 qCritical(log) << GetError();
341 return false;
342 }
343
344 QTextStream out(&file);
345#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
346 out.setEncoding(QStringConverter::Utf8);
347#else
348 out.setCodec("UTF-8");
349#endif
350 out.setGenerateByteOrderMark(true); // 添加 UTF-8 BOM
351
352 QJsonDocument doc;
353 QJsonObject root;
354 root.insert("Title", "Rabbit Remote Control");
355 root.insert("Author", "Kang Lin <kl222@126.com>");
356 root.insert("Version", "0.1.0");
357
358 bool bRet = true;
359 bRet = ExportToJson(root);
360 if(bRet) {
361 doc.setObject(root);
362 out << doc.toJson();
363 }
364
365 file.close();
366 return true;
367}
368
369bool CDatabase::ImportFromJsonFile(const QString &szFile)
370{
371 bool bRet = false;
372 SetError();
373 QFile file(szFile);
374 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
375 SetError(tr("Failed to open import JSON file: %1; Error: %2").arg(szFile, file.errorString()));
376 qCritical(log) << GetError();
377 return false;
378 }
379
380 do {
381 QJsonDocument doc;
382 doc = QJsonDocument::fromJson(file.readAll());
383 if(!doc.isObject()) {
384 SetError(tr("Not a valid JSON file"));
385 qCritical(log) << GetError();
386 break;
387 }
388 auto root = doc.object();
389 QString szTitle = root["Title"].toString();
390 if(szTitle != "Rabbit Remote Control") {
391 SetError(tr("File format error. The title: \"%1\" is not \"Rabbit Remote Control\"").arg(szTitle));
392 qCritical(log) << GetError();
393 break;
394 }
395 QString szVersion = root["Version"].toString();
396 if(RabbitCommon::CTools::VersionCompare(szVersion, m_MinVersion) < 0) {
397 SetError(tr("The version is no longer supported: ")
398 + szVersion + " < " + m_MinVersion);
399 qCritical(log) << GetError();
400 break;
401 }
402 bRet = ImportFromJson(doc.object());
403 } while(0);
404
405 file.close();
406 return bRet;
407}
408
409bool CDatabase::ImportFromJson(const QJsonObject &obj)
410{
411 return true;
412}
413
414bool CDatabase::ExportToJson(QJsonObject &obj)
415{
416 return true;
417}
418
419CDatabaseIcon::CDatabaseIcon(const QString &szSuffix, QObject *parent)
420 : CDatabase(parent)
421{
422 m_szTableName = "icon";
423 if(!szSuffix.isEmpty())
424 m_szTableName = m_szTableName + "_" + szSuffix;
425 m_szConnectName = "connect_" + m_szTableName;
426}
427
428bool CDatabaseIcon::OnInitializeSqliteDatabase()
429{
430 QSqlQuery query(GetDatabase());
431
432 // Create icon table
433 QString szSql =
434 "CREATE TABLE IF NOT EXISTS " + m_szTableName + " ("
435 " id INTEGER PRIMARY KEY AUTOINCREMENT,"
436 " name TEXT UNIQUE," // Icon name. see QIcon::name()
437 " hash TEXT," // Icon hash value
438 " data BLOB" // Icon binary data
439 ")"
440 ;
441 bool success = query.exec(szSql);
442 if (!success) {
443 SetError("Failed to create icon sqlite table: " + m_szTableName
444 + "; Error: " + query.lastError().text()
445 + "; Sql: " + szSql);
446 qCritical(log) << GetError();
447 return false;
448 }
449 szSql = "CREATE INDEX IF NOT EXISTS idx_" + m_szTableName + "_name ON " + m_szTableName + "(name)";
450 success = query.exec(szSql);
451 if (!success) {
452 qWarning(log) << "Failed to create icon name index in" << m_szTableName
453 << "Error:" << query.lastError().text()
454 << "Sql:" << szSql;
455 }
456 szSql = "CREATE INDEX IF NOT EXISTS idx_" + m_szTableName + "_hash ON " + m_szTableName + "(hash)";
457 success = query.exec(szSql);
458 if (!success) {
459 qWarning(log) << "Failed to create icon hash index in" << m_szTableName
460 << "Error:" << query.lastError().text()
461 << "Sql:" << szSql;
462 }
463 return true;
464}
465
466bool CDatabaseIcon::OnInitializeMySqlDatabase()
467{
468 QSqlQuery query(GetDatabase());
469
470 // Create icon table
471 QString szSql =
472 "CREATE TABLE IF NOT EXISTS " + m_szTableName + " ("
473 " id INTEGER PRIMARY KEY AUTO_INCREMENT,"
474 " name TEXT," // Icon name. see QIcon::name()
475 " hash TEXT," // Icon hash value
476 " data LONGBLOB," // Icon binary data
477 " UNIQUE KEY idx_icon_name (name(255)),"
478 " INDEX idx_icon_hash (hash(255))"
479 ")"
480 ;
481 bool success = query.exec(szSql);
482 if (!success) {
483 SetError("Failed to create icon mysql table: " + m_szTableName
484 + "; Error: " + query.lastError().text()
485 + "; Sql: " + szSql);
486 qCritical(log) << GetError();
487 return false;
488 }
489
490 return true;
491}
492
493int CDatabaseIcon::GetIcon(const QIcon &icon)
494{
495 bool bRet = false;
496 if(icon.isNull()) return 0;
497
498 QString szSql;
499 QSqlQuery query(GetDatabase());
500 QString szName = icon.name();
501 if(szName.isEmpty()) {
502 // Check hash and data
503 QByteArray data = RabbitCommon::CIconUtils::iconToByteArray(icon);
504 QString szHash = RabbitCommon::CIconUtils::hashIconData(data);
505 if(data.isEmpty() || szHash.isEmpty())
506 return 0;
507 szSql = "SELECT id, data FROM " + m_szTableName + " WHERE hash=:hash";
508 query.prepare(szSql);
509 query.bindValue(":hash", szHash);
510 // qDebug(log) << "prepare:" << query.executedQuery();
511 // qDebug(log) << "Bound values:" << query.boundValues();
512 bRet = query.exec();
513 if(!bRet) {
514 qDebug(log) << "Failed to select icon hash:" << szHash
515 << "Error:" << query.lastError().text()
516 << "Sql:" << query.executedQuery();
517 return 0;
518 }
519 while (query.next()) {
520 // check a same data
521 if(data == query.value(1).toByteArray()) {
522 return query.value(0).toInt();
523 }
524 }
525
526 szSql = "INSERT INTO " + m_szTableName + " (hash, data) "
527 "VALUES (:hash, :data)";
528 query.prepare(szSql);
529 query.bindValue(":hash", szHash);
530 query.bindValue(":data", data);
531 bRet = query.exec();
532 if(!bRet) {
533 SetError("Failed to insert icon hash: " + szHash
534 + "; Error: " + query.lastError().text()
535 + "; Sql: " + query.executedQuery());
536 qCritical(log) << GetError();
537 return 0;
538 }
539 return query.lastInsertId().toInt();
540 }
541
542 // Check name
543 szSql = "SELECT id FROM " + m_szTableName + " WHERE name=:name";
544 query.prepare(szSql);
545 query.bindValue(":name", szName);
546 bRet = query.exec();
547 if(!bRet) {
548 SetError("Failed to select icon name: " + szName
549 + "; Error: " + query.lastError().text()
550 + "; Sql: " + query.executedQuery());
551 qCritical(log) << GetError();
552 return 0;
553 }
554 if(query.next()) {
555 return query.value(0).toInt();
556 }
557
558 // Insert icon
559 szSql = "INSERT INTO " + m_szTableName + " (name) VALUES (:name)";
560 query.prepare(szSql);
561 query.bindValue(":name", szName);
562 bRet = query.exec();
563 if(!bRet) {
564 SetError("Failed to insert icon name: " + szName
565 + "; Error: " + query.lastError().text()
566 + "; Sql: " + query.executedQuery());
567 qCritical(log) << GetError();
568 return 0;
569 }
570 return query.lastInsertId().toInt();
571}
572
573QIcon CDatabaseIcon::GetIcon(int id)
574{
575 QIcon icon;
576 QSqlQuery query(GetDatabase());
577 query.prepare(
578 "SELECT name, data FROM " + m_szTableName +
579 " WHERE id=:id "
580 );
581 query.bindValue(":id", id);
582 bool bRet = query.exec();
583 if(!bRet) {
584 SetError("Failed to get icon id: " + QString::number(id)
585 + "; Error: " + query.lastError().text()
586 + "; Sql: " + query.executedQuery());
587 qCritical(log) << GetError();
588 return icon;
589 }
590
591 if (query.next()) {
592 QString szName = query.value(0).toString();
593 if(!szName.isEmpty()) {
594 return QIcon::fromTheme(szName);
595 }
596 QByteArray ba = query.value(1).toByteArray();
597 return RabbitCommon::CIconUtils::byteArrayToIcon(ba);
598 }
599 return icon;
600}
601/*
602bool CDatabaseIcon::ExportToJson(QJsonObject &obj)
603{
604 QSqlQuery query(GetDatabase());
605 query.prepare(
606 "SELECT id, name, hash, data FROM " + m_szTableName
607 );
608 bool bRet = query.exec();
609 if(!bRet) {
610 SetError("Failed to export icon to json. Error: " + query.lastError().text()
611 + "; Sql: " + query.executedQuery());
612 qCritical(log) << GetError();
613 return false;
614 }
615
616 QJsonArray icon;
617 while (query.next()) {
618 QJsonObject i;
619 i.insert("id", query.value(0).toInt());
620 i.insert("name", query.value(1).toString());
621 i.insert("hash", query.value(2).toString());
622 i.insert("data", query.value(3).toByteArray().toBase64().toStdString().c_str());
623 icon.append(i);
624 }
625 if(!icon.isEmpty())
626 obj.insert("icon", icon);
627 return true;
628}
629//*/
630bool CDatabaseIcon::ExportIconToJson(const QIcon &icon, QJsonObject &obj)
631{
632 QString szIconName = icon.name();
633 if(szIconName.isEmpty()) {
634 QByteArray baIcon = RabbitCommon::CIconUtils::iconToByteArray(icon);
635 obj.insert("IconData", baIcon.toBase64().toStdString().c_str());
636 } else {
637 obj.insert("IconName", szIconName);
638 }
639 return true;
640}
641
642bool CDatabaseIcon::ImportIconFromJson(const QJsonObject &itemObj, QIcon &icon)
643{
644 QString szIconName = itemObj["IconName"].toString();
645 if(szIconName.isEmpty()) {
646 QByteArray baIcon(itemObj["IconData"].toString().toStdString().c_str());
647 if(!baIcon.isEmpty()) {
648 baIcon = QByteArray::fromBase64(baIcon);
649 icon = RabbitCommon::CIconUtils::byteArrayToIcon(baIcon);
650 }
651 } else {
652 icon = QIcon::fromTheme(szIconName);
653 }
654 return true;
655}
656
657bool CDatabaseFile::ExportFileToJson(const QString &szFile, QJsonObject &obj)
658{
659 QString szErr;
660 QFileInfo fi(szFile);
661 if(fi.isRelative()) {
662 fi = QFileInfo(SetFile(szFile));
663 }
664 if(!fi.exists()) {
665 szErr = "File is not exist: " + fi.filePath();
666 qCritical(log) << szErr;
667 return false;
668 }
669 QFile f(fi.absoluteFilePath());
670 if(!f.open(QFile::ReadOnly | QFile::Text)) {
671 szErr = "Failed to open file: " + f.fileName() + "; Error: " + f.errorString();
672 qCritical(log) << szErr;
673 return false;
674 }
675 QString szFileContent = f.readAll();
676 f.close();
677 if(szFileContent.isEmpty()) {
678 qCritical(log) << "The file is empty:" << szFile;
679 return false;
680 };
681 obj.insert("FileName", fi.fileName());
682 obj.insert("FileContent", szFileContent);
683 return true;
684}
685
686bool CDatabaseFile::ImportFileFromJson(const QJsonObject &obj, QString &szFile)
687{
688 QString szErr;
689 QString szFileContent = obj["FileContent"].toString();
690 if(szFileContent.isEmpty()) {
691 qCritical(log) << "The file content is empty.";
692 return false;
693 }
694 szFile = obj["FileName"].toString();
695 if(szFile.isEmpty()) {
696 qCritical(log) << "The file name is empty.";
697 return false;
698 }
699 szFile = GetFile(szFile);
700 QFileInfo fi(szFile);
701 if(!fi.exists()) {
702 QFile f(szFile);
703 if(!f.open(QFile::WriteOnly | QFile::Text)) {
704 szErr = "Failed to open file: " + szFile
705 + "; Error: " + f.errorString();
706 qCritical(log) << szErr;
707 return false;
708 }
709 f.write(szFileContent.toStdString().c_str(), szFileContent.size());
710 f.close();
711 }
712 return true;
713}
714
715bool CDatabaseFile::ImportFileToDatabaseFromJson(const QJsonObject &obj, QString &szFile)
716{
717 bool bRet = ImportFileFromJson(obj, szFile);
718 if(!bRet) return bRet;
719 bRet = Save(szFile);
720 return bRet;
721}
722
723CDatabaseFile::CDatabaseFile(const QString &szSuffix, QObject *parent)
724 : CDatabase(parent)
725{
726 m_szTableName = "file";
727 if(!szSuffix.isEmpty())
728 m_szTableName = m_szTableName + "_" + szSuffix;
729 m_szConnectName = "connect_" + m_szTableName;
730}
731
732QByteArray CDatabaseFile::Load(const QString &szFile)
733{
734 QByteArray content;
735 if(szFile.isEmpty()) return content;
736 QFileInfo fi(szFile);
737 QSqlQuery query(GetDatabase());
738 query.prepare(
739 "SELECT content FROM " + m_szTableName + " "
740 " WHERE file=:file");
741 query.bindValue(":file", fi.fileName());
742 bool ok = query.exec();
743 if(ok) {
744 if(query.next()) {
745 content = query.value(0).toByteArray();
746 }
747 } else {
748 SetError("Failed to Load file from: " + m_szTableName
749 + "; Error: " + query.lastError().text()
750 + "; Sql: " + query.executedQuery());
751 qCritical(log) << GetError();
752 }
753 return content;
754}
755
756bool CDatabaseFile::Save(const QString &szFile)
757{
758 bool bRet = true;
759 if(szFile.isEmpty()) return false;
760 QFile f(szFile);
761 if(!f.open(QFile::ReadOnly | QFile::Text)) {
762 SetError("Failed to open file: " + szFile
763 + "; Error: " + f.errorString());
764 return false;
765 }
766 QByteArray content = f.readAll();
767 f.close();
768 QFileInfo fi(szFile);
769 QSqlQuery query(GetDatabase());
770 bRet = query.prepare(
771 "SELECT content FROM " + m_szTableName + " "
772 " WHERE file=:file"
773 );
774 if(!bRet) {
775 SetError("Failed to prepare: " + query.executedQuery()
776 + "; Error: " + query.lastError().text());
777 qCritical(log) << GetError();
778 return false;
779 }
780 query.bindValue(":file", fi.fileName());
781 bRet = query.exec();
782 if(!bRet){
783 SetError("Failed to exec: " + query.executedQuery()
784 + "; Error: " + query.lastError().text());
785 qCritical(log) << GetError();
786 return false;
787 }
788 if(query.next()) {
789 query.prepare(
790 "UPDATE " + m_szTableName + " "
791 "SET content = :content "
792 "WHERE file = :file"
793 );
794 query.bindValue(":file", fi.fileName());
795 query.bindValue(":content", content);
796 } else {
797 query.prepare(
798 "INSERT INTO " + m_szTableName + " "
799 "(file, content) "
800 "VALUES (:file, :content)"
801 );
802 query.bindValue(":file", fi.fileName());
803 query.bindValue(":content", content);
804 }
805 bRet = query.exec();
806 if (!bRet) {
807 SetError("Failed to save file to:" + m_szTableName
808 + "; Error: " + query.lastError().text()
809 + "; Sql: " + query.executedQuery());
810 qCritical(log) << GetError();
811 return false;
812 }
813 return bRet;
814}
815
816bool CDatabaseFile::OnInitializeSqliteDatabase()
817{
818 QSqlQuery query(GetDatabase());
819
820 // Create file table
821 QString szSql =
822 "CREATE TABLE IF NOT EXISTS " + m_szTableName + " ("
823 " file TEXT KEY NOT NULL UNIQUE,"
824 " content LONGBLOB"
825 ")"
826 ;
827 bool success = query.exec(szSql);
828 if (!success) {
829 SetError("Failed to create file sqlite table: " + m_szTableName
830 + "; Error: " + query.lastError().text()
831 + "; Sql: " + query.executedQuery());
832 qCritical(log) << GetError();
833 return false;
834 }
835
836 return true;
837}
838
839bool CDatabaseFile::OnInitializeMySqlDatabase()
840{
841 QSqlQuery query(GetDatabase());
842 QString szSql = "CREATE TABLE IF NOT EXISTS `" + m_szTableName + "` ( "
843 "`file` TEXT NOT NULL , "
844 "`content` LONGBLOB, "
845 "UNIQUE KEY `uk_file` (`file`(255))"
846 ")";
847 bool success = query.exec(szSql);
848 if (!success) {
849 SetError("Failed to create file mysql table: " + m_szTableName
850 + "; Error: " + query.lastError().text()
851 + "; Sql: " + query.executedQuery());
852 qCritical(log) << GetError();
853 return false;
854 }
855
856 return true;
857}
858
859bool CDatabaseFile::IsExist(const QString &szFile)
860{
861 QSqlQuery query(GetDatabase());
862 bool ok = query.prepare("SELECT * from " + m_szTableName +
863 " WHERE `file`=:file");
864 if(!ok) {
865 SetError("Failed to prepare: " + query.executedQuery()
866 + "; Error: " + query.lastError().text());
867 qCritical(log) << GetError();
868 return false;
869 }
870 query.bindValue(":file", szFile);
871 ok = query.exec();
872 if(!ok) {
873 SetError("Failed to exec: " + query.executedQuery()
874 + "; Error: " + query.lastError().text());
875 qCritical(log) << GetError();
876 return false;
877 }
878 return query.next();
879}
880
881QString CDatabaseFile::GetFile(const QString &szFile)
882{
883 QFileInfo fi(szFile);
884 //qDebug(log) << szFile << fi.absolutePath();
885 if(fi.isRelative()) {
886 return RabbitCommon::CDir::Instance()->GetDirUserData()
887 + QDir::separator() + szFile;
888 }
889 return szFile;
890}
891
892QString CDatabaseFile::SetFile(const QString &file)
893{
894 QString szFile;
895 QFileInfo fi(file);
896 QFileInfo d(RabbitCommon::CDir::Instance()->GetDirUserData() + QDir::separator());
897 if(fi.absolutePath() == d.absolutePath())
898 szFile = fi.fileName();
899 else
900 szFile = file;
901 return szFile;
902}
bool ImportFileToDatabaseFromJson(const QJsonObject &obj, QString &szFile)
Import file to database from JSON
Definition Database.cpp:715
static bool ExportFileToJson(const QString &szFile, QJsonObject &obj)
ExportFileToJson
Definition Database.cpp:657
static bool ImportFileFromJson(const QJsonObject &obj, QString &szFile)
Import file from JSON
Definition Database.cpp:686
bool Save(const QString &szFile)
Save
Definition Database.cpp:756
QByteArray Load(const QString &szFile)
Load
Definition Database.cpp:732
static QString SetFile(const QString &szFile)
Set the file with file system to the file in database
Definition Database.cpp:892
static QString GetFile(const QString &szFile)
Get the file with file system from the file in database
Definition Database.cpp:881
int GetIcon(const QIcon &icon)
Get icon id
Definition Database.cpp:493
提供打开数据库和初始化数据库等接口
Definition Database.h:21
void CloseDatabase()
Close database
Definition Database.cpp:321
virtual bool OnInitializeDatabase()
Initialize database
Definition Database.cpp:288
bool SetDatabase(const CDatabase *db)
Share an existing database
Definition Database.cpp:34
bool OpenDatabase(const CParameterDatabase *pPara=nullptr, const QString &szConnectName=QString())
Open a new database
Definition Database.cpp:69