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 <kexidb/utils.h>
00026
00027 #include <assert.h>
00028
00029 #include <qvaluelist.h>
00030 #include <qasciidict.h>
00031 #include <qptrdict.h>
00032 #include <qintdict.h>
00033 #include <qbitarray.h>
00034
00035 #include <kdebug.h>
00036 #include <klocale.h>
00037
00038 using namespace KexiDB;
00039
00040
00041 namespace KexiDB {
00043 class QuerySchemaPrivate
00044 {
00045 public:
00046 QuerySchemaPrivate(QuerySchema* q)
00047 : query(q)
00048 , masterTable(0)
00049 , maxIndexWithAlias(-1)
00050 , visibility(64)
00051 , fieldsExpanded(0)
00052 , orderByColumnList(0)
00053 , autoincFields(0)
00054 , fieldsOrder(0)
00055 , pkeyFieldsOrder(0)
00056 , pkeyFieldsCount(0)
00057 , tablesBoundToColumns(64, -1)
00058 , tablePositionsForAliases(67, false)
00059 , columnPositionsForAliases(67, false)
00060 , whereExpr(0)
00061 , regenerateExprAliases(false)
00062 {
00063 columnAliases.setAutoDelete(true);
00064 tableAliases.setAutoDelete(true);
00065 asterisks.setAutoDelete(true);
00066 relations.setAutoDelete(true);
00067 tablePositionsForAliases.setAutoDelete(true);
00068 columnPositionsForAliases.setAutoDelete(true);
00069 visibility.fill(false);
00070 }
00071 ~QuerySchemaPrivate()
00072 {
00073 delete fieldsExpanded;
00074 delete orderByColumnList;
00075 delete autoincFields;
00076 delete fieldsOrder;
00077 delete pkeyFieldsOrder;
00078 delete whereExpr;
00079 }
00080
00081 void clear()
00082 {
00083 columnAliases.clear();
00084 tableAliases.clear();
00085 asterisks.clear();
00086 relations.clear();
00087 masterTable = 0;
00088 tables.clear();
00089 clearCachedData();
00090 delete pkeyFieldsOrder;
00091 pkeyFieldsOrder=0;
00092 visibility.fill(false);
00093 tablesBoundToColumns = QValueVector<int>(64,-1);
00094 tablePositionsForAliases.clear();
00095 columnPositionsForAliases.clear();
00096 }
00097
00098 void clearCachedData()
00099 {
00100 if (fieldsExpanded) {
00101 delete fieldsExpanded;
00102 fieldsExpanded = 0;
00103 delete fieldsOrder;
00104 fieldsOrder = 0;
00105 delete autoincFields;
00106 autoincFields = 0;
00107 autoIncrementSQLFieldsList = QString::null;
00108 }
00109 }
00110
00111 void setColumnAliasInternal(uint position, const QCString& alias)
00112 {
00113 columnAliases.replace(position, new QCString(alias));
00114 columnPositionsForAliases.replace(alias, new int(position));
00115 maxIndexWithAlias = QMAX( maxIndexWithAlias, (int)position );
00116 }
00117
00118 void setColumnAlias(uint position, const QCString& alias)
00119 {
00120 QCString *oldAlias = columnAliases.take(position);
00121 if (oldAlias) {
00122 tablePositionsForAliases.remove(*oldAlias);
00123 delete oldAlias;
00124 }
00125 if (alias.isEmpty()) {
00126 maxIndexWithAlias = -1;
00127 }
00128 else {
00129 setColumnAliasInternal(position, alias);
00130 }
00131 }
00132
00133 bool hasColumnAliases()
00134 {
00135 tryRegenerateExprAliases();
00136 return !columnAliases.isEmpty();
00137 }
00138
00139 QCString* columnAlias(uint position)
00140 {
00141 tryRegenerateExprAliases();
00142 return columnAliases[position];
00143 }
00144
00145 QuerySchema *query;
00146
00150 TableSchema *masterTable;
00151
00153 TableSchema::List tables;
00154
00155 protected:
00156 void tryRegenerateExprAliases()
00157 {
00158 if (!regenerateExprAliases)
00159 return;
00160
00161 Field *f;
00162 uint p=0;
00163 uint colNum=0;
00164 QCString columnAlias;
00165 for (Field::ListIterator it(query->fieldsIterator()); (f = it.current()); ++it, p++) {
00166 if (f->isExpression() && !columnAliases[p]) {
00167
00168 for (;;) {
00169 colNum++;
00170 columnAlias = (i18n("short for 'expression' word (only latin letters, please)", "expr")
00171 + QString::number(colNum)).latin1();
00172 if (!tablePositionsForAliases[columnAlias])
00173 break;
00174 }
00175 setColumnAliasInternal(p, columnAlias);
00176 }
00177 }
00178 regenerateExprAliases = false;
00179 }
00180
00182 QIntDict<QCString> columnAliases;
00183
00184 public:
00186 QIntDict<QCString> tableAliases;
00187
00189 int maxIndexWithAlias;
00190
00192 int maxIndexWithTableAlias;
00193
00195 QBitArray visibility;
00196
00198 Field::List asterisks;
00199
00201
00202 QueryColumnInfo::Vector *fieldsExpanded;
00203
00205 QueryColumnInfo::Vector *orderByColumnList;
00206
00208 QueryColumnInfo::List *autoincFields;
00209
00211 QString autoIncrementSQLFieldsList;
00212 QGuardedPtr<Driver> lastUsedDriverForAutoIncrementSQLFieldsList;
00213
00217 QMap<QueryColumnInfo*,int> *fieldsOrder;
00218
00219
00220
00222 QValueVector<int> *pkeyFieldsOrder;
00223
00225 uint pkeyFieldsCount;
00226
00228 QString statement;
00229
00231 Relationship::List relations;
00232
00248 QValueVector<int> tablesBoundToColumns;
00249
00251 QAsciiDict<int> tablePositionsForAliases;
00252
00254 QAsciiDict<int> columnPositionsForAliases;
00255
00257 BaseExpr *whereExpr;
00258
00259 QDict<QueryColumnInfo> columnInfosByName;
00260
00263 bool regenerateExprAliases : 1;
00264 };
00265 }
00266
00267
00268
00269 QuerySchema::QuerySchema()
00270 : FieldList(false)
00271 , SchemaData(KexiDB::QueryObjectType)
00272 , d( new QuerySchemaPrivate(this) )
00273 {
00274 init();
00275 }
00276
00277 QuerySchema::QuerySchema(TableSchema* tableSchema)
00278 : FieldList(false)
00279 , SchemaData(KexiDB::QueryObjectType)
00280 , d( new QuerySchemaPrivate(this) )
00281 {
00282 d->masterTable = tableSchema;
00283
00284 init();
00285 if (!d->masterTable) {
00286 KexiDBWarn << "QuerySchema(TableSchema*): !d->masterTable" << endl;
00287 m_name = QString::null;
00288 return;
00289 }
00290 addTable(d->masterTable);
00291
00292
00293 m_name = d->masterTable->name();
00294
00295 m_caption = d->masterTable->caption();
00296
00297
00298
00299
00300
00301 for (Field::ListIterator it( d->masterTable->fieldsIterator() ); it.current(); ++it) {
00302 addField( it.current() );
00303 }
00304 }
00305
00306 QuerySchema::~QuerySchema()
00307 {
00308 delete d;
00309 }
00310
00311 void QuerySchema::init()
00312 {
00313 m_type = KexiDB::QueryObjectType;
00314
00315 }
00316
00317 void QuerySchema::clear()
00318 {
00319 FieldList::clear();
00320 SchemaData::clear();
00321 d->clear();
00322 }
00323
00324 FieldList& QuerySchema::insertField(uint position, Field *field, bool visible)
00325 {
00326 return insertField(position, field, -1, visible);
00327 }
00328
00329
00330 FieldList& QuerySchema::insertField(uint position, Field *field)
00331 {
00332 return insertField( position, field, -1, true );
00333 }
00334
00335 FieldList& QuerySchema::insertField(uint position, Field *field,
00336 int bindToTable, bool visible)
00337 {
00338 if (!field) {
00339 KexiDBWarn << "QuerySchema::insertField(): !field" << endl;
00340 return *this;
00341 }
00342
00343 if (position>m_fields.count()) {
00344 KexiDBWarn << "QuerySchema::insertField(): position (" << position << ") out of range" << endl;
00345 return *this;
00346 }
00347 if (!field->isQueryAsterisk() && !field->isExpression() && !field->table()) {
00348 KexiDBWarn << "QuerySchema::addField(): WARNING: field '"<<field->name()
00349 <<"' must contain table information!" <<endl;
00350 return *this;
00351 }
00352 if (fieldCount()>=d->visibility.size()) {
00353 d->visibility.resize(d->visibility.size()*2);
00354 d->tablesBoundToColumns.resize(d->tablesBoundToColumns.size()*2);
00355 }
00356 d->clearCachedData();
00357 FieldList::insertField(position, field);
00358 if (field->isQueryAsterisk()) {
00359 d->asterisks.append(field);
00360
00361
00362 if (field->table() && (d->tables.findRef(field->table())==-1))
00363 d->tables.append(field->table());
00364 }
00365 else if (field->table()) {
00366
00367 if (d->tables.findRef(field->table())==-1)
00368 d->tables.append(field->table());
00369 }
00370
00371
00372
00373
00374
00375 for (uint i=fieldCount()-1; i>position; i--)
00376 d->visibility.setBit(i, d->visibility.testBit(i-1));
00377 d->visibility.setBit(position, visible);
00378
00379
00380 if (bindToTable < -1 && bindToTable>(int)d->tables.count()) {
00381 KexiDBWarn << "QuerySchema::insertField(): bindToTable (" << bindToTable
00382 << ") out of range" << endl;
00383 bindToTable = -1;
00384 }
00385
00386 for (uint i=fieldCount()-1; i>position; i--)
00387 d->tablesBoundToColumns[i] = d->tablesBoundToColumns[i-1];
00388 d->tablesBoundToColumns[ position ] = bindToTable;
00389
00390 KexiDBDbg << "QuerySchema::insertField(): bound to table (" << bindToTable << "): " <<endl;
00391 if (bindToTable==-1)
00392 KexiDBDbg << " <NOT SPECIFIED>" << endl;
00393 else
00394 KexiDBDbg << " name=" << d->tables.at(bindToTable)->name()
00395 << " alias=" << tableAlias(bindToTable) << endl;
00396 QString s;
00397 for (uint i=0; i<fieldCount();i++)
00398 s+= (QString::number(d->tablesBoundToColumns[i]) + " ");
00399 KexiDBDbg << "tablesBoundToColumns == [" << s << "]" <<endl;
00400
00401 if (field->isExpression())
00402 d->regenerateExprAliases = true;
00403
00404 return *this;
00405 }
00406
00407 int QuerySchema::tableBoundToColumn(uint columnPosition) const
00408 {
00409 if (columnPosition > d->tablesBoundToColumns.count()) {
00410 KexiDBWarn << "QuerySchema::tableBoundToColumn(): columnPosition (" << columnPosition
00411 << ") out of range" << endl;
00412 return -1;
00413 }
00414 return d->tablesBoundToColumns[columnPosition];
00415 }
00416
00417 KexiDB::FieldList& QuerySchema::addField(KexiDB::Field* field, bool visible)
00418 {
00419 return insertField(m_fields.count(), field, visible);
00420 }
00421
00422 KexiDB::FieldList& QuerySchema::addField(KexiDB::Field* field, int bindToTable,
00423 bool visible)
00424 {
00425 return insertField(m_fields.count(), field, bindToTable, visible);
00426 }
00427
00428 void QuerySchema::removeField(KexiDB::Field *field)
00429 {
00430 if (!field)
00431 return;
00432 d->clearCachedData();
00433 if (field->isQueryAsterisk()) {
00434 d->asterisks.remove(field);
00435 }
00436
00437 FieldList::removeField(field);
00438 }
00439
00440 bool QuerySchema::isColumnVisible(uint position) const
00441 {
00442 return (position < fieldCount()) ? d->visibility.testBit(position) : false;
00443 }
00444
00445 void QuerySchema::setColumnVisible(uint position, bool v)
00446 {
00447 if (position < fieldCount())
00448 d->visibility.setBit(position, v);
00449 }
00450
00451 FieldList& QuerySchema::addAsterisk(QueryAsterisk *asterisk, bool visible)
00452 {
00453 if (!asterisk)
00454 return *this;
00455
00456 asterisk->m_name = (asterisk->table() ? asterisk->table()->name() + ".*" : "*")
00457 + QString::number(asterisks()->count());
00458 return addField(asterisk, visible);
00459 }
00460
00461 Connection* QuerySchema::connection() const
00462 {
00463 TableSchema *mt = masterTable();
00464 return mt ? mt->connection() : 0;
00465 }
00466
00467 QString QuerySchema::debugString()
00468 {
00469 QString dbg;
00470 dbg.reserve(1024);
00471
00472 TableSchema *mt = masterTable();
00473 dbg = QString("QUERY ") + schemaDataDebugString() + "\n"
00474 + "-masterTable=" + (mt ? mt->name() :"<NULL>")
00475 + "\n-COLUMNS:\n"
00476 + ((fieldCount()>0) ? FieldList::debugString() : "<NONE>") + "\n"
00477 + "-FIELDS EXPANDED ";
00478
00479 QString dbg1;
00480 uint fieldsExpandedCount = 0;
00481 if (fieldCount()>0) {
00482 QueryColumnInfo::Vector fe( fieldsExpanded() );
00483 fieldsExpandedCount = fe.size();
00484 for ( uint i=0; i < fieldsExpandedCount; i++ ) {
00485 QueryColumnInfo *ci = fe[i];
00486 if (!dbg1.isEmpty())
00487 dbg1 += ",\n";
00488 dbg1 += (ci->field->name() +
00489 (ci->alias.isEmpty() ? QString::null : (QString::fromLatin1(" AS ") + QString(ci->alias))));
00490 }
00491 dbg1 += "\n";
00492 }
00493 else {
00494 dbg1 = "<NONE>\n";
00495 }
00496 dbg1.prepend( QString("(%1):\n").arg(fieldsExpandedCount) );
00497 dbg += dbg1;
00498
00499
00500
00501
00502
00503
00504 QString dbg2;
00505 dbg2.reserve(512);
00506 for (uint i = 0; i<fieldCount(); i++) {
00507 int tablePos = tableBoundToColumn(i);
00508 if (tablePos>=0) {
00509 QCString tAlias = tableAlias(tablePos);
00510 if (!tAlias.isEmpty()) {
00511 dbg2 += (QString::fromLatin1(" field \"") + FieldList::field(i)->name()
00512 + "\" uses alias \"" + QString(tAlias) + "\" of table \""
00513 + d->tables.at(tablePos)->name() + "\"\n");
00514 }
00515 }
00516 }
00517 if (!dbg2.isEmpty()) {
00518 dbg += "\n-BINDINGS:\n";
00519 dbg += dbg2;
00520 }
00521
00522
00523 TableSchema *table;
00524 QString table_names;
00525 table_names.reserve(512);
00526 for ( table = d->tables.first(); table; table = d->tables.next() ) {
00527 if (!table_names.isEmpty())
00528 table_names += ", ";
00529 table_names += (QString("'") + table->name() + "'");
00530 }
00531 if (d->tables.isEmpty())
00532 table_names = "<NONE>";
00533 dbg += (QString("-TABLES:\n") + table_names);
00534 QString aliases;
00535 if (!d->hasColumnAliases())
00536 aliases = "<NONE>\n";
00537 else {
00538 Field::ListIterator it( m_fields );
00539 for (int i=0; it.current(); ++it, i++) {
00540 QCString *alias = d->columnAlias(i);
00541 if (alias)
00542 aliases += (QString("field #%1: ").arg(i)
00543 + (it.current()->name().isEmpty() ? "<noname>" : it.current()->name())
00544 + " -> " + (const char*)*alias + "\n");
00545 }
00546 }
00547
00548 dbg += QString("\n-COLUMN ALIASES:\n" + aliases);
00549 if (d->tableAliases.isEmpty())
00550 aliases = "<NONE>";
00551 else {
00552 aliases = "";
00553 TableSchema::ListIterator t_it(d->tables);
00554 for (int i=0; t_it.current(); ++t_it, i++) {
00555 QCString *alias = d->tableAliases[i];
00556 if (alias)
00557 aliases += (QString("table #%1: ").arg(i)
00558 + (t_it.current()->name().isEmpty() ? "<noname>" : t_it.current()->name())
00559 + " -> " + (const char*)*alias + "\n");
00560 }
00561 }
00562 dbg += QString("-TABLE ALIASES:\n" + aliases);
00563 QString where = d->whereExpr ? d->whereExpr->debugString() : QString::null;
00564 if (!where.isEmpty())
00565 dbg += QString("\n-WHERE EXPRESSION:\n" + where);
00566 return dbg;
00567 }
00568
00569 TableSchema* QuerySchema::masterTable() const
00570 {
00571 if (d->masterTable)
00572 return d->masterTable;
00573 if (d->tables.isEmpty())
00574 return 0;
00575
00576
00577 int num = 0;
00578 QString tableNameLower;
00579 for (TableSchema::ListIterator it(d->tables); it.current(); ++it, num++) {
00580 if (!tableNameLower.isEmpty() && it.current()->name().lower()!=tableNameLower) {
00581
00582 return 0;
00583 }
00584 tableNameLower = tableAlias(num);
00585 }
00586 return d->tables.first();
00587 }
00588
00589 void QuerySchema::setMasterTable(TableSchema *table)
00590 {
00591 if (table)
00592 d->masterTable=table;
00593 }
00594
00595 TableSchema::List* QuerySchema::tables() const
00596 {
00597 return &d->tables;
00598 }
00599
00600 void QuerySchema::addTable(TableSchema *table, const QCString& alias)
00601 {
00602 KexiDBDbg << "QuerySchema::addTable() " << (void *)table
00603 << " alias=" << alias << endl;
00604 if (!table)
00605 return;
00606
00607
00608
00609
00610 if (alias.isEmpty() && d->tables.findRef(table)!=-1) {
00611 const QString& tableNameLower = table->name().lower();
00612 const QString& aliasLower = QString(alias.lower());
00613 int num = 0;
00614 for (TableSchema::ListIterator it(d->tables); it.current(); ++it, num++) {
00615 if (it.current()->name().lower()==tableNameLower) {
00616 const QString& tAlias = tableAlias(num);
00617 if (tAlias == aliasLower) {
00618 KexiDBWarn << "QuerySchema::addTable(): table with \""
00619 << tAlias << "\" alias already added!" << endl;
00620 return;
00621 }
00622 }
00623 }
00624 }
00625
00626 d->tables.append(table);
00627
00628 if (!alias.isEmpty())
00629 setTableAlias(d->tables.count()-1, alias);
00630 }
00631
00632 void QuerySchema::removeTable(TableSchema *table)
00633 {
00634 if (!table)
00635 return;
00636 if (d->masterTable == table)
00637 d->masterTable = 0;
00638 d->tables.remove(table);
00639
00640 }
00641
00642 TableSchema* QuerySchema::table(const QString& tableName) const
00643 {
00644
00645 for (TableSchema::ListIterator it(d->tables); it.current(); ++it) {
00646 if (it.current()->name().lower()==tableName.lower())
00647 return it.current();
00648 }
00649 return 0;
00650 }
00651
00652 bool QuerySchema::contains(TableSchema *table) const
00653 {
00654 return d->tables.findRef(table)!=-1;
00655 }
00656
00657 Field* QuerySchema::findTableField(const QString &tableDotFieldName) const
00658 {
00659 QString tableName, fieldName;
00660 if (!KexiDB::splitToTableAndFieldParts(tableDotFieldName, tableName, fieldName))
00661 return 0;
00662 TableSchema *tableSchema = table(tableName);
00663 if (!tableSchema)
00664 return 0;
00665 return tableSchema->field(fieldName);
00666 }
00667
00668 QCString QuerySchema::columnAlias(uint position) const
00669 {
00670 QCString *a = d->columnAlias(position);
00671 return a ? *a : QCString();
00672 }
00673
00674 bool QuerySchema::hasColumnAlias(uint position) const
00675 {
00676 return d->columnAlias(position)!=0;
00677 }
00678
00679 void QuerySchema::setColumnAlias(uint position, const QCString& alias)
00680 {
00681 if (position >= m_fields.count()) {
00682 KexiDBWarn << "QuerySchema::setColumnAlias(): position (" << position
00683 << ") out of range!" << endl;
00684 return;
00685 }
00686 QCString fixedAlias = alias.stripWhiteSpace();
00687 Field *f = FieldList::field(position);
00688 if (f->captionOrName().isEmpty() && fixedAlias.isEmpty()) {
00689 KexiDBWarn << "QuerySchema::setColumnAlias(): position (" << position
00690 << ") could not remove alias when no name is specified for expression column!" << endl;
00691 return;
00692 }
00693 d->setColumnAlias(position, fixedAlias);
00694 }
00695
00696 QCString QuerySchema::tableAlias(uint position) const
00697 {
00698 QCString *a = d->tableAliases[position];
00699 return a ? *a : QCString();
00700 }
00701
00702 int QuerySchema::tablePositionForAlias(const QCString& name) const
00703 {
00704 int *num = d->tablePositionsForAliases[name];
00705 if (!num)
00706 return -1;
00707 return *num;
00708 }
00709
00710 int QuerySchema::tablePosition(const QString& tableName) const
00711 {
00712 int num = 0;
00713 for (TableSchema::ListIterator it(d->tables); it.current(); ++it, num++) {
00714 if (it.current()->name().lower()==tableName.lower())
00715 return num;
00716 }
00717 return -1;
00718 }
00719
00720 QValueList<int> QuerySchema::tablePositions(const QString& tableName) const
00721 {
00722 int num = 0;
00723 QValueList<int> result;
00724 const QString& tableNameLower = tableName.lower();
00725 for (TableSchema::ListIterator it(d->tables); it.current(); ++it, num++) {
00726 if (it.current()->name().lower()==tableNameLower) {
00727 result += num;
00728 }
00729 }
00730 return result;
00731 }
00732
00733 bool QuerySchema::hasTableAlias(uint position) const
00734 {
00735 return d->tableAliases[position]!=0;
00736 }
00737
00738 int QuerySchema::columnPositionForAlias(const QCString& name) const
00739 {
00740 int *num = d->columnPositionsForAliases[name];
00741 if (!num)
00742 return -1;
00743 return *num;
00744 }
00745
00746 void QuerySchema::setTableAlias(uint position, const QCString& alias)
00747 {
00748 if (position >= d->tables.count()) {
00749 KexiDBWarn << "QuerySchema::setTableAlias(): position (" << position
00750 << ") out of range!" << endl;
00751 return;
00752 }
00753 QCString fixedAlias = alias.stripWhiteSpace();
00754 if (fixedAlias.isEmpty()) {
00755 QCString *oldAlias = d->tableAliases.take(position);
00756 if (oldAlias) {
00757 d->tablePositionsForAliases.remove(*oldAlias);
00758 delete oldAlias;
00759 }
00760
00761 }
00762 else {
00763 d->tableAliases.replace(position, new QCString(fixedAlias));
00764 d->tablePositionsForAliases.replace(fixedAlias, new int(position));
00765
00766 }
00767 }
00768
00769 Relationship::List* QuerySchema::relationships() const
00770 {
00771 return &d->relations;
00772 }
00773
00774 Field::List* QuerySchema::asterisks() const
00775 {
00776 return &d->asterisks;
00777 }
00778
00779 QString QuerySchema::statement() const
00780 {
00781 return d->statement;
00782 }
00783
00784 void QuerySchema::setStatement(const QString &s)
00785 {
00786 d->statement = s;
00787 }
00788
00789 Field* QuerySchema::field(const QString& name)
00790 {
00791 computeFieldsExpanded();
00792 QueryColumnInfo *ci = d->columnInfosByName[name];
00793 return ci ? ci->field : 0;
00794 }
00795
00796 QueryColumnInfo* QuerySchema::columnInfo(const QString& name)
00797 {
00798 computeFieldsExpanded();
00799 return d->columnInfosByName[name];
00800 }
00801
00802 QueryColumnInfo::Vector QuerySchema::fieldsExpanded(bool unique)
00803 {
00804 computeFieldsExpanded();
00805 if (!unique)
00806 return *d->fieldsExpanded;
00807
00808 QDict<char> columnsAlreadyFound;
00809 QueryColumnInfo::Vector result( d->fieldsExpanded->count() );
00810
00811
00812 uint uniqueListCount = 0;
00813 for (uint i=0; i<d->fieldsExpanded->count(); i++) {
00814 QueryColumnInfo *ci = (*d->fieldsExpanded)[i];
00815
00816
00817 if (!columnsAlreadyFound[ci->aliasOrName()]) {
00818 columnsAlreadyFound.insert(ci->aliasOrName(), (char*)1);
00819 result.insert(uniqueListCount++, ci);
00820 }
00821 }
00822 result.resize(uniqueListCount);
00823 return result;
00824 }
00825
00826 void QuerySchema::computeFieldsExpanded()
00827 {
00828 if (d->fieldsExpanded) {
00829
00830
00831 return;
00832 }
00833
00834
00835
00836
00837
00838
00839
00840
00841 QueryColumnInfo::List list;
00842 int i = 0;
00843 int fieldPosition = 0;
00844 for (Field *f = m_fields.first(); f; f = m_fields.next(), fieldPosition++) {
00845 if (f->isQueryAsterisk()) {
00846 if (static_cast<QueryAsterisk*>(f)->isSingleTableAsterisk()) {
00847 Field::List *ast_fields = static_cast<QueryAsterisk*>(f)->table()->fields();
00848 for (Field *ast_f = ast_fields->first(); ast_f; ast_f=ast_fields->next()) {
00849
00850 list.append( new QueryColumnInfo(ast_f, QCString(),
00851 isColumnVisible(fieldPosition))
00852 );
00853
00854 }
00855 }
00856 else {
00857 for (TableSchema *table = d->tables.first(); table; table = d->tables.next()) {
00858
00859 Field::List *tab_fields = table->fields();
00860 for (Field *tab_f = tab_fields->first(); tab_f; tab_f = tab_fields->next()) {
00862
00863
00864 list.append( new QueryColumnInfo(tab_f, QCString(),
00865 isColumnVisible(fieldPosition))
00866 );
00867 }
00868 }
00869 }
00870 }
00871 else {
00872
00873
00874 list.append(
00875 new QueryColumnInfo(f, columnAlias(fieldPosition), isColumnVisible(fieldPosition)) );
00876
00877 }
00878 }
00879
00880 if (!d->fieldsExpanded) {
00881 d->fieldsExpanded = new QueryColumnInfo::Vector( list.count() );
00882 d->fieldsExpanded->setAutoDelete(true);
00883 d->fieldsOrder = new QMap<QueryColumnInfo*,int>();
00884 }
00885 else {
00886 d->fieldsExpanded->clear();
00887 d->fieldsExpanded->resize( list.count() );
00888 d->fieldsOrder->clear();
00889 }
00890
00891
00892
00893
00894
00895
00896 d->columnInfosByName.clear();
00897 QueryColumnInfo::ListIterator it(list);
00898 for (i=0; it.current(); ++it, i++)
00899 {
00900 d->fieldsExpanded->insert(i,it.current());
00901 d->fieldsOrder->insert(it.current(),i);
00902
00903 if (!it.current()->alias.isEmpty()) {
00904
00905 if (!d->columnInfosByName[ it.current()->alias ])
00906 d->columnInfosByName.insert( it.current()->alias, it.current() );
00907 }
00908 else {
00909
00910 if (!d->columnInfosByName[ it.current()->field->name() ])
00911 d->columnInfosByName.insert( it.current()->field->name(), it.current() );
00912 QString tableAndName( it.current()->field->table()->name() + "." + it.current()->field->name() );
00913 if (!d->columnInfosByName[ tableAndName ])
00914 d->columnInfosByName.insert( tableAndName, it.current() );
00915 }
00916 }
00917
00918
00919 }
00920
00921 QMap<QueryColumnInfo*,int> QuerySchema::fieldsOrder()
00922 {
00923 if (!d->fieldsOrder)
00924 computeFieldsExpanded();
00925 return *d->fieldsOrder;
00926 }
00927
00928 QValueVector<int> QuerySchema::pkeyFieldsOrder()
00929 {
00930 if (d->pkeyFieldsOrder)
00931 return *d->pkeyFieldsOrder;
00932
00933 TableSchema *tbl = masterTable();
00934 if (!tbl || !tbl->primaryKey())
00935 return QValueVector<int>();
00936
00937
00938 IndexSchema *pkey = tbl->primaryKey();
00939 d->pkeyFieldsOrder = new QValueVector<int>( pkey->fieldCount(), -1 );
00940
00941 const uint fCount = fieldsExpanded().count();
00942 d->pkeyFieldsCount = 0;
00943 for (uint i = 0; i<fCount; i++) {
00944 QueryColumnInfo *fi = d->fieldsExpanded->at(i);
00945 const int fieldIndex = fi->field->table()==tbl ? pkey->indexOf(fi->field) : -1;
00946 if (fieldIndex!=-1
00947 && d->pkeyFieldsOrder->at(fieldIndex)==-1 )
00948 {
00949 KexiDBDbg << "QuerySchema::pkeyFieldsOrder(): FIELD " << fi->field->name()
00950 << " IS IN PKEY AT POSITION #" << fieldIndex << endl;
00951
00952 (*d->pkeyFieldsOrder)[fieldIndex]=i;
00953 d->pkeyFieldsCount++;
00954
00955 }
00956 }
00957 KexiDBDbg << "QuerySchema::pkeyFieldsOrder(): " << d->pkeyFieldsCount
00958 << " OUT OF " << pkey->fieldCount() << " PKEY'S FIELDS FOUND IN QUERY " << name() << endl;
00959 return *d->pkeyFieldsOrder;
00960 }
00961
00962 uint QuerySchema::pkeyFieldsCount()
00963 {
00964 (void)pkeyFieldsOrder();
00965 return d->pkeyFieldsCount;
00966 }
00967
00968 Relationship* QuerySchema::addRelationship( Field *field1, Field *field2 )
00969 {
00970
00971 Relationship *r = new Relationship(this, field1, field2);
00972 if (r->isEmpty()) {
00973 delete r;
00974 return 0;
00975 }
00976
00977 d->relations.append( r );
00978 return r;
00979 }
00980
00981 QueryColumnInfo::List* QuerySchema::autoIncrementFields()
00982 {
00983 if (!d->autoincFields) {
00984 d->autoincFields = new QueryColumnInfo::List();
00985 }
00986 TableSchema *mt = masterTable();
00987 if (!mt) {
00988 KexiDBWarn << "QuerySchema::autoIncrementFields(): no master table!" << endl;
00989 return d->autoincFields;
00990 }
00991 if (d->autoincFields->isEmpty()) {
00992 QueryColumnInfo::Vector fexp = fieldsExpanded();
00993 for (int i=0; i<(int)fexp.count(); i++) {
00994 QueryColumnInfo *fi = fexp[i];
00995 if (fi->field->table() == mt && fi->field->isAutoIncrement()) {
00996 d->autoincFields->append( fi );
00997 }
00998 }
00999 }
01000 return d->autoincFields;
01001 }
01002
01003 QString QuerySchema::sqlColumnsList(QueryColumnInfo::List* infolist, Driver *driver)
01004 {
01005 if (!infolist)
01006 return QString::null;
01007 QString result;
01008 result.reserve(256);
01009 QueryColumnInfo::ListIterator it( *infolist );
01010 bool start = true;
01011 for (; it.current(); ++it) {
01012 if (!start)
01013 result += ",";
01014 else
01015 start = false;
01016 result += driver->escapeIdentifier( it.current()->field->name() );
01017 }
01018 return result;
01019 }
01020
01021 QString QuerySchema::autoIncrementSQLFieldsList(Driver *driver)
01022 {
01023 if ((Driver *)d->lastUsedDriverForAutoIncrementSQLFieldsList != driver
01024 || d->autoIncrementSQLFieldsList.isEmpty())
01025 {
01026 d->autoIncrementSQLFieldsList = QuerySchema::sqlColumnsList( autoIncrementFields(), driver );
01027 d->lastUsedDriverForAutoIncrementSQLFieldsList = driver;
01028 }
01029 return d->autoIncrementSQLFieldsList;
01030 }
01031
01032 void QuerySchema::setWhereExpression(BaseExpr *expr)
01033 {
01034 delete d->whereExpr;
01035 d->whereExpr = expr;
01036 }
01037
01038 void QuerySchema::addToWhereExpression(KexiDB::Field *field, const QVariant& value, int relation)
01039 {
01040 int token;
01041 if (value.isNull())
01042 token = SQL_NULL;
01043 else if (field->isIntegerType()) {
01044 token = INTEGER_CONST;
01045 }
01046 else if (field->isFPNumericType()) {
01047 token = REAL_CONST;
01048 }
01049 else {
01050 token = CHARACTER_STRING_LITERAL;
01052 }
01053
01054 BinaryExpr * newExpr = new BinaryExpr(
01055 KexiDBExpr_Relational,
01056 new ConstExpr( token, value ),
01057 relation,
01058 new VariableExpr((field->table() ? (field->table()->name()+".") : QString::null)+field->name())
01059 );
01060 if (d->whereExpr) {
01061 d->whereExpr = new BinaryExpr(
01062 KexiDBExpr_Logical,
01063 d->whereExpr,
01064 AND,
01065 newExpr
01066 );
01067 }
01068 else {
01069 d->whereExpr = newExpr;
01070 }
01071 }
01072
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082
01083
01084
01086
01087
01088
01089 BaseExpr *QuerySchema::whereExpression() const
01090 {
01091 return d->whereExpr;
01092 }
01093
01094 void QuerySchema::setOrderByColumnList(const QStringList& columnNames)
01095 {
01096 Q_UNUSED(columnNames);
01098
01099
01100
01101
01102
01103 }
01104
01106 void QuerySchema::setOrderByColumnList(const QString& column1, const QString& column2,
01107 const QString& column3, const QString& column4, const QString& column5)
01108 {
01109 Q_UNUSED(column1);
01110 Q_UNUSED(column2);
01111 Q_UNUSED(column3);
01112 Q_UNUSED(column4);
01113 Q_UNUSED(column5);
01116 }
01117
01118 QueryColumnInfo::Vector QuerySchema::orderByColumnList() const
01119 {
01120 return d->orderByColumnList ? *d->orderByColumnList: QueryColumnInfo::Vector();
01121 }
01122
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181 QueryAsterisk::QueryAsterisk( QuerySchema *query, TableSchema *table )
01182 :Field()
01183 ,m_table(table)
01184 {
01185 assert(query);
01186 m_parent = query;
01187 setType(Field::Asterisk);
01188 }
01189
01190 QueryAsterisk::~QueryAsterisk()
01191 {
01192 }
01193
01194 void QueryAsterisk::setTable(TableSchema *table)
01195 {
01196 KexiDBDbg << "QueryAsterisk::setTable()" << endl;
01197 m_table=table;
01198 }
01199
01200 QString QueryAsterisk::debugString()
01201 {
01202 QString dbg;
01203 if (isAllTableAsterisk()) {
01204 dbg += "ALL-TABLES ASTERISK (*) ON TABLES(";
01205 TableSchema *table;
01206 QString table_names;
01207 TableSchema::List *tables = query()->tables();
01208 for ( table = tables->first(); table; table = tables->next() ) {
01209 if (!table_names.isEmpty())
01210 table_names += ", ";
01211 table_names += table->name();
01212 }
01213 dbg += (table_names + ")");
01214 }
01215 else {
01216 dbg += ("SINGLE-TABLE ASTERISK (" + table()->name() + ".*)");
01217 }
01218 return dbg;
01219 }
01220