File indexing completed on 2024-04-28 04:50:50
0001 /* 0002 * sqlinterface.cpp 0003 * 0004 * Copyright (C) 2009-2011 Christoph Pfister <christophpfister@gmail.com> 0005 * 0006 * This program is free software; you can redistribute it and/or modify 0007 * it under the terms of the GNU General Public License as published by 0008 * the Free Software Foundation; either version 2 of the License, or 0009 * (at your option) any later version. 0010 * 0011 * This program is distributed in the hope that it will be useful, 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0014 * GNU General Public License for more details. 0015 * 0016 * You should have received a copy of the GNU General Public License along 0017 * with this program; if not, write to the Free Software Foundation, Inc., 0018 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 0019 */ 0020 0021 #include "log.h" 0022 0023 #include <QAbstractItemModel> 0024 #include <QStringList> 0025 0026 #include "sqlhelper.h" 0027 #include "sqlinterface.h" 0028 0029 SqlInterface::SqlInterface() : createTable(false), hasPendingStatements(false), 0030 sqlColumnCount(0) 0031 { 0032 sqlHelper = SqlHelper::getInstance(); 0033 } 0034 0035 SqlInterface::~SqlInterface() 0036 { 0037 if (hasPendingStatements) { 0038 qCWarning(logSql, "Pending statements at destruction"); 0039 /* data isn't valid anymore */ 0040 pendingStatements.clear(); 0041 createTable = false; 0042 /* make sure we don't get called after destruction */ 0043 sqlHelper->collectSubmissions(); 0044 } 0045 } 0046 0047 void SqlInterface::sqlFlush() 0048 { 0049 if (hasPendingStatements) { 0050 sqlHelper->collectSubmissions(); 0051 } 0052 } 0053 0054 void SqlInterface::sqlInit(const QString &tableName, const QStringList &columnNames) 0055 { 0056 QString existsStatement = QLatin1String("SELECT name FROM sqlite_master WHERE name='") + tableName + 0057 QLatin1String("' AND type = 'table'"); 0058 createStatement = QLatin1String("CREATE TABLE ") + tableName + QLatin1String(" (Id INTEGER PRIMARY KEY, "); 0059 QString selectStatement = QLatin1String("SELECT Id, "); 0060 insertStatement = QLatin1String("INSERT INTO ") + tableName + QLatin1String(" (Id, "); 0061 updateStatement = QLatin1String("UPDATE ") + tableName + QLatin1String(" SET "); 0062 deleteStatement = QLatin1String("DELETE FROM ") + tableName + QLatin1String(" WHERE Id = ?"); 0063 0064 sqlColumnCount = columnNames.size(); 0065 0066 for (int i = 0; i < sqlColumnCount; ++i) { 0067 if (i > 0) { 0068 createStatement.append(QLatin1String(", ")); 0069 selectStatement.append(QLatin1String(", ")); 0070 insertStatement.append(QLatin1String(", ")); 0071 updateStatement.append(QLatin1String(" = ?, ")); 0072 } 0073 0074 const QString &columnName = columnNames.at(i); 0075 createStatement.append(columnName); 0076 selectStatement.append(columnName); 0077 insertStatement.append(columnName); 0078 updateStatement.append(columnName); 0079 } 0080 0081 createStatement.append(QLatin1Char(')')); 0082 selectStatement.append(QLatin1String(" FROM ")); 0083 selectStatement.append(tableName); 0084 insertStatement.append(QLatin1String(") VALUES (?")); 0085 updateStatement.append(QLatin1String(" = ? WHERE Id = ?")); 0086 0087 for (int i = 0; i < sqlColumnCount; ++i) { 0088 insertStatement.append(QLatin1String(", ?")); 0089 } 0090 0091 insertStatement.append(QLatin1Char(')')); 0092 0093 if (!sqlHelper->exec(existsStatement).next()) { 0094 createTable = true; 0095 requestSubmission(); 0096 } else { 0097 // queries can only be prepared if the table exists 0098 insertQuery = sqlHelper->prepare(insertStatement); 0099 updateQuery = sqlHelper->prepare(updateStatement); 0100 deleteQuery = sqlHelper->prepare(deleteStatement); 0101 0102 for (QSqlQuery query = sqlHelper->exec(selectStatement); query.next();) { 0103 qint64 fullKey = query.value(0).toLongLong(); 0104 SqlKey sqlKey(static_cast<int>(fullKey)); 0105 0106 if (!sqlKey.isSqlKeyValid() || (sqlKey.sqlKey != fullKey)) { 0107 qCWarning(logSql, "Invalid key %Ld", fullKey); 0108 continue; 0109 } 0110 0111 if (!insertFromSqlQuery(sqlKey, query, 1)) { 0112 pendingStatements.insert(sqlKey, Remove); 0113 requestSubmission(); 0114 } 0115 } 0116 } 0117 } 0118 0119 void SqlInterface::sqlInsert(SqlKey key) 0120 { 0121 PendingStatement pendingStatement = pendingStatements.value(key, Nothing); 0122 0123 switch (pendingStatement) { 0124 case Nothing: 0125 pendingStatements.insert(key, Insert); 0126 requestSubmission(); 0127 return; 0128 case Remove: 0129 pendingStatements.insert(key, RemoveAndInsert); 0130 requestSubmission(); 0131 return; 0132 case RemoveAndInsert: 0133 case Insert: 0134 case Update: 0135 break; 0136 } 0137 0138 qCWarning(logSql, "Invalid pending statement '%d'", pendingStatement); 0139 } 0140 0141 void SqlInterface::sqlUpdate(SqlKey key) 0142 { 0143 PendingStatement pendingStatement = pendingStatements.value(key, Nothing); 0144 0145 switch (pendingStatement) { 0146 case Nothing: 0147 pendingStatements.insert(key, Update); 0148 requestSubmission(); 0149 return; 0150 case RemoveAndInsert: 0151 case Insert: 0152 case Update: 0153 return; 0154 case Remove: 0155 break; 0156 } 0157 0158 qCWarning(logSql, "Invalid pending statement '%d'", pendingStatement); 0159 } 0160 0161 void SqlInterface::sqlRemove(SqlKey key) 0162 { 0163 PendingStatement pendingStatement = pendingStatements.value(key, Nothing); 0164 0165 switch (pendingStatement) { 0166 case Nothing: 0167 case RemoveAndInsert: 0168 case Update: 0169 pendingStatements.insert(key, Remove); 0170 requestSubmission(); 0171 return; 0172 case Insert: 0173 pendingStatements.remove(key); 0174 return; 0175 case Remove: 0176 break; 0177 } 0178 0179 qCWarning(logSql, "Invalid pending statement %d", pendingStatement); 0180 } 0181 0182 void SqlInterface::requestSubmission() 0183 { 0184 if (!hasPendingStatements) { 0185 hasPendingStatements = true; 0186 sqlHelper->requestSubmission(this); 0187 } 0188 } 0189 0190 void SqlInterface::sqlSubmit() 0191 { 0192 if (createTable) { 0193 createTable = false; 0194 sqlHelper->exec(createStatement); 0195 0196 // queries can only be prepared if the table exists 0197 insertQuery = sqlHelper->prepare(insertStatement); 0198 updateQuery = sqlHelper->prepare(updateStatement); 0199 deleteQuery = sqlHelper->prepare(deleteStatement); 0200 } 0201 0202 for (QMap<SqlKey, PendingStatement>::ConstIterator it = pendingStatements.constBegin(); 0203 it != pendingStatements.constEnd(); ++it) { 0204 PendingStatement pendingStatement = it.value(); 0205 0206 switch (pendingStatement) { 0207 case Nothing: 0208 break; 0209 case RemoveAndInsert: 0210 deleteQuery.bindValue(0, it.key().sqlKey); 0211 sqlHelper->exec(deleteQuery); 0212 // fall through 0213 case Insert: 0214 bindToSqlQuery(it.key(), insertQuery, 1); 0215 insertQuery.bindValue(0, it.key().sqlKey); 0216 sqlHelper->exec(insertQuery); 0217 continue; 0218 case Update: 0219 bindToSqlQuery(it.key(), updateQuery, 0); 0220 updateQuery.bindValue(sqlColumnCount, it.key().sqlKey); 0221 sqlHelper->exec(updateQuery); 0222 continue; 0223 case Remove: 0224 deleteQuery.bindValue(0, it.key().sqlKey); 0225 sqlHelper->exec(deleteQuery); 0226 continue; 0227 } 0228 0229 qCWarning(logSql, "Invalid pending statement %d", pendingStatement); 0230 } 0231 0232 pendingStatements.clear(); 0233 hasPendingStatements = false; 0234 }