00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "kexidb/queryschema.h"
00021 #include "kexidb/driver.h"
00022 #include "kexidb/connection.h"
00023 #include "kexidb/expression.h"
00024 #include "kexidb/parser/sqlparser.h"
00025 #include "utils.h"
00026 #include "lookupfieldschema.h"
00027
00028 #include <assert.h>
00029
00030 #include <qvaluelist.h>
00031 #include <qasciidict.h>
00032 #include <qptrdict.h>
00033 #include <qintdict.h>
00034 #include <qbitarray.h>
00035
00036 #include <kdebug.h>
00037 #include <klocale.h>
00038
00039 using namespace KexiDB;
00040
00041 QueryColumnInfo::QueryColumnInfo(Field *f, const QCString& _alias, bool _visible,
00042 QueryColumnInfo *foreignColumn)
00043 : field(f), alias(_alias), visible(_visible), m_indexForVisibleLookupValue(-1)
00044 , m_foreignColumn(foreignColumn)
00045 {
00046 }
00047
00048 QueryColumnInfo::~QueryColumnInfo()
00049 {
00050 }
00051
00052 QString QueryColumnInfo::debugString() const
00053 {
00054 return field->name() +
00055 ( alias.isEmpty() ? QString::null
00056 : (QString::fromLatin1(" AS ") + QString(alias)) );
00057 }
00058
00059
00060 namespace KexiDB {
00062 class QuerySchemaPrivate
00063 {
00064 public:
00065 QuerySchemaPrivate(QuerySchema* q)
00066 : query(q)
00067 , masterTable(0)
00068 , fakeRowIDField(0)
00069 , fakeRowIDCol(0)
00070 , maxIndexWithAlias(-1)
00071 , visibility(64)
00072 , fieldsExpanded(0)
00073 , internalFields(0)
00074 , fieldsExpandedWithInternalAndRowID(0)
00075 , fieldsExpandedWithInternal(0)
00076 , autoincFields(0)
00077 , columnsOrder(0)
00078 , columnsOrderWithoutAsterisks(0)
00079 , columnsOrderExpanded(0)
00080 , pkeyFieldsOrder(0)
00081 , pkeyFieldsCount(0)
00082 , tablesBoundToColumns(64, -1)
00083 , tablePositionsForAliases(67, false)
00084 , columnPositionsForAliases(67, false)
00085 , whereExpr(0)
00086 , regenerateExprAliases(false)
00087 {
00088 columnAliases.setAutoDelete(true);
00089 tableAliases.setAutoDelete(true);
00090 asterisks.setAutoDelete(true);
00091 relations.setAutoDelete(true);
00092 tablePositionsForAliases.setAutoDelete(true);
00093 columnPositionsForAliases.setAutoDelete(true);
00094 visibility.fill(false);
00095 }
00096 ~QuerySchemaPrivate()
00097 {
00098 delete fieldsExpanded;
00099 delete internalFields;
00100 delete fieldsExpandedWithInternalAndRowID;
00101 delete fieldsExpandedWithInternal;
00102 delete autoincFields;
00103 delete columnsOrder;
00104 delete columnsOrderWithoutAsterisks;
00105 delete columnsOrderExpanded;
00106 delete pkeyFieldsOrder;
00107 delete whereExpr;
00108 delete fakeRowIDCol;
00109 delete fakeRowIDField;
00110 }
00111
00112 void clear()
00113 {
00114 columnAliases.clear();
00115 tableAliases.clear();
00116 asterisks.clear();
00117 relations.clear();
00118 masterTable = 0;
00119 tables.clear();
00120 clearCachedData();
00121 delete pkeyFieldsOrder;
00122 pkeyFieldsOrder=0;
00123 visibility.fill(false);
00124 tablesBoundToColumns = QValueVector<int>(64,-1);
00125 tablePositionsForAliases.clear();
00126 columnPositionsForAliases.clear();
00127 }
00128
00129 void clearCachedData()
00130 {
00131 orderByColumnList.clear();
00132 if (fieldsExpanded) {
00133 delete fieldsExpanded;
00134 fieldsExpanded = 0;
00135 delete internalFields;
00136 internalFields = 0;
00137 delete columnsOrder;
00138 columnsOrder = 0;
00139 delete columnsOrderWithoutAsterisks;
00140 columnsOrderWithoutAsterisks = 0;
00141 delete columnsOrderExpanded;
00142 columnsOrderExpanded = 0;
00143 delete autoincFields;
00144 autoincFields = 0;
00145 autoIncrementSQLFieldsList = QString::null;
00146 columnInfosByNameExpanded.clear();
00147 columnInfosByName.clear();
00148 }
00149 }
00150
00151 void setColumnAliasInternal(uint position, const QCString& alias)
00152 {
00153 columnAliases.replace(position, new QCString(alias));
00154 columnPositionsForAliases.replace(alias, new int(position));
00155 maxIndexWithAlias = QMAX( maxIndexWithAlias, (int)position );
00156 }
00157
00158 void setColumnAlias(uint position, const QCString& alias)
00159 {
00160 QCString *oldAlias = columnAliases.take(position);
00161 if (oldAlias) {
00162 tablePositionsForAliases.remove(*oldAlias);
00163 delete oldAlias;
00164 }
00165 if (alias.isEmpty()) {
00166 maxIndexWithAlias = -1;
00167 }
00168 else {
00169 setColumnAliasInternal(position, alias);
00170 }
00171 }
00172
00173 bool hasColumnAliases()
00174 {
00175 tryRegenerateExprAliases();
00176 return !columnAliases.isEmpty();
00177 }
00178
00179 QCString* columnAlias(uint position)
00180 {
00181 tryRegenerateExprAliases();
00182 return columnAliases[position];
00183 }
00184
00185 QuerySchema *query;
00186
00190 TableSchema *masterTable;
00191
00193 TableSchema::List tables;
00194
00195 Field *fakeRowIDField;
00196 QueryColumnInfo *fakeRowIDCol;
00197
00198 protected:
00199 void tryRegenerateExprAliases()
00200 {
00201 if (!regenerateExprAliases)
00202 return;
00203
00204 Field *f;
00205 uint p=0;
00206 uint colNum=0;
00207 QCString columnAlias;
00208 for (Field::ListIterator it(query->fieldsIterator()); (f = it.current()); ++it, p++) {
00209 if (f->isExpression() && !columnAliases[p]) {
00210
00211 for (;;) {
00212 colNum++;
00213 columnAlias = (i18n("short for 'expression' word (only latin letters, please)", "expr")
00214 + QString::number(colNum)).latin1();
00215 if (!tablePositionsForAliases[columnAlias])
00216 break;
00217 }
00218 setColumnAliasInternal(p, columnAlias);
00219 }
00220 }
00221 regenerateExprAliases = false;
00222 }
00223
00225 QIntDict<QCString> columnAliases;
00226
00227 public:
00229 QIntDict<QCString> tableAliases;
00230
00232 int maxIndexWithAlias;
00233
00235 int maxIndexWithTableAlias;
00236
00238 QBitArray visibility;
00239
00241 Field::List asterisks;
00242
00244
00245 QueryColumnInfo::Vector *fieldsExpanded;
00246
00248 QueryColumnInfo::Vector *internalFields;
00249
00252 QueryColumnInfo::Vector *fieldsExpandedWithInternalAndRowID;
00253
00256 QueryColumnInfo::Vector *fieldsExpandedWithInternal;
00257
00259 OrderByColumnList orderByColumnList;
00260
00262 QueryColumnInfo::List *autoincFields;
00263
00265 QString autoIncrementSQLFieldsList;
00266 QGuardedPtr<Driver> lastUsedDriverForAutoIncrementSQLFieldsList;
00267
00269 QMap<QueryColumnInfo*,int> *columnsOrder;
00270
00272 QMap<QueryColumnInfo*,int> *columnsOrderWithoutAsterisks;
00273
00277 QMap<QueryColumnInfo*,int> *columnsOrderExpanded;
00278
00279
00280
00282 QValueVector<int> *pkeyFieldsOrder;
00283
00285 uint pkeyFieldsCount;
00286
00288 QString statement;
00289
00291 Relationship::List relations;
00292
00308 QValueVector<int> tablesBoundToColumns;
00309
00311 QAsciiDict<int> tablePositionsForAliases;
00312
00314 QAsciiDict<int> columnPositionsForAliases;
00315
00317 BaseExpr *whereExpr;
00318
00319 QDict<QueryColumnInfo> columnInfosByNameExpanded;
00320
00321 QDict<QueryColumnInfo> columnInfosByName;
00322
00325 bool regenerateExprAliases : 1;
00326 };
00327 }
00328
00329
00330
00331 OrderByColumn::OrderByColumn()
00332 : m_column(0)
00333 , m_pos(-1)
00334 , m_field(0)
00335 , m_ascending(true)
00336 {
00337 }
00338
00339 OrderByColumn::OrderByColumn(QueryColumnInfo& column, bool ascending, int pos)
00340 : m_column(&column)
00341 , m_pos(pos)
00342 , m_field(0)
00343 , m_ascending(ascending)
00344 {
00345 }
00346
00347 OrderByColumn::OrderByColumn(Field& field, bool ascending)
00348 : m_column(0)
00349 , m_pos(-1)
00350 , m_field(&field)
00351 , m_ascending(ascending)
00352 {
00353 }
00354
00355 OrderByColumn::~OrderByColumn()
00356 {
00357 }
00358
00359 QString OrderByColumn::debugString() const
00360 {
00361 QString orderString( m_ascending ? "ascending" : "descending" );
00362 if (m_column) {
00363 if (m_pos>-1)
00364 return QString("COLUMN_AT_POSITION_%1(%2, %3)")
00365 .arg(m_pos+1).arg(m_column->debugString()).arg(orderString);
00366 else
00367 return QString("COLUMN(%1, %2)").arg(m_column->debugString()).arg(orderString);
00368 }
00369 return m_field ? QString("FIELD(%1, %2)").arg(m_field->debugString()).arg(orderString)
00370 : QString("NONE");
00371 }
00372
00373 QString OrderByColumn::toSQLString(bool includeTableName) const
00374 {
00375 QString orderString( m_ascending ? "" : " DESC" );
00376 if (m_column) {
00377 if (m_pos>-1)
00378 return QString::number(m_pos+1) + orderString;
00379 else
00380 return ((includeTableName && m_column->alias.isEmpty())
00381 ? m_column->field->table()->name()+"." : QString::null)
00382 + QString(m_column->aliasOrName()) + orderString;
00383 }
00384 else {
00385 return
00386 (includeTableName ? m_field->table()->name()+"." : QString::null)
00387 + (m_field ? m_field->name() : "??") + orderString;
00388 }
00389 }
00390
00391
00392
00393 OrderByColumnList::OrderByColumnList()
00394 : OrderByColumnListBase()
00395 {
00396 }
00397
00398 bool OrderByColumnList::appendFields(QuerySchema& querySchema,
00399 const QString& field1, bool ascending1,
00400 const QString& field2, bool ascending2,
00401 const QString& field3, bool ascending3,
00402 const QString& field4, bool ascending4,
00403 const QString& field5, bool ascending5)
00404 {
00405 uint numAdded = 0;
00406 #define ADD_COL(fieldName, ascending) \
00407 if (ok && !fieldName.isEmpty()) { \
00408 if (!appendField( querySchema, fieldName, ascending )) \
00409 ok = false; \
00410 else \
00411 numAdded++; \
00412 }
00413 bool ok = true;
00414 ADD_COL(field1, ascending1);
00415 ADD_COL(field2, ascending2);
00416 ADD_COL(field3, ascending3);
00417 ADD_COL(field4, ascending4);
00418 ADD_COL(field5, ascending5);
00419 #undef ADD_COL
00420 if (ok)
00421 return true;
00422 for (uint i=0; i<numAdded; i++)
00423 pop_back();
00424 return false;
00425 }
00426
00427 OrderByColumnList::~OrderByColumnList()
00428 {
00429 }
00430
00431 void OrderByColumnList::appendColumn(QueryColumnInfo& columnInfo, bool ascending)
00432 {
00433 appendColumn( OrderByColumn(columnInfo, ascending) );
00434 }
00435
00436 bool OrderByColumnList::appendColumn(QuerySchema& querySchema, bool ascending, int pos)
00437 {
00438 QueryColumnInfo::Vector fieldsExpanded( querySchema.fieldsExpanded() );
00439 QueryColumnInfo* ci = (pos >= (int)fieldsExpanded.size()) ? 0 : fieldsExpanded[pos];
00440 if (!ci)
00441 return false;
00442 appendColumn( OrderByColumn(*ci, ascending, pos) );
00443 return true;
00444 }
00445
00446 void OrderByColumnList::appendField(Field& field, bool ascending)
00447 {
00448 appendColumn( OrderByColumn(field, ascending) );
00449 }
00450
00451 bool OrderByColumnList::appendField(QuerySchema& querySchema,
00452 const QString& fieldName, bool ascending)
00453 {
00454 QueryColumnInfo *columnInfo = querySchema.columnInfo( fieldName );
00455 if (columnInfo) {
00456 appendColumn( OrderByColumn(*columnInfo, ascending) );
00457 return true;
00458 }
00459 Field *field = querySchema.findTableField(fieldName);
00460 if (field) {
00461 appendColumn( OrderByColumn(*field, ascending) );
00462 return true;
00463 }
00464 KexiDBWarn << "OrderByColumnList::addColumn(QuerySchema& querySchema, "
00465 "const QString& column, bool ascending): no such field \"" << fieldName << "\"" << endl;
00466 return false;
00467 }
00468
00469 void OrderByColumnList::appendColumn(const OrderByColumn& column)
00470 {
00471 append( column );
00472 }
00473
00474 QString OrderByColumnList::debugString() const
00475 {
00476 if (isEmpty())
00477 return "NONE";
00478 QString dbg;
00479 for (OrderByColumn::ListConstIterator it=constBegin(); it!=constEnd(); ++it) {
00480 if (!dbg.isEmpty())
00481 dbg += "\n";
00482 dbg += (*it).debugString();
00483 }
00484 return dbg;
00485 }
00486
00487 QString OrderByColumnList::toSQLString(bool includeTableNames) const
00488 {
00489 QString string;
00490 for (OrderByColumn::ListConstIterator it=constBegin(); it!=constEnd(); ++it) {
00491 if (!string.isEmpty())
00492 string += ", ";
00493 string += (*it).toSQLString(includeTableNames);
00494 }
00495 return string;
00496 }
00497
00498
00499
00500 QuerySchema::QuerySchema()
00501 : FieldList(false)
00502 , SchemaData(KexiDB::QueryObjectType)
00503 , d( new QuerySchemaPrivate(this) )
00504 {
00505 init();
00506 }
00507
00508 QuerySchema::QuerySchema(TableSchema* tableSchema)
00509 : FieldList(false)
00510 , SchemaData(KexiDB::QueryObjectType)
00511 , d( new QuerySchemaPrivate(this) )
00512 {
00513 d->masterTable = tableSchema;
00514
00515 init();
00516 if (!d->masterTable) {
00517 KexiDBWarn << "QuerySchema(TableSchema*): !d->masterTable" << endl;
00518 m_name = QString::null;
00519 return;
00520 }
00521 addTable(d->masterTable);
00522
00523
00524 m_name = d->masterTable->name();
00525
00526 m_caption = d->masterTable->caption();
00527
00528
00529
00530
00531
00532 for (Field::ListIterator it( d->masterTable->fieldsIterator() ); it.current(); ++it) {
00533 addField( it.current() );
00534 }
00535 }
00536
00537 QuerySchema::~QuerySchema()
00538 {
00539 delete d;
00540 }
00541
00542 void QuerySchema::init()
00543 {
00544 m_type = KexiDB::QueryObjectType;
00545
00546 }
00547
00548 void QuerySchema::clear()
00549 {
00550 FieldList::clear();
00551 SchemaData::clear();
00552 d->clear();
00553 }
00554
00555 FieldList& QuerySchema::insertField(uint position, Field *field, bool visible)
00556 {
00557 return insertField(position, field, -1, visible);
00558 }
00559
00560
00561 FieldList& QuerySchema::insertField(uint position, Field *field)
00562 {
00563 return insertField( position, field, -1, true );
00564 }
00565
00566 FieldList& QuerySchema::insertField(uint position, Field *field,
00567 int bindToTable, bool visible)
00568 {
00569 if (!field) {
00570 KexiDBWarn << "QuerySchema::insertField(): !field" << endl;
00571 return *this;
00572 }
00573
00574 if (position>m_fields.count()) {
00575 KexiDBWarn << "QuerySchema::insertField(): position (" << position << ") out of range" << endl;
00576 return *this;
00577 }
00578 if (!field->isQueryAsterisk() && !field->isExpression() && !field->table()) {
00579 KexiDBWarn << "QuerySchema::insertField(): WARNING: field '"<<field->name()
00580 <<"' must contain table information!" <<endl;
00581 return *this;
00582 }
00583 if (fieldCount()>=d->visibility.size()) {
00584 d->visibility.resize(d->visibility.size()*2);
00585 d->tablesBoundToColumns.resize(d->tablesBoundToColumns.size()*2);
00586 }
00587 d->clearCachedData();
00588 FieldList::insertField(position, field);
00589 if (field->isQueryAsterisk()) {
00590 d->asterisks.append(field);
00591
00592
00593 if (field->table() && (d->tables.findRef(field->table())==-1))
00594 d->tables.append(field->table());
00595 }
00596 else if (field->table()) {
00597
00598 if (d->tables.findRef(field->table())==-1)
00599 d->tables.append(field->table());
00600 }
00601
00602
00603
00604
00605
00606 for (uint i=fieldCount()-1; i>position; i--)
00607 d->visibility.setBit(i, d->visibility.testBit(i-1));
00608 d->visibility.setBit(position, visible);
00609
00610
00611 if (bindToTable < -1 && bindToTable>(int)d->tables.count()) {
00612 KexiDBWarn << "QuerySchema::insertField(): bindToTable (" << bindToTable
00613 << ") out of range" << endl;
00614 bindToTable = -1;
00615 }
00616
00617 for (uint i=fieldCount()-1; i>position; i--)
00618 d->tablesBoundToColumns[i] = d->tablesBoundToColumns[i-1];
00619 d->tablesBoundToColumns[ position ] = bindToTable;
00620
00621 KexiDBDbg << "QuerySchema::insertField(): bound to table (" << bindToTable << "): " <<endl;
00622 if (bindToTable==-1)
00623 KexiDBDbg << " <NOT SPECIFIED>" << endl;
00624 else
00625 KexiDBDbg << " name=" << d->tables.at(bindToTable)->name()
00626 << " alias=" << tableAlias(bindToTable) << endl;
00627 QString s;
00628 for (uint i=0; i<fieldCount();i++)
00629 s+= (QString::number(d->tablesBoundToColumns[i]) + " ");
00630 KexiDBDbg << "tablesBoundToColumns == [" << s << "]" <<endl;
00631
00632 if (field->isExpression())
00633 d->regenerateExprAliases = true;
00634
00635 return *this;
00636 }
00637
00638 int QuerySchema::tableBoundToColumn(uint columnPosition) const
00639 {
00640 if (columnPosition > d->tablesBoundToColumns.count()) {
00641 KexiDBWarn << "QuerySchema::tableBoundToColumn(): columnPosition (" << columnPosition
00642 << ") out of range" << endl;
00643 return -1;
00644 }
00645 return d->tablesBoundToColumns[columnPosition];
00646 }
00647
00648 KexiDB::FieldList& QuerySchema::addField(KexiDB::Field* field, bool visible)
00649 {
00650 return insertField(m_fields.count(), field, visible);
00651 }
00652
00653 KexiDB::FieldList& QuerySchema::addField(KexiDB::Field* field, int bindToTable,
00654 bool visible)
00655 {
00656 return insertField(m_fields.count(), field, bindToTable, visible);
00657 }
00658
00659 void QuerySchema::removeField(KexiDB::Field *field)
00660 {
00661 if (!field)
00662 return;
00663 d->clearCachedData();
00664 if (field->isQueryAsterisk()) {
00665 d->asterisks.remove(field);
00666 }
00667
00668 FieldList::removeField(field);
00669 }
00670
00671 FieldList& QuerySchema::addExpression(BaseExpr* expr, bool visible)
00672 {
00673 return addField( new Field(this, expr), visible );
00674 }
00675
00676 bool QuerySchema::isColumnVisible(uint position) const
00677 {
00678 return (position < fieldCount()) ? d->visibility.testBit(position) : false;
00679 }
00680
00681 void QuerySchema::setColumnVisible(uint position, bool v)
00682 {
00683 if (position < fieldCount())
00684 d->visibility.setBit(position, v);
00685 }
00686
00687 FieldList& QuerySchema::addAsterisk(QueryAsterisk *asterisk, bool visible)
00688 {
00689 if (!asterisk)
00690 return *this;
00691
00692 asterisk->m_name = (asterisk->table() ? asterisk->table()->name() + ".*" : "*")
00693 + QString::number(asterisks()->count());
00694 return addField(asterisk, visible);
00695 }
00696
00697 Connection* QuerySchema::connection() const
00698 {
00699 TableSchema *mt = masterTable();
00700 return mt ? mt->connection() : 0;
00701 }
00702
00703 QString QuerySchema::debugString()
00704 {
00705 QString dbg;
00706 dbg.reserve(1024);
00707
00708 TableSchema *mt = masterTable();
00709 dbg = QString("QUERY ") + schemaDataDebugString() + "\n"
00710 + "-masterTable=" + (mt ? mt->name() :"<NULL>")
00711 + "\n-COLUMNS:\n"
00712 + ((fieldCount()>0) ? FieldList::debugString() : "<NONE>") + "\n"
00713 + "-FIELDS EXPANDED ";
00714
00715 QString dbg1;
00716 uint fieldsExpandedCount = 0;
00717 if (fieldCount()>0) {
00718 QueryColumnInfo::Vector fe( fieldsExpanded() );
00719 fieldsExpandedCount = fe.size();
00720 for ( uint i=0; i < fieldsExpandedCount; i++ ) {
00721 QueryColumnInfo *ci = fe[i];
00722 if (!dbg1.isEmpty())
00723 dbg1 += ",\n";
00724 dbg1 += ci->debugString();
00725 }
00726 dbg1 += "\n";
00727 }
00728 else {
00729 dbg1 = "<NONE>\n";
00730 }
00731 dbg1.prepend( QString("(%1):\n").arg(fieldsExpandedCount) );
00732 dbg += dbg1;
00733
00734
00735
00736
00737
00738
00739 QString dbg2;
00740 dbg2.reserve(512);
00741 for (uint i = 0; i<fieldCount(); i++) {
00742 int tablePos = tableBoundToColumn(i);
00743 if (tablePos>=0) {
00744 QCString tAlias = tableAlias(tablePos);
00745 if (!tAlias.isEmpty()) {
00746 dbg2 += (QString::fromLatin1(" field \"") + FieldList::field(i)->name()
00747 + "\" uses alias \"" + QString(tAlias) + "\" of table \""
00748 + d->tables.at(tablePos)->name() + "\"\n");
00749 }
00750 }
00751 }
00752 if (!dbg2.isEmpty()) {
00753 dbg += "\n-BINDINGS:\n";
00754 dbg += dbg2;
00755 }
00756
00757
00758 TableSchema *table;
00759 QString table_names;
00760 table_names.reserve(512);
00761 for ( table = d->tables.first(); table; table = d->tables.next() ) {
00762 if (!table_names.isEmpty())
00763 table_names += ", ";
00764 table_names += (QString("'") + table->name() + "'");
00765 }
00766 if (d->tables.isEmpty())
00767 table_names = "<NONE>";
00768 dbg += (QString("-TABLES:\n") + table_names);
00769 QString aliases;
00770 if (!d->hasColumnAliases())
00771 aliases = "<NONE>\n";
00772 else {
00773 Field::ListIterator it( m_fields );
00774 for (int i=0; it.current(); ++it, i++) {
00775 QCString *alias = d->columnAlias(i);
00776 if (alias)
00777 aliases += (QString("field #%1: ").arg(i)
00778 + (it.current()->name().isEmpty() ? "<noname>" : it.current()->name())
00779 + " -> " + (const char*)*alias + "\n");
00780 }
00781 }
00782
00783 dbg += QString("\n-COLUMN ALIASES:\n" + aliases);
00784 if (d->tableAliases.isEmpty())
00785 aliases = "<NONE>";
00786 else {
00787 aliases = "";
00788 TableSchema::ListIterator t_it(d->tables);
00789 for (int i=0; t_it.current(); ++t_it, i++) {
00790 QCString *alias = d->tableAliases[i];
00791 if (alias)
00792 aliases += (QString("table #%1: ").arg(i)
00793 + (t_it.current()->name().isEmpty() ? "<noname>" : t_it.current()->name())
00794 + " -> " + (const char*)*alias + "\n");
00795 }
00796 }
00797 dbg += QString("-TABLE ALIASES:\n" + aliases);
00798 QString where = d->whereExpr ? d->whereExpr->debugString() : QString::null;
00799 if (!where.isEmpty())
00800 dbg += (QString("\n-WHERE EXPRESSION:\n") + where);
00801 if (!orderByColumnList().isEmpty())
00802 dbg += (QString("\n-ORDER BY (%1):\n").arg(orderByColumnList().count())
00803 + orderByColumnList().debugString());
00804 return dbg;
00805 }
00806
00807 TableSchema* QuerySchema::masterTable() const
00808 {
00809 if (d->masterTable)
00810 return d->masterTable;
00811 if (d->tables.isEmpty())
00812 return 0;
00813
00814
00815 int num = 0;
00816 QString tableNameLower;
00817 for (TableSchema::ListIterator it(d->tables); it.current(); ++it, num++) {
00818 if (!tableNameLower.isEmpty() && it.current()->name().lower()!=tableNameLower) {
00819
00820 return 0;
00821 }
00822 tableNameLower = tableAlias(num);
00823 }
00824 return d->tables.first();
00825 }
00826
00827 void QuerySchema::setMasterTable(TableSchema *table)
00828 {
00829 if (table)
00830 d->masterTable=table;
00831 }
00832
00833 TableSchema::List* QuerySchema::tables() const
00834 {
00835 return &d->tables;
00836 }
00837
00838 void QuerySchema::addTable(TableSchema *table, const QCString& alias)
00839 {
00840 KexiDBDbg << "QuerySchema::addTable() " << (void *)table
00841 << " alias=" << alias << endl;
00842 if (!table)
00843 return;
00844
00845
00846
00847
00848 if (alias.isEmpty() && d->tables.findRef(table)!=-1) {
00849 const QString& tableNameLower = table->name().lower();
00850 const QString& aliasLower = QString(alias.lower());
00851 int num = 0;
00852 for (TableSchema::ListIterator it(d->tables); it.current(); ++it, num++) {
00853 if (it.current()->name().lower()==tableNameLower) {
00854 const QString& tAlias = tableAlias(num);
00855 if (tAlias == aliasLower) {
00856 KexiDBWarn << "QuerySchema::addTable(): table with \""
00857 << tAlias << "\" alias already added!" << endl;
00858 return;
00859 }
00860 }
00861 }
00862 }
00863
00864 d->tables.append(table);
00865
00866 if (!alias.isEmpty())
00867 setTableAlias(d->tables.count()-1, alias);
00868 }
00869
00870 void QuerySchema::removeTable(TableSchema *table)
00871 {
00872 if (!table)
00873 return;
00874 if (d->masterTable == table)
00875 d->masterTable = 0;
00876 d->tables.remove(table);
00877
00878 }
00879
00880 TableSchema* QuerySchema::table(const QString& tableName) const
00881 {
00882
00883 for (TableSchema::ListIterator it(d->tables); it.current(); ++it) {
00884 if (it.current()->name().lower()==tableName.lower())
00885 return it.current();
00886 }
00887 return 0;
00888 }
00889
00890 bool QuerySchema::contains(TableSchema *table) const
00891 {
00892 return d->tables.findRef(table)!=-1;
00893 }
00894
00895 Field* QuerySchema::findTableField(const QString &tableOrTableAndFieldName) const
00896 {
00897 QString tableName, fieldName;
00898 if (!KexiDB::splitToTableAndFieldParts(tableOrTableAndFieldName,
00899 tableName, fieldName, KexiDB::SetFieldNameIfNoTableName)) {
00900 return 0;
00901 }
00902 if (tableName.isEmpty()) {
00903 for (TableSchema::ListIterator it(d->tables); it.current(); ++it) {
00904 if (it.current()->field(fieldName))
00905 return it.current()->field(fieldName);
00906 }
00907 return 0;
00908 }
00909 TableSchema *tableSchema = table(tableName);
00910 if (!tableSchema)
00911 return 0;
00912 return tableSchema->field(fieldName);
00913 }
00914
00915 QCString QuerySchema::columnAlias(uint position) const
00916 {
00917 QCString *a = d->columnAlias(position);
00918 return a ? *a : QCString();
00919 }
00920
00921 bool QuerySchema::hasColumnAlias(uint position) const
00922 {
00923 return d->columnAlias(position)!=0;
00924 }
00925
00926 void QuerySchema::setColumnAlias(uint position, const QCString& alias)
00927 {
00928 if (position >= m_fields.count()) {
00929 KexiDBWarn << "QuerySchema::setColumnAlias(): position (" << position
00930 << ") out of range!" << endl;
00931 return;
00932 }
00933 QCString fixedAlias = alias.stripWhiteSpace();
00934 Field *f = FieldList::field(position);
00935 if (f->captionOrName().isEmpty() && fixedAlias.isEmpty()) {
00936 KexiDBWarn << "QuerySchema::setColumnAlias(): position (" << position
00937 << ") could not remove alias when no name is specified for expression column!" << endl;
00938 return;
00939 }
00940 d->setColumnAlias(position, fixedAlias);
00941 }
00942
00943 QCString QuerySchema::tableAlias(uint position) const
00944 {
00945 QCString *a = d->tableAliases[position];
00946 return a ? *a : QCString();
00947 }
00948
00949 int QuerySchema::tablePositionForAlias(const QCString& name) const
00950 {
00951 int *num = d->tablePositionsForAliases[name];
00952 if (!num)
00953 return -1;
00954 return *num;
00955 }
00956
00957 int QuerySchema::tablePosition(const QString& tableName) const
00958 {
00959 int num = 0;
00960 for (TableSchema::ListIterator it(d->tables); it.current(); ++it, num++) {
00961 if (it.current()->name().lower()==tableName.lower())
00962 return num;
00963 }
00964 return -1;
00965 }
00966
00967 QValueList<int> QuerySchema::tablePositions(const QString& tableName) const
00968 {
00969 int num = 0;
00970 QValueList<int> result;
00971 const QString& tableNameLower = tableName.lower();
00972 for (TableSchema::ListIterator it(d->tables); it.current(); ++it, num++) {
00973 if (it.current()->name().lower()==tableNameLower) {
00974 result += num;
00975 }
00976 }
00977 return result;
00978 }
00979
00980 bool QuerySchema::hasTableAlias(uint position) const
00981 {
00982 return d->tableAliases[position]!=0;
00983 }
00984
00985 int QuerySchema::columnPositionForAlias(const QCString& name) const
00986 {
00987 int *num = d->columnPositionsForAliases[name];
00988 if (!num)
00989 return -1;
00990 return *num;
00991 }
00992
00993 void QuerySchema::setTableAlias(uint position, const QCString& alias)
00994 {
00995 if (position >= d->tables.count()) {
00996 KexiDBWarn << "QuerySchema::setTableAlias(): position (" << position
00997 << ") out of range!" << endl;
00998 return;
00999 }
01000 QCString fixedAlias = alias.stripWhiteSpace();
01001 if (fixedAlias.isEmpty()) {
01002 QCString *oldAlias = d->tableAliases.take(position);
01003 if (oldAlias) {
01004 d->tablePositionsForAliases.remove(*oldAlias);
01005 delete oldAlias;
01006 }
01007
01008 }
01009 else {
01010 d->tableAliases.replace(position, new QCString(fixedAlias));
01011 d->tablePositionsForAliases.replace(fixedAlias, new int(position));
01012
01013 }
01014 }
01015
01016 Relationship::List* QuerySchema::relationships() const
01017 {
01018 return &d->relations;
01019 }
01020
01021 Field::List* QuerySchema::asterisks() const
01022 {
01023 return &d->asterisks;
01024 }
01025
01026 QString QuerySchema::statement() const
01027 {
01028 return d->statement;
01029 }
01030
01031 void QuerySchema::setStatement(const QString &s)
01032 {
01033 d->statement = s;
01034 }
01035
01036 Field* QuerySchema::field(const QString& identifier, bool expanded)
01037 {
01038 QueryColumnInfo *ci = columnInfo(identifier, expanded);
01039 return ci ? ci->field : 0;
01040 }
01041
01042 QueryColumnInfo* QuerySchema::columnInfo(const QString& identifier, bool expanded)
01043 {
01044 computeFieldsExpanded();
01045 return expanded ? d->columnInfosByNameExpanded[identifier] : d->columnInfosByName[identifier];
01046 }
01047
01048 QueryColumnInfo::Vector QuerySchema::fieldsExpanded(FieldsExpandedOptions options)
01049 {
01050 computeFieldsExpanded();
01051 if (options == WithInternalFields || options == WithInternalFieldsAndRowID) {
01052
01053 QueryColumnInfo::Vector*& tmpFieldsExpandedWithInternal =
01054 (options == WithInternalFields) ? d->fieldsExpandedWithInternal : d->fieldsExpandedWithInternalAndRowID;
01055
01056 if (!tmpFieldsExpandedWithInternal) {
01057
01058 const uint size = d->fieldsExpanded->count()
01059 + (d->internalFields ? d->internalFields->count() : 0)
01060 + ((options == WithInternalFieldsAndRowID) ? 1 : 0) ;
01061 tmpFieldsExpandedWithInternal = new QueryColumnInfo::Vector( size );
01062 const uint fieldsExpandedVectorSize = d->fieldsExpanded->size();
01063 for (uint i=0; i<fieldsExpandedVectorSize; i++)
01064 tmpFieldsExpandedWithInternal->insert(i, d->fieldsExpanded->at(i));
01065 const uint internalFieldsCount = d->internalFields ? d->internalFields->size() : 0;
01066 if (internalFieldsCount > 0) {
01067 for (uint i=0; i < internalFieldsCount; i++)
01068 tmpFieldsExpandedWithInternal->insert(
01069 fieldsExpandedVectorSize + i, d->internalFields->at(i));
01070 }
01071 if (options == WithInternalFieldsAndRowID) {
01072 if (!d->fakeRowIDField) {
01073 d->fakeRowIDField = new Field("rowID", Field::BigInteger);
01074 d->fakeRowIDCol = new QueryColumnInfo(d->fakeRowIDField, QCString(), true);
01075 }
01076 tmpFieldsExpandedWithInternal->insert(
01077 fieldsExpandedVectorSize + internalFieldsCount, d->fakeRowIDCol );
01078 }
01079 }
01080 return *tmpFieldsExpandedWithInternal;
01081 }
01082
01083 if (options == Default)
01084 return *d->fieldsExpanded;
01085
01086
01087 QDict<char> columnsAlreadyFound;
01088 QueryColumnInfo::Vector result( d->fieldsExpanded->count() );
01089
01090
01091 uint uniqueListCount = 0;
01092 for (uint i=0; i<d->fieldsExpanded->count(); i++) {
01093 QueryColumnInfo *ci = (*d->fieldsExpanded)[i];
01094
01095
01096 if (!columnsAlreadyFound[ci->aliasOrName()]) {
01097 columnsAlreadyFound.insert(ci->aliasOrName(), (char*)1);
01098 result.insert(uniqueListCount++, ci);
01099 }
01100 }
01101 result.resize(uniqueListCount);
01102 return result;
01103 }
01104
01105 QueryColumnInfo::Vector QuerySchema::internalFields()
01106 {
01107 computeFieldsExpanded();
01108 return d->internalFields ? *d->internalFields : QueryColumnInfo::Vector();
01109 }
01110
01111 QueryColumnInfo* QuerySchema::expandedOrInternalField(uint index)
01112 {
01113 QueryColumnInfo::Vector vector = fieldsExpanded(WithInternalFields);
01114 return (index < vector.size()) ? vector[index] : 0;
01115 }
01116
01117 void QuerySchema::computeFieldsExpanded()
01118 {
01119 if (d->fieldsExpanded)
01120 return;
01121
01122 if (!d->columnsOrder) {
01123 d->columnsOrder = new QMap<QueryColumnInfo*,int>();
01124 d->columnsOrderWithoutAsterisks = new QMap<QueryColumnInfo*,int>();
01125 }
01126 else {
01127 d->columnsOrder->clear();
01128 d->columnsOrderWithoutAsterisks->clear();
01129 }
01130
01131
01132 QueryColumnInfo::List list;
01133 QueryColumnInfo::List lookup_list;
01134 QMap<QueryColumnInfo*, bool> columnInfosOutsideAsterisks;
01135 uint i = 0;
01136 uint fieldPosition = 0;
01137 Field *f;
01138 for (Field::ListIterator it = fieldsIterator(); (f = it.current()); ++it, fieldPosition++) {
01139 if (f->isQueryAsterisk()) {
01140 if (static_cast<QueryAsterisk*>(f)->isSingleTableAsterisk()) {
01141 Field::List *ast_fields = static_cast<QueryAsterisk*>(f)->table()->fields();
01142 for (Field *ast_f = ast_fields->first(); ast_f; ast_f=ast_fields->next()) {
01143
01144 QueryColumnInfo *ci = new QueryColumnInfo(ast_f, QCString(),
01145 isColumnVisible(fieldPosition));
01146 list.append( ci );
01147 KexiDBDbg << "QuerySchema::computeFieldsExpanded(): caching (unexpanded) columns order: "
01148 << ci->debugString() << " at position " << fieldPosition << endl;
01149 d->columnsOrder->insert(ci, fieldPosition);
01150
01151 }
01152 }
01153 else {
01154 for (TableSchema *table = d->tables.first(); table; table = d->tables.next()) {
01155
01156 Field::List *tab_fields = table->fields();
01157 for (Field *tab_f = tab_fields->first(); tab_f; tab_f = tab_fields->next()) {
01159
01160
01161 QueryColumnInfo *ci = new QueryColumnInfo(tab_f, QCString(),
01162 isColumnVisible(fieldPosition));
01163 list.append( ci );
01164 KexiDBDbg << "QuerySchema::computeFieldsExpanded(): caching (unexpanded) columns order: "
01165 << ci->debugString() << " at position " << fieldPosition << endl;
01166 d->columnsOrder->insert(ci, fieldPosition);
01167 }
01168 }
01169 }
01170 }
01171 else {
01172
01173
01174 QueryColumnInfo *ci = new QueryColumnInfo(f, columnAlias(fieldPosition), isColumnVisible(fieldPosition));
01175 list.append( ci );
01176 columnInfosOutsideAsterisks.insert( ci, true );
01177 KexiDBDbg << "QuerySchema::computeFieldsExpanded(): caching (unexpanded) column's order: "
01178 << ci->debugString() << " at position " << fieldPosition << endl;
01179 d->columnsOrder->insert(ci, fieldPosition);
01180 d->columnsOrderWithoutAsterisks->insert(ci, fieldPosition);
01181
01182
01183 LookupFieldSchema *lookupFieldSchema = f->table() ? f->table()->lookupFieldSchema( *f ) : 0;
01184 if (lookupFieldSchema) {
01185
01186
01187
01188
01189 LookupFieldSchema::RowSource& rowSource = lookupFieldSchema->rowSource();
01190 if (rowSource.type()==LookupFieldSchema::RowSource::Table) {
01191 TableSchema *lookupTable = connection()->tableSchema( rowSource.name() );
01192 Field *visibleField = 0;
01193 Field *boundField = 0;
01194 if (lookupTable && lookupFieldSchema->boundColumn()>=0
01195 && (uint)lookupFieldSchema->boundColumn() < lookupTable->fieldCount()
01196 && (visibleField = lookupTable->field( lookupFieldSchema->visibleColumn()))
01197 && (boundField = lookupTable->field( lookupFieldSchema->boundColumn() )))
01198 {
01199 lookup_list.append( new QueryColumnInfo(visibleField, QCString(), true, ci) );
01200
01201
01202
01203
01204
01205
01206
01207
01208
01209
01210 }
01211 }
01212 }
01213 }
01214 }
01215
01216 if (!d->fieldsExpanded) {
01217 d->fieldsExpanded = new QueryColumnInfo::Vector( list.count() );
01218 d->fieldsExpanded->setAutoDelete(true);
01219 d->columnsOrderExpanded = new QMap<QueryColumnInfo*,int>();
01220 }
01221 else {
01222 d->fieldsExpanded->clear();
01223 d->fieldsExpanded->resize( list.count() );
01224 d->columnsOrderExpanded->clear();
01225 }
01226
01227
01228
01229
01230
01231
01232 d->columnInfosByName.clear();
01233 d->columnInfosByNameExpanded.clear();
01234 i=0;
01235 QueryColumnInfo *ci;
01236 for (QueryColumnInfo::ListIterator it(list); (ci = it.current()); ++it, i++)
01237 {
01238 d->fieldsExpanded->insert(i, ci);
01239 d->columnsOrderExpanded->insert(ci, i);
01240
01241 if (!ci->alias.isEmpty()) {
01242
01243 if (!d->columnInfosByNameExpanded[ ci->alias ])
01244 d->columnInfosByNameExpanded.insert( ci->alias, ci );
01245 QString tableAndAlias( ci->alias );
01246 if (ci->field->table())
01247 tableAndAlias.prepend(ci->field->table()->name() + ".");
01248 if (!d->columnInfosByNameExpanded[ tableAndAlias ])
01249 d->columnInfosByNameExpanded.insert( tableAndAlias, ci );
01250
01251 if (columnInfosOutsideAsterisks.contains(ci)) {
01252 if (!d->columnInfosByName[ ci->alias ])
01253 d->columnInfosByName.insert( ci->alias, ci );
01254 if (!d->columnInfosByName[ tableAndAlias ])
01255 d->columnInfosByName.insert( tableAndAlias, ci );
01256 }
01257 }
01258 else {
01259
01260 if (!d->columnInfosByNameExpanded[ ci->field->name() ])
01261 d->columnInfosByNameExpanded.insert( ci->field->name(), ci );
01262 QString tableAndName( ci->field->name() );
01263 if (ci->field->table())
01264 tableAndName.prepend(ci->field->table()->name() + ".");
01265 if (!d->columnInfosByNameExpanded[ tableAndName ])
01266 d->columnInfosByNameExpanded.insert( tableAndName, ci );
01267
01268 if (columnInfosOutsideAsterisks.contains(ci)) {
01269 if (!d->columnInfosByName[ ci->field->name() ])
01270 d->columnInfosByName.insert( ci->field->name(), ci );
01271 if (!d->columnInfosByName[ tableAndName ])
01272 d->columnInfosByName.insert( tableAndName, ci );
01273 }
01274 }
01275 }
01276
01277
01278 QDict<uint> lookup_dict;
01279
01280 lookup_dict.setAutoDelete(true);
01281 #define LOOKUP_COLUMN_KEY(foreignField, field) ( field->table()->name() + "." + field->name() \
01282 + "_" + foreignField->table()->name() + "." + foreignField->name() )
01283 i=0;
01284 for (QueryColumnInfo::ListIterator it(lookup_list); (ci = it.current());)
01285 {
01286 QString key( LOOKUP_COLUMN_KEY(ci->foreignColumn()->field, ci->field) );
01287 if (
01288 lookup_dict[ key ]) {
01289
01290 ++it;
01291 lookup_list.removeRef( ci );
01292 }
01293 else {
01294 lookup_dict.replace( key, new uint( i ) );
01295 ++it;
01296 i++;
01297 }
01298 }
01299
01300
01301 if (d->internalFields) {
01302 d->internalFields->clear();
01303 d->internalFields->resize( lookup_list.count() );
01304 }
01305 delete d->fieldsExpandedWithInternal;
01306 delete d->fieldsExpandedWithInternalAndRowID;
01307 d->fieldsExpandedWithInternal = 0;
01308 d->fieldsExpandedWithInternalAndRowID = 0;
01309 i=0;
01310 if (!lookup_list.isEmpty() && !d->internalFields) {
01311 d->internalFields = new QueryColumnInfo::Vector( lookup_list.count() );
01312 d->internalFields->setAutoDelete(true);
01313 }
01314 for (QueryColumnInfo::ListIterator it(lookup_list); it.current();i++, ++it)
01315 {
01316
01317 d->internalFields->insert(i, it.current());
01318 d->columnsOrderExpanded->insert(it.current(), list.count()+i);
01319 }
01320
01321
01322 for (i=0; i < d->fieldsExpanded->size(); i++) {
01323 QueryColumnInfo* ci = d->fieldsExpanded->at(i);
01325 LookupFieldSchema *lookupFieldSchema
01326 = ci->field->table() ? ci->field->table()->lookupFieldSchema( *ci->field ) : 0;
01327 if (lookupFieldSchema) {
01328 LookupFieldSchema::RowSource& rowSource = lookupFieldSchema->rowSource();
01329 TableSchema *lookupTable = connection()->tableSchema( rowSource.name() );
01330 Field *visibleField = 0;
01331 if (lookupTable && lookupFieldSchema->boundColumn()>=0
01332 && (uint)lookupFieldSchema->boundColumn() < lookupTable->fieldCount()
01333 && (visibleField = lookupTable->field( lookupFieldSchema->visibleColumn())))
01334 {
01335 QString key( LOOKUP_COLUMN_KEY(ci->field, visibleField) );
01336 uint *index = lookup_dict[ key ];
01337 if (index)
01338 ci->setIndexForVisibleLookupValue( d->fieldsExpanded->size() + *index );
01339 }
01340 }
01341 }
01342 }
01343
01344 QMap<QueryColumnInfo*,int> QuerySchema::columnsOrder(ColumnsOrderOptions options)
01345 {
01346 if (!d->columnsOrder)
01347 computeFieldsExpanded();
01348 if (options == UnexpandedList)
01349 return *d->columnsOrder;
01350 else if (options == UnexpandedListWithoutAsterisks)
01351 return *d->columnsOrderWithoutAsterisks;
01352 return *d->columnsOrderExpanded;
01353 }
01354
01355 QValueVector<int> QuerySchema::pkeyFieldsOrder()
01356 {
01357 if (d->pkeyFieldsOrder)
01358 return *d->pkeyFieldsOrder;
01359
01360 TableSchema *tbl = masterTable();
01361 if (!tbl || !tbl->primaryKey())
01362 return QValueVector<int>();
01363
01364
01365 IndexSchema *pkey = tbl->primaryKey();
01366 d->pkeyFieldsOrder = new QValueVector<int>( pkey->fieldCount(), -1 );
01367
01368 const uint fCount = fieldsExpanded().count();
01369 d->pkeyFieldsCount = 0;
01370 for (uint i = 0; i<fCount; i++) {
01371 QueryColumnInfo *fi = d->fieldsExpanded->at(i);
01372 const int fieldIndex = fi->field->table()==tbl ? pkey->indexOf(fi->field) : -1;
01373 if (fieldIndex!=-1
01374 && d->pkeyFieldsOrder->at(fieldIndex)==-1 )
01375 {
01376 KexiDBDbg << "QuerySchema::pkeyFieldsOrder(): FIELD " << fi->field->name()
01377 << " IS IN PKEY AT POSITION #" << fieldIndex << endl;
01378
01379 (*d->pkeyFieldsOrder)[fieldIndex]=i;
01380 d->pkeyFieldsCount++;
01381
01382 }
01383 }
01384 KexiDBDbg << "QuerySchema::pkeyFieldsOrder(): " << d->pkeyFieldsCount
01385 << " OUT OF " << pkey->fieldCount() << " PKEY'S FIELDS FOUND IN QUERY " << name() << endl;
01386 return *d->pkeyFieldsOrder;
01387 }
01388
01389 uint QuerySchema::pkeyFieldsCount()
01390 {
01391 (void)pkeyFieldsOrder();
01392 return d->pkeyFieldsCount;
01393 }
01394
01395 Relationship* QuerySchema::addRelationship( Field *field1, Field *field2 )
01396 {
01397
01398 Relationship *r = new Relationship(this, field1, field2);
01399 if (r->isEmpty()) {
01400 delete r;
01401 return 0;
01402 }
01403
01404 d->relations.append( r );
01405 return r;
01406 }
01407
01408 QueryColumnInfo::List* QuerySchema::autoIncrementFields()
01409 {
01410 if (!d->autoincFields) {
01411 d->autoincFields = new QueryColumnInfo::List();
01412 }
01413 TableSchema *mt = masterTable();
01414 if (!mt) {
01415 KexiDBWarn << "QuerySchema::autoIncrementFields(): no master table!" << endl;
01416 return d->autoincFields;
01417 }
01418 if (d->autoincFields->isEmpty()) {
01419 QueryColumnInfo::Vector fexp =