File indexing completed on 2025-01-05 04:46:58
0001 /* 0002 SPDX-FileCopyrightText: 2006 Tobias Koenig <tokoe@kde.org> 0003 SPDX-FileCopyrightText: 2012 Volker Krause <vkrause@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "dbintrospector.h" 0009 #include "akonadiserver_debug.h" 0010 #include "datastore.h" 0011 #include "dbexception.h" 0012 #include "dbintrospector_impl.h" 0013 #include "dbtype.h" 0014 #include "querybuilder.h" 0015 0016 #include <QSqlField> 0017 #include <QSqlQuery> 0018 #include <QSqlRecord> 0019 0020 using namespace Akonadi::Server; 0021 0022 DbIntrospector::Ptr DbIntrospector::createInstance(const QSqlDatabase &database) 0023 { 0024 switch (DbType::type(database)) { 0025 case DbType::MySQL: 0026 return Ptr(new DbIntrospectorMySql(database)); 0027 case DbType::Sqlite: 0028 return Ptr(new DbIntrospectorSqlite(database)); 0029 case DbType::PostgreSQL: 0030 return Ptr(new DbIntrospectorPostgreSql(database)); 0031 case DbType::Unknown: 0032 break; 0033 } 0034 qCCritical(AKONADISERVER_LOG) << database.driverName() << "backend not supported"; 0035 return Ptr(); 0036 } 0037 0038 DbIntrospector::DbIntrospector(const QSqlDatabase &database) 0039 : m_database(database) 0040 { 0041 } 0042 0043 DbIntrospector::~DbIntrospector() 0044 { 0045 } 0046 0047 bool DbIntrospector::hasTable(const QString &tableName) 0048 { 0049 return m_database.tables().contains(tableName, Qt::CaseInsensitive); 0050 } 0051 0052 bool DbIntrospector::hasIndex(const QString &tableName, const QString &indexName) 0053 { 0054 QSqlQuery query(m_database); 0055 if (!query.exec(hasIndexQuery(tableName, indexName))) { 0056 throw DbException(query, "Failed to query index"); 0057 } 0058 return query.next(); 0059 } 0060 0061 bool DbIntrospector::hasColumn(const QString &tableName, const QString &columnName) 0062 { 0063 QStringList columns = m_columnCache.value(tableName); 0064 0065 if (columns.isEmpty()) { 0066 // QPSQL requires the name to be lower case, but it breaks compatibility with existing 0067 // tables with other drivers (see BKO#409234). Yay for abstraction... 0068 const auto name = (DbType::type(m_database) == DbType::PostgreSQL) ? tableName.toLower() : tableName; 0069 const QSqlRecord table = m_database.record(name); 0070 const int numTables = table.count(); 0071 columns.reserve(numTables); 0072 for (int i = 0; i < numTables; ++i) { 0073 const QSqlField column = table.field(i); 0074 columns.push_back(column.name().toLower()); 0075 } 0076 0077 m_columnCache.insert(tableName, columns); 0078 } 0079 0080 return columns.contains(columnName.toLower()); 0081 } 0082 0083 bool DbIntrospector::isTableEmpty(const QString &tableName) 0084 { 0085 auto *store = DataStore::dataStoreForDatabase(m_database); 0086 QueryBuilder queryBuilder(store, tableName, QueryBuilder::Select); 0087 queryBuilder.addColumn(QStringLiteral("*")); 0088 queryBuilder.setLimit(1); 0089 if (!queryBuilder.exec()) { 0090 throw DbException(queryBuilder.query(), "Unable to retrieve data from table."); 0091 } 0092 0093 QSqlQuery query = queryBuilder.query(); 0094 return (query.size() == 0 || !query.first()); 0095 } 0096 0097 QList<DbIntrospector::ForeignKey> DbIntrospector::foreignKeyConstraints(const QString &tableName) 0098 { 0099 Q_UNUSED(tableName) 0100 return QList<ForeignKey>(); 0101 } 0102 0103 QString DbIntrospector::hasIndexQuery(const QString &tableName, const QString &indexName) 0104 { 0105 Q_UNUSED(tableName) 0106 Q_UNUSED(indexName) 0107 qCCritical(AKONADISERVER_LOG) << "Implement index support for your database!"; 0108 return QString(); 0109 }