File indexing completed on 2024-12-01 07:24:56

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 }