File indexing completed on 2024-12-08 04:17:22
0001 /* This file is part of the KDE project 0002 Copyright (C) 2003-2012 Jarosław Staniek <staniek@kde.org> 0003 0004 This library is free software; you can redistribute it and/or 0005 modify it under the terms of the GNU Library General Public 0006 License as published by the Free Software Foundation; either 0007 version 2 of the License, or (at your option) any later version. 0008 0009 This library is distributed in the hope that it will be useful, 0010 but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 Library General Public License for more details. 0013 0014 You should have received a copy of the GNU Library General Public License 0015 along with this library; see the file COPYING.LIB. If not, write to 0016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 * Boston, MA 02110-1301, USA. 0018 */ 0019 0020 #include "KDbFieldList.h" 0021 #include "KDbConnection.h" 0022 #include "kdb_debug.h" 0023 0024 class Q_DECL_HIDDEN KDbFieldList::Private 0025 { 0026 public: 0027 Private() 0028 { 0029 } 0030 ~Private() 0031 { 0032 delete autoincFields; 0033 } 0034 0035 //! Clear cached autoinc fields list 0036 void clearAutoincFields() 0037 { 0038 delete autoincFields; 0039 autoincFields = nullptr; 0040 } 0041 0042 bool renameFieldInternal(KDbField *field, const QString& newNameLower) 0043 { 0044 if (fieldsByName.value(newNameLower)) { 0045 kdbWarning() << "Field" << newNameLower << "already exists"; 0046 return false; 0047 } 0048 fieldsByName.remove(field->name().toLower()); 0049 field->setName(newNameLower); 0050 fieldsByName.insert(newNameLower, field); 0051 return true; 0052 } 0053 0054 KDbField::List fields; 0055 0056 //!< Fields collected by name. Not used by KDbQuerySchema. 0057 QHash<QString, KDbField*> fieldsByName; 0058 0059 KDbField::List *autoincFields = nullptr; 0060 0061 //! cached 0062 KDbEscapedString sqlFields; 0063 }; 0064 0065 //------------------------------------------------------- 0066 0067 KDbFieldList::KDbFieldList(bool owner) 0068 : d(new Private) 0069 { 0070 d->fields.setAutoDelete(owner); 0071 } 0072 0073 //! @todo IMPORTANT: (API) improve deepCopyFields 0074 KDbFieldList::KDbFieldList(const KDbFieldList& fl, bool deepCopyFields) 0075 : KDbFieldList(fl.d->fields.autoDelete()) 0076 { 0077 if (deepCopyFields) { 0078 //deep copy for the fields 0079 for (KDbField *origField : *fl.fields()) { 0080 KDbField *f = origField->copy(); 0081 if (origField->parent() == &fl) { 0082 f->setParent(this); 0083 } 0084 const bool addFieldOk = addField(f); 0085 Q_ASSERT(addFieldOk); 0086 } 0087 } 0088 } 0089 0090 KDbFieldList::~KDbFieldList() 0091 { 0092 delete d; 0093 } 0094 0095 KDbField::List *KDbFieldList::fields() 0096 { 0097 return &d->fields; 0098 } 0099 0100 const KDbField::List* KDbFieldList::fields() const 0101 { 0102 return &d->fields; 0103 } 0104 0105 int KDbFieldList::fieldCount() const 0106 { 0107 return d->fields.count(); 0108 } 0109 0110 bool KDbFieldList::isEmpty() const 0111 { 0112 return d->fields.isEmpty(); 0113 } 0114 0115 void KDbFieldList::clear() 0116 { 0117 d->fieldsByName.clear(); 0118 d->clearAutoincFields(); 0119 d->fields.clear(); 0120 d->sqlFields.clear(); 0121 } 0122 0123 bool KDbFieldList::insertField(int index, KDbField *field) 0124 { 0125 if (!field) { 0126 return false; 0127 } 0128 if (index > d->fields.count()) { 0129 kdbWarning() << "index (" << index << ") out of range"; 0130 return false; 0131 } 0132 d->fields.insert(index, field); 0133 if (!field->name().isEmpty()) { 0134 d->fieldsByName.insert(field->name().toLower(), field); 0135 } 0136 d->sqlFields.clear(); 0137 d->clearAutoincFields(); 0138 return true; 0139 } 0140 0141 bool KDbFieldList::renameField(const QString& oldName, const QString& newName) 0142 { 0143 KDbField *field = d->fieldsByName.value(oldName.toLower()); 0144 if (!field) { 0145 kdbWarning() << "Fiels" << oldName << "not found"; 0146 return false; 0147 } 0148 return d->renameFieldInternal(field, newName.toLower()); 0149 } 0150 0151 bool KDbFieldList::renameField(KDbField *field, const QString& newName) 0152 { 0153 if (!field || field != d->fieldsByName.value(field->name().toLower())) { 0154 kdbWarning() << "No field found" 0155 << QString::fromLatin1("\"%1\"").arg(field ? field->name() : QString()); 0156 return false; 0157 } 0158 return d->renameFieldInternal(field, newName.toLower()); 0159 } 0160 0161 bool KDbFieldList::addField(KDbField *field) 0162 { 0163 return insertField(d->fields.count(), field); 0164 } 0165 0166 bool KDbFieldList::removeField(KDbField *field) 0167 { 0168 if (!field) { 0169 return false; 0170 } 0171 if (d->fieldsByName.remove(field->name().toLower()) < 1) { 0172 return false; 0173 } 0174 d->fields.removeAt(d->fields.indexOf(field)); 0175 d->sqlFields.clear(); 0176 d->clearAutoincFields(); 0177 return true; 0178 } 0179 0180 bool KDbFieldList::moveField(KDbField *field, int newIndex) 0181 { 0182 if (!field || !d->fields.removeOne(field)) { 0183 return false; 0184 } 0185 if (newIndex > d->fields.count()) { 0186 newIndex = d->fields.count(); 0187 } 0188 d->fields.insert(newIndex, field); 0189 d->sqlFields.clear(); 0190 d->clearAutoincFields(); 0191 return true; 0192 } 0193 0194 KDbField* KDbFieldList::field(int id) 0195 { 0196 return d->fields.value(id); 0197 } 0198 0199 const KDbField* KDbFieldList::field(int id) const 0200 { 0201 return d->fields.value(id); 0202 } 0203 0204 KDbField* KDbFieldList::field(const QString& name) 0205 { 0206 return d->fieldsByName.value(name.toLower()); 0207 } 0208 0209 const KDbField* KDbFieldList::field(const QString& name) const 0210 { 0211 return d->fieldsByName.value(name.toLower()); 0212 } 0213 0214 bool KDbFieldList::hasField(const KDbField& field) const 0215 { 0216 return d->fields.contains(const_cast<KDbField*>(&field)); 0217 } 0218 0219 int KDbFieldList::indexOf(const KDbField& field) const 0220 { 0221 return d->fields.indexOf(const_cast<KDbField*>(&field)); 0222 } 0223 0224 KDB_EXPORT QDebug operator<<(QDebug dbg, const KDbFieldList& list) 0225 { 0226 if (list.fields()->isEmpty()) 0227 dbg.nospace() << "<NO FIELDS>"; 0228 bool start = true; 0229 foreach(const KDbField *field, *list.fields()) { 0230 if (!start) 0231 dbg.nospace() << '\n'; 0232 else 0233 start = false; 0234 dbg.nospace() << " - " << *field; 0235 } 0236 return dbg.space(); 0237 } 0238 0239 #define _ADD_FIELD(fname) \ 0240 { \ 0241 if (fname.isEmpty()) return fl; \ 0242 KDbField *f = d->fieldsByName.value(fname.toLower()); \ 0243 if (!f || !fl->addField(f)) { kdbWarning() << subListWarning1(fname); delete fl; return nullptr; } \ 0244 } 0245 0246 static QString subListWarning1(const QString& fname) 0247 { 0248 return QString::fromLatin1("could not find field \"%1\"").arg(fname); 0249 } 0250 0251 KDbFieldList* KDbFieldList::subList(const QString& n1, const QString& n2, 0252 const QString& n3, const QString& n4, 0253 const QString& n5, const QString& n6, 0254 const QString& n7, const QString& n8, 0255 const QString& n9, const QString& n10, 0256 const QString& n11, const QString& n12, 0257 const QString& n13, const QString& n14, 0258 const QString& n15, const QString& n16, 0259 const QString& n17, const QString& n18) 0260 { 0261 if (n1.isEmpty()) 0262 return nullptr; 0263 KDbFieldList *fl = new KDbFieldList(false); 0264 _ADD_FIELD(n1); 0265 _ADD_FIELD(n2); 0266 _ADD_FIELD(n3); 0267 _ADD_FIELD(n4); 0268 _ADD_FIELD(n5); 0269 _ADD_FIELD(n6); 0270 _ADD_FIELD(n7); 0271 _ADD_FIELD(n8); 0272 _ADD_FIELD(n9); 0273 _ADD_FIELD(n10); 0274 _ADD_FIELD(n11); 0275 _ADD_FIELD(n12); 0276 _ADD_FIELD(n13); 0277 _ADD_FIELD(n14); 0278 _ADD_FIELD(n15); 0279 _ADD_FIELD(n16); 0280 _ADD_FIELD(n17); 0281 _ADD_FIELD(n18); 0282 return fl; 0283 } 0284 0285 KDbFieldList* KDbFieldList::subList(const QStringList& list) 0286 { 0287 KDbFieldList *fl = new KDbFieldList(false); 0288 for (QStringList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it) { 0289 _ADD_FIELD((*it)); 0290 } 0291 return fl; 0292 } 0293 0294 #undef _ADD_FIELD 0295 0296 #define _ADD_FIELD(fname) \ 0297 { \ 0298 if (fname.isEmpty()) return fl; \ 0299 KDbField *f = d->fieldsByName.value(QLatin1String(fname.toLower())); \ 0300 if (!f || !fl->addField(f)) { kdbWarning() << subListWarning1(QLatin1String(fname)); delete fl; return nullptr; } \ 0301 } 0302 0303 KDbFieldList* KDbFieldList::subList(const QList<QByteArray>& list) 0304 { 0305 KDbFieldList *fl = new KDbFieldList(false); 0306 for (QList<QByteArray>::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it) { 0307 _ADD_FIELD((*it)); 0308 } 0309 return fl; 0310 } 0311 0312 #undef _ADD_FIELD 0313 0314 KDbFieldList* KDbFieldList::subList(const QList<int>& list) 0315 { 0316 QScopedPointer<KDbFieldList> fl(new KDbFieldList(false)); 0317 foreach(int index, list) { 0318 KDbField *f = field(index); 0319 if (!f) { 0320 kdbWarning() << QString::fromLatin1("could not find field at position %1").arg(index); 0321 return nullptr; 0322 } 0323 if (!fl->addField(f)) { 0324 kdbWarning() << QString::fromLatin1("could not add field at position %1").arg(index); 0325 return nullptr; 0326 } 0327 } 0328 return fl.take(); 0329 } 0330 0331 QStringList KDbFieldList::names() const 0332 { 0333 QStringList r; 0334 for (KDbField *f : qAsConst(d->fields)) { 0335 r += f->name().toLower(); 0336 } 0337 return r; 0338 } 0339 0340 KDbField::ListIterator KDbFieldList::fieldsIterator() const 0341 { 0342 return d->fields.constBegin(); 0343 } 0344 0345 KDbField::ListIterator KDbFieldList::fieldsIteratorConstEnd() const 0346 { 0347 return d->fields.constEnd(); 0348 } 0349 0350 bool KDbFieldList::isOwner() const 0351 { 0352 return d->fields.autoDelete(); 0353 } 0354 0355 //static 0356 KDbEscapedString KDbFieldList::sqlFieldsList(const KDbField::List& list, KDbConnection *conn, 0357 const QString& separator, const QString& tableOrAlias, 0358 KDb::IdentifierEscapingType escapingType) 0359 { 0360 KDbEscapedString result; 0361 result.reserve(256); 0362 bool start = true; 0363 QString tableOrAliasAndDot; 0364 if (!tableOrAlias.isEmpty()) { 0365 tableOrAliasAndDot 0366 = ((conn && escapingType == KDb::DriverEscaping) 0367 ? conn->escapeIdentifier(tableOrAlias) 0368 : KDb::escapeIdentifier(tableOrAlias)) 0369 + QLatin1Char('.'); 0370 } 0371 foreach(KDbField *f, list) { 0372 if (!start) 0373 result.append(separator); 0374 else 0375 start = false; 0376 result = (result + tableOrAliasAndDot + 0377 ((conn && escapingType == KDb::DriverEscaping) 0378 ? conn->escapeIdentifier(f->name()) 0379 : KDb::escapeIdentifier(f->name())) 0380 ); 0381 } 0382 return result; 0383 } 0384 0385 KDbEscapedString KDbFieldList::sqlFieldsList(KDbConnection *conn, 0386 const QString& separator, const QString& tableOrAlias, 0387 KDb::IdentifierEscapingType escapingType) const 0388 { 0389 if (!d->sqlFields.isEmpty()) 0390 return d->sqlFields; 0391 0392 d->sqlFields = KDbFieldList::sqlFieldsList(d->fields, conn, separator, tableOrAlias, escapingType); 0393 return d->sqlFields; 0394 } 0395 0396 KDbField::List* KDbFieldList::autoIncrementFields() const 0397 { 0398 if (d->autoincFields) 0399 return d->autoincFields; 0400 0401 d->autoincFields = new KDbField::List(false); 0402 for (KDbField *f : d->fields) { 0403 if (f->isAutoIncrement()) { 0404 d->autoincFields->append(f); 0405 } 0406 } 0407 return d->autoincFields; 0408 }