kexi

relationship.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2003-2004 Jaroslaw Staniek <js@iidea.pl>
00003 
00004    This program is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this program; see the file COPYING.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include <kexidb/relationship.h>
00021 
00022 #include <kexidb/indexschema.h>
00023 #include <kexidb/tableschema.h>
00024 #include <kexidb/queryschema.h>
00025 #include <kexidb/driver.h>
00026 
00027 #include <kdebug.h>
00028 
00029 using namespace KexiDB;
00030 
00031 Relationship::Relationship()
00032     : m_masterIndex(0)
00033     , m_detailsIndex(0)
00034     , m_masterIndexOwned(false)
00035     , m_detailsIndexOwned(false)
00036 {
00037     m_pairs.setAutoDelete(true);
00038 }
00039 
00040 Relationship::Relationship(IndexSchema* masterIndex, IndexSchema* detailsIndex)
00041     : m_masterIndex(0)
00042     , m_detailsIndex(0)
00043     , m_masterIndexOwned(false)
00044     , m_detailsIndexOwned(false)
00045 {
00046     m_pairs.setAutoDelete(true);
00047     setIndices(masterIndex, detailsIndex);
00048 }
00049 
00050 Relationship::Relationship( QuerySchema *query, Field *field1, Field *field2 )
00051     : m_masterIndex(0)
00052     , m_detailsIndex(0)
00053     , m_masterIndexOwned(false)
00054     , m_detailsIndexOwned(false)
00055 {
00056     m_pairs.setAutoDelete(true);
00057     createIndices( query, field1, field2 );
00058 }
00059 
00060 Relationship::~Relationship()
00061 {
00062     if (m_masterIndexOwned)
00063         delete m_masterIndex;
00064     if (m_detailsIndexOwned)
00065         delete m_detailsIndex;
00066 }
00067 
00068 void Relationship::createIndices( QuerySchema *query, Field *field1, Field *field2 )
00069 {
00070     if (!field1 || !field2 || !query) {
00071         KexiDBWarn << "Relationship::addRelationship(): !masterField || !detailsField || !query" << endl;
00072         return;
00073     }
00074     if (field1->isQueryAsterisk() || field2->isQueryAsterisk()) {
00075         KexiDBWarn << "Relationship::addRelationship(): relationship's fields cannot be asterisks" << endl;
00076         return;
00077     }
00078     if (field1->table() == field2->table()) {
00079         KexiDBWarn << "Relationship::addRelationship(): fields cannot belong to the same table" << endl;
00080         return;
00081     }
00082 //  if (!query->hasField(field1) && !query->hasField(field2)) {
00083     if (!query->contains(field1->table()) || !query->contains(field2->table())) {
00084         KexiDBWarn << "Relationship::addRelationship(): fields do not belong to this query" << endl;
00085         return;
00086     }
00087 //@todo: check more things: -types
00088 //@todo: find existing global db relationships
00089 
00090     Field *masterField = 0, *detailsField = 0;
00091     bool p1 = field1->isPrimaryKey(), p2 = field2->isPrimaryKey();
00092     if (p1 && p2) {
00093         //2 primary keys
00094         masterField = field1;
00095         m_masterIndex = masterField->table()->primaryKey();
00096         detailsField = field2;
00097         m_detailsIndex = detailsField->table()->primaryKey();
00098     }
00099     else if (!p1 && p2) {
00100         //foreign + primary: swap
00101         Field *tmp = field1;
00102         field1 = field2;
00103         field2 = tmp;
00104         p1 = !p1;
00105         p2 = !p2;
00106     }
00107 
00108     if (p1 && !p2) {
00109         //primary + foreign
00110         masterField = field1;
00111         m_masterIndex = masterField->table()->primaryKey();
00112         detailsField = field2;
00113         //create foreign key
00114 //@todo: check if it already exists
00115         m_detailsIndex = new IndexSchema(detailsField->table());
00116         m_detailsIndexOwned = true;
00117         m_detailsIndex->addField(detailsField);
00118         m_detailsIndex->setForeignKey(true);
00119     }
00120     else if (!p1 && !p2) {
00121         masterField = field1;
00122         m_masterIndex = new IndexSchema(masterField->table());
00123         m_masterIndexOwned = true;
00124         m_masterIndex->addField(masterField);
00125         m_masterIndex->setForeignKey(true);
00126         
00127         detailsField = field2;
00128         m_detailsIndex = new IndexSchema(detailsField->table());
00129         m_detailsIndexOwned = true;
00130         m_detailsIndex->addField(detailsField);
00131         m_detailsIndex->setForeignKey(true);
00132     }
00133 
00134     if (!m_masterIndex || !m_detailsIndex)
00135         return; //failed
00136 
00137     setIndices(m_masterIndex, m_detailsIndex, false);
00138 }
00139 
00140 TableSchema* Relationship::masterTable() const
00141 {
00142     return m_masterIndex ? m_masterIndex->table() : 0;
00143 }
00144 
00145 TableSchema* Relationship::detailsTable() const
00146 {
00147     return m_detailsIndex ? m_detailsIndex->table() : 0;
00148 }
00149 
00150 void Relationship::setIndices(IndexSchema* masterIndex, IndexSchema* detailsIndex)
00151 {
00152     setIndices(masterIndex, detailsIndex, true);
00153 }
00154 
00155 void Relationship::setIndices(IndexSchema* masterIndex, IndexSchema* detailsIndex, bool ownedByMaster)
00156 {
00157     m_masterIndex = 0;
00158     m_detailsIndex = 0;
00159     m_pairs.clear();
00160     if (!masterIndex || !detailsIndex || !masterIndex->table() || !detailsIndex->table() 
00161     || masterIndex->table()==detailsIndex->table() || masterIndex->fieldCount()!=detailsIndex->fieldCount())
00162         return;
00163     Field::ListIterator it1(*masterIndex->fields());
00164     Field::ListIterator it2(*detailsIndex->fields());
00165     for (;it1.current() && it1.current(); ++it1, ++it2) {
00166         Field *f1 = it1.current(); //masterIndex->fields()->first();
00167         Field *f2 = it2.current(); //detailsIndex->fields()->first();
00168     //  while (f1 && f2) {
00169         if (f1->type()!=f1->type() && f1->isIntegerType()!=f2->isIntegerType() && f1->isTextType()!=f2->isTextType()) {
00170             KexiDBWarn << "Relationship::setIndices(INDEX on '"<<masterIndex->table()->name()
00171             <<"',INDEX on "<<detailsIndex->table()->name()<<"): !equal field types: "
00172             <<Driver::defaultSQLTypeName(f1->type())<<" "<<f1->name()<<", "
00173             <<Driver::defaultSQLTypeName(f2->type())<<" "<<f2->name() <<endl;
00174             m_pairs.clear();
00175             return;
00176         }
00177 #if 0 //too STRICT!
00178         if ((f1->isUnsigned() && !f2->isUnsigned()) || (!f1->isUnsigned() && f1->isUnsigned())) {
00179             KexiDBWarn << "Relationship::setIndices(INDEX on '"<<masterIndex->table()->name()
00180             <<"',INDEX on "<<detailsIndex->table()->name()<<"): !equal signedness of field types: "
00181             <<Driver::defaultSQLTypeName(f1->type())<<" "<<f1->name()<<", "
00182             <<Driver::defaultSQLTypeName(f2->type())<<" "<<f2->name() <<endl;
00183             m_pairs.clear();
00184             return;
00185         }
00186 #endif
00187         m_pairs.append( new Field::Pair(f1,f2) );
00188     }
00189     //ok: update information
00190     if (m_masterIndex) {//detach yourself
00191         m_masterIndex->detachRelationship(this);
00192     }
00193     if (m_detailsIndex) {//detach yourself
00194         m_detailsIndex->detachRelationship(this);
00195     }
00196     m_masterIndex = masterIndex;
00197     m_detailsIndex = detailsIndex;
00198     m_masterIndex->attachRelationship(this, ownedByMaster);
00199     m_detailsIndex->attachRelationship(this, ownedByMaster);
00200 }
00201 
KDE Home | KDE Accessibility Home | Description of Access Keys