summaryrefslogtreecommitdiffstats
path: root/kexi/kexidb/tableschema.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kexi/kexidb/tableschema.cpp')
-rw-r--r--kexi/kexidb/tableschema.cpp453
1 files changed, 453 insertions, 0 deletions
diff --git a/kexi/kexidb/tableschema.cpp b/kexi/kexidb/tableschema.cpp
new file mode 100644
index 000000000..8c0f5e07c
--- /dev/null
+++ b/kexi/kexidb/tableschema.cpp
@@ -0,0 +1,453 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Joseph Wenninger <jowenn@kde.org>
+ Copyright (C) 2003-2006 Jaroslaw Staniek <js@iidea.pl>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include "tableschema.h"
+#include "driver.h"
+#include "connection.h"
+#include "lookupfieldschema.h"
+
+#include <assert.h>
+#include <kdebug.h>
+
+namespace KexiDB {
+//! @internal
+class TableSchema::Private
+{
+public:
+ Private()
+ : anyNonPKField(0)
+ {
+ }
+
+ ~Private()
+ {
+ clearLookupFields();
+ }
+
+ void clearLookupFields()
+ {
+ for (QMap<const Field*, LookupFieldSchema*>::ConstIterator it = lookupFields.constBegin();
+ it!=lookupFields.constEnd(); ++it)
+ {
+ delete it.data();
+ }
+ lookupFields.clear();
+ }
+
+ Field *anyNonPKField;
+ QMap<const Field*, LookupFieldSchema*> lookupFields;
+ QPtrVector<LookupFieldSchema> lookupFieldsList;
+};
+}
+//-------------------------------------
+
+
+using namespace KexiDB;
+
+TableSchema::TableSchema(const QString& name)
+ : FieldList(true)
+ , SchemaData(KexiDB::TableObjectType)
+ , m_query(0)
+ , m_isKexiDBSystem(false)
+{
+ m_name = name.lower();
+ init();
+}
+
+TableSchema::TableSchema(const SchemaData& sdata)
+ : FieldList(true)
+ , SchemaData(sdata)
+ , m_query(0)
+ , m_isKexiDBSystem(false)
+{
+ init();
+}
+
+TableSchema::TableSchema()
+ : FieldList(true)
+ , SchemaData(KexiDB::TableObjectType)
+ , m_query(0)
+ , m_isKexiDBSystem(false)
+{
+ init();
+}
+
+TableSchema::TableSchema(const TableSchema& ts, bool copyId)
+ : FieldList(static_cast<const FieldList&>(ts))
+ , SchemaData(static_cast<const SchemaData&>(ts))
+{
+ init(ts, copyId);
+}
+
+TableSchema::TableSchema(const TableSchema& ts, int setId)
+ : FieldList(static_cast<const FieldList&>(ts))
+ , SchemaData(static_cast<const SchemaData&>(ts))
+{
+ init(ts, false);
+ m_id = setId;
+}
+
+// used by Connection
+TableSchema::TableSchema(Connection *conn, const QString & name)
+ : FieldList(true)
+ , SchemaData(KexiDB::TableObjectType)
+ , m_conn( conn )
+ , m_query(0)
+ , m_isKexiDBSystem(false)
+{
+ d = new Private();
+ assert(conn);
+ m_name = name;
+ m_indices.setAutoDelete( true );
+ m_pkey = new IndexSchema(this);
+ m_indices.append(m_pkey);
+}
+
+TableSchema::~TableSchema()
+{
+ if (m_conn)
+ m_conn->removeMe( this );
+ delete m_query;
+ delete d;
+}
+
+void TableSchema::init()
+{
+ d = new Private();
+ m_indices.setAutoDelete( true );
+ m_pkey = new IndexSchema(this);
+ m_indices.append(m_pkey);
+}
+
+void TableSchema::init(const TableSchema& ts, bool copyId)
+{
+ m_conn = ts.m_conn;
+ m_query = 0; //not cached
+ m_isKexiDBSystem = false;
+ d = new Private();
+ m_name = ts.m_name;
+ m_indices.setAutoDelete( true );
+ m_pkey = 0; //will be copied
+ if (!copyId)
+ m_id = -1;
+
+ //deep copy all members
+ IndexSchema::ListIterator idx_it(ts.m_indices);
+ for (;idx_it.current();++idx_it) {
+ IndexSchema *idx = new IndexSchema(
+ *idx_it.current(), *this /*fields from _this_ table will be assigned to the index*/);
+ if (idx->isPrimaryKey()) {//assign pkey
+ m_pkey = idx;
+ }
+ m_indices.append(idx);
+ }
+}
+
+void TableSchema::setPrimaryKey(IndexSchema *pkey)
+{
+ if (m_pkey && m_pkey!=pkey) {
+ if (m_pkey->fieldCount()==0) {//this is empty key, probably default - remove it
+ m_indices.remove(m_pkey);
+ }
+ else {
+ m_pkey->setPrimaryKey(false); //there can be only one pkey..
+ //thats ok, the old pkey is still on indices list, if not empty
+ }
+// m_pkey=0;
+ }
+
+ if (!pkey) {//clearing - set empty pkey
+ pkey = new IndexSchema(this);
+ }
+ m_pkey = pkey; //todo
+ m_pkey->setPrimaryKey(true);
+ d->anyNonPKField = 0; //for safety
+}
+
+FieldList& TableSchema::insertField(uint index, Field *field)
+{
+ assert(field);
+ FieldList::insertField(index, field);
+ if (!field || index>m_fields.count())
+ return *this;
+ field->setTable(this);
+ field->m_order = index; //m_fields.count();
+ //update order for next next fields
+ Field *f = m_fields.at(index+1);
+ for (int i=index+1; f; i++, f = m_fields.next())
+ f->m_order = i;
+
+ //Check for auto-generated indices:
+ IndexSchema *idx = 0;
+ if (field->isPrimaryKey()) {// this is auto-generated single-field unique index
+ idx = new IndexSchema(this);
+ idx->setAutoGenerated(true);
+ idx->addField( field );
+ setPrimaryKey(idx);
+ }
+ if (field->isUniqueKey()) {
+ if (!idx) {
+ idx = new IndexSchema(this);
+ idx->setAutoGenerated(true);
+ idx->addField( field );
+ }
+ idx->setUnique(true);
+ }
+ if (field->isIndexed()) {// this is auto-generated single-field
+ if (!idx) {
+ idx = new IndexSchema(this);
+ idx->setAutoGenerated(true);
+ idx->addField( field );
+ }
+ }
+ if (idx)
+ m_indices.append(idx);
+ return *this;
+}
+
+void TableSchema::removeField(KexiDB::Field *field)
+{
+ if (d->anyNonPKField && field == d->anyNonPKField) //d->anyNonPKField will be removed!
+ d->anyNonPKField = 0;
+ delete d->lookupFields[field];
+ d->lookupFields.remove(field);
+ FieldList::removeField(field);
+}
+
+#if 0 //original
+KexiDB::FieldList& TableSchema::addField(KexiDB::Field* field)
+{
+ assert(field);
+ FieldList::addField(field);
+ field->setTable(this);
+ field->m_order = m_fields.count();
+ //Check for auto-generated indices:
+
+ IndexSchema *idx = 0;
+ if (field->isPrimaryKey()) {// this is auto-generated single-field unique index
+ idx = new IndexSchema(this);
+ idx->setAutoGenerated(true);
+ idx->addField( field );
+ setPrimaryKey(idx);
+ }
+ if (field->isUniqueKey()) {
+ if (!idx) {
+ idx = new IndexSchema(this);
+ idx->setAutoGenerated(true);
+ idx->addField( field );
+ }
+ idx->setUnique(true);
+ }
+ if (field->isIndexed()) {// this is auto-generated single-field
+ if (!idx) {
+ idx = new IndexSchema(this);
+ idx->setAutoGenerated(true);
+ idx->addField( field );
+ }
+ }
+ if (idx)
+ m_indices.append(idx);
+ return *this;
+}
+#endif
+
+void TableSchema::clear()
+{
+ m_indices.clear();
+ d->clearLookupFields();
+ FieldList::clear();
+ SchemaData::clear();
+ m_conn = 0;
+}
+
+/*
+void TableSchema::addPrimaryKey(const QString& key)
+{
+ m_primaryKeys.append(key);
+}*/
+
+/*QStringList TableSchema::primaryKeys() const
+{
+ return m_primaryKeys;
+}
+
+bool TableSchema::hasPrimaryKeys() const
+{
+ return !m_primaryKeys.isEmpty();
+}
+*/
+
+//const QString& TableSchema::name() const
+//{
+// return m_name;
+//}
+
+//void TableSchema::setName(const QString& name)
+//{
+// m_name=name;
+/* ListIterator it( m_fields );
+ Field *field;
+ for (; (field = it.current())!=0; ++it) {
+
+ int fcnt=m_fields.count();
+ for (int i=0;i<fcnt;i++) {
+ m_fields[i].setTable(name);
+ }*/
+//}
+
+/*KexiDB::Field TableSchema::field(unsigned int id) const
+{
+ if (id<m_fields.count()) return m_fields[id];
+ return KexiDB::Field();
+}
+
+unsigned int TableSchema::fieldCount() const
+{
+ return m_fields.count();
+}*/
+
+QString TableSchema::debugString()
+{
+ return debugString(true);
+}
+
+QString TableSchema::debugString(bool includeTableName)
+{
+ QString s;
+ if (includeTableName)
+ s = QString("TABLE ") + schemaDataDebugString() + "\n";
+ s.append( FieldList::debugString() );
+
+ Field *f;
+ for (Field::ListIterator it(m_fields); (f = it.current()); ++it) {
+ LookupFieldSchema *lookupSchema = lookupFieldSchema( *f );
+ if (lookupSchema)
+ s.append( QString("\n") + lookupSchema->debugString() );
+ }
+ return s;
+}
+
+void TableSchema::setKexiDBSystem(bool set)
+{
+ if (set)
+ m_native=true;
+ m_isKexiDBSystem = set;
+}
+
+void TableSchema::setNative(bool set)
+{
+ if (m_isKexiDBSystem && !set) {
+ KexiDBWarn << "TableSchema::setNative(): cannot set native off"
+ " when KexiDB system flag is set on!" << endl;
+ return;
+ }
+ m_native=set;
+}
+
+QuerySchema* TableSchema::query()
+{
+ if (m_query)
+ return m_query;
+ m_query = new QuerySchema( *this ); //it's owned by me
+ return m_query;
+}
+
+Field* TableSchema::anyNonPKField()
+{
+ if (!d->anyNonPKField) {
+ Field *f;
+ Field::ListIterator it(m_fields);
+ it.toLast(); //from the end (higher chances to find)
+ for (; (f = it.current()); --it) {
+ if (!f->isPrimaryKey() && (!m_pkey || !m_pkey->hasField(f)))
+ break;
+ }
+ d->anyNonPKField = f;
+ }
+ return d->anyNonPKField;
+}
+
+bool TableSchema::setLookupFieldSchema( const QString& fieldName, LookupFieldSchema *lookupFieldSchema )
+{
+ Field *f = field(fieldName);
+ if (!f) {
+ KexiDBWarn << "TableSchema::setLookupFieldSchema(): no such field '" << fieldName
+ << "' in table " << name() << endl;
+ return false;
+ }
+ if (lookupFieldSchema)
+ d->lookupFields.replace( f, lookupFieldSchema );
+ else {
+ delete d->lookupFields[f];
+ d->lookupFields.remove( f );
+ }
+ d->lookupFieldsList.clear(); //this will force to rebuid the internal cache
+ return true;
+}
+
+LookupFieldSchema *TableSchema::lookupFieldSchema( const Field& field ) const
+{
+ return d->lookupFields[ &field ];
+}
+
+LookupFieldSchema *TableSchema::lookupFieldSchema( const QString& fieldName )
+{
+ Field *f = TableSchema::field(fieldName);
+ if (!f)
+ return 0;
+ return lookupFieldSchema( *f );
+}
+
+const QPtrVector<LookupFieldSchema>& TableSchema::lookupFieldsList()
+{
+ if (d->lookupFields.isEmpty())
+ return d->lookupFieldsList;
+ if (!d->lookupFields.isEmpty() && !d->lookupFieldsList.isEmpty())
+ return d->lookupFieldsList; //already updated
+ //update
+ d->lookupFieldsList.clear();
+ d->lookupFieldsList.resize( d->lookupFields.count() );
+ uint i = 0;
+ for (Field::ListIterator it(m_fields); it.current(); ++it) {
+ QMap<const Field*, LookupFieldSchema*>::ConstIterator itMap = d->lookupFields.find( it.current() );
+ if (itMap != d->lookupFields.constEnd()) {
+ d->lookupFieldsList.insert( i, itMap.data() );
+ i++;
+ }
+ }
+ return d->lookupFieldsList;
+}
+
+//--------------------------------------
+
+InternalTableSchema::InternalTableSchema(const QString& name)
+ : TableSchema(name)
+{
+}
+
+InternalTableSchema::InternalTableSchema(const TableSchema& ts)
+ : TableSchema(ts, false)
+{
+}
+
+InternalTableSchema::~InternalTableSchema()
+{
+}
+