kexi

queryschema.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2003-2007 Jaroslaw Staniek <js@iidea.pl>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18*/
19
20#include "kexidb/queryschema.h"
21#include "kexidb/driver.h"
22#include "kexidb/connection.h"
23#include "kexidb/expression.h"
24#include "kexidb/parser/sqlparser.h"
25#include "utils.h"
26#include "lookupfieldschema.h"
27
28#include <assert.h>
29
30#include <tqvaluelist.h>
31#include <tqasciidict.h>
32#include <tqptrdict.h>
33#include <tqintdict.h>
34#include <tqbitarray.h>
35
36#include <kdebug.h>
37#include <tdelocale.h>
38
39using namespace KexiDB;
40
41QueryColumnInfo::QueryColumnInfo(Field *f, const TQCString& _alias, bool _visible,
42 QueryColumnInfo *foreignColumn)
43 : field(f), alias(_alias), visible(_visible), m_indexForVisibleLookupValue(-1)
44 , m_foreignColumn(foreignColumn)
45{
46}
47
48QueryColumnInfo::~QueryColumnInfo()
49{
50}
51
53{
54 return field->name() +
55 ( alias.isEmpty() ? TQString()
56 : (TQString::fromLatin1(" AS ") + TQString(alias)) );
57}
58
59//=======================================
60namespace KexiDB {
62class QuerySchemaPrivate
63{
64 public:
65 QuerySchemaPrivate(QuerySchema* q, QuerySchemaPrivate* copy = 0)
66 : query(q)
67 , masterTable(0)
68 , fakeRowIDField(0)
69 , fakeRowIDCol(0)
70 , maxIndexWithAlias(-1)
71 , visibility(64)
72 , fieldsExpanded(0)
73 , internalFields(0)
74 , fieldsExpandedWithInternalAndRowID(0)
75 , fieldsExpandedWithInternal(0)
76 , autoincFields(0)
77 , columnsOrder(0)
78 , columnsOrderWithoutAsterisks(0)
79 , columnsOrderExpanded(0)
80 , pkeyFieldsOrder(0)
81 , pkeyFieldsCount(0)
82 , tablesBoundToColumns(64, -1)
83 , tablePositionsForAliases(67, false)
84 , columnPositionsForAliases(67, false)
85 , whereExpr(0)
86 , ownedVisibleColumns(0)
87 , regenerateExprAliases(false)
88 {
89 columnAliases.setAutoDelete(true);
90 tableAliases.setAutoDelete(true);
91 asterisks.setAutoDelete(true);
92 relations.setAutoDelete(true);
93 tablePositionsForAliases.setAutoDelete(true);
94 columnPositionsForAliases.setAutoDelete(true);
95 visibility.fill(false);
96 if (copy) {
97 // deep copy
98 *this = *copy;
99 if (copy->fieldsExpanded)
100 fieldsExpanded = new QueryColumnInfo::Vector(*copy->fieldsExpanded);
101 if (copy->internalFields)
102 internalFields = new QueryColumnInfo::Vector(*copy->internalFields);
103 if (copy->fieldsExpandedWithInternalAndRowID)
104 fieldsExpandedWithInternalAndRowID = new QueryColumnInfo::Vector(
105 *copy->fieldsExpandedWithInternalAndRowID);
106 if (copy->fieldsExpandedWithInternal)
107 fieldsExpandedWithInternal = new QueryColumnInfo::Vector(
108 *copy->fieldsExpandedWithInternal);
109 if (copy->autoincFields)
110 autoincFields = new QueryColumnInfo::List(*copy->autoincFields);
111 if (copy->columnsOrder)
112 columnsOrder = new TQMap<QueryColumnInfo*,int>(*copy->columnsOrder);
113 if (copy->columnsOrderWithoutAsterisks)
114 columnsOrderWithoutAsterisks = new TQMap<QueryColumnInfo*,int>(
115 *copy->columnsOrderWithoutAsterisks);
116 if (copy->columnsOrderExpanded)
117 columnsOrderExpanded = new TQMap<QueryColumnInfo*,int>(*copy->columnsOrderExpanded);
118 if (copy->pkeyFieldsOrder)
119 pkeyFieldsOrder = new TQValueVector<int>(*copy->pkeyFieldsOrder);
120 if (copy->whereExpr)
121 whereExpr = copy->whereExpr->copy();
122 if (copy->fakeRowIDCol)
123 fakeRowIDCol = new QueryColumnInfo(*copy->fakeRowIDCol);
124 if (copy->fakeRowIDField)
125 fakeRowIDField = new Field(*copy->fakeRowIDField);
126 if (copy->ownedVisibleColumns)
127 ownedVisibleColumns = new Field::List(*copy->ownedVisibleColumns);
128 }
129 }
130 ~QuerySchemaPrivate()
131 {
132 delete fieldsExpanded;
133 delete internalFields;
134 delete fieldsExpandedWithInternalAndRowID;
135 delete fieldsExpandedWithInternal;
136 delete autoincFields;
137 delete columnsOrder;
138 delete columnsOrderWithoutAsterisks;
139 delete columnsOrderExpanded;
140 delete pkeyFieldsOrder;
141 delete whereExpr;
142 delete fakeRowIDCol;
143 delete fakeRowIDField;
144 delete ownedVisibleColumns;
145 }
146
147 void clear()
148 {
149 columnAliases.clear();
150 tableAliases.clear();
151 asterisks.clear();
152 relations.clear();
153 masterTable = 0;
154 tables.clear();
155 clearCachedData();
156 delete pkeyFieldsOrder;
157 pkeyFieldsOrder=0;
158 visibility.fill(false);
159 tablesBoundToColumns = TQValueVector<int>(64,-1);
160 tablePositionsForAliases.clear();
161 columnPositionsForAliases.clear();
162 }
163
164 void clearCachedData()
165 {
166 orderByColumnList.clear();
167 if (fieldsExpanded) {
168 delete fieldsExpanded;
169 fieldsExpanded = 0;
170 delete internalFields;
171 internalFields = 0;
172 delete columnsOrder;
173 columnsOrder = 0;
174 delete columnsOrderWithoutAsterisks;
175 columnsOrderWithoutAsterisks = 0;
176 delete columnsOrderExpanded;
177 columnsOrderExpanded = 0;
178 delete autoincFields;
179 autoincFields = 0;
180 autoIncrementSQLFieldsList = TQString();
181 columnInfosByNameExpanded.clear();
182 columnInfosByName.clear();
183 delete ownedVisibleColumns;
184 ownedVisibleColumns = 0;
185 }
186 }
187
188 void setColumnAliasInternal(uint position, const TQCString& alias)
189 {
190 columnAliases.replace(position, new TQCString(alias));
191 columnPositionsForAliases.replace(alias, new int(position));
192 maxIndexWithAlias = TQMAX( maxIndexWithAlias, (int)position );
193 }
194
195 void setColumnAlias(uint position, const TQCString& alias)
196 {
197 TQCString *oldAlias = columnAliases.take(position);
198 if (oldAlias) {
199 tablePositionsForAliases.remove(*oldAlias);
200 delete oldAlias;
201 }
202 if (alias.isEmpty()) {
203 maxIndexWithAlias = -1;
204 }
205 else {
206 setColumnAliasInternal(position, alias);
207 }
208 }
209
210 bool hasColumnAliases()
211 {
212 tryRegenerateExprAliases();
213 return !columnAliases.isEmpty();
214 }
215
216 TQCString* columnAlias(uint position)
217 {
218 tryRegenerateExprAliases();
219 return columnAliases[position];
220 }
221
222 QuerySchema *query;
223
227 TableSchema *masterTable;
228
230 TableSchema::List tables;
231
232 Field *fakeRowIDField;
233 QueryColumnInfo *fakeRowIDCol;
234
235 protected:
236 void tryRegenerateExprAliases()
237 {
238 if (!regenerateExprAliases)
239 return;
240 //regenerate missing aliases for experessions
241 Field *f;
242 uint p=0;
243 uint colNum=0; //used to generate a name
244 TQCString columnAlias;
245 for (Field::ListIterator it(query->fieldsIterator()); (f = it.current()); ++it, p++) {
246 if (f->isExpression() && !columnAliases[p]) {
247 //missing
248 for (;;) { //find 1st unused
249 colNum++;
250 columnAlias = (i18n("short for 'expression' word (only latin letters, please)", "expr")
251 + TQString::number(colNum)).latin1();
252 if (!tablePositionsForAliases[columnAlias])
253 break;
254 }
255 setColumnAliasInternal(p, columnAlias);
256 }
257 }
258 regenerateExprAliases = false;
259 }
260
262 TQIntDict<TQCString> columnAliases;
263
264 public:
266 TQIntDict<TQCString> tableAliases;
267
269 int maxIndexWithAlias;
270
272 int maxIndexWithTableAlias;
273
275 TQBitArray visibility;
276
278 Field::List asterisks;
279
281// Field::Vector *fieldsExpanded;
282 QueryColumnInfo::Vector *fieldsExpanded;
283
285 QueryColumnInfo::Vector *internalFields;
286
289 QueryColumnInfo::Vector *fieldsExpandedWithInternalAndRowID;
290
293 QueryColumnInfo::Vector *fieldsExpandedWithInternal;
294
296 OrderByColumnList orderByColumnList;
297
299 QueryColumnInfo::List *autoincFields;
300
302 TQString autoIncrementSQLFieldsList;
303 TQGuardedPtr<Driver> lastUsedDriverForAutoIncrementSQLFieldsList;
304
306 TQMap<QueryColumnInfo*,int> *columnsOrder;
307
309 TQMap<QueryColumnInfo*,int> *columnsOrderWithoutAsterisks;
310
314 TQMap<QueryColumnInfo*,int> *columnsOrderExpanded;
315
316// TQValueList<bool> detailedVisibility;
317
319 TQValueVector<int> *pkeyFieldsOrder;
320
322 uint pkeyFieldsCount;
323
325 TQString statement;
326
328 Relationship::List relations;
329
345 TQValueVector<int> tablesBoundToColumns;
346
348 TQAsciiDict<int> tablePositionsForAliases;
349
351 TQAsciiDict<int> columnPositionsForAliases;
352
354 BaseExpr *whereExpr;
355
356 TQDict<QueryColumnInfo> columnInfosByNameExpanded;
357
358 TQDict<QueryColumnInfo> columnInfosByName;
359
361 Field::List *ownedVisibleColumns;
362
365 bool regenerateExprAliases : 1;
366};
367}
368
369//=======================================
370
371OrderByColumn::OrderByColumn()
372 : m_column(0)
373 , m_pos(-1)
374 , m_field(0)
375 , m_ascending(true)
376{
377}
378
379OrderByColumn::OrderByColumn(QueryColumnInfo& column, bool ascending, int pos)
380 : m_column(&column)
381 , m_pos(pos)
382 , m_field(0)
383 , m_ascending(ascending)
384{
385}
386
387OrderByColumn::OrderByColumn(Field& field, bool ascending)
388 : m_column(0)
389 , m_pos(-1)
390 , m_field(&field)
392{
393}
394
395OrderByColumn::~OrderByColumn()
396{
397}
398
400{
401 TQString orderString( m_ascending ? "ascending" : "descending" );
402 if (m_column) {
403 if (m_pos>-1)
404 return TQString("COLUMN_AT_POSITION_%1(%2, %3)")
405 .arg(m_pos+1).arg(m_column->debugString()).arg(orderString);
406 else
407 return TQString("COLUMN(%1, %2)").arg(m_column->debugString()).arg(orderString);
408 }
409 return m_field ? TQString("FIELD(%1, %2)").arg(m_field->debugString()).arg(orderString)
410 : TQString("NONE");
411}
412
413TQString OrderByColumn::toSQLString(bool includeTableName, Driver *drv, int identifierEscaping) const
414{
415 const TQString orderString( m_ascending ? "" : " DESC" );
416 TQString fieldName, tableName;
417 if (m_column) {
418 if (m_pos>-1)
419 return TQString::number(m_pos+1) + orderString;
420 else {
421 if (includeTableName && m_column->alias.isEmpty()) {
422 tableName = m_column->field->table()->name();
423 if (drv)
424 tableName = drv->escapeIdentifier(tableName, identifierEscaping);
425 tableName += ".";
426 }
427 fieldName = m_column->aliasOrName();
428 if (drv)
429 fieldName = drv->escapeIdentifier(fieldName, identifierEscaping);
430 }
431 }
432 else {
433 if (includeTableName) {
434 tableName = m_field->table()->name();
435 if (drv)
436 tableName = drv->escapeIdentifier(tableName, identifierEscaping);
437 tableName += ".";
438 }
439 fieldName = m_field ? m_field->name() : "??"/*error*/;
440 if (drv)
441 fieldName = drv->escapeIdentifier(fieldName, identifierEscaping);
442 }
443 return tableName + fieldName + orderString;
444}
445
446//=======================================
447
452
454 const TQString& field1, bool ascending1,
455 const TQString& field2, bool ascending2,
456 const TQString& field3, bool ascending3,
457 const TQString& field4, bool ascending4,
458 const TQString& field5, bool ascending5)
459{
460 uint numAdded = 0;
461#define ADD_COL(fieldName, ascending) \
462 if (ok && !fieldName.isEmpty()) { \
463 if (!appendField( querySchema, fieldName, ascending )) \
464 ok = false; \
465 else \
466 numAdded++; \
467 }
468 bool ok = true;
469 ADD_COL(field1, ascending1);
470 ADD_COL(field2, ascending2);
471 ADD_COL(field3, ascending3);
472 ADD_COL(field4, ascending4);
473 ADD_COL(field5, ascending5);
474#undef ADD_COL
475 if (ok)
476 return true;
477 for (uint i=0; i<numAdded; i++)
478 pop_back();
479 return false;
480}
481
482OrderByColumnList::~OrderByColumnList()
483{
484}
485
486void OrderByColumnList::appendColumn(QueryColumnInfo& columnInfo, bool ascending)
487{
488 appendColumn( OrderByColumn(columnInfo, ascending) );
489}
490
491bool OrderByColumnList::appendColumn(QuerySchema& querySchema, bool ascending, int pos)
492{
493 QueryColumnInfo::Vector fieldsExpanded( querySchema.fieldsExpanded() );
494 QueryColumnInfo* ci = (pos >= (int)fieldsExpanded.size()) ? 0 : fieldsExpanded[pos];
495 if (!ci)
496 return false;
497 appendColumn( OrderByColumn(*ci, ascending, pos) );
498 return true;
499}
500
501void OrderByColumnList::appendField(Field& field, bool ascending)
502{
503 appendColumn( OrderByColumn(field, ascending) );
504}
505
507 const TQString& fieldName, bool ascending)
508{
509 QueryColumnInfo *columnInfo = querySchema.columnInfo( fieldName );
510 if (columnInfo) {
511 appendColumn( OrderByColumn(*columnInfo, ascending) );
512 return true;
513 }
514 Field *field = querySchema.findTableField(fieldName);
515 if (field) {
516 appendColumn( OrderByColumn(*field, ascending) );
517 return true;
518 }
519 KexiDBWarn << "OrderByColumnList::addColumn(QuerySchema& querySchema, "
520 "const TQString& column, bool ascending): no such field \"" << fieldName << "\"" << endl;
521 return false;
522}
523
525{
526 append( column );
527}
528
530{
531 if (isEmpty())
532 return "NONE";
533 TQString dbg;
534 for (OrderByColumn::ListConstIterator it=constBegin(); it!=constEnd(); ++it) {
535 if (!dbg.isEmpty())
536 dbg += "\n";
537 dbg += (*it).debugString();
538 }
539 return dbg;
540}
541
542TQString OrderByColumnList::toSQLString(bool includeTableNames, Driver *drv, int identifierEscaping) const
543{
544 TQString string;
545 for (OrderByColumn::ListConstIterator it=constBegin(); it!=constEnd(); ++it) {
546 if (!string.isEmpty())
547 string += ", ";
548 string += (*it).toSQLString(includeTableNames, drv, identifierEscaping);
549 }
550 return string;
551}
552
553//=======================================
554
556 : FieldList(false)//fields are not owned by QuerySchema object
557 , SchemaData(KexiDB::QueryObjectType)
558 , d( new QuerySchemaPrivate(this) )
559{
560 init();
561}
562
564 : FieldList(false)
565 , SchemaData(KexiDB::QueryObjectType)
566 , d( new QuerySchemaPrivate(this) )
567{
568 d->masterTable = &tableSchema;
569 init();
570/* if (!d->masterTable) {
571 KexiDBWarn << "QuerySchema(TableSchema*): !d->masterTable" << endl;
572 m_name = TQString();
573 return;
574 }*/
575 addTable(d->masterTable);
576 //defaults:
577 //inherit name from a table
578 m_name = d->masterTable->name();
579 //inherit caption from a table
580 m_caption = d->masterTable->caption();
581
582//replaced by explicit field list: //add all fields of the table as asterisk:
583//replaced by explicit field list: addField( new QueryAsterisk(this) );
584
585 // add explicit field list to avoid problems (e.g. with fields added outside of Kexi):
586 for (Field::ListIterator it( d->masterTable->fieldsIterator() ); it.current(); ++it) {
587 addField( it.current() );
588 }
589}
590
592 : FieldList(querySchema, false /* !deepCopyFields */)
593 , SchemaData(querySchema)
594 , d( new QuerySchemaPrivate(this, querySchema.d) )
595{
596 //only deep copy query asterisks
597 for (Field::ListIterator f_it(querySchema.m_fields); f_it.current(); ++f_it) {
598 Field *f;
599 if (dynamic_cast<QueryAsterisk*>( f_it.current() )) {
600 f = f_it.current()->copy();
601 if (static_cast<const KexiDB::FieldList *>(f_it.current()->m_parent) == &querySchema)
602 f->m_parent = this;
603 }
604 else
605 f = f_it.current();
606 addField( f );
607 }
608}
609
610QuerySchema::~QuerySchema()
611{
612 delete d;
613}
614
615void QuerySchema::init()
616{
617 m_type = KexiDB::QueryObjectType;
618//m_fields_by_name.setAutoDelete( true ); //because we're using QueryColumnInfoEntry objects
619}
620
622{
625 d->clear();
626}
627
628FieldList& QuerySchema::insertField(uint position, Field *field, bool visible)
629{
630 return insertField(position, field, -1/*don't bind*/, visible);
631}
632
633/*virtual*/
635{
636 return insertField( position, field, -1/*don't bind*/, true );
637}
638
639FieldList& QuerySchema::insertField(uint position, Field *field,
640 int bindToTable, bool visible)
641{
642 if (!field) {
643 KexiDBWarn << "QuerySchema::insertField(): !field" << endl;
644 return *this;
645 }
646
647 if (position>m_fields.count()) {
648 KexiDBWarn << "QuerySchema::insertField(): position (" << position << ") out of range" << endl;
649 return *this;
650 }
651 if (!field->isQueryAsterisk() && !field->isExpression() && !field->table()) {
652 KexiDBWarn << "QuerySchema::insertField(): WARNING: field '"<<field->name()
653 <<"' must contain table information!" <<endl;
654 return *this;
655 }
656 if (fieldCount()>=d->visibility.size()) {
657 d->visibility.resize(d->visibility.size()*2);
658 d->tablesBoundToColumns.resize(d->tablesBoundToColumns.size()*2);
659 }
660 d->clearCachedData();
661 FieldList::insertField(position, field);
662 if (field->isQueryAsterisk()) {
663 d->asterisks.append(field);
664 //if this is single-table asterisk,
665 //add a table to list if doesn't exist there:
666 if (field->table() && (d->tables.findRef(field->table())==-1))
667 d->tables.append(field->table());
668 }
669 else if (field->table()) {
670 //add a table to list if doesn't exist there:
671 if (d->tables.findRef(field->table())==-1)
672 d->tables.append(field->table());
673 }
674// //visible by default
675// setFieldVisible(field, true);
676// d->visibility.setBit(fieldCount()-1, visible);
677 //update visibility
678 //--move bits to make a place for a new one
679 for (uint i=fieldCount()-1; i>position; i--)
680 d->visibility.setBit(i, d->visibility.testBit(i-1));
681 d->visibility.setBit(position, visible);
682
683 //bind to table
684 if (bindToTable < -1 && bindToTable>(int)d->tables.count()) {
685 KexiDBWarn << "QuerySchema::insertField(): bindToTable (" << bindToTable
686 << ") out of range" << endl;
687 bindToTable = -1;
688 }
689 //--move items to make a place for a new one
690 for (uint i=fieldCount()-1; i>position; i--)
691 d->tablesBoundToColumns[i] = d->tablesBoundToColumns[i-1];
692 d->tablesBoundToColumns[ position ] = bindToTable;
693
694 KexiDBDbg << "QuerySchema::insertField(): bound to table (" << bindToTable << "): " <<endl;
695 if (bindToTable==-1)
696 KexiDBDbg << " <NOT SPECIFIED>" << endl;
697 else
698 KexiDBDbg << " name=" << d->tables.at(bindToTable)->name()
699 << " alias=" << tableAlias(bindToTable) << endl;
700 TQString s;
701 for (uint i=0; i<fieldCount();i++)
702 s+= (TQString::number(d->tablesBoundToColumns[i]) + " ");
703 KexiDBDbg << "tablesBoundToColumns == [" << s << "]" <<endl;
704
705 if (field->isExpression())
706 d->regenerateExprAliases = true;
707
708 return *this;
709}
710
711int QuerySchema::tableBoundToColumn(uint columnPosition) const
712{
713 if (columnPosition > d->tablesBoundToColumns.count()) {
714 KexiDBWarn << "QuerySchema::tableBoundToColumn(): columnPosition (" << columnPosition
715 << ") out of range" << endl;
716 return -1;
717 }
718 return d->tablesBoundToColumns[columnPosition];
719}
720
722{
723 return insertField(m_fields.count(), field, visible);
724}
725
727 bool visible)
728{
729 return insertField(m_fields.count(), field, bindToTable, visible);
730}
731
733{
734 if (!field)
735 return;
736 d->clearCachedData();
737 if (field->isQueryAsterisk()) {
738 d->asterisks.remove(field); //this will destroy this asterisk
739 }
740//TODO: should we also remove table for this field or asterisk?
742}
743
745{
746 return addField( new Field(this, expr), visible );
747}
748
749bool QuerySchema::isColumnVisible(uint position) const
750{
751 return (position < fieldCount()) ? d->visibility.testBit(position) : false;
752}
753
754void QuerySchema::setColumnVisible(uint position, bool v)
755{
756 if (position < fieldCount())
757 d->visibility.setBit(position, v);
758}
759
761{
762 if (!asterisk)
763 return *this;
764 //make unique name
765 asterisk->m_name = (asterisk->table() ? asterisk->table()->name() + ".*" : "*")
766 + TQString::number(asterisks()->count());
767 return addField(asterisk, visible);
768}
769
770Connection* QuerySchema::connection() const
771{
772 TableSchema *mt = masterTable();
773 return mt ? mt->connection() : 0;
774}
775
777{
778 TQString dbg;
779 dbg.reserve(1024);
780 //fields
781 TableSchema *mt = masterTable();
782 dbg = TQString("QUERY ") + schemaDataDebugString() + "\n"
783 + "-masterTable=" + (mt ? mt->name() :"<NULL>")
784 + "\n-COLUMNS:\n"
785 + ((fieldCount()>0) ? FieldList::debugString() : "<NONE>") + "\n"
786 + "-FIELDS EXPANDED ";
787
788 TQString dbg1;
789 uint fieldsExpandedCount = 0;
790 if (fieldCount()>0) {
791 QueryColumnInfo::Vector fe( fieldsExpanded() );
792 fieldsExpandedCount = fe.size();
793 for ( uint i=0; i < fieldsExpandedCount; i++ ) {
794 QueryColumnInfo *ci = fe[i];
795 if (!dbg1.isEmpty())
796 dbg1 += ",\n";
797 dbg1 += ci->debugString();
798 }
799 dbg1 += "\n";
800 }
801 else {
802 dbg1 = "<NONE>\n";
803 }
804 dbg1.prepend( TQString("(%1):\n").arg(fieldsExpandedCount) );
805 dbg += dbg1;
806
807 //it's safer to delete fieldsExpanded for now
808 // (debugString() could be called before all fields are added)
809//causes a crash d->clearCachedData();
810
811 //bindings
812 TQString dbg2;
813 dbg2.reserve(512);
814 for (uint i = 0; i<fieldCount(); i++) {
815 int tablePos = tableBoundToColumn(i);
816 if (tablePos>=0) {
817 TQCString tAlias = tableAlias(tablePos);
818 if (!tAlias.isEmpty()) {
819 dbg2 += (TQString::fromLatin1(" field \"") + FieldList::field(i)->name()
820 + "\" uses alias \"" + TQString(tAlias) + "\" of table \""
821 + d->tables.at(tablePos)->name() + "\"\n");
822 }
823 }
824 }
825 if (!dbg2.isEmpty()) {
826 dbg += "\n-BINDINGS:\n";
827 dbg += dbg2;
828 }
829
830 //tables
832 TQString table_names;
833 table_names.reserve(512);
834 for ( table = d->tables.first(); table; table = d->tables.next() ) {
835 if (!table_names.isEmpty())
836 table_names += ", ";
837 table_names += (TQString("'") + table->name() + "'");
838 }
839 if (d->tables.isEmpty())
840 table_names = "<NONE>";
841 dbg += (TQString("-TABLES:\n") + table_names);
842 TQString aliases;
843 if (!d->hasColumnAliases())
844 aliases = "<NONE>\n";
845 else {
846 Field::ListIterator it( m_fields );
847 for (int i=0; it.current(); ++it, i++) {
848 TQCString *alias = d->columnAlias(i);
849 if (alias)
850 aliases += (TQString("field #%1: ").arg(i)
851 + (it.current()->name().isEmpty() ? "<noname>" : it.current()->name())
852 + " -> " + (const char*)*alias + "\n");
853 }
854 }
855 //aliases
856 dbg += TQString("\n-COLUMN ALIASES:\n" + aliases);
857 if (d->tableAliases.isEmpty())
858 aliases = "<NONE>";
859 else {
860 aliases = "";
861 TableSchema::ListIterator t_it(d->tables);
862 for (int i=0; t_it.current(); ++t_it, i++) {
863 TQCString *alias = d->tableAliases[i];
864 if (alias)
865 aliases += (TQString("table #%1: ").arg(i)
866 + (t_it.current()->name().isEmpty() ? "<noname>" : t_it.current()->name())
867 + " -> " + (const char*)*alias + "\n");
868 }
869 }
870 dbg += TQString("-TABLE ALIASES:\n" + aliases);
871 TQString where = d->whereExpr ? d->whereExpr->debugString() : TQString();
872 if (!where.isEmpty())
873 dbg += (TQString("\n-WHERE EXPRESSION:\n") + where);
874 if (!orderByColumnList().isEmpty())
875 dbg += (TQString("\n-ORDER BY (%1):\n").arg(orderByColumnList().count())
877 return dbg;
878}
879
881{
882 if (d->masterTable)
883 return d->masterTable;
884 if (d->tables.isEmpty())
885 return 0;
886
887 //try to find master table if there's only one table (with possible aliasses)
888 int num = 0;
889 TQString tableNameLower;
890 for (TableSchema::ListIterator it(d->tables); it.current(); ++it, num++) {
891 if (!tableNameLower.isEmpty() && it.current()->name().lower()!=tableNameLower) {
892 //two or more different tables
893 return 0;
894 }
895 tableNameLower = tableAlias(num);
896 }
897 return d->tables.first();
898}
899
901{
902 if (table)
903 d->masterTable=table;
904}
905
907{
908 return &d->tables;
909}
910
911void QuerySchema::addTable(TableSchema *table, const TQCString& alias)
912{
913 KexiDBDbg << "QuerySchema::addTable() " << (void *)table
914 << " alias=" << alias << endl;
915 if (!table)
916 return;
917
918 //only append table if:
919 //-it has alias
920 //-it has no alias but there is no such table on the list
921 if (alias.isEmpty() && d->tables.findRef(table)!=-1) {
922 const TQString& tableNameLower = table->name().lower();
923 const TQString& aliasLower = TQString(alias.lower());
924 int num = 0;
925 for (TableSchema::ListIterator it(d->tables); it.current(); ++it, num++) {
926 if (it.current()->name().lower()==tableNameLower) {
927 const TQString& tAlias = tableAlias(num);
928 if (tAlias == aliasLower) {
929 KexiDBWarn << "QuerySchema::addTable(): table with \""
930 << tAlias << "\" alias already added!" << endl;
931 return;
932 }
933 }
934 }
935 }
936
937 d->tables.append(table);
938
939 if (!alias.isEmpty())
940 setTableAlias(d->tables.count()-1, alias);
941}
942
944{
945 if (!table)
946 return;
947 if (d->masterTable == table)
948 d->masterTable = 0;
949 d->tables.remove(table);
950 //todo: remove fields!
951}
952
953TableSchema* QuerySchema::table(const TQString& tableName) const
954{
955//TODO: maybe use tables_byname?
956 for (TableSchema::ListIterator it(d->tables); it.current(); ++it) {
957 if (it.current()->name().lower()==tableName.lower())
958 return it.current();
959 }
960 return 0;
961}
962
964{
965 return d->tables.findRef(table)!=-1;
966}
967
968Field* QuerySchema::findTableField(const TQString &tableOrTableAndFieldName) const
969{
970 TQString tableName, fieldName;
971 if (!KexiDB::splitToTableAndFieldParts(tableOrTableAndFieldName,
972 tableName, fieldName, KexiDB::SetFieldNameIfNoTableName)) {
973 return 0;
974 }
975 if (tableName.isEmpty()) {
976 for (TableSchema::ListIterator it(d->tables); it.current(); ++it) {
977 if (it.current()->field(fieldName))
978 return it.current()->field(fieldName);
979 }
980 return 0;
981 }
982 TableSchema *tableSchema = table(tableName);
983 if (!tableSchema)
984 return 0;
985 return tableSchema->field(fieldName);
986}
987
988TQCString QuerySchema::columnAlias(uint position) const
989{
990 TQCString *a = d->columnAlias(position);
991 return a ? *a : TQCString();
992}
993
994bool QuerySchema::hasColumnAlias(uint position) const
995{
996 return d->columnAlias(position)!=0;
997}
998
999void QuerySchema::setColumnAlias(uint position, const TQCString& alias)
1000{
1001 if (position >= m_fields.count()) {
1002 KexiDBWarn << "QuerySchema::setColumnAlias(): position (" << position
1003 << ") out of range!" << endl;
1004 return;
1005 }
1006 TQCString fixedAlias = alias.stripWhiteSpace();
1007 Field *f = FieldList::field(position);
1008 if (f->captionOrName().isEmpty() && fixedAlias.isEmpty()) {
1009 KexiDBWarn << "QuerySchema::setColumnAlias(): position (" << position
1010 << ") could not remove alias when no name is specified for expression column!" << endl;
1011 return;
1012 }
1013 d->setColumnAlias(position, fixedAlias);
1014}
1015
1016TQCString QuerySchema::tableAlias(uint position) const
1017{
1018 TQCString *a = d->tableAliases[position];
1019 return a ? *a : TQCString();
1020}
1021
1022int QuerySchema::tablePositionForAlias(const TQCString& name) const
1023{
1024 int *num = d->tablePositionsForAliases[name];
1025 if (!num)
1026 return -1;
1027 return *num;
1028}
1029
1030int QuerySchema::tablePosition(const TQString& tableName) const
1031{
1032 int num = 0;
1033 for (TableSchema::ListIterator it(d->tables); it.current(); ++it, num++) {
1034 if (it.current()->name().lower()==tableName.lower())
1035 return num;
1036 }
1037 return -1;
1038}
1039
1040TQValueList<int> QuerySchema::tablePositions(const TQString& tableName) const
1041{
1042 int num = 0;
1043 TQValueList<int> result;
1044 const TQString& tableNameLower = tableName.lower();
1045 for (TableSchema::ListIterator it(d->tables); it.current(); ++it, num++) {
1046 if (it.current()->name().lower()==tableNameLower) {
1047 result += num;
1048 }
1049 }
1050 return result;
1051}
1052
1053bool QuerySchema::hasTableAlias(uint position) const
1054{
1055 return d->tableAliases[position]!=0;
1056}
1057
1058int QuerySchema::columnPositionForAlias(const TQCString& name) const
1059{
1060 int *num = d->columnPositionsForAliases[name];
1061 if (!num)
1062 return -1;
1063 return *num;
1064}
1065
1066void QuerySchema::setTableAlias(uint position, const TQCString& alias)
1067{
1068 if (position >= d->tables.count()) {
1069 KexiDBWarn << "QuerySchema::setTableAlias(): position (" << position
1070 << ") out of range!" << endl;
1071 return;
1072 }
1073 TQCString fixedAlias = alias.stripWhiteSpace();
1074 if (fixedAlias.isEmpty()) {
1075 TQCString *oldAlias = d->tableAliases.take(position);
1076 if (oldAlias) {
1077 d->tablePositionsForAliases.remove(*oldAlias);
1078 delete oldAlias;
1079 }
1080// d->maxIndexWithTableAlias = -1;
1081 }
1082 else {
1083 d->tableAliases.replace(position, new TQCString(fixedAlias));
1084 d->tablePositionsForAliases.replace(fixedAlias, new int(position));
1085// d->maxIndexWithTableAlias = TQMAX( d->maxIndexWithTableAlias, (int)index );
1086 }
1087}
1088
1089Relationship::List* QuerySchema::relationships() const
1090{
1091 return &d->relations;
1092}
1093
1095{
1096 return &d->asterisks;
1097}
1098
1100{
1101 return d->statement;
1102}
1103
1104void QuerySchema::setStatement(const TQString &s)
1105{
1106 d->statement = s;
1107}
1108
1109Field* QuerySchema::field(const TQString& identifier, bool expanded)
1110{
1111 QueryColumnInfo *ci = columnInfo(identifier, expanded);
1112 return ci ? ci->field : 0;
1113}
1114
1115QueryColumnInfo* QuerySchema::columnInfo(const TQString& identifier, bool expanded)
1116{
1118 return expanded ? d->columnInfosByNameExpanded[identifier] : d->columnInfosByName[identifier];
1119}
1120
1122{
1124 if (options == WithInternalFields || options == WithInternalFieldsAndRowID) {
1125 //a ref to a proper pointer (as we cache the vector for two cases)
1126 QueryColumnInfo::Vector*& tmpFieldsExpandedWithInternal =
1127 (options == WithInternalFields) ? d->fieldsExpandedWithInternal : d->fieldsExpandedWithInternalAndRowID;
1128 //special case
1129 if (!tmpFieldsExpandedWithInternal) {
1130 //glue expanded and internal fields and cache it
1131 const uint size = d->fieldsExpanded->count()
1132 + (d->internalFields ? d->internalFields->count() : 0)
1133 + ((options == WithInternalFieldsAndRowID) ? 1 : 0) /*ROWID*/;
1134 tmpFieldsExpandedWithInternal = new QueryColumnInfo::Vector( size );
1135 const uint fieldsExpandedVectorSize = d->fieldsExpanded->size();
1136 for (uint i=0; i<fieldsExpandedVectorSize; i++)
1137 tmpFieldsExpandedWithInternal->insert(i, d->fieldsExpanded->at(i));
1138 const uint internalFieldsCount = d->internalFields ? d->internalFields->size() : 0;
1139 if (internalFieldsCount > 0) {
1140 for (uint i=0; i < internalFieldsCount; i++)
1141 tmpFieldsExpandedWithInternal->insert(
1142 fieldsExpandedVectorSize + i, d->internalFields->at(i));
1143 }
1144 if (options == WithInternalFieldsAndRowID) {
1145 if (!d->fakeRowIDField) {
1146 d->fakeRowIDField = new Field("rowID", Field::BigInteger);
1147 d->fakeRowIDCol = new QueryColumnInfo(d->fakeRowIDField, TQCString(), true);
1148 }
1149 tmpFieldsExpandedWithInternal->insert(
1150 fieldsExpandedVectorSize + internalFieldsCount, d->fakeRowIDCol );
1151 }
1152 }
1153 return *tmpFieldsExpandedWithInternal;
1154 }
1155
1156 if (options == Default)
1157 return *d->fieldsExpanded;
1158
1159 //options == Unique:
1160 TQDict<char> columnsAlreadyFound;
1161 QueryColumnInfo::Vector result( d->fieldsExpanded->count() ); //initial size is set
1162// TQMapConstIterator<QueryColumnInfo*, bool> columnsAlreadyFoundIt;
1163 //compute unique list
1164 uint uniqueListCount = 0;
1165 for (uint i=0; i<d->fieldsExpanded->count(); i++) {
1166 QueryColumnInfo *ci = (*d->fieldsExpanded)[i];
1167// columnsAlreadyFoundIt = columnsAlreadyFound.find(ci);
1168// uint foundColumnIndex = -1;
1169 if (!columnsAlreadyFound[ci->aliasOrName()]) {// columnsAlreadyFoundIt==columnsAlreadyFound.constEnd())
1170 columnsAlreadyFound.insert(ci->aliasOrName(), (char*)1);
1171 result.insert(uniqueListCount++, ci);
1172 }
1173 }
1174 result.resize(uniqueListCount); //update result size
1175 return result;
1176}
1177
1178QueryColumnInfo::Vector QuerySchema::internalFields()
1179{
1181 return d->internalFields ? *d->internalFields : QueryColumnInfo::Vector();
1182}
1183
1185{
1186 QueryColumnInfo::Vector vector = fieldsExpanded(WithInternalFields);
1187 return (index < vector.size()) ? vector[index] : 0;
1188}
1189
1190inline TQString lookupColumnKey(Field *foreignField, Field* field)
1191{
1192 TQString res;
1193 if (field->table()) // can be 0 for anonymous fields built as joined multiple visible columns
1194 res = field->table()->name() + ".";
1195 return res + field->name() + "_" + foreignField->table()->name() + "." + foreignField->name();
1196}
1197
1199{
1200 if (d->fieldsExpanded)
1201 return;
1202
1203 if (!d->columnsOrder) {
1204 d->columnsOrder = new TQMap<QueryColumnInfo*,int>();
1205 d->columnsOrderWithoutAsterisks = new TQMap<QueryColumnInfo*,int>();
1206 }
1207 else {
1208 d->columnsOrder->clear();
1209 d->columnsOrderWithoutAsterisks->clear();
1210 }
1211 if (d->ownedVisibleColumns)
1212 d->ownedVisibleColumns->clear();
1213
1214 //collect all fields in a list (not a vector yet, because we do not know its size)
1215 QueryColumnInfo::List list; //temporary
1216 QueryColumnInfo::List lookup_list; //temporary, for collecting additional fields related to lookup fields
1217 TQMap<QueryColumnInfo*, bool> columnInfosOutsideAsterisks; //helper for filling d->columnInfosByName
1218 uint i = 0;
1219 uint fieldPosition = 0;
1220 uint numberOfColumnsWithMultipleVisibleFields = 0; //used to find an unique name for anonymous field
1221 Field *f;
1222 for (Field::ListIterator it = fieldsIterator(); (f = it.current()); ++it, fieldPosition++) {
1223 if (f->isQueryAsterisk()) {
1224 if (static_cast<QueryAsterisk*>(f)->isSingleTableAsterisk()) {
1225 Field::List *ast_fields = static_cast<QueryAsterisk*>(f)->table()->fields();
1226 for (Field *ast_f = ast_fields->first(); ast_f; ast_f=ast_fields->next()) {
1227// d->detailedVisibility += isFieldVisible(fieldPosition);
1228 QueryColumnInfo *ci = new QueryColumnInfo(ast_f, TQCString()/*no field for asterisk!*/,
1229 isColumnVisible(fieldPosition));
1230 list.append( ci );
1231 KexiDBDbg << "QuerySchema::computeFieldsExpanded(): caching (unexpanded) columns order: "
1232 << ci->debugString() << " at position " << fieldPosition << endl;
1233 d->columnsOrder->insert(ci, fieldPosition);
1234// list.append(ast_f);
1235 }
1236 }
1237 else {//all-tables asterisk: iterate through table list
1238 for (TableSchema *table = d->tables.first(); table; table = d->tables.next()) {
1239 //add all fields from this table
1240 Field::List *tab_fields = table->fields();
1241 for (Field *tab_f = tab_fields->first(); tab_f; tab_f = tab_fields->next()) {
1243// d->detailedVisibility += isFieldVisible(fieldPosition);
1244// list.append(tab_f);
1245 QueryColumnInfo *ci = new QueryColumnInfo(tab_f, TQCString()/*no field for asterisk!*/,
1246 isColumnVisible(fieldPosition));
1247 list.append( ci );
1248 KexiDBDbg << "QuerySchema::computeFieldsExpanded(): caching (unexpanded) columns order: "
1249 << ci->debugString() << " at position " << fieldPosition << endl;
1250 d->columnsOrder->insert(ci, fieldPosition);
1251 }
1252 }
1253 }
1254 }
1255 else {
1256 //a single field
1257// d->detailedVisibility += isFieldVisible(fieldPosition);
1258 QueryColumnInfo *ci = new QueryColumnInfo(f, columnAlias(fieldPosition), isColumnVisible(fieldPosition));
1259 list.append( ci );
1260 columnInfosOutsideAsterisks.insert( ci, true );
1261 KexiDBDbg << "QuerySchema::computeFieldsExpanded(): caching (unexpanded) column's order: "
1262 << ci->debugString() << " at position " << fieldPosition << endl;
1263 d->columnsOrder->insert(ci, fieldPosition);
1264 d->columnsOrderWithoutAsterisks->insert(ci, fieldPosition);
1265
1266 //handle lookup field schema
1267 LookupFieldSchema *lookupFieldSchema = f->table() ? f->table()->lookupFieldSchema( *f ) : 0;
1268 if (!lookupFieldSchema || lookupFieldSchema->boundColumn()<0)
1269 continue;
1270 // Lookup field schema found:
1271 // Now we also need to fetch "visible" value from the lookup table, not only the value of binding.
1272 // -> build LEFT OUTER JOIN clause for this purpose (LEFT, not INNER because the binding can be broken)
1273 // "LEFT OUTER JOIN lookupTable ON thisTable.thisField=lookupTable.boundField"
1274 LookupFieldSchema::RowSource& rowSource = lookupFieldSchema->rowSource();
1275 if (rowSource.type() == LookupFieldSchema::RowSource::Table) {
1276 TableSchema *lookupTable = connection()->tableSchema( rowSource.name() );
1277 FieldList* visibleColumns = 0;
1278 Field *boundField = 0;
1279 if (lookupTable
1280 && (uint)lookupFieldSchema->boundColumn() < lookupTable->fieldCount()
1281 && (visibleColumns = lookupTable->subList( lookupFieldSchema->visibleColumns() ))
1282 && (boundField = lookupTable->field( lookupFieldSchema->boundColumn() )))
1283 {
1284 Field *visibleColumn = 0;
1285 // for single visible column, just add it as-is
1286 if (visibleColumns->fieldCount() == 1) {
1287 visibleColumn = visibleColumns->fields()->first();
1288 }
1289 else {
1290 // for multiple visible columns, build an expression column
1291 // (the expression object will be owned by column info)
1292 visibleColumn = new Field();
1293 visibleColumn->setName(
1294 TQString::fromLatin1("[multiple_visible_fields_%1]")
1295 .arg( ++numberOfColumnsWithMultipleVisibleFields ));
1296 visibleColumn->setExpression(
1297 new ConstExpr(CHARACTER_STRING_LITERAL, TQVariant()/*not important*/));
1298 if (!d->ownedVisibleColumns) {
1299 d->ownedVisibleColumns = new Field::List();
1300 d->ownedVisibleColumns->setAutoDelete(true);
1301 }
1302 d->ownedVisibleColumns->append( visibleColumn ); // remember to delete later
1303 }
1304
1305 lookup_list.append(
1306 new QueryColumnInfo(visibleColumn, TQCString(), true/*visible*/, ci/*foreign*/) );
1307/*
1308 //add visibleField to the list of SELECTed fields if it is not yes present there
1309 if (!findTableField( visibleField->table()->name()+"."+visibleField->name() )) {
1310 if (!table( visibleField->table()->name() )) {
1311 }
1312 if (!sql.isEmpty())
1313 sql += TQString::fromLatin1(", ");
1314 sql += (escapeIdentifier(visibleField->table()->name(), drvEscaping) + "."
1315 + escapeIdentifier(visibleField->name(), drvEscaping));
1316 }*/
1317 }
1318 delete visibleColumns;
1319 }
1320 else if (rowSource.type() == LookupFieldSchema::RowSource::Query) {
1321 QuerySchema *lookupQuery = connection()->querySchema( rowSource.name() );
1322 if (!lookupQuery)
1323 continue;
1324 const QueryColumnInfo::Vector lookupQueryFieldsExpanded( lookupQuery->fieldsExpanded() );
1325 if ((uint)lookupFieldSchema->boundColumn() >= lookupQueryFieldsExpanded.count())
1326 continue;
1327 QueryColumnInfo *boundColumnInfo = 0;
1328 if (!(boundColumnInfo = lookupQueryFieldsExpanded[ lookupFieldSchema->boundColumn() ]))
1329 continue;
1330 Field *boundField = boundColumnInfo->field;
1331 if (!boundField)
1332 continue;
1333 const TQValueList<uint> visibleColumns( lookupFieldSchema->visibleColumns() );
1334 bool ok = true;
1335 // all indices in visibleColumns should be in [0..lookupQueryFieldsExpanded.size()-1]
1336 foreach (TQValueList<uint>::ConstIterator, visibleColumnsIt, visibleColumns) {
1337 if ((*visibleColumnsIt) >= lookupQueryFieldsExpanded.count()) {
1338 ok = false;
1339 break;
1340 }
1341 }
1342 if (!ok)
1343 continue;
1344 Field *visibleColumn = 0;
1345 // for single visible column, just add it as-is
1346 if (visibleColumns.count() == 1) {
1347 visibleColumn = lookupQueryFieldsExpanded[ visibleColumns.first() ]->field;
1348 }
1349 else {
1350 // for multiple visible columns, build an expression column
1351 // (the expression object will be owned by column info)
1352 visibleColumn = new Field();
1353 visibleColumn->setName(
1354 TQString::fromLatin1("[multiple_visible_fields_%1]")
1355 .arg( ++numberOfColumnsWithMultipleVisibleFields ));
1356 visibleColumn->setExpression(
1357 new ConstExpr(CHARACTER_STRING_LITERAL, TQVariant()/*not important*/));
1358 if (!d->ownedVisibleColumns) {
1359 d->ownedVisibleColumns = new Field::List();
1360 d->ownedVisibleColumns->setAutoDelete(true);
1361 }
1362 d->ownedVisibleColumns->append( visibleColumn ); // remember to delete later
1363 }
1364
1365 lookup_list.append(
1366 new QueryColumnInfo(visibleColumn, TQCString(), true/*visible*/, ci/*foreign*/) );
1367/*
1368 //add visibleField to the list of SELECTed fields if it is not yes present there
1369 if (!findTableField( visibleField->table()->name()+"."+visibleField->name() )) {
1370 if (!table( visibleField->table()->name() )) {
1371 }
1372 if (!sql.isEmpty())
1373 sql += TQString::fromLatin1(", ");
1374 sql += (escapeIdentifier(visibleField->table()->name(), drvEscaping) + "."
1375 + escapeIdentifier(visibleField->name(), drvEscaping));
1376 }*/
1377 }
1378 }
1379 }
1380 //prepare clean vector for expanded list, and a map for order information
1381 if (!d->fieldsExpanded) {
1382 d->fieldsExpanded = new QueryColumnInfo::Vector( list.count() );// Field::Vector( list.count() );
1383 d->fieldsExpanded->setAutoDelete(true);
1384 d->columnsOrderExpanded = new TQMap<QueryColumnInfo*,int>();
1385 }
1386 else {//for future:
1387 d->fieldsExpanded->clear();
1388 d->fieldsExpanded->resize( list.count() );
1389 d->columnsOrderExpanded->clear();
1390 }
1391
1392 /*fill (based on prepared 'list' and 'lookup_list'):
1393 -the vector
1394 -the map
1395 -"fields by name" dictionary
1396 */
1397 d->columnInfosByName.clear();
1398 d->columnInfosByNameExpanded.clear();
1399 i=0;
1400 QueryColumnInfo *ci;
1401 for (QueryColumnInfo::ListIterator it(list); (ci = it.current()); ++it, i++) {
1402 d->fieldsExpanded->insert(i, ci);
1403 d->columnsOrderExpanded->insert(ci, i);
1404 //remember field by name/alias/table.name if there's no such string yet in d->columnInfosByNameExpanded
1405 if (!ci->alias.isEmpty()) {
1406 //store alias and table.alias
1407 if (!d->columnInfosByNameExpanded[ ci->alias ])
1408 d->columnInfosByNameExpanded.insert( ci->alias, ci );
1409 TQString tableAndAlias( ci->alias );
1410 if (ci->field->table())
1411 tableAndAlias.prepend(ci->field->table()->name() + ".");
1412 if (!d->columnInfosByNameExpanded[ tableAndAlias ])
1413 d->columnInfosByNameExpanded.insert( tableAndAlias, ci );
1414 //the same for "unexpanded" list
1415 if (columnInfosOutsideAsterisks.contains(ci)) {
1416 if (!d->columnInfosByName[ ci->alias ])
1417 d->columnInfosByName.insert( ci->alias, ci );
1418 if (!d->columnInfosByName[ tableAndAlias ])
1419 d->columnInfosByName.insert( tableAndAlias, ci );
1420 }
1421 }
1422 else {
1423 //no alias: store name and table.name
1424 if (!d->columnInfosByNameExpanded[ ci->field->name() ])
1425 d->columnInfosByNameExpanded.insert( ci->field->name(), ci );
1426 TQString tableAndName( ci->field->name() );
1427 if (ci->field->table())
1428 tableAndName.prepend(ci->field->table()->name() + ".");
1429 if (!d->columnInfosByNameExpanded[ tableAndName ])
1430 d->columnInfosByNameExpanded.insert( tableAndName, ci );
1431 //the same for "unexpanded" list
1432 if (columnInfosOutsideAsterisks.contains(ci)) {
1433 if (!d->columnInfosByName[ ci->field->name() ])
1434 d->columnInfosByName.insert( ci->field->name(), ci );
1435 if (!d->columnInfosByName[ tableAndName ])
1436 d->columnInfosByName.insert( tableAndName, ci );
1437 }
1438 }
1439 }
1440
1441 //remove duplicates for lookup fields
1442 TQDict<uint> lookup_dict(1009); //used to fight duplicates and to update QueryColumnInfo::indexForVisibleLookupValue()
1443 // (a mapping from table.name string to uint* lookupFieldIndex
1444 lookup_dict.setAutoDelete(true);
1445 i=0;
1446 for (QueryColumnInfo::ListIterator it(lookup_list); (ci = it.current());)
1447 {
1448 const TQString key( lookupColumnKey(ci->foreignColumn()->field, ci->field) );
1449 if ( /* not needed columnInfo( tableAndFieldName ) || */
1450 lookup_dict[ key ]) {
1451 // this table.field is already fetched by this query
1452 ++it;
1453 lookup_list.removeRef( ci );
1454 }
1455 else {
1456 lookup_dict.replace( key, new uint( i ) );
1457 ++it;
1458 i++;
1459 }
1460 }
1461
1462 //create internal expanded list with lookup fields
1463 if (d->internalFields) {
1464 d->internalFields->clear();
1465 d->internalFields->resize( lookup_list.count() );
1466 }
1467 delete d->fieldsExpandedWithInternal; //clear cache
1468 delete d->fieldsExpandedWithInternalAndRowID; //clear cache
1469 d->fieldsExpandedWithInternal = 0;
1470 d->fieldsExpandedWithInternalAndRowID = 0;
1471 if (!lookup_list.isEmpty() && !d->internalFields) {//create on demand
1472 d->internalFields = new QueryColumnInfo::Vector( lookup_list.count() );
1473 d->internalFields->setAutoDelete(true);
1474 }
1475 i=0;
1476 for (QueryColumnInfo::ListIterator it(lookup_list); it.current();i++, ++it)
1477 {
1478 //add it to the internal list
1479 d->internalFields->insert(i, it.current());
1480 d->columnsOrderExpanded->insert(it.current(), list.count()+i);
1481 }
1482
1483 //update QueryColumnInfo::indexForVisibleLookupValue() cache for columns
1484 numberOfColumnsWithMultipleVisibleFields = 0;
1485 for (i=0; i < d->fieldsExpanded->size(); i++) {
1486 QueryColumnInfo* ci = d->fieldsExpanded->at(i);
1488 LookupFieldSchema *lookupFieldSchema
1489 = ci->field->table() ? ci->field->table()->lookupFieldSchema( *ci->field ) : 0;
1490 if (!lookupFieldSchema || lookupFieldSchema->boundColumn()<0)
1491 continue;
1492 LookupFieldSchema::RowSource& rowSource = lookupFieldSchema->rowSource();
1493 if (rowSource.type() == LookupFieldSchema::RowSource::Table) {
1494 TableSchema *lookupTable = connection()->tableSchema( rowSource.name() );
1495 FieldList* visibleColumns = 0;
1496 if (lookupTable
1497 && (uint)lookupFieldSchema->boundColumn() < lookupTable->fieldCount()
1498 && (visibleColumns = lookupTable->subList( lookupFieldSchema->visibleColumns() )))
1499 {
1500 Field *visibleColumn = 0;
1501 // for single visible column, just add it as-is
1502 if (visibleColumns->fieldCount() == 1)
1503 {
1504 visibleColumn = visibleColumns->fields()->first();
1505 const TQString key( lookupColumnKey(ci->field, visibleColumn) );
1506 uint *index = lookup_dict[ key ];
1507 if (index)
1508 ci->setIndexForVisibleLookupValue( d->fieldsExpanded->size() + *index );
1509 }
1510 else {
1511 const TQString key( TQString::fromLatin1("[multiple_visible_fields_%1]_%2.%3")
1512 .arg( ++numberOfColumnsWithMultipleVisibleFields )
1513 .arg(ci->field->table()->name()).arg(ci->field->name()) );
1514 uint *index = lookup_dict[ key ];
1515 if (index)
1516 ci->setIndexForVisibleLookupValue( d->fieldsExpanded->size() + *index );
1517 }
1518 }
1519 delete visibleColumns;
1520 }
1521 else if (rowSource.type() == LookupFieldSchema::RowSource::Query) {
1522 QuerySchema *lookupQuery = connection()->querySchema( rowSource.name() );
1523 if (!lookupQuery)
1524 continue;
1525 const QueryColumnInfo::Vector lookupQueryFieldsExpanded( lookupQuery->fieldsExpanded() );
1526 if ((uint)lookupFieldSchema->boundColumn() >= lookupQueryFieldsExpanded.count())
1527 continue;
1528 QueryColumnInfo *boundColumnInfo = 0;
1529 if (!(boundColumnInfo = lookupQueryFieldsExpanded[ lookupFieldSchema->boundColumn() ]))
1530 continue;
1531 Field *boundField = boundColumnInfo->field;
1532 if (!boundField)
1533 continue;
1534 const TQValueList<uint> visibleColumns( lookupFieldSchema->visibleColumns() );
1535 Field *visibleColumn = 0;
1536 // for single visible column, just add it as-is
1537 if (visibleColumns.count() == 1) {
1538 visibleColumn = lookupQueryFieldsExpanded[ visibleColumns.first() ]->field;
1539 const TQString key( lookupColumnKey(ci->field, visibleColumn) );
1540 uint *index = lookup_dict[ key ];
1541 if (index)
1542 ci->setIndexForVisibleLookupValue( d->fieldsExpanded->size() + *index );
1543 }
1544 else {
1545 const TQString key( TQString::fromLatin1("[multiple_visible_fields_%1]_%2.%3")
1546 .arg( ++numberOfColumnsWithMultipleVisibleFields )
1547 .arg(ci->field->table()->name()).arg(ci->field->name()) );
1548 uint *index = lookup_dict[ key ];
1549 if (index)
1550 ci->setIndexForVisibleLookupValue( d->fieldsExpanded->size() + *index );
1551 }
1552 }
1553 else {
1554 KexiDBWarn << "QuerySchema::computeFieldsExpanded(): unsupported row source type "
1555 << rowSource.typeName() << endl;
1556 }
1557 }
1558}
1559
1560TQMap<QueryColumnInfo*,int> QuerySchema::columnsOrder(ColumnsOrderOptions options)
1561{
1562 if (!d->columnsOrder)
1564 if (options == UnexpandedList)
1565 return *d->columnsOrder;
1566 else if (options == UnexpandedListWithoutAsterisks)
1567 return *d->columnsOrderWithoutAsterisks;
1568 return *d->columnsOrderExpanded;
1569}
1570
1572{
1573 if (d->pkeyFieldsOrder)
1574 return *d->pkeyFieldsOrder;
1575
1576 TableSchema *tbl = masterTable();
1577 if (!tbl || !tbl->primaryKey())
1578 return TQValueVector<int>();
1579
1580 //get order of PKEY fields (e.g. for rows updating or inserting )
1581 IndexSchema *pkey = tbl->primaryKey();
1582 pkey->debug();
1583 debug();
1584 d->pkeyFieldsOrder = new TQValueVector<int>( pkey->fieldCount(), -1 );
1585
1586 const uint fCount = fieldsExpanded().count();
1587 d->pkeyFieldsCount = 0;
1588 for (uint i = 0; i<fCount; i++) {
1589 QueryColumnInfo *fi = d->fieldsExpanded->at(i);
1590 const int fieldIndex = fi->field->table()==tbl ? pkey->indexOf(fi->field) : -1;
1591 if (fieldIndex!=-1/* field found in PK */
1592 && d->pkeyFieldsOrder->at(fieldIndex)==-1 /* first time */)
1593 {
1594 KexiDBDbg << "QuerySchema::pkeyFieldsOrder(): FIELD " << fi->field->name()
1595 << " IS IN PKEY AT POSITION #" << fieldIndex << endl;
1596// (*d->pkeyFieldsOrder)[j]=i;
1597 (*d->pkeyFieldsOrder)[fieldIndex]=i;
1598 d->pkeyFieldsCount++;
1599// j++;
1600 }
1601 }
1602 KexiDBDbg << "QuerySchema::pkeyFieldsOrder(): " << d->pkeyFieldsCount
1603 << " OUT OF " << pkey->fieldCount() << " PKEY'S FIELDS FOUND IN QUERY " << name() << endl;
1604 return *d->pkeyFieldsOrder;
1605}
1606
1608{
1609 (void)pkeyFieldsOrder(); /* rebuild information */
1610 return d->pkeyFieldsCount;
1611}
1612
1613Relationship* QuerySchema::addRelationship( Field *field1, Field *field2 )
1614{
1615//@todo: find existing global db relationships
1616 Relationship *r = new Relationship(this, field1, field2);
1617 if (r->isEmpty()) {
1618 delete r;
1619 return 0;
1620 }
1621
1622 d->relations.append( r );
1623 return r;
1624}
1625
1626QueryColumnInfo::List* QuerySchema::autoIncrementFields()
1627{
1628 if (!d->autoincFields) {
1629 d->autoincFields = new QueryColumnInfo::List();
1630 }
1631 TableSchema *mt = masterTable();
1632 if (!mt) {
1633 KexiDBWarn << "QuerySchema::autoIncrementFields(): no master table!" << endl;
1634 return d->autoincFields;
1635 }
1636 if (d->autoincFields->isEmpty()) {//no cache
1637 QueryColumnInfo::Vector fexp = fieldsExpanded();
1638 for (int i=0; i<(int)fexp.count(); i++) {
1639 QueryColumnInfo *fi = fexp[i];
1640 if (fi->field->table() == mt && fi->field->isAutoIncrement()) {
1641 d->autoincFields->append( fi );
1642 }
1643 }
1644 }
1645 return d->autoincFields;
1646}
1647
1648TQString QuerySchema::sqlColumnsList(QueryColumnInfo::List* infolist, Driver *driver)
1649{
1650 if (!infolist)
1651 return TQString();
1652 TQString result;
1653 result.reserve(256);
1654 QueryColumnInfo::ListIterator it( *infolist );
1655 bool start = true;
1656 for (; it.current(); ++it) {
1657 if (!start)
1658 result += ",";
1659 else
1660 start = false;
1661 result += driver->escapeIdentifier( it.current()->field->name() );
1662 }
1663 return result;
1664}
1665
1667{
1668 if ((Driver *)d->lastUsedDriverForAutoIncrementSQLFieldsList != driver
1669 || d->autoIncrementSQLFieldsList.isEmpty())
1670 {
1671 d->autoIncrementSQLFieldsList = QuerySchema::sqlColumnsList( autoIncrementFields(), driver );
1672 d->lastUsedDriverForAutoIncrementSQLFieldsList = driver;
1673 }
1674 return d->autoIncrementSQLFieldsList;
1675}
1676
1678{
1679 delete d->whereExpr;
1680 d->whereExpr = expr;
1681}
1682
1683void QuerySchema::addToWhereExpression(KexiDB::Field *field, const TQVariant& value, int relation)
1684{
1685 int token;
1686 if (value.isNull())
1687 token = SQL_NULL;
1688 else if (field->isIntegerType()) {
1689 token = INTEGER_CONST;
1690 }
1691 else if (field->isFPNumericType()) {
1692 token = REAL_CONST;
1693 }
1694 else {
1695 token = CHARACTER_STRING_LITERAL;
1697 }
1698
1699 BinaryExpr * newExpr = new BinaryExpr(
1700 KexiDBExpr_Relational,
1701 new ConstExpr( token, value ),
1702 relation,
1703 new VariableExpr((field->table() ? (field->table()->name()+".") : TQString())+field->name())
1704 );
1705 if (d->whereExpr) {
1706 d->whereExpr = new BinaryExpr(
1707 KexiDBExpr_Logical,
1708 d->whereExpr,
1709 AND,
1710 newExpr
1711 );
1712 }
1713 else {
1714 d->whereExpr = newExpr;
1715 }
1716}
1717
1718/*
1719void QuerySchema::addToWhereExpression(KexiDB::Field *field, const TQVariant& value)
1720 switch (value.type()) {
1721 case Int: case UInt: case Bool: case LongLong: case ULongLong:
1722 token = INTEGER_CONST;
1723 break;
1724 case Double:
1725 token = REAL_CONST;
1726 break;
1727 default:
1728 token = CHARACTER_STRING_LITERAL;
1729 }
1731
1732*/
1733
1735{
1736 return d->whereExpr;
1737}
1738
1740{
1741 d->orderByColumnList = list;
1742// all field names should be found, exit otherwise ..........?
1743}
1744
1746{
1747 return d->orderByColumnList;
1748}
1749
1750QuerySchemaParameterList QuerySchema::parameters()
1751{
1752 if (!whereExpression())
1753 return QuerySchemaParameterList();
1754 QuerySchemaParameterList params;
1756 return params;
1757}
1758
1759/*
1760 new field1, Field *field2
1761 if (!field1 || !field2) {
1762 KexiDBWarn << "QuerySchema::addRelationship(): !masterField || !detailsField" << endl;
1763 return;
1764 }
1765 if (field1->isQueryAsterisk() || field2->isQueryAsterisk()) {
1766 KexiDBWarn << "QuerySchema::addRelationship(): relationship's fields cannot be asterisks" << endl;
1767 return;
1768 }
1769 if (!hasField(field1) && !hasField(field2)) {
1770 KexiDBWarn << "QuerySchema::addRelationship(): fields do not belong to this query" << endl;
1771 return;
1772 }
1773 if (field1->table() == field2->table()) {
1774 KexiDBWarn << "QuerySchema::addRelationship(): fields cannot belong to the same table" << endl;
1775 return;
1776 }
1777//@todo: check more things: -types
1778//@todo: find existing global db relationships
1779
1780 Field *masterField = 0, *detailsField = 0;
1781 IndexSchema *masterIndex = 0, *detailsIndex = 0;
1782 if (field1->isPrimaryKey() && field2->isPrimaryKey()) {
1783 //2 primary keys
1784 masterField = field1;
1785 masterIndex = masterField->table()->primaryKey();
1786 detailsField = field2;
1787 detailsIndex = masterField->table()->primaryKey();
1788 }
1789 else if (field1->isPrimaryKey()) {
1790 masterField = field1;
1791 masterIndex = masterField->table()->primaryKey();
1792 detailsField = field2;
1793//@todo: check if it already exists
1794 detailsIndex = new IndexSchema(detailsField->table());
1795 detailsIndex->addField(detailsField);
1796 detailsIndex->setForeigKey(true);
1797 // detailsField->setForeignKey(true);
1798 }
1799 else if (field2->isPrimaryKey()) {
1800 detailsField = field1;
1801 masterField = field2;
1802 masterIndex = masterField->table()->primaryKey();
1803//@todo
1804 }
1805
1806 if (!masterIndex || !detailsIndex)
1807 return; //failed
1808
1809 Relationship *rel = new Relationship(masterIndex, detailsIndex);
1810
1811 d->relations.append( rel );
1812}*/
1813
1814//---------------------------------------------------
1815
1816QueryAsterisk::QueryAsterisk( QuerySchema *query, TableSchema *table )
1817 :Field()
1818 ,m_table(table)
1819{
1820 assert(query);
1821 m_parent = query;
1823}
1824
1825QueryAsterisk::~QueryAsterisk()
1826{
1827}
1828
1830{
1831 return new QueryAsterisk(*this);
1832}
1833
1835{
1836 KexiDBDbg << "QueryAsterisk::setTable()" << endl;
1837 m_table=table;
1838}
1839
1841{
1842 TQString dbg;
1843 if (isAllTableAsterisk()) {
1844 dbg += "ALL-TABLES ASTERISK (*) ON TABLES(";
1845 TableSchema *table;
1846 TQString table_names;
1847 for (TableSchema::ListIterator it( *query()->tables() ); (table = it.current()); ++it) {
1848 if (!table_names.isEmpty())
1849 table_names += ", ";
1850 table_names += table->name();
1851 }
1852 dbg += (table_names + ")");
1853 }
1854 else {
1855 dbg += ("SINGLE-TABLE ASTERISK (" + table()->name() + ".*)");
1856 }
1857 return dbg;
1858}
1859
A base class for all expressions.
Definition expression.h:67
virtual void getQueryParameters(QuerySchemaParameterList &params)=0
virtual BaseExpr * copy() const =0
TableSchema * tableSchema(int tableId)
QuerySchema * querySchema(int queryId)
Generic database abstraction.
Definition driver.h:67
TQString escapeIdentifier(const TQString &str, int options=EscapeDriver|EscapeAsNecessary) const
Driver-specific identifier escaping (e.g. for a table name, db name, etc.).
Definition driver.cpp:316
virtual void removeField(KexiDB::Field *field)
FieldList(bool owner=false)
Definition fieldlist.cpp:29
FieldList * subList(const TQString &n1, const TQString &n2=TQString(), const TQString &n3=TQString(), const TQString &n4=TQString(), const TQString &n5=TQString(), const TQString &n6=TQString(), const TQString &n7=TQString(), const TQString &n8=TQString(), const TQString &n9=TQString(), const TQString &n10=TQString(), const TQString &n11=TQString(), const TQString &n12=TQString(), const TQString &n13=TQString(), const TQString &n14=TQString(), const TQString &n15=TQString(), const TQString &n16=TQString(), const TQString &n17=TQString(), const TQString &n18=TQString())
virtual TQString debugString()
uint fieldCount() const
Definition fieldlist.h:58
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
int indexOf(const Field *field)
Definition fieldlist.h:86
Meta-data for a field.
Definition field.h:73
void setName(const TQString &name)
Definition field.cpp:324
@ Asterisk
Special, internal types:
Definition field.h:104
TQString captionOrName() const
Definition field.h:374
TQPtrList< Field > List
list of fields
Definition field.h:75
FieldList * m_parent
Definition field.h:576
bool isAutoIncrement() const
Definition field.h:231
TQPtrListIterator< Field > ListIterator
iterator for list of fields
Definition field.h:77
void setType(Type t)
Definition field.cpp:330
virtual bool isQueryAsterisk() const
Definition field.h:510
bool isExpression() const
Definition field.h:537
void setExpression(KexiDB::BaseExpr *expr)
Definition field.cpp:633
virtual TableSchema * table() const
Definition field.cpp:300
Field(TableSchema *tableSchema)
Definition field.cpp:48
Provides information about database index that can be created for a database table.
Definition indexschema.h:44
Row source information that can be specified for the lookup field schema.
@ Table
table as lookup row source
@ Query
named query as lookup row source
Provides information about lookup field's setup.
TQValueList< uint > visibleColumns() const
KexiDB::OrderByColumnList provides list of sorted columns for a query schema.
void appendColumn(QueryColumnInfo &columnInfo, bool ascending=true)
TQString toSQLString(bool includeTableNames=true, Driver *drv=0, int identifierEscaping=Driver::EscapeDriver|Driver::EscapeAsNecessary) const
bool appendFields(QuerySchema &querySchema, const TQString &field1, bool ascending1=true, const TQString &field2=TQString(), bool ascending2=true, const TQString &field3=TQString(), bool ascending3=true, const TQString &field4=TQString(), bool ascending4=true, const TQString &field5=TQString(), bool ascending5=true)
TQString debugString() const
void appendField(Field &field, bool ascending=true)
KexiDB::OrderByColumn provides information about a single query column used for sorting.
QueryColumnInfo * m_column
Column to sort.
TQString debugString() const
TQString toSQLString(bool includeTableName=true, Driver *drv=0, int identifierEscaping=Driver::EscapeDriver|Driver::EscapeAsNecessary) const
Field * field() const
A field to sort, used only in case when the second constructor was used.
Field * m_field
Used only in case when the second contructor is used.
bool ascending() const
bool m_ascending
true if ascending sorting should be performed (the default).
KexiDB::QueryAsterisk class encapsulates information about single asterisk in query definition.
virtual void setTable(TableSchema *table)
bool isAllTableAsterisk() const
virtual Field * copy() const
QuerySchema * query() const
virtual TableSchema * table() const
TableSchema * m_table
virtual TQString debugString() const
QueryAsterisk(QuerySchema *query, TableSchema *table=0)
Helper class that assigns additional information for the column in a query.
Definition queryschema.h:49
TQCString aliasOrName() const
Definition queryschema.h:59
QueryColumnInfo * foreignColumn() const
Definition queryschema.h:81
void setIndexForVisibleLookupValue(int index)
Definition queryschema.h:78
TQString debugString() const
KexiDB::QuerySchema provides information about database query.
TableSchema * masterTable() const
TQCString columnAlias(uint position) const
virtual void clear()
FieldList & addExpression(BaseExpr *expr, bool visible=true)
int tablePosition(const TQString &tableName) const
Relationship::List * relationships() const
virtual TQString debugString()
virtual FieldList & insertField(uint position, Field *field)
void addTable(TableSchema *table, const TQCString &alias=TQCString())
Connection * connection() const
TQString autoIncrementSQLFieldsList(Driver *driver)
void setColumnVisible(uint position, bool v)
Sets visibility flag for column at position to v.
void setTableAlias(uint position, const TQCString &alias)
virtual Field * field(const TQString &name, bool expanded=true)
FieldList & addAsterisk(QueryAsterisk *asterisk, bool visible=true)
void setWhereExpression(BaseExpr *expr)
Relationship * addRelationship(Field *field1, Field *field2)
void setStatement(const TQString &s)
OrderByColumnList & orderByColumnList() const
TQValueList< int > tablePositions(const TQString &tableName) const
TableSchema * table(const TQString &tableName) const
@ Default
All fields are returned even if duplicated.
@ WithInternalFields
Like Default but internal fields (for lookup) are appended.
int tablePositionForAlias(const TQCString &name) const
TQMap< QueryColumnInfo *, int > columnsOrder(ColumnsOrderOptions options=ExpandedList)
bool hasColumnAlias(uint position) const
void removeTable(TableSchema *table)
QueryColumnInfo::Vector fieldsExpanded(FieldsExpandedOptions options=Default)
TQValueVector< int > pkeyFieldsOrder()
bool hasTableAlias(uint position) const
bool isColumnVisible(uint position) const
QueryColumnInfo::Vector internalFields()
@ UnexpandedList
A map for unexpanded list is created.
@ UnexpandedListWithoutAsterisks
A map for unexpanded list is created, with asterisks skipped.
QueryColumnInfo::List * autoIncrementFields()
int tableBoundToColumn(uint columnPosition) const
void setMasterTable(TableSchema *table)
int columnPositionForAlias(const TQCString &name) const
Field * findTableField(const TQString &tableOrTableAndFieldName) const
bool contains(TableSchema *table) const
Field::List * asterisks() const
TableSchema::List * tables() const
TQCString tableAlias(uint position) const
QueryColumnInfo * columnInfo(const TQString &identifier, bool expanded=true)
static TQString sqlColumnsList(QueryColumnInfo::List *infolist, Driver *driver)
TQString statement() const
void setOrderByColumnList(const OrderByColumnList &list)
BaseExpr * whereExpression() const
FieldList & addField(Field *field, bool visible=true)
virtual void removeField(Field *field)
QueryColumnInfo * expandedOrInternalField(uint index)
void addToWhereExpression(KexiDB::Field *field, const TQVariant &value, int relation='=')
void setColumnAlias(uint position, const TQCString &alias)
QuerySchemaParameterList parameters()
virtual TQString schemaDataDebugString() const
void clear()
Clears all properties except 'type'.
Connection * connection() const
IndexSchema * primaryKey() const
Definition tableschema.h:76
TQPtrListIterator< TableSchema > ListIterator
Iterator for tables list.
Definition tableschema.h:46
TQPtrList< TableSchema > List
Type of tables list.
Definition tableschema.h:45
LookupFieldSchema * lookupFieldSchema(const Field &field) const
Variables like fieldname or tablename.fieldname.
Definition expression.h:245
High-level database connectivity library with database backend drivers.
TQValueList< OrderByColumn > OrderByColumnListBase
A base for KexiDB::OrderByColumnList.
KEXI_DB_EXPORT bool splitToTableAndFieldParts(const TQString &string, TQString &tableName, TQString &fieldName, SplitToTableAndFieldPartsOptions option=FailIfNoTableOrFieldName)
@ SetFieldNameIfNoTableName
see splitToTableAndFieldParts()