Akonadi

parthelper.cpp
1 /***************************************************************************
2  * SPDX-FileCopyrightText: 2009 Andras Mantia <[email protected]> *
3  * SPDX-FileCopyrightText: 2010 Volker Krause <[email protected]> *
4  * *
5  * SPDX-License-Identifier: LGPL-2.0-or-later *
6  ***************************************************************************/
7 
8 #include "parthelper.h"
9 #include "dbconfig.h"
10 #include "parttypehelper.h"
11 #include "selectquerybuilder.h"
12 
13 #include <private/externalpartstorage_p.h>
14 
15 #include <QFile>
16 
17 #include "akonadiserver_debug.h"
18 
19 using namespace Akonadi;
20 using namespace Akonadi::Server;
21 
22 void PartHelper::update(Part *part, const QByteArray &data, qint64 dataSize)
23 {
24  if (!part) {
25  throw PartHelperException("Invalid part");
26  }
27 
28  const bool storeExternal = dataSize > DbConfig::configuredDatabase()->sizeThreshold();
29 
30  QByteArray newFile;
31  if (part->storage() == Part::External && storeExternal) {
32  if (!ExternalPartStorage::self()->updatePartFile(data, part->data(), newFile)) {
33  throw PartHelperException(QStringLiteral("Failed to update external payload part"));
34  }
35  part->setData(newFile);
36  } else if (part->storage() != Part::External && storeExternal) {
37  if (!ExternalPartStorage::self()->createPartFile(data, part->id(), newFile)) {
38  throw PartHelperException(QStringLiteral("Failed to create external payload part"));
39  }
40  part->setData(newFile);
41  part->setStorage(Part::External);
42  } else {
43  if (part->storage() == Part::External && !storeExternal) {
44  const QString file = ExternalPartStorage::resolveAbsolutePath(part->data());
45  ExternalPartStorage::self()->removePartFile(file);
46  }
47  part->setData(data);
48  part->setStorage(Part::Internal);
49  }
50 
51  part->setDatasize(dataSize);
52  const bool result = part->update();
53  if (!result) {
54  throw PartHelperException("Failed to update database record");
55  }
56 }
57 
58 bool PartHelper::insert(Part *part, qint64 *insertId)
59 {
60  if (!part) {
61  return false;
62  }
63 
64  const bool storeInFile = part->datasize() > DbConfig::configuredDatabase()->sizeThreshold();
65  // it is needed to insert first the metadata so a new id is generated for the part,
66  // and we need this id for the payload file name
67  QByteArray data;
68  if (storeInFile) {
69  data = part->data();
70  part->setData(QByteArray());
71  part->setStorage(Part::External);
72  } else {
73  part->setStorage(Part::Internal);
74  }
75 
76  bool result = part->insert(insertId);
77 
78  if (storeInFile && result) {
79  QByteArray filename;
80  if (!ExternalPartStorage::self()->createPartFile(data, part->id(), filename)) {
81  throw PartHelperException("Failed to create external payload part");
82  }
83  part->setData(filename);
84  result = part->update();
85  }
86 
87  return result;
88 }
89 
90 bool PartHelper::remove(Part *part)
91 {
92  if (!part) {
93  return false;
94  }
95 
96  if (part->storage() == Part::External) {
97  ExternalPartStorage::self()->removePartFile(ExternalPartStorage::resolveAbsolutePath(part->data()));
98  }
99  return part->remove();
100 }
101 
102 bool PartHelper::remove(const QString &column, const QVariant &value)
103 {
104  SelectQueryBuilder<Part> builder;
105  builder.addValueCondition(column, Query::Equals, value);
106  builder.addValueCondition(Part::storageColumn(), Query::Equals, Part::External);
107  builder.addValueCondition(Part::dataColumn(), Query::IsNot, QVariant());
108  if (!builder.exec()) {
109  // qCDebug(AKONADISERVER_LOG) << "Error selecting records to be deleted from table"
110  // << Part::tableName() << builder.query().lastError().text();
111  return false;
112  }
113  const Part::List parts = builder.result();
114  Part::List::ConstIterator it = parts.constBegin();
115  Part::List::ConstIterator end = parts.constEnd();
116  for (; it != end; ++it) {
117  ExternalPartStorage::self()->removePartFile(ExternalPartStorage::resolveAbsolutePath((*it).data()));
118  }
119  return Part::remove(column, value);
120 }
121 
122 QByteArray PartHelper::translateData(const QByteArray &data, Part::Storage storage)
123 {
124  if (storage == Part::External || storage == Part::Foreign) {
125  QFile file;
126  if (storage == Part::External) {
127  file.setFileName(ExternalPartStorage::resolveAbsolutePath(data));
128  } else {
129  file.setFileName(QString::fromUtf8(data));
130  }
131 
132  if (file.open(QIODevice::ReadOnly)) {
133  const QByteArray payload = file.readAll();
134  file.close();
135  return payload;
136  } else {
137  qCCritical(AKONADISERVER_LOG) << "Payload file " << file.fileName() << " could not be open for reading!";
138  qCCritical(AKONADISERVER_LOG) << "Error: " << file.errorString();
139  return QByteArray();
140  }
141  } else {
142  // not external
143  return data;
144  }
145 }
146 
148 {
149  return translateData(part.data(), part.storage());
150 }
151 
152 bool PartHelper::truncate(Part &part)
153 {
154  if (part.storage() == Part::External) {
155  ExternalPartStorage::self()->removePartFile(ExternalPartStorage::resolveAbsolutePath(part.data()));
156  }
157 
158  part.setData(QByteArray());
159  part.setDatasize(0);
160  part.setStorage(Part::Internal);
161  return part.update();
162 }
163 
164 bool PartHelper::verify(Part &part)
165 {
166  if (part.storage() == Part::Internal) {
167  return true;
168  }
169 
170  QString fileName;
171  if (part.storage() == Part::External) {
172  fileName = ExternalPartStorage::resolveAbsolutePath(part.data());
173  } else if (part.storage() == Part::Foreign) {
174  fileName = QString::fromUtf8(part.data());
175  } else {
176  Q_ASSERT(false);
177  }
178 
179  if (!QFile::exists(fileName)) {
180  qCCritical(AKONADISERVER_LOG) << "Payload file" << fileName << "is missing, trying to recover.";
181  part.setData(QByteArray());
182  part.setDatasize(0);
183  part.setStorage(Part::Internal);
184  return part.update();
185  }
186 
187  return true;
188 }
QString errorString() const const
QString fromUtf8(const char *str, int size)
virtual bool open(QIODevice::OpenMode mode) override
bool insert(Part *part, qint64 *insertId=nullptr)
Adds a new part to the database and if necessary to the filesystem.
Definition: parthelper.cpp:58
bool truncate(Part &part)
Truncate the payload of part and update filesystem/database accordingly.
Definition: parthelper.cpp:152
bool exists() const const
virtual QString fileName() const const override
QByteArray translateData(const QByteArray &data, Part::Storage storageType)
Returns the payload data.
Definition: parthelper.cpp:122
static DbConfig * configuredDatabase()
Returns the DbConfig instance for the database the user has configured.
Definition: dbconfig.cpp:73
bool remove(Part *part)
Deletes part from the database and also removes existing filesystem data if needed.
Definition: parthelper.cpp:90
QVector< T > result()
Returns the result of this SELECT query.
void setFileName(const QString &name)
void addValueCondition(const QString &column, Query::CompareOperator op, const QVariant &value, ConditionType type=WhereCondition)
Add a WHERE or HAVING condition which compares a column with a given value.
virtual void close() override
virtual qint64 sizeThreshold() const
Payload data bigger than this value will be stored in separate files, instead of the database.
Definition: dbconfig.cpp:128
bool exec()
Executes the query, returns true on success.
Helper class for creating and executing database SELECT queries.
void update(Part *part, const QByteArray &data, qint64 dataSize)
Update payload of an existing part part to data and size dataSize.
Definition: parthelper.cpp:22
QByteArray readAll()
bool verify(Part &part)
Verifies and if necessary fixes the external reference of this part.
Definition: parthelper.cpp:164
char * data()
Helper integration between Akonadi and Qt.
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon May 8 2023 03:52:16 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.