File indexing completed on 2024-12-08 07:18:25
0001 /* This file is part of the KDE project 0002 Copyright (C) 2003 Joseph Wenninger <jowenn@kde.org> 0003 Copyright (C) 2003-2016 Jarosław Staniek <staniek@kde.org> 0004 0005 This library is free software; you can redistribute it and/or 0006 modify it under the terms of the GNU Library General Public 0007 License as published by the Free Software Foundation; either 0008 version 2 of the License, or (at your option) any later version. 0009 0010 This library is distributed in the hope that it will be useful, 0011 but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 Library General Public License for more details. 0014 0015 You should have received a copy of the GNU Library General Public License 0016 along with this library; see the file COPYING.LIB. If not, write to 0017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0018 * Boston, MA 02110-1301, USA. 0019 */ 0020 0021 #include "KDbTableSchema.h" 0022 #include "KDbDriver.h" 0023 #include "KDbConnection.h" 0024 #include "KDbLookupFieldSchema.h" 0025 #include "KDbQuerySchema.h" 0026 #include "kdb_debug.h" 0027 0028 //! @internal 0029 class Q_DECL_HIDDEN KDbTableSchema::Private 0030 { 0031 public: 0032 Private(KDbTableSchema *t) 0033 : q(t) 0034 , anyNonPKField(nullptr) 0035 , conn(nullptr) 0036 , pkey(nullptr) 0037 , query(nullptr) 0038 { 0039 } 0040 0041 ~Private() { 0042 clearLookupFields(); 0043 qDeleteAll(indices); 0044 delete query; 0045 } 0046 0047 void clearLookupFields() { 0048 qDeleteAll(lookupFields); 0049 lookupFields.clear(); 0050 } 0051 0052 void addIndex(KDbIndexSchema *index) { 0053 indices.append(index); 0054 index->setTable(q); 0055 } 0056 0057 KDbTableSchema * const q; 0058 KDbField *anyNonPKField; 0059 QHash<const KDbField*, KDbLookupFieldSchema*> lookupFields; 0060 QVector<KDbLookupFieldSchema*> lookupFieldsList; 0061 QList<KDbIndexSchema*> indices; 0062 //! @todo IMPORTANT: use something like QPointer<KDbConnection> conn 0063 KDbConnection *conn; 0064 KDbIndexSchema *pkey; 0065 KDbQuerySchema *query; //!< cached query schema that is defined by "select * from <this_table_name>" 0066 private: 0067 Q_DISABLE_COPY(Private) 0068 }; 0069 0070 //------------------------------------- 0071 0072 KDbTableSchema::KDbTableSchema(const QString& name) 0073 : KDbFieldList(true) 0074 , KDbObject(KDb::TableObjectType) 0075 , d(new Private(this)) 0076 { 0077 setName(name); 0078 init(nullptr); 0079 } 0080 0081 KDbTableSchema::KDbTableSchema(const KDbObject& other) 0082 : KDbFieldList(true) 0083 , KDbObject(other) 0084 , d(new Private(this)) 0085 { 0086 init(nullptr); 0087 } 0088 0089 KDbTableSchema::KDbTableSchema() 0090 : KDbFieldList(true) 0091 , KDbObject(KDb::TableObjectType) 0092 , d(new Private(this)) 0093 { 0094 init(nullptr); 0095 } 0096 0097 KDbTableSchema::KDbTableSchema(const KDbTableSchema& ts, bool copyId) 0098 : KDbFieldList(static_cast<const KDbFieldList&>(ts)) 0099 , KDbObject(static_cast<const KDbObject&>(ts)) 0100 , d(new Private(this)) 0101 { 0102 init(ts, copyId); 0103 } 0104 0105 KDbTableSchema::KDbTableSchema(const KDbTableSchema& ts, int id) 0106 : KDbFieldList(static_cast<const KDbFieldList&>(ts)) 0107 , KDbObject(static_cast<const KDbObject&>(ts)) 0108 , d(new Private(this)) 0109 { 0110 init(ts, false); 0111 setId(id); 0112 } 0113 0114 // used by KDbConnection 0115 KDbTableSchema::KDbTableSchema(KDbConnection *conn, const QString & name) 0116 : KDbFieldList(true) 0117 , KDbObject(KDb::TableObjectType) 0118 , d(new Private(this)) 0119 { 0120 setName(name); 0121 init(conn); 0122 } 0123 0124 KDbTableSchema::~KDbTableSchema() 0125 { 0126 if (d->conn) { 0127 d->conn->removeMe(this); 0128 } 0129 delete d; 0130 } 0131 0132 void KDbTableSchema::init(KDbConnection* conn) 0133 { 0134 d->conn = conn; 0135 d->pkey = new KDbIndexSchema; 0136 d->addIndex(d->pkey); 0137 } 0138 0139 void KDbTableSchema::init(const KDbTableSchema& ts, bool copyId) 0140 { 0141 d->conn = ts.connection(); 0142 setName(ts.name()); 0143 d->pkey = nullptr; //will be copied 0144 if (!copyId) 0145 setId(-1); 0146 0147 //deep copy all members 0148 foreach(KDbIndexSchema* otherIdx, *ts.indices()) { 0149 // fields from _this_ table will be assigned to the index 0150 KDbIndexSchema *idx = copyIndexFrom(*otherIdx); 0151 if (idx->isPrimaryKey()) {//assign pkey 0152 d->pkey = idx; 0153 } 0154 } 0155 0156 KDbField::ListIterator tsIter(ts.fieldsIterator()); 0157 KDbField::ListIterator iter(fieldsIterator()); 0158 for (; iter != fieldsIteratorConstEnd(); ++tsIter, ++iter) { 0159 const KDbLookupFieldSchema *lookup = ts.lookupFieldSchema(**tsIter); 0160 if (lookup) { 0161 d->lookupFields.insert(*iter, new KDbLookupFieldSchema(*lookup)); 0162 } 0163 } 0164 } 0165 0166 KDbIndexSchema* KDbTableSchema::primaryKey() 0167 { 0168 return d->pkey; 0169 } 0170 0171 const KDbIndexSchema* KDbTableSchema::primaryKey() const 0172 { 0173 return d->pkey; 0174 } 0175 0176 const QList<KDbIndexSchema*>::ConstIterator KDbTableSchema::indicesIterator() const 0177 { 0178 return QList<KDbIndexSchema*>::ConstIterator (d->indices.constBegin()); 0179 } 0180 0181 const QList<KDbIndexSchema*>* KDbTableSchema::indices() const 0182 { 0183 return &d->indices; 0184 } 0185 0186 bool KDbTableSchema::addIndex(KDbIndexSchema *index) 0187 { 0188 if (index && !d->indices.contains(index)) { 0189 d->addIndex(index); 0190 return true; 0191 } 0192 return false; 0193 } 0194 0195 bool KDbTableSchema::removeIndex(KDbIndexSchema *index) 0196 { 0197 if (index) { 0198 d->indices.removeOne(index); 0199 return true; 0200 } 0201 return false; 0202 } 0203 0204 KDbIndexSchema* KDbTableSchema::copyIndexFrom(const KDbIndexSchema& index) 0205 { 0206 KDbIndexSchema *newIndex = new KDbIndexSchema(index, this); 0207 addIndex(newIndex); 0208 return newIndex; 0209 } 0210 0211 bool KDbTableSchema::isInternal() const 0212 { 0213 return dynamic_cast<const KDbInternalTableSchema*>(this); 0214 } 0215 0216 void KDbTableSchema::setPrimaryKey(KDbIndexSchema *pkey) 0217 { 0218 if (pkey && !d->indices.contains(pkey)) { 0219 kdbWarning() << *pkey << "index can't be made primary key because it does not belong " 0220 "to table schema" << name(); 0221 return; 0222 } 0223 if (d->pkey && d->pkey != pkey) { 0224 if (d->pkey->fieldCount() == 0) {//this is empty key, probably default - remove it 0225 d->indices.removeOne(d->pkey); 0226 delete d->pkey; 0227 } 0228 else { 0229 d->pkey->setPrimaryKey(false); //there can be only one pkey.. 0230 //that's ok, the old pkey is still on indices list, if not empty 0231 } 0232 } 0233 0234 if (!pkey) {//clearing - set empty pkey 0235 pkey = new KDbIndexSchema; 0236 d->addIndex(pkey); 0237 } 0238 d->pkey = pkey; //!< @todo 0239 d->pkey->setPrimaryKey(true); 0240 d->anyNonPKField = nullptr; //for safety 0241 } 0242 0243 bool KDbTableSchema::insertField(int index, KDbField *field) 0244 { 0245 if (!field) { 0246 return false; 0247 } 0248 KDbField::List *fieldsList = fields(); 0249 KDbFieldList::insertField(index, field); 0250 if (!field || index > fieldsList->count()) { 0251 return false; 0252 } 0253 field->setTable(this); 0254 field->setOrder(index); 0255 //update order for next next fields 0256 const int fieldCount = fieldsList->count(); 0257 for (int i = index + 1; i < fieldCount; i++) { 0258 fieldsList->at(i)->setOrder(i); 0259 } 0260 0261 //Check for auto-generated indices: 0262 KDbIndexSchema *idx = nullptr; 0263 if (field->isPrimaryKey()) {// this is auto-generated single-field unique index 0264 idx = new KDbIndexSchema; 0265 d->addIndex(idx); 0266 idx->setAutoGenerated(true); 0267 const bool ok = idx->addField(field); 0268 Q_ASSERT(ok); 0269 setPrimaryKey(idx); 0270 } 0271 if (field->isUniqueKey()) { 0272 if (!idx) { 0273 idx = new KDbIndexSchema; 0274 d->addIndex(idx); 0275 idx->setAutoGenerated(true); 0276 const bool ok = idx->addField(field); 0277 Q_ASSERT(ok); 0278 } 0279 idx->setUnique(true); 0280 } 0281 if (field->isIndexed()) {// this is auto-generated single-field 0282 if (!idx) { 0283 idx = new KDbIndexSchema; 0284 d->addIndex(idx); 0285 idx->setAutoGenerated(true); 0286 const bool ok = idx->addField(field); 0287 Q_ASSERT(ok); 0288 } 0289 } 0290 return true; 0291 } 0292 0293 bool KDbTableSchema::removeField(KDbField *field) 0294 { 0295 KDbLookupFieldSchema* lookup = d->lookupFields.take(field); 0296 if (!KDbFieldList::removeField(field)) { 0297 return false; 0298 } 0299 if (d->anyNonPKField && field == d->anyNonPKField) //d->anyNonPKField will be removed! 0300 d->anyNonPKField = nullptr; 0301 delete lookup; 0302 return true; 0303 } 0304 0305 void KDbTableSchema::clear() 0306 { 0307 d->indices.clear(); 0308 d->clearLookupFields(); 0309 KDbFieldList::clear(); 0310 KDbObject::clear(); 0311 d->conn = nullptr; 0312 } 0313 0314 QDebug KDbTableSchema::debugFields(QDebug dbg) const 0315 { 0316 dbg.nospace() << static_cast<const KDbFieldList&>(*this); 0317 for (const KDbField *f : *fields()) { 0318 const KDbLookupFieldSchema *lookupSchema = lookupFieldSchema(*f); 0319 if (lookupSchema) 0320 dbg.nospace() << '\n' << f->name() << *lookupSchema; 0321 } 0322 return dbg.space(); 0323 } 0324 0325 QDebug operator<<(QDebug dbg, const KDbTableSchema& table) 0326 { 0327 dbg.nospace() << "TABLE"; 0328 dbg.space() << static_cast<const KDbObject&>(table) << '\n'; 0329 table.debugFields(dbg); 0330 return dbg.space(); 0331 } 0332 0333 QDebug operator<<(QDebug dbg, const KDbInternalTableSchema& table) 0334 { 0335 dbg.nospace() << "INTERNAL_TABLE"; 0336 dbg.space() << static_cast<const KDbObject&>(table) << '\n'; 0337 table.debugFields(dbg); 0338 return dbg.space(); 0339 } 0340 0341 KDbConnection* KDbTableSchema::connection() const 0342 { 0343 return d->conn; 0344 } 0345 0346 void KDbTableSchema::setConnection(KDbConnection* conn) 0347 { 0348 d->conn = conn; 0349 } 0350 0351 KDbQuerySchema* KDbTableSchema::query() 0352 { 0353 if (d->query) 0354 return d->query; 0355 d->query = new KDbQuerySchema(this); //it's owned by me 0356 return d->query; 0357 } 0358 0359 KDbField* KDbTableSchema::anyNonPKField() 0360 { 0361 if (!d->anyNonPKField) { 0362 KDbField *f = nullptr; 0363 for (QListIterator<KDbField*> it(*fields()); it.hasPrevious();) { 0364 f = it.previous(); 0365 if (!f->isPrimaryKey() && (!d->pkey || !d->pkey->hasField(*f))) 0366 break; 0367 } 0368 d->anyNonPKField = f; 0369 } 0370 return d->anyNonPKField; 0371 } 0372 0373 bool KDbTableSchema::setLookupFieldSchema(const QString& fieldName, KDbLookupFieldSchema *lookupFieldSchema) 0374 { 0375 KDbField *f = field(fieldName); 0376 if (!f) { 0377 kdbWarning() << "no such field" << fieldName << "in table" << name(); 0378 return false; 0379 } 0380 delete d->lookupFields.take(f); 0381 if (lookupFieldSchema) { 0382 d->lookupFields.insert(f, lookupFieldSchema); 0383 } 0384 d->lookupFieldsList.clear(); //this will force to rebuid the internal cache 0385 return true; 0386 } 0387 0388 KDbLookupFieldSchema *KDbTableSchema::lookupFieldSchema(const KDbField& field) 0389 { 0390 return d->lookupFields.value(&field); 0391 } 0392 0393 const KDbLookupFieldSchema *KDbTableSchema::lookupFieldSchema(const KDbField& field) const 0394 { 0395 return d->lookupFields.value(&field); 0396 } 0397 0398 KDbLookupFieldSchema *KDbTableSchema::lookupFieldSchema(const QString& fieldName) 0399 { 0400 KDbField *f = KDbTableSchema::field(fieldName); 0401 if (!f) 0402 return nullptr; 0403 return lookupFieldSchema(*f); 0404 } 0405 0406 QVector<KDbLookupFieldSchema*> KDbTableSchema::lookupFields() const 0407 { 0408 if (d->lookupFields.isEmpty()) 0409 return QVector<KDbLookupFieldSchema*>(); 0410 if (!d->lookupFields.isEmpty() && !d->lookupFieldsList.isEmpty()) 0411 return d->lookupFieldsList; //already updated 0412 //update 0413 d->lookupFieldsList.clear(); 0414 d->lookupFieldsList.resize(d->lookupFields.count()); 0415 int i = 0; 0416 for (KDbField* f : *fields()) { 0417 QHash<const KDbField*, KDbLookupFieldSchema*>::ConstIterator itMap = d->lookupFields.constFind(f); 0418 if (itMap != d->lookupFields.constEnd()) { 0419 d->lookupFieldsList[i] = itMap.value(); 0420 i++; 0421 } 0422 } 0423 return d->lookupFieldsList; 0424 } 0425 0426 //-------------------------------------- 0427 0428 class Q_DECL_HIDDEN KDbInternalTableSchema::Private 0429 { 0430 public: 0431 Private() {} 0432 bool dummy = false; 0433 }; 0434 0435 KDbInternalTableSchema::KDbInternalTableSchema(const QString& name) 0436 : KDbTableSchema(name) 0437 , d(new Private) 0438 { 0439 } 0440 0441 KDbInternalTableSchema::KDbInternalTableSchema(const KDbTableSchema& ts) 0442 : KDbTableSchema(ts, false) 0443 , d(new Private) 0444 { 0445 } 0446 0447 KDbInternalTableSchema::KDbInternalTableSchema(const KDbInternalTableSchema& ts) 0448 : KDbTableSchema(ts, false) 0449 , d(new Private) 0450 { 0451 } 0452 0453 KDbInternalTableSchema::~KDbInternalTableSchema() 0454 { 0455 delete d; 0456 }