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 };
00057 }
00058 //-------------------------------------
00059 
00060 
00061 using namespace KexiDB;
00062 
00063 TableSchema::TableSchema(const QString& name)
00064     : FieldList(true)
00065     , SchemaData(KexiDB::TableObjectType)
00066     , m_query(0)
00067     , m_isKexiDBSystem(false)
00068 {
00069     m_name = name.lower();
00070     init();
00071 }
00072 
00073 TableSchema::TableSchema(const SchemaData& sdata)
00074     : FieldList(true)
00075     , SchemaData(sdata)
00076     , m_query(0)
00077     , m_isKexiDBSystem(false)
00078 {
00079     init();
00080 }
00081 
00082 TableSchema::TableSchema()
00083     : FieldList(true)
00084     , SchemaData(KexiDB::TableObjectType)
00085     , m_query(0)
00086     , m_isKexiDBSystem(false)
00087 {
00088     init();
00089 }
00090 
00091 TableSchema::TableSchema(const TableSchema& ts, bool copyId)
00092     : FieldList(static_cast<const FieldList&>(ts))
00093     , SchemaData(static_cast<const SchemaData&>(ts))
00094     , m_conn( ts.m_conn )
00095     , m_query(0) //not cached
00096     , m_isKexiDBSystem(false)
00097 {
00098     d = new Private();
00099     m_name = ts.m_name;
00100     m_indices.setAutoDelete( true );
00101     m_pkey = 0; //will be copied
00102     if (!copyId)
00103         m_id = -1;
00104 
00105     //deep copy all members
00106     IndexSchema::ListIterator idx_it(ts.m_indices);
00107     for (;idx_it.current();++idx_it) {
00108         IndexSchema *idx = new IndexSchema(
00109             *idx_it.current(), *this /*fields from _this_ table will be assigned to the index*/);
00110         if (idx->isPrimaryKey()) {//assign pkey
00111             m_pkey = idx;
00112         }
00113         m_indices.append(idx);
00114     }
00115 }
00116 
00117 // used by Connection
00118 TableSchema::TableSchema(Connection *conn, const QString & name)
00119     : FieldList(true)
00120     , SchemaData(KexiDB::TableObjectType)
00121     , m_conn( conn )
00122     , m_query(0)
00123     , m_isKexiDBSystem(false)
00124 {
00125     d = new Private();
00126     assert(conn);
00127     m_name = name;
00128     m_indices.setAutoDelete( true );
00129     m_pkey = new IndexSchema(this);
00130     m_indices.append(m_pkey);
00131 }
00132 
00133 TableSchema::~TableSchema()
00134 {
00135     if (m_conn)
00136         m_conn->removeMe( this );
00137     delete m_query;
00138     delete d;
00139 }
00140 
00141 void TableSchema::init()
00142 {
00143     d = new Private();
00144     m_indices.setAutoDelete( true );
00145     m_pkey = new IndexSchema(this);
00146     m_indices.append(m_pkey);
00147 }
00148 
00149 void TableSchema::setPrimaryKey(IndexSchema *pkey)
00150 {
00151     if (m_pkey && m_pkey!=pkey) {
00152         if (m_pkey->fieldCount()==0) {//this is empty key, probably default - remove it
00153             m_indices.remove(m_pkey);
00154         }
00155         else {
00156             m_pkey->setPrimaryKey(false); //there can be only one pkey..
00157             //thats ok, the old pkey is still on indices list, if not empty
00158         }
00159 //      m_pkey=0; 
00160     }
00161     
00162     if (!pkey) {//clearing - set empty pkey
00163         pkey = new IndexSchema(this);
00164     }
00165     m_pkey = pkey; //todo
00166     m_pkey->setPrimaryKey(true);
00167     d->anyNonPKField = 0; //for safety
00168 }
00169 
00170 FieldList& TableSchema::insertField(uint index, Field *field)
00171 {
00172     assert(field);
00173     FieldList::insertField(index, field);
00174     if (!field || index>m_fields.count())
00175         return *this;
00176     field->setTable(this);
00177     field->m_order = index; //m_fields.count();
00178     //update order for next next fields
00179     Field *f = m_fields.at(index+1);
00180     for (int i=index+1; f; i++, f = m_fields.next())
00181         f->m_order = i;
00182 
00183     //Check for auto-generated indices:
00184     IndexSchema *idx = 0;
00185     if (field->isPrimaryKey()) {// this is auto-generated single-field unique index
00186         idx = new IndexSchema(this);
00187         idx->setAutoGenerated(true);
00188         idx->addField( field );
00189         setPrimaryKey(idx);
00190     }
00191     if (field->isUniqueKey()) {
00192         if (!idx) {
00193             idx = new IndexSchema(this);
00194             idx->setAutoGenerated(true);
00195             idx->addField( field );
00196         }
00197         idx->setUnique(true);
00198     }
00199     if (field->isIndexed()) {// this is auto-generated single-field
00200         if (!idx) {
00201             idx = new IndexSchema(this);
00202             idx->setAutoGenerated(true);
00203             idx->addField( field );
00204         }
00205     }
00206     if (idx)
00207         m_indices.append(idx);
00208     return *this;
00209 }
00210 
00211 void TableSchema::removeField(KexiDB::Field *field)
00212 {
00213     if (d->anyNonPKField && field == d->anyNonPKField) //d->anyNonPKField will be removed!
00214         d->anyNonPKField = 0;
00215     delete d->lookupFields[field];
00216     d->lookupFields.remove(field);
00217     FieldList::removeField(field);
00218 }
00219 
00220 #if 0 //original        
00221 KexiDB::FieldList& TableSchema::addField(KexiDB::Field* field)
00222 {
00223     assert(field);
00224     FieldList::addField(field);
00225     field->setTable(this);
00226     field->m_order = m_fields.count();
00227     //Check for auto-generated indices:
00228 
00229     IndexSchema *idx = 0;
00230     if (field->isPrimaryKey()) {// this is auto-generated single-field unique index
00231         idx = new IndexSchema(this);
00232         idx->setAutoGenerated(true);
00233         idx->addField( field );
00234         setPrimaryKey(idx);
00235     }
00236     if (field->isUniqueKey()) {
00237         if (!idx) {
00238             idx = new IndexSchema(this);
00239             idx->setAutoGenerated(true);
00240             idx->addField( field );
00241         }
00242         idx->setUnique(true);
00243     }
00244     if (field->isIndexed()) {// this is auto-generated single-field
00245         if (!idx) {
00246             idx = new IndexSchema(this);
00247             idx->setAutoGenerated(true);
00248             idx->addField( field );
00249         }
00250     }
00251     if (idx)
00252         m_indices.append(idx);
00253     return *this;
00254 }
00255 #endif
00256 
00257 void TableSchema::clear()
00258 {
00259     m_indices.clear();
00260     d->clearLookupFields();
00261     FieldList::clear();
00262     SchemaData::clear();
00263     m_conn = 0;
00264 }
00265 
00266 /*
00267 void TableSchema::addPrimaryKey(const QString& key)
00268 {
00269     m_primaryKeys.append(key);
00270 }*/
00271 
00272 /*QStringList TableSchema::primaryKeys() const
00273 {
00274     return m_primaryKeys;
00275 }
00276 
00277 bool TableSchema::hasPrimaryKeys() const
00278 {
00279     return !m_primaryKeys.isEmpty();
00280 }
00281 */
00282 
00283 //const QString& TableSchema::name() const
00284 //{
00285 //  return m_name;
00286 //}
00287 
00288 //void TableSchema::setName(const QString& name)
00289 //{
00290 //  m_name=name;
00291 /*  ListIterator it( m_fields );
00292     Field *field;
00293     for (; (field = it.current())!=0; ++it) {
00294     
00295     int fcnt=m_fields.count();
00296     for (int i=0;i<fcnt;i++) {
00297         m_fields[i].setTable(name);
00298     }*/
00299 //}
00300 
00301 /*KexiDB::Field TableSchema::field(unsigned int id) const
00302 {
00303     if (id<m_fields.count()) return m_fields[id];
00304     return KexiDB::Field();
00305 }
00306 
00307 unsigned int TableSchema::fieldCount() const
00308 {
00309     return m_fields.count();
00310 }*/
00311 
00312 QString TableSchema::debugString()
00313 {
00314     return debugString(true);
00315 }
00316 
00317 QString TableSchema::debugString(bool includeTableName)
00318 {
00319     QString s;
00320     if (includeTableName)
00321         s = QString("TABLE ") + schemaDataDebugString() + "\n";
00322     s.append( FieldList::debugString() );
00323 
00324     Field *f;
00325     for (Field::ListIterator it(m_fields); (f = it.current()); ++it) {
00326         LookupFieldSchema *lookupSchema = lookupFieldSchema( *f );
00327         if (lookupSchema)
00328             s.append( QString("\n") + lookupSchema->debugString() );
00329     }
00330     return s;
00331 }
00332 
00333 void TableSchema::setKexiDBSystem(bool set)
00334 {
00335     if (set)
00336         m_native=true;
00337     m_isKexiDBSystem = set;
00338 }
00339 
00340 void TableSchema::setNative(bool set)
00341 {
00342     if (m_isKexiDBSystem && !set) {
00343         KexiDBWarn << "TableSchema::setNative(): cannot set native off"
00344             " when KexiDB system flag is set on!" << endl;
00345         return;
00346     }
00347     m_native=set;
00348 }
00349 
00350 QuerySchema* TableSchema::query()
00351 {
00352     if (m_query)
00353         return m_query;
00354     m_query = new QuerySchema( this ); //it's owned by me
00355     return m_query;
00356 }
00357 
00358 Field* TableSchema::anyNonPKField()
00359 {
00360     if (!d->anyNonPKField) {
00361         Field *f;
00362         Field::ListIterator it(m_fields);
00363         it.toLast(); //from the end (higher chances to find)
00364         for (; (f = it.current()); --it) {
00365             if (!f->isPrimaryKey() && (!m_pkey || !m_pkey->hasField(f)))
00366                 break;
00367         }
00368         d->anyNonPKField = f;
00369     }
00370     return d->anyNonPKField;
00371 }
00372 
00373 bool TableSchema::setLookupFieldSchema( const QString& fieldName, LookupFieldSchema *lookupFieldSchema )
00374 {
00375     Field *f = field(fieldName);
00376     if (!f) {
00377         KexiDBWarn << "TableSchema::setLookupFieldSchema(): no such field '" << fieldName 
00378             << "' in table " << name() << endl;
00379         return false;
00380     }
00381     if (lookupFieldSchema)
00382         d->lookupFields.replace( f, lookupFieldSchema );
00383     else {
00384         delete d->lookupFields[f];
00385         d->lookupFields.remove( f );
00386     }
00387     return true;
00388 }
00389 
00390 LookupFieldSchema *TableSchema::lookupFieldSchema( const Field& field ) const
00391 {
00392     return d->lookupFields[ &field ];
00393 }
00394 
00395 LookupFieldSchema *TableSchema::lookupFieldSchema( const QString& fieldName )
00396 {
00397     Field *f = TableSchema::field(fieldName);
00398     if (!f)
00399         return 0;
00400     return lookupFieldSchema( *f );
00401 }
00402 
00403 //--------------------------------------
00404 
00405 InternalTableSchema::InternalTableSchema(const QString& name)
00406  : TableSchema(name)
00407 {
00408 }
00409 
00410 InternalTableSchema::~InternalTableSchema()
00411 {
00412 }
00413 
KDE Home | KDE Accessibility Home | Description of Access Keys