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

KDE's Doxygen guidelines are available online.