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, QuerySchemaPrivate* copy = 0)
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 , ownedVisibleColumns(0)
00087 , regenerateExprAliases(false)
00088 {
00089 columnAliases.setAutoDelete(true);
00090 tableAliases.setAutoDelete(true);
00091 asterisks.setAutoDelete(true);
00092 relations.setAutoDelete(true);
00093 tablePositionsForAliases.setAutoDelete(true);
00094 columnPositionsForAliases.setAutoDelete(true);
00095 visibility.fill(false);
00096 if (copy) {
00097
00098 *this = *copy;
00099 if (copy->fieldsExpanded)
00100 fieldsExpanded = new QueryColumnInfo::Vector(*copy->fieldsExpanded);
00101 if (copy->internalFields)
00102 internalFields = new QueryColumnInfo::Vector(*copy->internalFields);
00103 if (copy->fieldsExpandedWithInternalAndRowID)
00104 fieldsExpandedWithInternalAndRowID = new QueryColumnInfo::Vector(
00105 *copy->fieldsExpandedWithInternalAndRowID);
00106 if (copy->fieldsExpandedWithInternal)
00107 fieldsExpandedWithInternal = new QueryColumnInfo::Vector(
00108 *copy->fieldsExpandedWithInternal);
00109 if (copy->autoincFields)
00110 autoincFields = new QueryColumnInfo::List(*copy->autoincFields);
00111 if (copy->columnsOrder)
00112 columnsOrder = new QMap<QueryColumnInfo*,int>(*copy->columnsOrder);
00113 if (copy->columnsOrderWithoutAsterisks)
00114 columnsOrderWithoutAsterisks = new QMap<QueryColumnInfo*,int>(
00115 *copy->columnsOrderWithoutAsterisks);
00116 if (copy->columnsOrderExpanded)
00117 columnsOrderExpanded = new QMap<QueryColumnInfo*,int>(*copy->columnsOrderExpanded);
00118 if (copy->pkeyFieldsOrder)
00119 pkeyFieldsOrder = new QValueVector<int>(*copy->pkeyFieldsOrder);
00120 if (copy->whereExpr)
00121 whereExpr = copy->whereExpr->copy();
00122 if (copy->fakeRowIDCol)
00123 fakeRowIDCol = new QueryColumnInfo(*copy->fakeRowIDCol);
00124 if (copy->fakeRowIDField)
00125 fakeRowIDField = new Field(*copy->fakeRowIDField);
00126 if (copy->ownedVisibleColumns)
00127 ownedVisibleColumns = new Field::List(*copy->ownedVisibleColumns);
00128 }
00129 }
00130 ~QuerySchemaPrivate()
00131 {
00132 delete fieldsExpanded;
00133 delete internalFields;
00134 delete fieldsExpandedWithInternalAndRowID;
00135 delete fieldsExpandedWithInternal;
00136 delete autoincFields;
00137 delete columnsOrder;
00138 delete columnsOrderWithoutAsterisks;
00139 delete columnsOrderExpanded;
00140 delete pkeyFieldsOrder;
00141 delete whereExpr;
00142 delete fakeRowIDCol;
00143 delete fakeRowIDField;
00144 delete ownedVisibleColumns;
00145 }
00146
00147 void clear()
00148 {
00149 columnAliases.clear();
00150 tableAliases.clear();
00151 asterisks.clear();
00152 relations.clear();
00153 masterTable = 0;
00154 tables.clear();
00155 clearCachedData();
00156 delete pkeyFieldsOrder;
00157 pkeyFieldsOrder=0;
00158 visibility.fill(false);
00159 tablesBoundToColumns = QValueVector<int>(64,-1);
00160 tablePositionsForAliases.clear();
00161 columnPositionsForAliases.clear();
00162 }
00163
00164 void clearCachedData()
00165 {
00166 orderByColumnList.clear();
00167 if (fieldsExpanded) {
00168 delete fieldsExpanded;
00169 fieldsExpanded = 0;
00170 delete internalFields;
00171 internalFields = 0;
00172 delete columnsOrder;
00173 columnsOrder = 0;
00174 delete columnsOrderWithoutAsterisks;
00175 columnsOrderWithoutAsterisks = 0;
00176 delete columnsOrderExpanded;
00177 columnsOrderExpanded = 0;
00178 delete autoincFields;
00179 autoincFields = 0;
00180 autoIncrementSQLFieldsList = QString::null;
00181 columnInfosByNameExpanded.clear();
00182 columnInfosByName.clear();
00183 delete ownedVisibleColumns;
00184 ownedVisibleColumns = 0;
00185 }
00186 }
00187
00188 void setColumnAliasInternal(uint position, const QCString& alias)
00189 {
00190 columnAliases.replace(position, new QCString(alias));
00191 columnPositionsForAliases.replace(alias, new int(position));
00192 maxIndexWithAlias = QMAX( maxIndexWithAlias, (int)position );
00193 }
00194
00195 void setColumnAlias(uint position, const QCString& alias)
00196 {
00197 QCString *oldAlias = columnAliases.take(position);
00198 if (oldAlias) {
00199 tablePositionsForAliases.remove(*oldAlias);
00200 delete oldAlias;
00201 }
00202 if (alias.isEmpty()) {
00203 maxIndexWithAlias = -1;
00204 }
00205 else {
00206 setColumnAliasInternal(position, alias);
00207 }
00208 }
00209
00210 bool hasColumnAliases()
00211 {
00212 tryRegenerateExprAliases();
00213 return !columnAliases.isEmpty();
00214 }
00215
00216 QCString* columnAlias(uint position)
00217 {
00218 tryRegenerateExprAliases();
00219 return columnAliases[position];
00220 }
00221
00222 QuerySchema *query;
00223
00227 TableSchema *masterTable;
00228
00230 TableSchema::List tables;
00231
00232 Field *fakeRowIDField;
00233 QueryColumnInfo *fakeRowIDCol;
00234
00235 protected:
00236 void tryRegenerateExprAliases()
00237 {
00238 if (!regenerateExprAliases)
00239 return;
00240
00241 Field *f;
00242 uint p=0;
00243 uint colNum=0;
00244 QCString columnAlias;
00245 for (Field::ListIterator it(query->fieldsIterator()); (f = it.current()); ++it, p++) {
00246 if (f->isExpression() && !columnAliases[p]) {
00247
00248 for (;;) {
00249 colNum++;
00250 columnAlias = (i18n("short for 'expression' word (only latin letters, please)", "expr")
00251 + QString::number(colNum)).latin1();
00252 if (!tablePositionsForAliases[columnAlias])
00253 break;
00254 }
00255 setColumnAliasInternal(p, columnAlias);
00256 }
00257 }
00258 regenerateExprAliases = false;
00259 }
00260
00262 QIntDict<QCString> columnAliases;
00263
00264 public:
00266 QIntDict<QCString> tableAliases;
00267
00269 int maxIndexWithAlias;
00270
00272 int maxIndexWithTableAlias;
00273
00275 QBitArray visibility;
00276
00278 Field::List asterisks;
00279
00281
00282 QueryColumnInfo::Vector *fieldsExpanded;
00283
00285 QueryColumnInfo::Vector *internalFields;
00286
00289 QueryColumnInfo::Vector *fieldsExpandedWithInternalAndRowID;
00290
00293 QueryColumnInfo::Vector *fieldsExpandedWithInternal;
00294
00296 OrderByColumnList orderByColumnList;
00297
00299 QueryColumnInfo::List *autoincFields;
00300
00302 QString autoIncrementSQLFieldsList;
00303 QGuardedPtr<Driver> lastUsedDriverForAutoIncrementSQLFieldsList;
00304
00306 QMap<QueryColumnInfo*,int> *columnsOrder;
00307
00309 QMap<QueryColumnInfo*,int> *columnsOrderWithoutAsterisks;
00310
00314 QMap<QueryColumnInfo*,int> *columnsOrderExpanded;
00315
00316
00317
00319 QValueVector<int> *pkeyFieldsOrder;
00320
00322 uint pkeyFieldsCount;
00323
00325 QString statement;
00326
00328 Relationship::List relations;
00329
00345 QValueVector<int> tablesBoundToColumns;
00346
00348 QAsciiDict<int> tablePositionsForAliases;
00349
00351 QAsciiDict<int> columnPositionsForAliases;
00352
00354 BaseExpr *whereExpr;
00355
00356 QDict<QueryColumnInfo> columnInfosByNameExpanded;
00357
00358 QDict<QueryColumnInfo> columnInfosByName;
00359
00361 Field::List *ownedVisibleColumns;
00362
00365 bool regenerateExprAliases : 1;
00366 };
00367 }
00368
00369
00370
00371 OrderByColumn::OrderByColumn()
00372 : m_column(0)
00373 , m_pos(-1)
00374 , m_field(0)
00375 , m_ascending(true)
00376 {
00377 }
00378
00379 OrderByColumn::OrderByColumn(QueryColumnInfo& column, bool ascending, int pos)
00380 : m_column(&column)
00381 , m_pos(pos)
00382 , m_field(0)
00383 , m_ascending(ascending)
00384 {
00385 }
00386
00387 OrderByColumn::OrderByColumn(Field& field, bool ascending)
00388 : m_column(0)
00389 , m_pos(-1)
00390 , m_field(&field)
00391 , m_ascending(ascending)
00392 {
00393 }
00394
00395 OrderByColumn::~OrderByColumn()
00396 {
00397 }
00398
00399 QString OrderByColumn::debugString() const
00400 {
00401 QString orderString( m_ascending ? "ascending" : "descending" );
00402 if (m_column) {
00403 if (m_pos>-1)
00404 return QString("COLUMN_AT_POSITION_%1(%2, %3)")
00405 .arg(m_pos+1).arg(m_column->debugString()).arg(orderString);
00406 else
00407 return QString("COLUMN(%1, %2)").arg(m_column->debugString()).arg(orderString);
00408 }
00409 return m_field ? QString("FIELD(%1, %2)").arg(m_field->debugString()).arg(orderString)
00410 : QString("NONE");
00411 }
00412
00413 QString OrderByColumn::toSQLString(bool includeTableName, Driver *drv, int identifierEscaping) const
00414 {
00415 const QString orderString( m_ascending ? "" : " DESC" );
00416 QString fieldName, tableName;
00417 if (m_column) {
00418 if (m_pos>-1)
00419 return QString::number(m_pos+1) + orderString;
00420 else {
00421 if (includeTableName && m_column->alias.isEmpty()) {
00422 tableName = m_column->field->table()->name();
00423 if (drv)
00424 tableName = drv->escapeIdentifier(tableName, identifierEscaping);
00425 tableName += ".";
00426 }
00427 fieldName = m_column->aliasOrName();
00428 if (drv)
00429 fieldName = drv->escapeIdentifier(fieldName, identifierEscaping);
00430 }
00431 }
00432 else {
00433 if (includeTableName) {
00434 tableName = m_column->field->table()->name();
00435 if (drv)
00436 tableName = drv->escapeIdentifier(tableName, identifierEscaping);
00437 tableName += ".";
00438 }
00439 fieldName = m_field ? m_field->name() : "??";
00440 if (drv)
00441 fieldName = drv->escapeIdentifier(fieldName, identifierEscaping);
00442 }
00443 return tableName + fieldName + orderString;
00444 }
00445
00446
00447
00448 OrderByColumnList::OrderByColumnList()
00449 : OrderByColumnListBase()
00450 {
00451 }
00452
00453 bool OrderByColumnList::appendFields(QuerySchema& querySchema,
00454 const QString& field1, bool ascending1,
00455 const QString& field2, bool ascending2,
00456 const QString& field3, bool ascending3,
00457 const QString& field4, bool ascending4,
00458 const QString& field5, bool ascending5)
00459 {
00460 uint numAdded = 0;
00461 #define ADD_COL(fieldName, ascending) \
00462 if (ok && !fieldName.isEmpty()) { \
00463 if (!appendField( querySchema, fieldName, ascending )) \
00464 ok = false; \
00465 else \
00466 numAdded++; \
00467 }
00468 bool ok = true;
00469 ADD_COL(field1, ascending1);
00470 ADD_COL(field2, ascending2);
00471 ADD_COL(field3, ascending3);
00472 ADD_COL(field4, ascending4);
00473 ADD_COL(field5, ascending5);
00474 #undef ADD_COL
00475 if (ok)
00476 return true;
00477 for (uint i=0; i<numAdded; i++)
00478 pop_back();
00479 return false;
00480 }
00481
00482 OrderByColumnList::~OrderByColumnList()
00483 {
00484 }
00485
00486 void OrderByColumnList::appendColumn(QueryColumnInfo& columnInfo, bool ascending)
00487 {
00488 appendColumn( OrderByColumn(columnInfo, ascending) );
00489 }
00490
00491 bool OrderByColumnList::appendColumn(QuerySchema& querySchema, bool ascending, int pos)
00492 {
00493 QueryColumnInfo::Vector fieldsExpanded( querySchema.fieldsExpanded() );
00494 QueryColumnInfo* ci = (pos >= (int)fieldsExpanded.size()) ? 0 : fieldsExpanded[pos];
00495 if (!ci)
00496 return false;
00497 appendColumn( OrderByColumn(*ci, ascending, pos) );
00498 return true;
00499 }
00500
00501 void OrderByColumnList::appendField(Field& field, bool ascending)
00502 {
00503 appendColumn( OrderByColumn(field, ascending) );
00504 }
00505
00506 bool OrderByColumnList::appendField(QuerySchema& querySchema,
00507 const QString& fieldName, bool ascending)
00508 {
00509 QueryColumnInfo *columnInfo = querySchema.columnInfo( fieldName );
00510 if (columnInfo) {
00511 appendColumn( OrderByColumn(*columnInfo, ascending) );
00512 return true;
00513 }
00514 Field *field = querySchema.findTableField(fieldName);
00515 if (field) {
00516 appendColumn( OrderByColumn(*field, ascending) );
00517 return true;
00518 }
00519 KexiDBWarn << "OrderByColumnList::addColumn(QuerySchema& querySchema, "
00520 "const QString& column, bool ascending): no such field \"" << fieldName << "\"" << endl;
00521 return false;
00522 }
00523
00524 void OrderByColumnList::appendColumn(const OrderByColumn& column)
00525 {
00526 append( column );
00527 }
00528
00529 QString OrderByColumnList::debugString() const
00530 {
00531 if (isEmpty())
00532 return "NONE";
00533 QString dbg;
00534 for (OrderByColumn::ListConstIterator it=constBegin(); it!=constEnd(); ++it) {
00535 if (!dbg.isEmpty())
00536 dbg += "\n";
00537 dbg += (*it).debugString();
00538 }
00539 return dbg;
00540 }
00541
00542 QString OrderByColumnList::toSQLString(bool includeTableNames, Driver *drv, int identifierEscaping) const
00543 {
00544 QString string;
00545 for (OrderByColumn::ListConstIterator it=constBegin(); it!=constEnd(); ++it) {
00546 if (!string.isEmpty())
00547 string += ", ";
00548 string += (*it).toSQLString(includeTableNames, drv, identifierEscaping);
00549 }
00550 return string;
00551 }
00552
00553
00554
00555 QuerySchema::QuerySchema()
00556 : FieldList(false)
00557 , SchemaData(KexiDB::QueryObjectType)
00558 , d( new QuerySchemaPrivate(this) )
00559 {
00560 init();
00561 }
00562
00563 QuerySchema::QuerySchema(TableSchema& tableSchema)
00564 : FieldList(false)
00565 , SchemaData(KexiDB::QueryObjectType)
00566 , d( new QuerySchemaPrivate(this) )
00567 {
00568 d->masterTable = &tableSchema;
00569 init();
00570
00571
00572
00573
00574
00575 addTable(d->masterTable);
00576
00577
00578 m_name = d->masterTable->name();
00579
00580 m_caption = d->masterTable->caption();
00581
00582
00583
00584
00585
00586 for (Field::ListIterator it( d->masterTable->fieldsIterator() ); it.current(); ++it) {
00587 addField( it.current() );
00588 }
00589 }
00590
00591 QuerySchema::QuerySchema(const QuerySchema& querySchema)
00592 : FieldList(querySchema, false )
00593 , SchemaData(querySchema)
00594 , d( new QuerySchemaPrivate(this, querySchema.d) )
00595 {
00596
00597 for (Field::ListIterator f_it(querySchema.m_fields); f_it.current(); ++f_it) {
00598 Field *f;
00599 if (dynamic_cast<QueryAsterisk*>( f_it.current() )) {
00600 f = f_it.current()->copy();
00601 if (f_it.current()->m_parent == &querySchema)
00602 f->m_parent = this;
00603 }
00604 else
00605 f = f_it.current();
00606 addField( f );
00607 }
00608 }
00609
00610 QuerySchema::~QuerySchema()
00611 {
00612 delete d;
00613 }
00614
00615 void QuerySchema::init()
00616 {
00617 m_type = KexiDB::QueryObjectType;
00618
00619 }
00620
00621 void QuerySchema::clear()
00622 {
00623 FieldList::clear();
00624 SchemaData::clear();
00625 d->clear();
00626 }
00627
00628 FieldList& QuerySchema::insertField(uint position, Field *field, bool visible)
00629 {
00630 return insertField(position, field, -1, visible);
00631 }
00632
00633
00634 FieldList& QuerySchema::insertField(uint position, Field *field)
00635 {
00636 return insertField( position, field, -1, true );
00637 }
00638
00639 FieldList& QuerySchema::insertField(uint position, Field *field,
00640 int bindToTable, bool visible)
00641 {
00642 if (!field) {
00643 KexiDBWarn << "QuerySchema::insertField(): !field" << endl;
00644 return *this;
00645 }
00646
00647 if (position>m_fields.count()) {
00648 KexiDBWarn << "QuerySchema::insertField(): position (" << position << ") out of range" << endl;
00649 return *this;
00650 }
00651 if (!field->isQueryAsterisk() && !field->isExpression() && !field->table()) {
00652 KexiDBWarn << "QuerySchema::insertField(): WARNING: field '"<<field->name()
00653 <<"' must contain table information!" <<endl;
00654 return *this;
00655 }
00656 if (fieldCount()>=d->visibility.size()) {
00657 d->visibility.resize(d->visibility.size()*2);
00658 d->tablesBoundToColumns.resize(d->tablesBoundToColumns.size()*2);
00659 }
00660 d->clearCachedData();
00661 FieldList::insertField(position, field);
00662 if (field->isQueryAsterisk()) {
00663 d->asterisks.append(field);
00664
00665
00666 if (field->table() && (d->tables.findRef(field->table())==-1))
00667 d->tables.append(field->table());
00668 }
00669 else if (field->table()) {
00670
00671 if (d->tables.findRef(field->table())==-1)
00672 d->tables.append(field->table());
00673 }
00674
00675
00676
00677
00678
00679 for (uint i=fieldCount()-1; i>position; i--)
00680 d->visibility.setBit(i, d->visibility.testBit(i-1));
00681 d->visibility.setBit(position, visible);
00682
00683
00684 if (bindToTable < -1 && bindToTable>(int)d->tables.count()) {
00685 KexiDBWarn << "QuerySchema::insertField(): bindToTable (" << bindToTable
00686 << ") out of range" << endl;
00687 bindToTable = -1;
00688 }
00689
00690 for (uint i=fieldCount()-1; i>position; i--)
00691 d->tablesBoundToColumns[i] = d->tablesBoundToColumns[i-1];
00692 d->tablesBoundToColumns[ position ] = bindToTable;
00693
00694 KexiDBDbg << "QuerySchema::insertField(): bound to table (" << bindToTable << "): " <<endl;
00695 if (bindToTable==-1)
00696 KexiDBDbg << " <NOT SPECIFIED>" << endl;
00697 else
00698 KexiDBDbg << " name=" << d->tables.at(bindToTable)->name()
00699 << " alias=" << tableAlias(bindToTable) << endl;
00700 QString s;
00701 for (uint i=0; i<fieldCount();i++)
00702 s+= (QString::number(d->tablesBoundToColumns[i]) + " ");
00703 KexiDBDbg << "tablesBoundToColumns == [" << s << "]" <<endl;
00704
00705 if (field->isExpression())
00706 d->regenerateExprAliases = true;
00707
00708 return *this;
00709 }
00710
00711 int QuerySchema::tableBoundToColumn(uint columnPosition) const
00712 {
00713 if (columnPosition > d->tablesBoundToColumns.count()) {
00714 KexiDBWarn << "QuerySchema::tableBoundToColumn(): columnPosition (" << columnPosition
00715 << ") out of range" << endl;
00716 return -1;
00717 }
00718 return d->tablesBoundToColumns[columnPosition];
00719 }
00720
00721 KexiDB::FieldList& QuerySchema::addField(KexiDB::Field* field, bool visible)
00722 {
00723 return insertField(m_fields.count(), field, visible);
00724 }
00725
00726 KexiDB::FieldList& QuerySchema::addField(KexiDB::Field* field, int bindToTable,
00727 bool visible)
00728 {
00729 return insertField(m_fields.count(), field, bindToTable, visible);
00730 }
00731
00732 void QuerySchema::removeField(KexiDB::Field *field)
00733 {
00734 if (!field)
00735 return;
00736 d->clearCachedData();
00737 if (field->isQueryAsterisk()) {
00738 d->asterisks.remove(field);
00739 }
00740
00741 FieldList::removeField(field);
00742 }
00743
00744 FieldList& QuerySchema::addExpression(BaseExpr* expr, bool visible)
00745 {
00746 return addField( new Field(this, expr), visible );
00747 }
00748
00749 bool QuerySchema::isColumnVisible(uint position) const
00750 {
00751 return (position < fieldCount()) ? d->visibility.testBit(position) : false;
00752 }
00753
00754 void QuerySchema::setColumnVisible(uint position, bool v)
00755 {
00756 if (position < fieldCount())
00757 d->visibility.setBit(position, v);
00758 }
00759
00760 FieldList& QuerySchema::addAsterisk(QueryAsterisk *asterisk, bool visible)
00761 {
00762 if (!asterisk)
00763 return *this;
00764
00765 asterisk->m_name = (asterisk->table() ? asterisk->table()->name() + ".*" : "*")
00766 + QString::number(asterisks()->count());
00767 return addField(asterisk, visible);
00768 }
00769
00770 Connection* QuerySchema::connection() const
00771 {
00772 TableSchema *mt = masterTable();
00773 return mt ? mt->connection() : 0;
00774 }
00775
00776 QString QuerySchema::debugString()
00777 {
00778 QString dbg;
00779 dbg.reserve(1024);
00780
00781 TableSchema *mt = masterTable();
00782 dbg = QString("QUERY ") + schemaDataDebugString() + "\n"
00783 + "-masterTable=" + (mt ? mt->name() :"<NULL>")
00784 + "\n-COLUMNS:\n"
00785 + ((fieldCount()>0) ? FieldList::debugString() : "<NONE>") + "\n"
00786 + "-FIELDS EXPANDED ";
00787
00788 QString dbg1;
00789 uint fieldsExpandedCount = 0;
00790 if (fieldCount()>0) {
00791 QueryColumnInfo::Vector fe( fieldsExpanded() );
00792 fieldsExpandedCount = fe.size();
00793 for ( uint i=0; i < fieldsExpandedCount; i++ ) {
00794 QueryColumnInfo *ci = fe[i];
00795 if (!dbg1.isEmpty())
00796 dbg1 += ",\n";
00797 dbg1 += ci->debugString();
00798 }
00799 dbg1 += "\n";
00800 }
00801 else {
00802 dbg1 = "<NONE>\n";
00803 }
00804 dbg1.prepend( QString("(%1):\n").arg(fieldsExpandedCount) );
00805 dbg += dbg1;
00806
00807
00808
00809
00810
00811
00812 QString dbg2;
00813 dbg2.reserve(512);
00814 for (uint i = 0; i<fieldCount(); i++) {
00815 int tablePos = tableBoundToColumn(i);
00816 if (tablePos>=0) {
00817 QCString tAlias = tableAlias(tablePos);
00818 if (!tAlias.isEmpty()) {
00819 dbg2 += (QString::fromLatin1(" field \"") + FieldList::field(i)->name()
00820 + "\" uses alias \"" + QString(tAlias) + "\" of table \""
00821 + d->tables.at(tablePos)->name() + "\"\n");
00822 }
00823 }
00824 }
00825 if (!dbg2.isEmpty()) {
00826 dbg += "\n-BINDINGS:\n";
00827 dbg += dbg2;
00828 }
00829
00830
00831 TableSchema *table;
00832 QString table_names;
00833 table_names.reserve(512);
00834 for ( table = d->tables.first(); table; table = d->tables.next() ) {
00835 if (!table_names.isEmpty())
00836 table_names += ", ";
00837 table_names += (QString("'") + table->name() + "'");
00838 }
00839 if (d->tables.isEmpty())
00840 table_names = "<NONE>";
00841 dbg += (QString("-TABLES:\n") + table_names);
00842 QString aliases;
00843 if (!d->hasColumnAliases())
00844 aliases = "<NONE>\n";
00845 else {
00846 Field::ListIterator it( m_fields );
00847 for (int i=0; it.current(); ++it, i++) {
00848 QCString *alias = d->columnAlias(i);
00849 if (alias)
00850 aliases += (QString("field #%1: ").arg(i)
00851 + (it.current()->name().isEmpty() ? "<noname>" : it.current()->name())
00852 + " -> " + (const char*)*alias + "\n");
00853 }
00854 }
00855
00856 dbg += QString("\n-COLUMN ALIASES:\n" + aliases);
00857 if (d->tableAliases.isEmpty())
00858 aliases = "<NONE>";
00859 else {
00860 aliases = "";
00861 TableSchema::ListIterator t_it(d->tables);
00862 for (int i=0; t_it.current(); ++t_it, i++) {
00863 QCString *alias = d->tableAliases[i];
00864 if (alias)
00865 aliases += (QString("table #%1: ").arg(i)
00866 + (t_it.current()->name().isEmpty() ? "<noname>" : t_it.current()->name())
00867 + " -> " + (const char*)*alias + "\n");
00868 }
00869 }
00870 dbg += QString("-TABLE ALIASES:\n" + aliases);
00871 QString where = d->whereExpr ? d->whereExpr->debugString() : QString::null;
00872 if (!where.isEmpty())
00873 dbg += (QString("\n-WHERE EXPRESSION:\n") + where);
00874 if (!orderByColumnList().isEmpty())
00875 dbg += (QString("\n-ORDER BY (%1):\n").arg(orderByColumnList().count())
00876 + orderByColumnList().debugString());
00877 return dbg;
00878 }
00879
00880 TableSchema* QuerySchema::masterTable() const
00881 {
00882 if (d->masterTable)
00883 return d->masterTable;
00884 if (d->tables.isEmpty())
00885 return 0;
00886
00887
00888 int num = 0;
00889 QString tableNameLower;
00890 for (TableSchema::ListIterator it(d->tables); it.current(); ++it, num++) {
00891 if (!tableNameLower.isEmpty() && it.current()->name().lower()!=tableNameLower) {
00892
00893 return 0;
00894 }
00895 tableNameLower = tableAlias(num);
00896 }
00897 return d->tables.first();
00898 }
00899
00900 void QuerySchema::setMasterTable(TableSchema *table)
00901 {
00902 if (table)
00903 d->masterTable=table;
00904 }
00905
00906 TableSchema::List* QuerySchema::tables() const
00907 {
00908 return &d->tables;
00909 }
00910
00911 void QuerySchema::addTable(TableSchema *table, const QCString& alias)
00912 {
00913 KexiDBDbg << "QuerySchema::addTable() " << (void *)table
00914 << " alias=" << alias << endl;
00915 if (!table)
00916 return;
00917
00918
00919
00920
00921 if (alias.isEmpty() && d->tables.findRef(table)!=-1) {
00922 const QString& tableNameLower = table->name().lower();
00923 const QString& aliasLower = QString(alias.lower());
00924 int num = 0;
00925 for (TableSchema::ListIterator it(d->tables); it.current(); ++it, num++) {
00926 if (it.current()->name().lower()==tableNameLower) {
00927 const QString& tAlias = tableAlias(num);
00928 if (tAlias == aliasLower) {
00929 KexiDBWarn << "QuerySchema::addTable(): table with \""
00930 << tAlias << "\" alias already added!" << endl;
00931 return;
00932 }
00933 }
00934 }
00935 }
00936
00937 d->tables.append(table);
00938
00939 if (!alias.isEmpty())
00940 setTableAlias(d->tables.count()-1, alias);
00941 }
00942
00943 void QuerySchema::removeTable(TableSchema *table)
00944 {
00945 if (!table)
00946 return;
00947 if (d->masterTable == table)
00948 d->masterTable = 0;
00949 d->tables.remove(table);
00950
00951 }
00952
00953 TableSchema* QuerySchema::table(const QString& tableName) const
00954 {
00955
00956 for (TableSchema::ListIterator it(d->tables); it.current(); ++it) {
00957 if (it.current()->name().lower()==tableName.lower())
00958 return it.current();
00959 }
00960 return 0;
00961 }
00962
00963 bool QuerySchema::contains(TableSchema *table) const
00964 {
00965 return d->tables.findRef(table)!=-1;
00966 }
00967
00968 Field* QuerySchema::findTableField(const QString &tableOrTableAndFieldName) const
00969 {
00970 QString tableName, fieldName;
00971 if (!KexiDB::splitToTableAndFieldParts(tableOrTableAndFieldName,
00972 tableName, fieldName, KexiDB::SetFieldNameIfNoTableName)) {
00973 return 0;
00974 }
00975 if (tableName.isEmpty()) {
00976 for (TableSchema::ListIterator it(d->tables); it.current(); ++it) {
00977 if (it.current()->field(fieldName))
00978 return it.current()->field(fieldName);
00979 }
00980 return 0;
00981 }
00982 TableSchema *tableSchema = table(tableName);
00983 if (!tableSchema)
00984 return 0;
00985 return tableSchema->field(fieldName);
00986 }
00987
00988 QCString QuerySchema::columnAlias(uint position) const
00989 {
00990 QCString *a = d->columnAlias(position);
00991 return a ? *a : QCString();
00992 }
00993
00994 bool QuerySchema::hasColumnAlias(uint position) const
00995 {
00996 return d->columnAlias(position)!=0;
00997 }
00998
00999 void QuerySchema::setColumnAlias(uint position, const QCString& alias)
01000 {
01001 if (position >= m_fields.count()) {
01002 KexiDBWarn << "QuerySchema::setColumnAlias(): position (" << position
01003 << ") out of range!" << endl;
01004 return;
01005 }
01006 QCString fixedAlias = alias.stripWhiteSpace();
01007 Field *f = FieldList::field(position);
01008 if (f->captionOrName().isEmpty() && fixedAlias.isEmpty()) {
01009 KexiDBWarn << "QuerySchema::setColumnAlias(): position (" << position
01010 << ") could not remove alias when no name is specified for expression column!" << endl;
01011 return;
01012 }
01013 d->setColumnAlias(position, fixedAlias);
01014 }
01015
01016 QCString QuerySchema::tableAlias(uint position) const
01017 {
01018 QCString *a = d->tableAliases[position];
01019 return a ? *a : QCString();
01020 }
01021
01022 int QuerySchema::tablePositionForAlias(const QCString& name) const
01023 {
01024 int *num = d->tablePositionsForAliases[name];
01025 if (!num)
01026 return -1;
01027 return *num;
01028 }
01029
01030 int QuerySchema::tablePosition(const QString& tableName) const
01031 {
01032 int num = 0;
01033 for (TableSchema::ListIterator it(d->tables); it.current(); ++it, num++) {
01034 if (it.current()->name().lower()==tableName.lower())
01035 return num;
01036 }
01037 return -1;
01038 }
01039
01040 QValueList<int> QuerySchema::tablePositions(const QString& tableName) const
01041 {
01042 int num = 0;
01043 QValueList<int> result;
01044 const QString& tableNameLower = tableName.lower();
01045 for (TableSchema::ListIterator it(d->tables); it.current(); ++it, num++) {
01046 if (it.current()->name().lower()==tableNameLower) {
01047 result += num;
01048 }
01049 }
01050 return result;
01051 }
01052
01053 bool QuerySchema::hasTableAlias(uint position) const
01054 {
01055 return d->tableAliases[position]!=0;
01056 }
01057
01058 int QuerySchema::columnPositionForAlias(const QCString& name) const
01059 {
01060 int *num = d->columnPositionsForAliases[name];
01061 if (!num)
01062 return -1;
01063 return *num;
01064 }
01065
01066 void QuerySchema::setTableAlias(uint position, const QCString& alias)
01067 {
01068 if (position >= d->tables.count()) {
01069 KexiDBWarn << "QuerySchema::setTableAlias(): position (" << position
01070 << ") out of range!" << endl;
01071 return;
01072 }
01073 QCString fixedAlias = alias.stripWhiteSpace();
01074 if (fixedAlias.isEmpty()) {
01075 QCString *oldAlias = d->tableAliases.take(position);
01076 if (oldAlias) {
01077 d->tablePositionsForAliases.remove(*oldAlias);
01078 delete oldAlias;
01079 }
01080
01081 }
01082 else {
01083 d->tableAliases.replace(position, new QCString(fixedAlias));
01084 d->tablePositionsForAliases.replace(fixedAlias, new int(position));
01085
01086 }
01087 }
01088
01089 Relationship::List* QuerySchema::relationships() const
01090 {
01091 return &d->relations;
01092 }
01093
01094 Field::List* QuerySchema::asterisks() const
01095 {
01096 return &d->asterisks;
01097 }
01098
01099 QString QuerySchema::statement() const
01100 {
01101 return d->statement;
01102 }
01103
01104 void QuerySchema::setStatement(const QString &s)
01105 {
01106 d->statement = s;
01107 }
01108
01109 Field* QuerySchema::field(const QString& identifier, bool expanded)
01110 {
01111 QueryColumnInfo *ci = columnInfo(identifier, expanded);
01112 return ci ? ci->field : 0;
01113 }
01114
01115 QueryColumnInfo* QuerySchema::columnInfo(const QString& identifier, bool expanded)
01116 {
01117 computeFieldsExpanded();
01118 return expanded ? d->columnInfosByNameExpanded[identifier] : d->columnInfosByName[identifier];
01119 }
01120
01121 QueryColumnInfo::Vector QuerySchema::fieldsExpanded(FieldsExpandedOptions options)
01122 {
01123 computeFieldsExpanded();
01124 if (options == WithInternalFields || options == WithInternalFieldsAndRowID) {
01125
01126 QueryColumnInfo::Vector*& tmpFieldsExpandedWithInternal =
01127 (options == WithInternalFields) ? d->fieldsExpandedWithInternal : d->fieldsExpandedWithInternalAndRowID;
01128
01129 if (!tmpFieldsExpandedWithInternal) {
01130
01131 const uint size = d->fieldsExpanded->count()
01132 + (d->internalFields ? d->internalFields->count() : 0)
01133 + ((options == WithInternalFieldsAndRowID) ? 1 : 0) ;
01134 tmpFieldsExpandedWithInternal = new QueryColumnInfo::Vector( size );
01135 const uint fieldsExpandedVectorSize = d->fieldsExpanded->size();
01136 for (uint i=0; i<fieldsExpandedVectorSize; i++)
01137 tmpFieldsExpandedWithInternal->insert(i, d->fieldsExpanded->at(i));
01138 const uint internalFieldsCount = d->internalFields ? d->internalFields->size() : 0;
01139 if (internalFieldsCount > 0) {
01140 for (uint i=0; i < internalFieldsCount; i++)
01141 tmpFieldsExpandedWithInternal->insert(
01142 fieldsExpandedVectorSize + i, d->internalFields->at(i));
01143 }
01144 if (options == WithInternalFieldsAndRowID) {
01145 if (!d->fakeRowIDField) {
01146 d->fakeRowIDField = new Field("rowID", Field::BigInteger);
01147 d->fakeRowIDCol = new QueryColumnInfo(d->fakeRowIDField, QCString(), true);
01148 }
01149 tmpFieldsExpandedWithInternal->insert(
01150 fieldsExpandedVectorSize + internalFieldsCount, d->fakeRowIDCol );
01151 }
01152 }
01153 return *tmpFieldsExpandedWithInternal;
01154 }
01155
01156 if (options == Default)
01157 return *d->fieldsExpanded;
01158
01159
01160 QDict<char> columnsAlreadyFound;
01161 QueryColumnInfo::Vector result( d->fieldsExpanded->count() );
01162
01163
01164 uint uniqueListCount = 0;
01165 for (uint i=0; i<d->fieldsExpanded->count(); i++) {
01166 QueryColumnInfo *ci = (*d->fieldsExpanded)[i];
01167
01168
01169 if (!columnsAlreadyFound[ci->aliasOrName()]) {
01170 columnsAlreadyFound.insert(ci->aliasOrName(), (char*)1);
01171 result.insert(uniqueListCount++, ci);
01172 }
01173 }
01174 result.resize(uniqueListCount);
01175 return result;
01176 }
01177
01178 QueryColumnInfo::Vector QuerySchema::internalFields()
01179 {
01180 computeFieldsExpanded();
01181 return d->internalFields ? *d->internalFields : QueryColumnInfo::Vector();
01182 }
01183
01184 QueryColumnInfo* QuerySchema::expandedOrInternalField(uint index)
01185 {
01186 QueryColumnInfo::Vector vector = fieldsExpanded(WithInternalFields);
01187 return (index < vector.size()) ? vector[index] : 0;
01188 }
01189
01190 inline QString lookupColumnKey(Field *foreignField, Field* field)
01191 {
01192 QString res;
01193 if (field->table())
01194 res = field->table()->name() + ".";
01195 return res + field->name() + "_" + foreignField->table()->name() + "." + foreignField->name();
01196 }
01197
01198 void QuerySchema::computeFieldsExpanded()
01199 {
01200 if (d->fieldsExpanded)
01201 return;
01202
01203 if (!d->columnsOrder) {
01204 d->columnsOrder = new QMap<QueryColumnInfo*,int>();
01205 d->columnsOrderWithoutAsterisks = new QMap<QueryColumnInfo*,int>();
01206 }
01207 else {
01208 d->columnsOrder->clear();
01209 d->columnsOrderWithoutAsterisks->clear();
01210 }
01211 if (d->ownedVisibleColumns)
01212 d->ownedVisibleColumns->clear();
01213
01214
01215 QueryColumnInfo::List list;
01216 QueryColumnInfo::List lookup_list;
01217 QMap<QueryColumnInfo*, bool> columnInfosOutsideAsterisks;
01218 uint i = 0;
01219 uint fieldPosition = 0;
01220 uint numberOfColumnsWithMultipleVisibleFields = 0;
01221 Field *f;
01222 for (Field::ListIterator it = fieldsIterator(); (f = it.current()); ++it, fieldPosition++) {
01223 if (f->isQueryAsterisk()) {
01224 if (static_cast<QueryAsterisk*>(f)->isSingleTableAsterisk()) {
01225 Field::List *ast_fields = static_cast<QueryAsterisk*>(f)->table()->fields();
01226 for (Field *ast_f = ast_fields->first(); ast_f; ast_f=ast_fields->next()) {
01227
01228 QueryColumnInfo *ci = new QueryColumnInfo(ast_f, QCString(),
01229 isColumnVisible(fieldPosition));
01230 list.append( ci );
01231 KexiDBDbg << "QuerySchema::computeFieldsExpanded(): caching (unexpanded) columns order: "
01232 << ci->debugString() << " at position " << fieldPosition << endl;
01233 d->columnsOrder->insert(ci, fieldPosition);
01234
01235 }
01236 }
01237 else {
01238 for (TableSchema *table = d->tables.first(); table; table = d->tables.next()) {
01239
01240 Field::List *tab_fields = table->fields();
01241 for (Field *tab_f = tab_fields->first(); tab_f; tab_f = tab_fields->next()) {
01243
01244
01245 QueryColumnInfo *ci = new QueryColumnInfo(tab_f, QCString(),
01246 isColumnVisible(fieldPosition));
01247 list.append( ci );
01248 KexiDBDbg << "QuerySchema::computeFieldsExpanded(): caching (unexpanded) columns order: "
01249 << ci->debugString() << " at position " << fieldPosition << endl;
01250 d->columnsOrder->insert(ci, fieldPosition);
01251 }
01252 }
01253 }
01254 }
01255 else {
01256
01257
01258 QueryColumnInfo *ci = new QueryColumnInfo(f, columnAlias(fieldPosition), isColumnVisible(fieldPosition));
01259 list.append( ci );
01260 columnInfosOutsideAsterisks.insert( ci, true );
01261 KexiDBDbg << "QuerySchema::computeFieldsExpanded(): caching (unexpanded) column's order: "
01262 << ci->debugString() << " at position " << fieldPosition << endl;
01263 d->columnsOrder->insert(ci, fieldPosition);
01264 d->columnsOrderWithoutAsterisks->insert(ci, fieldPosition);
01265
01266
01267 LookupFieldSchema *lookupFieldSchema = f->table() ? f->table()->lookupFieldSchema( *f ) : 0;
01268 if (!lookupFieldSchema || lookupFieldSchema->boundColumn()<0)
01269 continue;
01270
01271
01272
01273
01274 LookupFieldSchema::RowSource& rowSource = lookupFieldSchema->rowSource();
01275 if (rowSource.type() == LookupFieldSchema::RowSource::Table) {
01276 TableSchema *lookupTable = connection()->tableSchema( rowSource.name() );
01277 FieldList* visibleColumns = 0;
01278 Field *boundField = 0;
01279 if (lookupTable
01280 && (uint)lookupFieldSchema->boundColumn() < lookupTable->fieldCount()
01281 && (visibleColumns = lookupTable->subList( lookupFieldSchema->visibleColumns() ))
01282 && (boundField = lookupTable->field( lookupFieldSchema->boundColumn() )))
01283 {
01284 Field *visibleColumn = 0;
01285
01286 if (visibleColumns->fieldCount() == 1) {
01287 visibleColumn = visibleColumns->fields()->first();
01288 }
01289 else {
01290
01291
01292 visibleColumn = new Field();
01293 visibleColumn->setName(
01294 QString::fromLatin1("[multiple_visible_fields_%1]")
01295 .arg( ++numberOfColumnsWithMultipleVisibleFields ));
01296 visibleColumn->setExpression(
01297 new ConstExpr(CHARACTER_STRING_LITERAL, QVariant()));
01298 if (!d->ownedVisibleColumns) {
01299 d->ownedVisibleColumns = new Field::List();
01300 d->ownedVisibleColumns->setAutoDelete(true);
01301 }
01302 d->ownedVisibleColumns->append( visibleColumn );
01303 }
01304
01305 lookup_list.append(
01306 new QueryColumnInfo(visibleColumn, QCString(), true, ci) );
01307
01308
01309
01310
01311
01312
01313
01314
01315
01316
01317 }
01318 delete visibleColumns;
01319 }
01320 else if (rowSource.type() == LookupFieldSchema::RowSource::Query) {
01321 QuerySchema *lookupQuery = connection()->querySchema( rowSource.name() );
01322 if (!lookupQuery)
01323 continue;
01324 const QueryColumnInfo::Vector lookupQueryFieldsExpanded( lookupQuery->fieldsExpanded() );
01325 if ((uint)lookupFieldSchema->boundColumn() >= lookupQueryFieldsExpanded.count())
01326 continue;
01327 QueryColumnInfo *boundColumnInfo = 0;
01328 if (!(boundColumnInfo = lookupQueryFieldsExpanded[ lookupFieldSchema->boundColumn() ]))
01329 continue;
01330 Field *boundField = boundColumnInfo->field;
01331 if (!boundField)
01332 continue;
01333 const QValueList<uint> visibleColumns( lookupFieldSchema->visibleColumns() );
01334 bool ok = true;
01335
01336 foreach (QValueList<uint>::ConstIterator, visibleColumnsIt, visibleColumns) {
01337 if ((*visibleColumnsIt) >= lookupQueryFieldsExpanded.count()) {
01338 ok = false;
01339 break;
01340 }
01341 }
01342 if (!ok)
01343 continue;
01344 Field *visibleColumn = 0;
01345
01346 if (visibleColumns.count() == 1) {
01347 visibleColumn = lookupQueryFieldsExpanded[ visibleColumns.first() ]->field;
01348 }
01349 else {
01350
01351
01352 visibleColumn = new Field();
01353 visibleColumn->setName(
01354 QString::fromLatin1("[multiple_visible_fields_%1]")
01355 .arg( ++numberOfColumnsWithMultipleVisibleFields ));
01356 visibleColumn->setExpression(
01357 new ConstExpr(CHARACTER_STRING_LITERAL, QVariant()));
01358 if (!d->ownedVisibleColumns) {
01359 d->ownedVisibleColumns = new Field::List();
01360 d->ownedVisibleColumns->setAutoDelete(true);
01361 }
01362 d->ownedVisibleColumns->append( visibleColumn );
01363 }
01364
01365 lookup_list.append(
01366 new QueryColumnInfo(visibleColumn, QCString(), true, ci) );
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377 }
01378 }
01379 }
01380
01381 if (!d->fieldsExpanded) {
01382 d->fieldsExpanded = new QueryColumnInfo::Vector( list.count() );
01383 d->fieldsExpanded->setAutoDelete(true);
01384 d->columnsOrderExpanded = new QMap<QueryColumnInfo*,int>();
01385 }
01386 else {
01387 d->fieldsExpanded->clear();
01388 d->fieldsExpanded->resize( list.count() );
01389 d->columnsOrderExpanded->clear();
01390 }
01391
01392
01393
01394
01395
01396
01397 d->columnInfosByName.clear();
01398 d->columnInfosByNameExpanded.clear();
01399 i=0;
01400 QueryColumnInfo *ci;
01401 for (QueryColumnInfo::ListIterator it(list); (ci = it.current()); ++it, i++) {
01402 d->fieldsExpanded->insert(i, ci);
01403 d->columnsOrderExpanded->insert(ci, i);
01404
01405 if (!ci->alias.isEmpty()) {
01406
01407 if (!d->columnInfosByNameExpanded[ ci->alias ])
01408 d->columnInfosByNameExpanded.insert( ci->alias, ci );
01409 QString tableAndAlias( ci->alias );
01410 if (ci->field->table())
01411 tableAndAlias.prepend(ci->field->table()->name() + ".");
01412 if (!d->columnInfosByNameExpanded[ tableAndAlias ])
01413 d->columnInfosByNameExpanded.insert( tableAndAlias, ci );
01414
01415 if (columnInfosOutsideAsterisks.contains(ci)) {
01416 if (!d->columnInfosByName[ ci->alias ])
01417 d->columnInfosByName.insert( ci->alias, ci );
01418 if (!d->columnInfosByName[ tableAndAlias ])
01419 d->columnInfosByName.insert( tableAndAlias, ci );
01420 }
01421 }
01422 else {
01423
01424 if (!d->columnInfosByNameExpanded[ ci->field->name() ])
01425 d->columnInfosByNameExpanded.insert( ci->field->name(), ci );
01426 QString tableAndName( ci->field->name() );
01427 if (ci->field->table())
01428 tableAndName.prepend(ci->field->table()->name() + ".");
01429 if (!d->columnInfosByNameExpanded[ tableAndName ])
01430 d->columnInfosByNameExpanded.insert( tableAndName, ci );
01431
01432 if (columnInfosOutsideAsterisks.contains(ci)) {
01433 if (!d->columnInfosByName[ ci->field->name() ])
01434 d->columnInfosByName.insert( ci->field->name(), ci );
01435 if (!d->columnInfosByName[ tableAndName ])
01436 d->columnInfosByName.insert( tableAndName, ci );
01437 }
01438 }
01439 }
01440
01441
01442 QDict<uint> lookup_dict(101);
01443
01444 lookup_dict.setAutoDelete(true);
01445 i=0;
01446 for (QueryColumnInfo::ListIterator it(lookup_list); (ci = it.current());)
01447 {
01448 const QString key( lookupColumnKey(ci->foreignColumn()->field, ci->field) );
01449 if (
01450 lookup_dict[ key ]) {
01451
01452 ++it;
01453 lookup_list.removeRef( ci );
01454 }
01455 else {
01456 lookup_dict.replace( key, new uint( i ) );
01457 ++it;
01458 i++;
01459 }
01460 }
01461
01462
01463 if (d->internalFields) {
01464 d->internalFields->clear();
01465 d->internalFields->resize( lookup_list.count() );
01466 }
01467 delete d->fieldsExpandedWithInternal;
01468 delete d->fieldsExpandedWithInternalAndRowID;
01469 d->fieldsExpandedWithInternal = 0;
01470 d->fieldsExpandedWithInternalAndRowID = 0;
01471 if (!lookup_list.isEmpty() && !d->internalFields) {
01472 d->internalFields = new QueryColumnInfo::Vector( lookup_list.count() );
01473 d->internalFields->setAutoDelete(true);
01474 }
01475 i=0;
01476 for (QueryColumnInfo::ListIterator it(lookup_list); it.current();i++, ++it)
01477 {
01478
01479 d->internalFields->insert(i, it.current());
01480 d->columnsOrderExpanded->insert(it.current(), list.count()+i);
01481 }
01482
01483
01484 numberOfColumnsWithMultipleVisibleFields = 0;
01485 for (i=0; i < d->fieldsExpanded->size(); i++) {
01486 QueryColumnInfo* ci = d->fieldsExpanded->at(i);
01488 LookupFieldSchema *lookupFieldSchema
01489 = ci->field->table() ? ci->field->table()->lookupFieldSchema( *ci->field ) : 0;
01490 if (!lookupFieldSchema || lookupFieldSchema->boundColumn()<0)
01491 continue;
01492 LookupFieldSchema::RowSource& rowSource = lookupFieldSchema->rowSource();
01493 if (rowSource.type() == LookupFieldSchema::RowSource::Table) {
01494 TableSchema *lookupTable = connection()->tableSchema( rowSource.name() );
01495 FieldList* visibleColumns = 0;
01496 if (lookupTable
01497 && (uint)lookupFieldSchema->boundColumn() < lookupTable->fieldCount()
01498 && (visibleColumns = lookupTable->subList( lookupFieldSchema->visibleColumns() )))
01499 {
01500 Field *visibleColumn = 0;
01501
01502 if (visibleColumns->fieldCount() == 1)
01503 {
01504 visibleColumn = visibleColumns->fields()->first();
01505 const QString key( lookupColumnKey(ci->field, visibleColumn) );
01506 uint *index = lookup_dict[ key ];
01507 if (index)
01508 ci->setIndexForVisibleLookupValue( d->fieldsExpanded->size() + *index );
01509 }
01510 else {
01511 const QString key( QString::fromLatin1("[multiple_visible_fields_%1]_%2.%3")
01512 .arg( ++numberOfColumnsWithMultipleVisibleFields )
01513 .arg(ci->field->table()->name()).arg(ci->field->name()) );
01514 uint *index = lookup_dict[ key ];
01515 if (index)
01516 ci->setIndexForVisibleLookupValue( d->fieldsExpanded->size() + *index );
01517 }
01518 }
01519 delete visibleColumns;
01520 }
01521 else if (rowSource.type() == LookupFieldSchema::RowSource::Query) {
01522 QuerySchema *lookupQuery = connection()->querySchema( rowSource.name() );
01523 if (!lookupQuery)
01524 continue;
01525 const QueryColumnInfo::Vector lookupQueryFieldsExpanded( lookupQuery->fieldsExpanded() );
01526 if ((uint)lookupFieldSchema->boundColumn() >= lookupQueryFieldsExpanded.count())
01527 continue;
01528 QueryColumnInfo *boundColumnInfo = 0;
01529 if (!(boundColumnInfo = lookupQueryFieldsExpanded[ lookupFieldSchema->boundColumn() ]))
01530 continue;
01531 Field *boundField = boundColumnInfo->field;
01532 if (!boundField)
01533 continue;
01534 const QValueList<uint> visibleColumns( lookupFieldSchema->visibleColumns() );
01535 Field *visibleColumn = 0;
01536
01537 if (visibleColumns.count() == 1) {
01538 visibleColumn = lookupQueryFieldsExpanded[ visibleColumns.first() ]->field;
01539 const QString key( lookupColumnKey(ci->field, visibleColumn) );
01540 uint *index = lookup_dict[ key ];
01541 if (index)
01542 ci->setIndexForVisibleLookupValue( d->fieldsExpanded->size() + *index );
01543 }
01544 else {
01545 const QString key( QString::fromLatin1("[multiple_visible_fields_%1]_%2.%3")
01546 .arg( ++numberOfColumnsWithMultipleVisibleFields )
01547 .arg(ci->field->table()->name()).arg(ci->field->name()) );
01548 uint *index = lookup_dict[ key ];
01549 if (index)
01550 ci->setIndexForVisibleLookupValue( d->fieldsExpanded->size() + *index );
01551 }
01552 }
01553 else {
01554 KexiDBWarn << "QuerySchema::computeFieldsExpanded(): unsupported row source type "
01555 << rowSource.typeName() << endl;
01556 }
01557 }
01558 }
01559
01560 QMap<QueryColumnInfo*,int> QuerySchema::columnsOrder(ColumnsOrderOptions options)
01561 {
01562 if (!d->columnsOrder)
01563 computeFieldsExpanded();
01564 if (options == UnexpandedList)
01565 return *d->columnsOrder;
01566 else if (options == UnexpandedListWithoutAsterisks)
01567 return *d->columnsOrderWithoutAsterisks;
01568 return *d->columnsOrderExpanded;
01569 }
01570
01571 QValueVector<int> QuerySchema::pkeyFieldsOrder()
01572 {
01573 if (d->pkeyFieldsOrder)
01574 return *d->pkeyFieldsOrder;
01575
01576 TableSchema *tbl = masterTable();
01577 if (!tbl || !tbl->primaryKey())
01578 return QValueVector<int>();
01579
01580
01581 IndexSchema *pkey = tbl->primaryKey();
01582 pkey->debug();
01583 debug();
01584 d->pkeyFieldsOrder = new QValueVector<int>( pkey->fieldCount(), -1 );
01585
01586 const uint fCount = fieldsExpanded().count();
01587 d->pkeyFieldsCount = 0;
01588 for (uint i = 0; i<fCount; i++) {
01589 QueryColumnInfo *fi = d->fieldsExpanded->at(i);
01590 const int fieldIndex = fi->field->table()==tbl ? pkey->indexOf(fi->field) : -1;
01591 if (fieldIndex!=-1
01592 && d->pkeyFieldsOrder->at(fieldIndex)==-1 )
01593 {
01594 KexiDBDbg << "QuerySchema::pkeyFieldsOrder(): FIELD " << fi->field->name()
01595 << " IS IN PKEY AT POSITION #" << fieldIndex << endl;
01596
01597 (*d->pkeyFieldsOrder)[fieldIndex]=i;
01598 d->pkeyFieldsCount++;
01599
01600 }
01601 }
01602 KexiDBDbg << "QuerySchema::pkeyFieldsOrder(): " << d->pkeyFieldsCount
01603 << " OUT OF " << pkey->fieldCount() << " PKEY'S FIELDS FOUND IN QUERY " << name() << endl;
01604 return *d->pkeyFieldsOrder;
01605 }
01606
01607 uint QuerySchema::pkeyFieldsCount()
01608 {
01609 (void)pkeyFieldsOrder();
01610 return d->pkeyFieldsCount;
01611 }
01612
01613 Relationship* QuerySchema::addRelationship( Field *field1, Field *field2 )
01614 {
01615
01616 Relationship *r = new Relationship(this, field1, field2);
01617 if (r->isEmpty()) {
01618 delete r;
01619 return 0;
01620 }
01621
01622 d->relations.append( r );
01623 return r;
01624 }
01625
01626 QueryColumnInfo::List* QuerySchema::autoIncrementFields()
01627 {
01628 if (!d->autoincFields) {
01629 d->autoincFields = new QueryColumnInfo::List();
01630 }
01631 TableSchema *mt = masterTable();
01632 if (!mt) {
01633 KexiDBWarn << "QuerySchema::autoIncrementFields(): no master table!" << endl;
01634 return d->autoincFields;
01635 }
01636 if (d->autoincFields->isEmpty()) {
01637 QueryColumnInfo::Vector fexp = fieldsExpanded();
01638 for (int i=0; i<(int)fexp.count(); i++) {
01639 QueryColumnInfo *fi = fexp[i];
01640 if (fi->field->table() == mt && fi->field->isAutoIncrement()) {
01641 d->autoincFields->append( fi );
01642 }
01643 }
01644 }
01645 return d->autoincFields;
01646 }
01647
01648 QString QuerySchema::sqlColumnsList(QueryColumnInfo::List* infolist, Driver *driver)
01649 {
01650 if (!infolist)
01651 return QString::null;
01652 QString result;
01653 result.reserve(256);
01654 QueryColumnInfo::ListIterator it( *infolist );
01655 bool start = true;
01656 for (; it.current(); ++it) {
01657 if (!start)
01658 result += ",";
01659 else
01660 start = false;
01661 result += driver->escapeIdentifier( it.current()->field->name() );
01662 }
01663 return result;
01664 }
01665
01666 QString QuerySchema::autoIncrementSQLFieldsList(Driver *driver)
01667 {
01668 if ((Driver *)d->lastUsedDriverForAutoIncrementSQLFieldsList != driver
01669 || d->autoIncrementSQLFieldsList.isEmpty())
01670 {
01671 d->autoIncrementSQLFieldsList = QuerySchema::sqlColumnsList( autoIncrementFields(), driver );
01672 d->lastUsedDriverForAutoIncrementSQLFieldsList = driver;
01673 }
01674 return d->autoIncrementSQLFieldsList;
01675 }
01676
01677 void QuerySchema::setWhereExpression(BaseExpr *expr)
01678 {
01679 delete d->whereExpr;
01680 d->whereExpr = expr;
01681 }
01682
01683 void QuerySchema::addToWhereExpression(KexiDB::Field *field, const QVariant& value, int relation)
01684 {
01685 int token;
01686 if (value.isNull())
01687 token = SQL_NULL;
01688 else if (field->isIntegerType()) {
01689 token = INTEGER_CONST;
01690 }
01691 else if (field->isFPNumericType()) {
01692 token = REAL_CONST;
01693 }
01694 else {
01695 token = CHARACTER_STRING_LITERAL;
01697 }
01698
01699 BinaryExpr * newExpr = new BinaryExpr(
01700 KexiDBExpr_Relational,
01701 new ConstExpr( token, value ),
01702 relation,
01703 new VariableExpr((field->table() ? (field->table()->name()+".") : QString::null)+field->name())
01704 );
01705 if (d->whereExpr) {
01706 d->whereExpr = new BinaryExpr(
01707 KexiDBExpr_Logical,
01708 d->whereExpr,
01709 AND,
01710 newExpr
01711 );
01712 }
01713 else {
01714 d->whereExpr = newExpr;
01715 }
01716 }
01717
01718
01719
01720
01721
01722
01723
01724
01725
01726
01727
01728
01729
01731
01732
01733
01734 BaseExpr *QuerySchema::whereExpression() const
01735 {
01736 return d->whereExpr;
01737 }
01738
01739 void QuerySchema::setOrderByColumnList(const OrderByColumnList& list)
01740 {
01741 d->orderByColumnList = list;
01742
01743 }
01744
01745 OrderByColumnList& QuerySchema::orderByColumnList() const
01746 {
01747 return d->orderByColumnList;
01748 }
01749
01750 QuerySchemaParameterList QuerySchema::parameters()
01751 {
01752 if (!whereExpression())
01753 return QuerySchemaParameterList();
01754 QuerySchemaParameterList params;
01755 whereExpression()->getQueryParameters(params);
01756 return params;
01757 }
01758
01759
01760
01761
01762
01763
01764
01765
01766
01767
01768
01769
01770
01771
01772
01773
01774
01775
01776
01777
01778
01779
01780
01781
01782
01783
01784
01785
01786
01787
01788
01789
01790
01791
01792
01793
01794
01795
01796
01797
01798
01799
01800
01801
01802
01803
01804
01805
01806
01807
01808
01809
01810
01811
01812
01813
01814
01815
01816 QueryAsterisk::QueryAsterisk( QuerySchema *query, TableSchema *table )
01817 :Field()
01818 ,m_table(table)
01819 {
01820 assert(query);
01821 m_parent = query;
01822 setType(Field::Asterisk);
01823 }
01824
01825 QueryAsterisk::~QueryAsterisk()
01826 {
01827 }
01828
01829 Field* QueryAsterisk::copy() const
01830 {
01831 return new QueryAsterisk(*this);
01832 }
01833
01834 void QueryAsterisk::setTable(TableSchema *table)
01835 {
01836 KexiDBDbg << "QueryAsterisk::setTable()" << endl;
01837 m_table=table;
01838 }
01839
01840 QString QueryAsterisk::debugString()
01841 {
01842 QString dbg;
01843 if (isAllTableAsterisk()) {
01844 dbg += "ALL-TABLES ASTERISK (*) ON TABLES(";
01845 TableSchema *table;
01846 QString table_names;
01847 for (TableSchema::ListIterator it( *query()->tables() ); (table = it.current()); ++it) {
01848 if (!table_names.isEmpty())
01849 table_names += ", ";
01850 table_names += table->name();
01851 }
01852 dbg += (table_names + ")");
01853 }
01854 else {
01855 dbg += ("SINGLE-TABLE ASTERISK (" + table()->name() + ".*)");
01856 }
01857 return dbg;
01858 }
01859