kexi

tableschema.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2003 Joseph Wenninger <jowenn@kde.org>
00003    Copyright (C) 2003-2006 Jaroslaw Staniek <js@iidea.pl>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include "tableschema.h"
00022 #include "driver.h"
00023 #include "connection.h"
00024 #include "lookupfieldschema.h"
00025 
00026 #include <assert.h>
00027 #include <kdebug.h>
00028 
00029 namespace KexiDB {
00031 class TableSchema::Private
00032 {
00033 public:
00034     Private()
00035      : anyNonPKField(0)
00036     {
00037     }
00038 
00039     ~Private()
00040     {
00041         clearLookupFields();
00042     }
00043 
00044     void clearLookupFields()
00045     {
00046         for (QMap<const Field*, LookupFieldSchema*>::ConstIterator it = lookupFields.constBegin(); 
00047             it!=lookupFields.constEnd(); ++it)
00048         {
00049             delete it.data();
00050         }
00051         lookupFields.clear();
00052     }
00053 
00054     Field *anyNonPKField;
00055     QMap<const Field*, LookupFieldSchema*> lookupFields;
00056     QPtrVector<LookupFieldSchema> lookupFieldsList;
00057 };
00058 }
00059 //-------------------------------------
00060 
00061 
00062 using namespace KexiDB;
00063 
00064 TableSchema::TableSchema(const QString& name)
00065     : FieldList(true)
00066     , SchemaData(KexiDB::TableObjectType)
00067     , m_query(0)
00068     , m_isKexiDBSystem(false)
00069 {
00070     m_name = name.lower();
00071     init();
00072 }
00073 
00074 TableSchema::TableSchema(const SchemaData& sdata)
00075     : FieldList(true)
00076     , SchemaData(sdata)
00077     , m_query(0)
00078     , m_isKexiDBSystem(false)
00079 {
00080     init();
00081 }
00082 
00083 TableSchema::TableSchema()
00084     : FieldList(true)
00085     , SchemaData(KexiDB::TableObjectType)
00086     , m_query(0)
00087     , m_isKexiDBSystem(false)
00088 {
00089     init();
00090 }
00091 
00092 TableSchema::TableSchema(const TableSchema& ts, bool copyId)
00093     : FieldList(static_cast<const FieldList&>(ts))
00094     , SchemaData(static_cast<const SchemaData&>(ts))
00095 {
00096     init(ts, copyId);
00097 }
00098 
00099 TableSchema::TableSchema(const TableSchema& ts, int setId)
00100     : FieldList(static_cast<const FieldList&>(ts))
00101     , SchemaData(static_cast<const SchemaData&>(ts))
00102 {
00103     init(ts, false);
00104     m_id = setId;
00105 }
00106 
00107 // used by Connection
00108 TableSchema::TableSchema(Connection *conn, const QString & name)
00109     : FieldList(true)
00110     , SchemaData(KexiDB::TableObjectType)
00111     , m_conn( conn )
00112     , m_query(0)
00113     , m_isKexiDBSystem(false)
00114 {
00115     d = new Private();
00116     assert(conn);
00117     m_name = name;
00118     m_indices.setAutoDelete( true );
00119     m_pkey = new IndexSchema(this);
00120     m_indices.append(m_pkey);
00121 }
00122 
00123 TableSchema::~TableSchema()
00124 {
00125     if (m_conn)
00126         m_conn->removeMe( this );
00127     delete m_query;
00128     delete d;
00129 }
00130 
00131 void TableSchema::init()
00132 {
00133     d = new Private();
00134     m_indices.setAutoDelete( true );
00135     m_pkey = new IndexSchema(this);
00136     m_indices.append(m_pkey);
00137 }
00138 
00139 void TableSchema::init(const TableSchema& ts, bool copyId)
00140 {
00141     m_conn = ts.m_conn;
00142     m_query = 0; //not cached
00143     m_isKexiDBSystem = false;
00144     d = new Private();
00145     m_name = ts.m_name;
00146     m_indices.setAutoDelete( true );
00147     m_pkey = 0; //will be copied
00148     if (!copyId)
00149         m_id = -1;
00150 
00151     //deep copy all members
00152     IndexSchema::ListIterator idx_it(ts.m_indices);
00153     for (;idx_it.current();++idx_it) {
00154         IndexSchema *idx = new IndexSchema(
00155             *idx_it.current(), *this /*fields from _this_ table will be assigned to the index*/);
00156         if (idx->isPrimaryKey()) {//assign pkey
00157             m_pkey = idx;
00158         }
00159         m_indices.append(idx);
00160     }
00161 }
00162 
00163 void TableSchema::setPrimaryKey(IndexSchema *pkey)
00164 {
00165     if (m_pkey && m_pkey!=pkey) {
00166         if (m_pkey->fieldCount()==0) {//this is empty key, probably default - remove it
00167             m_indices.remove(m_pkey);
00168         }
00169         else {
00170             m_pkey->setPrimaryKey(false); //there can be only one pkey..
00171             //thats ok, the old pkey is still on indices list, if not empty
00172         }
00173 //      m_pkey=0; 
00174     }
00175     
00176     if (!pkey) {//clearing - set empty pkey
00177         pkey = new IndexSchema(this);
00178     }
00179     m_pkey = pkey; //todo
00180     m_pkey->setPrimaryKey(true);
00181     d->anyNonPKField = 0; //for safety
00182 }
00183 
00184 FieldList& TableSchema::insertField(uint index, Field *field)
00185 {
00186     assert(field);
00187     FieldList::insertField(index, field);
00188     if (!field || index>m_fields.count())
00189         return *this;
00190     field->setTable(this);
00191     field->m_order = index; //m_fields.count();
00192     //update order for next next fields
00193     Field *f = m_fields.at(index+1);
00194     for (int i=index+1; f; i++, f = m_fields.next())
00195         f->m_order = i;
00196 
00197     //Check for auto-generated indices:
00198     IndexSchema *idx = 0;
00199     if (field->isPrimaryKey()) {// this is auto-generated single-field unique index
00200         idx = new IndexSchema(this);
00201         idx->setAutoGenerated(true);
00202         idx->addField( field );
00203         setPrimaryKey(idx);
00204     }
00205     if (field->isUniqueKey()) {
00206         if (!idx) {
00207             idx = new IndexSchema(this);
00208             idx->setAutoGenerated(true);
00209             idx->addField( field );
00210         }
00211         idx->setUnique(true);
00212     }
00213     if (field->isIndexed()) {// this is auto-generated single-field
00214         if (!idx) {
00215             idx = new IndexSchema(this);
00216             idx->setAutoGenerated(true);
00217             idx->addField( field );
00218         }
00219     }
00220     if (idx)
00221         m_indices.append(idx);
00222     return *this;
00223 }
00224 
00225 void TableSchema::removeField(KexiDB::Field *field)
00226 {
00227     if (d->anyNonPKField && field == d->anyNonPKField) //d->anyNonPKField will be removed!
00228         d->anyNonPKField = 0;
00229     delete d->lookupFields[field];
00230     d->lookupFields.remove(field);
00231     FieldList::removeField(field);
00232 }
00233 
00234 #if 0 //original        
00235 KexiDB::FieldList& TableSchema::addField(KexiDB::Field* field)
00236 {
00237     assert(field);
00238     FieldList::addField(field);
00239     field->setTable(this);
00240     field->m_order = m_fields.count();
00241     //Check for auto-generated indices:
00242 
00243     IndexSchema *idx = 0;
00244     if (field->isPrimaryKey()) {// this is auto-generated single-field unique index
00245         idx = new IndexSchema(this);
00246         idx->setAutoGenerated(true);
00247         idx->addField( field );
00248         setPrimaryKey(idx);
00249     }
00250     if (field->isUniqueKey()) {
00251         if (!idx) {
00252             idx = new IndexSchema(this);
00253             idx->setAutoGenerated(true);
00254             idx->addField( field );
00255         }
00256         idx->setUnique(true);
00257     }
00258     if (field->isIndexed()) {// this is auto-generated single-field
00259         if (!idx) {
00260             idx = new IndexSchema(this);
00261             idx->setAutoGenerated(true);
00262             idx->addField( field );
00263         }
00264     }
00265     if (idx)
00266         m_indices.append(idx);
00267     return *this;
00268 }
00269 #endif
00270 
00271 void TableSchema::clear()
00272 {
00273     m_indices.clear();
00274     d->clearLookupFields();
00275     FieldList::clear();
00276     SchemaData::clear();
00277     m_conn = 0;
00278 }
00279 
00280 /*
00281 void TableSchema::addPrimaryKey(const QString& key)
00282 {
00283     m_primaryKeys.append(key);
00284 }*/
00285 
00286 /*QStringList TableSchema::primaryKeys() const
00287 {
00288     return m_primaryKeys;
00289 }
00290 
00291 bool TableSchema::hasPrimaryKeys() const
00292 {
00293     return !m_primaryKeys.isEmpty();
00294 }
00295 */
00296 
00297 //const QString& TableSchema::name() const
00298 //{
00299 //  return m_name;
00300 //}
00301 
00302 //void TableSchema::setName(const QString& name)
00303 //{
00304 //  m_name=name;
00305 /*  ListIterator it( m_fields );
00306     Field *field;
00307     for (; (field = it.current())!=0; ++it) {
00308     
00309     int fcnt=m_fields.count();
00310     for (int i=0;i<fcnt;i++) {
00311         m_fields[i].setTable(name);
00312     }*/
00313 //}
00314 
00315 /*KexiDB::Field TableSchema::field(unsigned int id) const
00316 {
00317     if (id<m_fields.count()) return m_fields[id];
00318     return KexiDB::Field();
00319 }
00320 
00321 unsigned int TableSchema::fieldCount() const
00322 {
00323     return m_fields.count();
00324 }*/
00325 
00326 QString TableSchema::debugString()
00327 {
00328     return debugString(true);
00329 }
00330 
00331 QString TableSchema::debugString(bool includeTableName)
00332 {
00333     QString s;
00334     if (includeTableName)
00335         s = QString("TABLE ") + schemaDataDebugString() + "\n";
00336     s.append( FieldList::debugString() );
00337 
00338     Field *f;
00339     for (Field::ListIterator it(m_fields); (f = it.current()); ++it) {
00340         LookupFieldSchema *lookupSchema = lookupFieldSchema( *f );
00341         if (lookupSchema)
00342             s.append( QString("\n") + lookupSchema->debugString() );
00343     }
00344     return s;
00345 }
00346 
00347 void TableSchema::setKexiDBSystem(bool set)
00348 {
00349     if (set)
00350         m_native=true;
00351     m_isKexiDBSystem = set;
00352 }
00353 
00354 void TableSchema::setNative(bool set)
00355 {
00356     if (m_isKexiDBSystem && !set) {
00357         KexiDBWarn << "TableSchema::setNative(): cannot set native off"
00358             " when KexiDB system flag is set on!" << endl;
00359         return;
00360     }
00361     m_native=set;
00362 }
00363 
00364 QuerySchema* TableSchema::query()
00365 {
00366     if (m_query)
00367         return m_query;
00368     m_query = new QuerySchema( *this ); //it's owned by me
00369     return m_query;
00370 }
00371 
00372 Field* TableSchema::anyNonPKField()
00373 {
00374     if (!d->anyNonPKField) {
00375         Field *f;
00376         Field::ListIterator it(m_fields);
00377         it.toLast(); //from the end (higher chances to find)
00378         for (; (f = it.current()); --it) {
00379             if (!f->isPrimaryKey() && (!m_pkey || !m_pkey->hasField(f)))
00380                 break;
00381         }
00382         d->anyNonPKField = f;
00383     }
00384     return d->anyNonPKField;
00385 }
00386 
00387 bool TableSchema::setLookupFieldSchema( const QString& fieldName, LookupFieldSchema *lookupFieldSchema )
00388 {
00389     Field *f = field(fieldName);
00390     if (!f) {
00391         KexiDBWarn << "TableSchema::setLookupFieldSchema(): no such field '" << fieldName 
00392             << "' in table " << name() << endl;
00393         return false;
00394     }
00395     if (lookupFieldSchema)
00396         d->lookupFields.replace( f, lookupFieldSchema );
00397     else {
00398         delete d->lookupFields[f];
00399         d->lookupFields.remove( f );
00400     }
00401     d->lookupFieldsList.clear(); //this will force to rebuid the internal cache
00402     return true;
00403 }
00404 
00405 LookupFieldSchema *TableSchema::lookupFieldSchema( const Field& field ) const
00406 {
00407     return d->lookupFields[ &field ];
00408 }
00409 
00410 LookupFieldSchema *TableSchema::lookupFieldSchema( const QString& fieldName )
00411 {
00412     Field *f = TableSchema::field(fieldName);
00413     if (!f)
00414         return 0;
00415     return lookupFieldSchema( *f );
00416 }
00417 
00418 const QPtrVector<LookupFieldSchema>& TableSchema::lookupFieldsList()
00419 {
00420     if (d->lookupFields.isEmpty())
00421         return d->lookupFieldsList;
00422     if (!d->lookupFields.isEmpty() && !d->lookupFieldsList.isEmpty())
00423         return d->lookupFieldsList; //already updated
00424     //update
00425     d->lookupFieldsList.clear();
00426     d->lookupFieldsList.resize( d->lookupFields.count() );
00427     uint i = 0;
00428     for (Field::ListIterator it(m_fields); it.current(); ++it) {
00429         QMap<const Field*, LookupFieldSchema*>::ConstIterator itMap = d->lookupFields.find( it.current() );
00430         if (itMap != d->lookupFields.constEnd()) {
00431             d->lookupFieldsList.insert( i, itMap.data() );
00432             i++;
00433         }
00434     }
00435     return d->lookupFieldsList;
00436 }
00437 
00438 //--------------------------------------
00439 
00440 InternalTableSchema::InternalTableSchema(const QString& name)
00441  : TableSchema(name)
00442 {
00443 }
00444 
00445 InternalTableSchema::InternalTableSchema(const TableSchema& ts)
00446  : TableSchema(ts, false)
00447 {
00448 }
00449 
00450 InternalTableSchema::~InternalTableSchema()
00451 {
00452 }
00453 
KDE Home | KDE Accessibility Home | Description of Access Keys