kexi

tableschema.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2003 Joseph Wenninger <jowenn@kde.org>
3 Copyright (C) 2003-2006 Jaroslaw Staniek <js@iidea.pl>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19*/
20
21#include "tableschema.h"
22#include "driver.h"
23#include "connection.h"
24#include "lookupfieldschema.h"
25
26#include <assert.h>
27#include <kdebug.h>
28
29namespace KexiDB {
31class TableSchema::Private
32{
33public:
34 Private()
35 : anyNonPKField(0)
36 {
37 }
38
39 ~Private()
40 {
41 clearLookupFields();
42 }
43
44 void clearLookupFields()
45 {
46 for (TQMap<const Field*, LookupFieldSchema*>::ConstIterator it = lookupFields.constBegin();
47 it!=lookupFields.constEnd(); ++it)
48 {
49 delete it.data();
50 }
51 lookupFields.clear();
52 }
53
54 Field *anyNonPKField;
55 TQMap<const Field*, LookupFieldSchema*> lookupFields;
56 TQPtrVector<LookupFieldSchema> lookupFieldsList;
57};
58}
59//-------------------------------------
60
61
62using namespace KexiDB;
63
64TableSchema::TableSchema(const TQString& name)
65 : FieldList(true)
66 , SchemaData(KexiDB::TableObjectType)
67 , m_query(0)
68 , m_isKexiDBSystem(false)
69{
70 m_name = name.lower();
71 init();
72}
73
74TableSchema::TableSchema(const SchemaData& sdata)
75 : FieldList(true)
76 , SchemaData(sdata)
77 , m_query(0)
78 , m_isKexiDBSystem(false)
79{
80 init();
81}
82
83TableSchema::TableSchema()
84 : FieldList(true)
85 , SchemaData(KexiDB::TableObjectType)
86 , m_query(0)
87 , m_isKexiDBSystem(false)
88{
89 init();
90}
91
92TableSchema::TableSchema(const TableSchema& ts, bool copyId)
93 : FieldList(static_cast<const FieldList&>(ts))
94 , SchemaData(static_cast<const SchemaData&>(ts))
95{
96 init(ts, copyId);
97}
98
99TableSchema::TableSchema(const TableSchema& ts, int setId)
100 : FieldList(static_cast<const FieldList&>(ts))
101 , SchemaData(static_cast<const SchemaData&>(ts))
102{
103 init(ts, false);
104 m_id = setId;
105}
106
107// used by Connection
108TableSchema::TableSchema(Connection *conn, const TQString & name)
109 : FieldList(true)
110 , SchemaData(KexiDB::TableObjectType)
111 , m_conn( conn )
112 , m_query(0)
113 , m_isKexiDBSystem(false)
114{
115 d = new Private();
116 assert(conn);
117 m_name = name;
118 m_indices.setAutoDelete( true );
119 m_pkey = new IndexSchema(this);
120 m_indices.append(m_pkey);
121}
122
123TableSchema::~TableSchema()
124{
125 if (m_conn)
126 m_conn->removeMe( this );
127 delete m_query;
128 delete d;
129}
130
131void TableSchema::init()
132{
133 d = new Private();
134 m_indices.setAutoDelete( true );
135 m_pkey = new IndexSchema(this);
136 m_indices.append(m_pkey);
137}
138
139void TableSchema::init(const TableSchema& ts, bool copyId)
140{
141 m_conn = ts.m_conn;
142 m_query = 0; //not cached
143 m_isKexiDBSystem = false;
144 d = new Private();
145 m_name = ts.m_name;
146 m_indices.setAutoDelete( true );
147 m_pkey = 0; //will be copied
148 if (!copyId)
149 m_id = -1;
150
151 //deep copy all members
152 IndexSchema::ListIterator idx_it(ts.m_indices);
153 for (;idx_it.current();++idx_it) {
154 IndexSchema *idx = new IndexSchema(
155 *idx_it.current(), *this /*fields from _this_ table will be assigned to the index*/);
156 if (idx->isPrimaryKey()) {//assign pkey
157 m_pkey = idx;
158 }
159 m_indices.append(idx);
160 }
161}
162
164{
165 if (m_pkey && m_pkey!=pkey) {
166 if (m_pkey->fieldCount()==0) {//this is empty key, probably default - remove it
167 m_indices.remove(m_pkey);
168 }
169 else {
170 m_pkey->setPrimaryKey(false); //there can be only one pkey..
171 //thats ok, the old pkey is still on indices list, if not empty
172 }
173// m_pkey=0;
174 }
175
176 if (!pkey) {//clearing - set empty pkey
177 pkey = new IndexSchema(this);
178 }
179 m_pkey = pkey; //todo
180 m_pkey->setPrimaryKey(true);
181 d->anyNonPKField = 0; //for safety
182}
183
185{
186 assert(field);
188 if (!field || index>m_fields.count())
189 return *this;
190 field->setTable(this);
191 field->m_order = index; //m_fields.count();
192 //update order for next next fields
193 Field *f = m_fields.at(index+1);
194 for (int i=index+1; f; i++, f = m_fields.next())
195 f->m_order = i;
196
197 //Check for auto-generated indices:
198 IndexSchema *idx = 0;
199 if (field->isPrimaryKey()) {// this is auto-generated single-field unique index
200 idx = new IndexSchema(this);
201 idx->setAutoGenerated(true);
202 idx->addField( field );
203 setPrimaryKey(idx);
204 }
205 if (field->isUniqueKey()) {
206 if (!idx) {
207 idx = new IndexSchema(this);
208 idx->setAutoGenerated(true);
209 idx->addField( field );
210 }
211 idx->setUnique(true);
212 }
213 if (field->isIndexed()) {// this is auto-generated single-field
214 if (!idx) {
215 idx = new IndexSchema(this);
216 idx->setAutoGenerated(true);
217 idx->addField( field );
218 }
219 }
220 if (idx)
221 m_indices.append(idx);
222 return *this;
223}
224
226{
227 if (d->anyNonPKField && field == d->anyNonPKField) //d->anyNonPKField will be removed!
228 d->anyNonPKField = 0;
229 delete d->lookupFields[field];
230 d->lookupFields.remove(field);
232}
233
234#if 0 //original
236{
237 assert(field);
238 FieldList::addField(field);
239 field->setTable(this);
240 field->m_order = m_fields.count();
241 //Check for auto-generated indices:
242
243 IndexSchema *idx = 0;
244 if (field->isPrimaryKey()) {// this is auto-generated single-field unique index
245 idx = new IndexSchema(this);
246 idx->setAutoGenerated(true);
247 idx->addField( field );
248 setPrimaryKey(idx);
249 }
250 if (field->isUniqueKey()) {
251 if (!idx) {
252 idx = new IndexSchema(this);
253 idx->setAutoGenerated(true);
254 idx->addField( field );
255 }
256 idx->setUnique(true);
257 }
258 if (field->isIndexed()) {// this is auto-generated single-field
259 if (!idx) {
260 idx = new IndexSchema(this);
261 idx->setAutoGenerated(true);
262 idx->addField( field );
263 }
264 }
265 if (idx)
266 m_indices.append(idx);
267 return *this;
268}
269#endif
270
272{
273 m_indices.clear();
274 d->clearLookupFields();
277 m_conn = 0;
278}
279
280/*
281void TableSchema::addPrimaryKey(const TQString& key)
282{
283 m_primaryKeys.append(key);
284}*/
285
286/*TQStringList TableSchema::primaryKeys() const
287{
288 return m_primaryKeys;
289}
290
291bool TableSchema::hasPrimaryKeys() const
292{
293 return !m_primaryKeys.isEmpty();
294}
295*/
296
297//const TQString& TableSchema::name() const
298//{
299// return m_name;
300//}
301
302//void TableSchema::setName(const TQString& name)
303//{
304// m_name=name;
305/* ListIterator it( m_fields );
306 Field *field;
307 for (; (field = it.current())!=0; ++it) {
308
309 int fcnt=m_fields.count();
310 for (int i=0;i<fcnt;i++) {
311 m_fields[i].setTable(name);
312 }*/
313//}
314
315/*KexiDB::Field TableSchema::field(unsigned int id) const
316{
317 if (id<m_fields.count()) return m_fields[id];
318 return KexiDB::Field();
319}
320
321unsigned int TableSchema::fieldCount() const
322{
323 return m_fields.count();
324}*/
325
327{
328 return debugString(true);
329}
330
331TQString TableSchema::debugString(bool includeTableName)
332{
333 TQString s;
334 if (includeTableName)
335 s = TQString("TABLE ") + schemaDataDebugString() + "\n";
336 s.append( FieldList::debugString() );
337
338 Field *f;
339 for (Field::ListIterator it(m_fields); (f = it.current()); ++it) {
340 LookupFieldSchema *lookupSchema = lookupFieldSchema( *f );
341 if (lookupSchema)
342 s.append( TQString("\n") + lookupSchema->debugString() );
343 }
344 return s;
345}
346
348{
349 if (set)
350 m_native=true;
351 m_isKexiDBSystem = set;
352}
353
354void TableSchema::setNative(bool set)
355{
356 if (m_isKexiDBSystem && !set) {
357 KexiDBWarn << "TableSchema::setNative(): cannot set native off"
358 " when KexiDB system flag is set on!" << endl;
359 return;
360 }
361 m_native=set;
362}
363
365{
366 if (m_query)
367 return m_query;
368 m_query = new QuerySchema( *this ); //it's owned by me
369 return m_query;
370}
371
373{
374 if (!d->anyNonPKField) {
375 Field *f;
376 Field::ListIterator it(m_fields);
377 it.toLast(); //from the end (higher chances to find)
378 for (; (f = it.current()); --it) {
379 if (!f->isPrimaryKey() && (!m_pkey || !m_pkey->hasField(f)))
380 break;
381 }
382 d->anyNonPKField = f;
383 }
384 return d->anyNonPKField;
385}
386
388{
389 Field *f = field(fieldName);
390 if (!f) {
391 KexiDBWarn << "TableSchema::setLookupFieldSchema(): no such field '" << fieldName
392 << "' in table " << name() << endl;
393 return false;
394 }
396 d->lookupFields.replace( f, lookupFieldSchema );
397 else {
398 delete d->lookupFields[f];
399 d->lookupFields.remove( f );
400 }
401 d->lookupFieldsList.clear(); //this will force to rebuid the internal cache
402 return true;
403}
404
406{
407 return d->lookupFields[ &field ];
408}
409
410LookupFieldSchema *TableSchema::lookupFieldSchema( const TQString& fieldName )
411{
412 Field *f = TableSchema::field(fieldName);
413 if (!f)
414 return 0;
415 return lookupFieldSchema( *f );
416}
417
418const TQPtrVector<LookupFieldSchema>& TableSchema::lookupFieldsList()
419{
420 if (d->lookupFields.isEmpty())
421 return d->lookupFieldsList;
422 if (!d->lookupFields.isEmpty() && !d->lookupFieldsList.isEmpty())
423 return d->lookupFieldsList; //already updated
424 //update
425 d->lookupFieldsList.clear();
426 d->lookupFieldsList.resize( d->lookupFields.count() );
427 uint i = 0;
428 for (Field::ListIterator it(m_fields); it.current(); ++it) {
429 TQMap<const Field*, LookupFieldSchema*>::ConstIterator itMap = d->lookupFields.find( it.current() );
430 if (itMap != d->lookupFields.constEnd()) {
431 d->lookupFieldsList.insert( i, itMap.data() );
432 i++;
433 }
434 }
435 return d->lookupFieldsList;
436}
437
438//--------------------------------------
439
440InternalTableSchema::InternalTableSchema(const TQString& name)
441 : TableSchema(name)
442{
443}
444
445InternalTableSchema::InternalTableSchema(const TableSchema& ts)
446 : TableSchema(ts, false)
447{
448}
449
450InternalTableSchema::~InternalTableSchema()
451{
452}
453
virtual void removeField(KexiDB::Field *field)
FieldList(bool owner=false)
Definition fieldlist.cpp:29
FieldList & addField(Field *field)
virtual TQString debugString()
Field * field(uint id)
Definition fieldlist.h:76
virtual void clear()
Definition fieldlist.cpp:61
virtual FieldList & insertField(uint index, Field *field)
Definition fieldlist.cpp:71
Meta-data for a field.
Definition field.h:73
bool isPrimaryKey() const
Definition field.h:234
TQPtrListIterator< Field > ListIterator
iterator for list of fields
Definition field.h:77
Provides information about database index that can be created for a database table.
Definition indexschema.h:44
void setUnique(bool set)
bool isPrimaryKey() const
void setAutoGenerated(bool set)
virtual FieldList & addField(Field *field)
void setPrimaryKey(bool set)
Provides information about lookup field's setup.
KexiDB::QuerySchema provides information about database query.
virtual TQString schemaDataDebugString() const
void clear()
Clears all properties except 'type'.
const TQPtrVector< LookupFieldSchema > & lookupFieldsList()
void setPrimaryKey(IndexSchema *pkey)
QuerySchema * query()
virtual void clear()
virtual TQString debugString()
QuerySchema * m_query
cached query schema that is defined by "select * from <this_table_name>"
virtual FieldList & insertField(uint index, Field *field)
void setKexiDBSystem(bool set)
LookupFieldSchema * lookupFieldSchema(const Field &field) const
virtual void removeField(KexiDB::Field *field)
bool setLookupFieldSchema(const TQString &fieldName, LookupFieldSchema *lookupFieldSchema)
High-level database connectivity library with database backend drivers.