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 addField( new QueryAsterisk(this) );
00298 }
00299
00300 QuerySchema::~QuerySchema()
00301 {
00302 delete d;
00303 }
00304
00305 void QuerySchema::init()
00306 {
00307 m_type = KexiDB::QueryObjectType;
00308
00309 }
00310
00311 void QuerySchema::clear()
00312 {
00313 FieldList::clear();
00314 SchemaData::clear();
00315 d->clear();
00316 }
00317
00318 FieldList& QuerySchema::insertField(uint position, Field *field, bool visible)
00319 {
00320 return insertField(position, field, -1, visible);
00321 }
00322
00323
00324 FieldList& QuerySchema::insertField(uint position, Field *field)
00325 {
00326 return insertField( position, field, -1, true );
00327 }
00328
00329 FieldList& QuerySchema::insertField(uint position, Field *field,
00330 int bindToTable, bool visible)
00331 {
00332 if (!field) {
00333 KexiDBWarn << "QuerySchema::insertField(): !field" << endl;
00334 return *this;
00335 }
00336
00337 if (position>m_fields.count()) {
00338 KexiDBWarn << "QuerySchema::insertField(): position (" << position << ") out of range" << endl;
00339 return *this;
00340 }
00341 if (!field->isQueryAsterisk() && !field->isExpression() && !field->table()) {
00342 KexiDBWarn << "QuerySchema::addField(): WARNING: field '"<<field->name()
00343 <<"' must contain table information!" <<endl;
00344 return *this;
00345 }
00346 if (fieldCount()>=d->visibility.size()) {
00347 d->visibility.resize(d->visibility.size()*2);
00348 d->tablesBoundToColumns.resize(d->tablesBoundToColumns.size()*2);
00349 }
00350 d->clearCachedData();
00351 FieldList::insertField(position, field);
00352 if (field->isQueryAsterisk()) {
00353 d->asterisks.append(field);
00354
00355
00356 if (field->table() && (d->tables.findRef(field->table())==-1))
00357 d->tables.append(field->table());
00358 }
00359 else if (field->table()) {
00360
00361 if (d->tables.findRef(field->table())==-1)
00362 d->tables.append(field->table());
00363 }
00364
00365
00366
00367
00368
00369 for (uint i=fieldCount()-1; i>position; i--)
00370 d->visibility.setBit(i, d->visibility.testBit(i-1));
00371 d->visibility.setBit(position, visible);
00372
00373
00374 if (bindToTable < -1 && bindToTable>(int)d->tables.count()) {
00375 KexiDBWarn << "QuerySchema::insertField(): bindToTable (" << bindToTable
00376 << ") out of range" << endl;
00377 bindToTable = -1;
00378 }
00379
00380 for (uint i=fieldCount()-1; i>position; i--)
00381 d->tablesBoundToColumns[i] = d->tablesBoundToColumns[i-1];
00382 d->tablesBoundToColumns[ position ] = bindToTable;
00383
00384 KexiDBDbg << "QuerySchema::insertField(): bound to table (" << bindToTable << "): " <<endl;
00385 if (bindToTable==-1)
00386 KexiDBDbg << " <NOT SPECIFIED>" << endl;
00387 else
00388 KexiDBDbg << " name=" << d->tables.at(bindToTable)->name()
00389 << " alias=" << tableAlias(bindToTable) << endl;
00390 QString s;
00391 for (uint i=0; i<fieldCount();i++)
00392 s+= (QString::number(d->tablesBoundToColumns[i]) + " ");
00393 KexiDBDbg << "tablesBoundToColumns == [" << s << "]" <<endl;
00394
00395 if (field->isExpression())
00396 d->regenerateExprAliases = true;
00397
00398 return *this;
00399 }
00400
00401 int QuerySchema::tableBoundToColumn(uint columnPosition) const
00402 {
00403 if (columnPosition > d->tablesBoundToColumns.count()) {
00404 KexiDBWarn << "QuerySchema::tableBoundToColumn(): columnPosition (" << columnPosition
00405 << ") out of range" << endl;
00406 return -1;
00407 }
00408 return d->tablesBoundToColumns[columnPosition];
00409 }
00410
00411 KexiDB::FieldList& QuerySchema::addField(KexiDB::Field* field, bool visible)
00412 {
00413 return insertField(m_fields.count(), field, visible);
00414 }
00415
00416 KexiDB::FieldList& QuerySchema::addField(KexiDB::Field* field, int bindToTable,
00417 bool visible)
00418 {
00419 return insertField(m_fields.count(), field, bindToTable, visible);
00420 }
00421
00422 void QuerySchema::removeField(KexiDB::Field *field)
00423 {
00424 if (!field)
00425 return;
00426 d->clearCachedData();
00427 if (field->isQueryAsterisk()) {
00428 d->asterisks.remove(field);
00429 }
00430
00431 FieldList::removeField(field);
00432 }
00433
00434 bool QuerySchema::isColumnVisible(uint position) const
00435 {
00436 return (position < fieldCount()) ? d->visibility.testBit(position) : false;
00437 }
00438
00439 void QuerySchema::setColumnVisible(uint position, bool v)
00440 {
00441 if (position < fieldCount())
00442 d->visibility.setBit(position, v);
00443 }
00444
00445 FieldList& QuerySchema::addAsterisk(QueryAsterisk *asterisk, bool visible)
00446 {
00447 if (!asterisk)
00448 return *this;
00449
00450 asterisk->m_name = (asterisk->table() ? asterisk->table()->name() + ".*" : "*")
00451 + QString::number(asterisks()->count());
00452 return addField(asterisk, visible);
00453 }
00454
00455 Connection* QuerySchema::connection() const
00456 {
00457 TableSchema *mt = masterTable();
00458 return mt ? mt->connection() : 0;
00459 }
00460
00461 QString QuerySchema::debugString()
00462 {
00463 QString dbg;
00464 dbg.reserve(1024);
00465
00466 TableSchema *mt = masterTable();
00467 dbg = QString("QUERY ") + schemaDataDebugString() + "\n"
00468 + "-masterTable=" + (mt ? mt->name() :"<NULL>")
00469 + "\n-COLUMNS:\n"
00470 + ((fieldCount()>0) ? FieldList::debugString() : "<NONE>") + "\n"
00471 + "-FIELDS EXPANDED ";
00472
00473 QString dbg1;
00474 uint fieldsExpandedCount = 0;
00475 if (fieldCount()>0) {
00476 QueryColumnInfo::Vector fe( fieldsExpanded() );
00477 fieldsExpandedCount = fe.size();
00478 for ( uint i=0; i < fieldsExpandedCount; i++ ) {
00479 QueryColumnInfo *ci = fe[i];
00480 if (!dbg1.isEmpty())
00481 dbg1 += ",\n";
00482 dbg1 += (ci->field->name() +
00483 (ci->alias.isEmpty() ? QString::null : (QString::fromLatin1(" AS ") + QString(ci->alias))));
00484 }
00485 dbg1 += "\n";
00486 }
00487 else {
00488 dbg1 = "<NONE>\n";
00489 }
00490 dbg1.prepend( QString("(%1):\n").arg(fieldsExpandedCount) );
00491 dbg += dbg1;
00492
00493
00494
00495
00496
00497
00498 QString dbg2;
00499 dbg2.reserve(512);
00500 for (uint i = 0; i<fieldCount(); i++) {
00501 int tablePos = tableBoundToColumn(i);
00502 if (tablePos>=0) {
00503 QCString tAlias = tableAlias(tablePos);
00504 if (!tAlias.isEmpty()) {
00505 dbg2 += (QString::fromLatin1(" field \"") + FieldList::field(i)->name()
00506 + "\" uses alias \"" + QString(tAlias) + "\" of table \""
00507 + d->tables.at(tablePos)->name() + "\"\n");
00508 }
00509 }
00510 }
00511 if (!dbg2.isEmpty()) {
00512 dbg += "\n-BINDINGS:\n";
00513 dbg += dbg2;
00514 }
00515
00516
00517 TableSchema *table;
00518 QString table_names;
00519 table_names.reserve(512);
00520 for ( table = d->tables.first(); table; table = d->tables.next() ) {
00521 if (!table_names.isEmpty())
00522 table_names += ", ";
00523 table_names += (QString("'") + table->name() + "'");
00524 }
00525 if (d->tables.isEmpty())
00526 table_names = "<NONE>";
00527 dbg += (QString("-TABLES:\n") + table_names);
00528 QString aliases;
00529 if (!d->hasColumnAliases())
00530 aliases = "<NONE>\n";
00531 else {
00532 Field::ListIterator it( m_fields );
00533 for (int i=0; it.current(); ++it, i++) {
00534 QCString *alias = d->columnAlias(i);
00535 if (alias)
00536 aliases += (QString("field #%1: ").arg(i)
00537 + (it.current()->name().isEmpty() ? "<noname>" : it.current()->name())
00538 + " -> " + (const char*)*alias + "\n");
00539 }
00540 }
00541
00542 dbg += QString("\n-COLUMN ALIASES:\n" + aliases);
00543 if (d->tableAliases.isEmpty())
00544 aliases = "<NONE>";
00545 else {
00546 aliases = "";
00547 TableSchema::ListIterator t_it(d->tables);
00548 for (int i=0; t_it.current(); ++t_it, i++) {
00549 QCString *alias = d->tableAliases[i];
00550 if (alias)
00551 aliases += (QString("table #%1: ").arg(i)
00552 + (t_it.current()->name().isEmpty() ? "<noname>" : t_it.current()->name())
00553 + " -> " + (const char*)*alias + "\n");
00554 }
00555 }
00556 dbg += QString("-TABLE ALIASES:\n" + aliases);
00557 QString where = d->whereExpr ? d->whereExpr->debugString() : QString::null;
00558 if (!where.isEmpty())
00559 dbg += QString("\n-WHERE EXPRESSION:\n" + where);
00560 return dbg;
00561 }
00562
00563 TableSchema* QuerySchema::masterTable() const
00564 {
00565 if (d->masterTable)
00566 return d->masterTable;
00567 if (d->tables.isEmpty())
00568 return 0;
00569
00570
00571 int num = 0;
00572 QString tableNameLower;
00573 for (TableSchema::ListIterator it(d->tables); it.current(); ++it, num++) {
00574 if (!tableNameLower.isEmpty() && it.current()->name().lower()!=tableNameLower) {
00575
00576 return 0;
00577 }
00578 tableNameLower = tableAlias(num);
00579 }
00580 return d->tables.first();
00581 }
00582
00583 void QuerySchema::setMasterTable(TableSchema *table)
00584 {
00585 if (table)
00586 d->masterTable=table;
00587 }
00588
00589 TableSchema::List* QuerySchema::tables() const
00590 {
00591 return &d->tables;
00592 }
00593
00594 void QuerySchema::addTable(TableSchema *table, const QCString& alias)
00595 {
00596 KexiDBDbg << "QuerySchema::addTable() " << (void *)table
00597 << " alias=" << alias << endl;
00598 if (!table)
00599 return;
00600
00601
00602
00603
00604 if (alias.isEmpty() && d->tables.findRef(table)!=-1) {
00605 const QString& tableNameLower = table->name().lower();
00606 const QString& aliasLower = QString(alias.lower());
00607 int num = 0;
00608 for (TableSchema::ListIterator it(d->tables); it.current(); ++it, num++) {
00609 if (it.current()->name().lower()==tableNameLower) {
00610 const QString& tAlias = tableAlias(num);
00611 if (tAlias == aliasLower) {
00612 KexiDBWarn << "QuerySchema::addTable(): table with \""
00613 << tAlias << "\" alias already added!" << endl;
00614 return;
00615 }
00616 }
00617 }
00618 }
00619
00620 d->tables.append(table);
00621
00622 if (!alias.isEmpty())
00623 setTableAlias(d->tables.count()-1, alias);
00624 }
00625
00626 void QuerySchema::removeTable(TableSchema *table)
00627 {
00628 if (!table)
00629 return;
00630 if (d->masterTable == table)
00631 d->masterTable = 0;
00632 d->tables.remove(table);
00633
00634 }
00635
00636 TableSchema* QuerySchema::table(const QString& tableName) const
00637 {
00638
00639 for (TableSchema::ListIterator it(d->tables); it.current(); ++it) {
00640 if (it.current()->name().lower()==tableName.lower())
00641 return it.current();
00642 }
00643 return 0;
00644 }
00645
00646 bool QuerySchema::contains(TableSchema *table) const
00647 {
00648 return d->tables.findRef(table)!=-1;
00649 }
00650
00651 Field* QuerySchema::findTableField(const QString &tableDotFieldName) const
00652 {
00653 QString tableName, fieldName;
00654 if (!KexiDB::splitToTableAndFieldParts(tableDotFieldName, tableName, fieldName))
00655 return 0;
00656 TableSchema *tableSchema = table(tableName);
00657 if (!tableSchema)
00658 return 0;
00659 return tableSchema->field(fieldName);
00660 }
00661
00662 QCString QuerySchema::columnAlias(uint position) const
00663 {
00664 QCString *a = d->columnAlias(position);
00665 return a ? *a : QCString();
00666 }
00667
00668 bool QuerySchema::hasColumnAlias(uint position) const
00669 {
00670 return d->columnAlias(position)!=0;
00671 }
00672
00673 void QuerySchema::setColumnAlias(uint position, const QCString& alias)
00674 {
00675 if (position >= m_fields.count()) {
00676 KexiDBWarn << "QuerySchema::setColumnAlias(): position (" << position
00677 << ") out of range!" << endl;
00678 return;
00679 }
00680 QCString fixedAlias = alias.stripWhiteSpace();
00681 Field *f = FieldList::field(position);
00682 if (f->captionOrName().isEmpty() && fixedAlias.isEmpty()) {
00683 KexiDBWarn << "QuerySchema::setColumnAlias(): position (" << position
00684 << ") could not remove alias when no name is specified for expression column!" << endl;
00685 return;
00686 }
00687 d->setColumnAlias(position, fixedAlias);
00688 }
00689
00690 QCString QuerySchema::tableAlias(uint position) const
00691 {
00692 QCString *a = d->tableAliases[position];
00693 return a ? *a : QCString();
00694 }
00695
00696 int QuerySchema::tablePositionForAlias(const QCString& name) const
00697 {
00698 int *num = d->tablePositionsForAliases[name];
00699 if (!num)
00700 return -1;
00701 return *num;
00702 }
00703
00704 int QuerySchema::tablePosition(const QString& tableName) const
00705 {
00706 int num = 0;
00707 for (TableSchema::ListIterator it(d->tables); it.current(); ++it, num++) {
00708 if (it.current()->name().lower()==tableName.lower())
00709 return num;
00710 }
00711 return -1;
00712 }
00713
00714 QValueList<int> QuerySchema::tablePositions(const QString& tableName) const
00715 {
00716 int num = 0;
00717 QValueList<int> result;
00718 const QString& tableNameLower = tableName.lower();
00719 for (TableSchema::ListIterator it(d->tables); it.current(); ++it, num++) {
00720 if (it.current()->name().lower()==tableNameLower) {
00721 result += num;
00722 }
00723 }
00724 return result;
00725 }
00726
00727 bool QuerySchema::hasTableAlias(uint position) const
00728 {
00729 return d->tableAliases[position]!=0;
00730 }
00731
00732 int QuerySchema::columnPositionForAlias(const QCString& name) const
00733 {
00734 int *num = d->columnPositionsForAliases[name];
00735 if (!num)
00736 return -1;
00737 return *num;
00738 }
00739
00740 void QuerySchema::setTableAlias(uint position, const QCString& alias)
00741 {
00742 if (position >= d->tables.count()) {
00743 KexiDBWarn << "QuerySchema::setTableAlias(): position (" << position
00744 << ") out of range!" << endl;
00745 return;
00746 }
00747 QCString fixedAlias = alias.stripWhiteSpace();
00748 if (fixedAlias.isEmpty()) {
00749 QCString *oldAlias = d->tableAliases.take(position);
00750 if (oldAlias) {
00751 d->tablePositionsForAliases.remove(*oldAlias);
00752 delete oldAlias;
00753 }
00754
00755 }
00756 else {
00757 d->tableAliases.replace(position, new QCString(fixedAlias));
00758 d->tablePositionsForAliases.replace(fixedAlias, new int(position));
00759
00760 }
00761 }
00762
00763 Relationship::List* QuerySchema::relationships() const
00764 {
00765 return &d->relations;
00766 }
00767
00768 Field::List* QuerySchema::asterisks() const
00769 {
00770 return &d->asterisks;
00771 }
00772
00773 QString QuerySchema::statement() const
00774 {
00775 return d->statement;
00776 }
00777
00778 void QuerySchema::setStatement(const QString &s)
00779 {
00780 d->statement = s;
00781 }
00782
00783 Field* QuerySchema::field(const QString& name)
00784 {
00785 computeFieldsExpanded();
00786 QueryColumnInfo *ci = d->columnInfosByName[name];
00787 return ci ? ci->field : 0;
00788 }
00789
00790 QueryColumnInfo* QuerySchema::columnInfo(const QString& name)
00791 {
00792 computeFieldsExpanded();
00793 return d->columnInfosByName[name];
00794 }
00795
00796 QueryColumnInfo::Vector QuerySchema::fieldsExpanded(bool unique)
00797 {
00798 computeFieldsExpanded();
00799 if (!unique)
00800 return *d->fieldsExpanded;
00801
00802 QDict<char> columnsAlreadyFound;
00803 QueryColumnInfo::Vector result( d->fieldsExpanded->count() );
00804
00805
00806 uint uniqueListCount = 0;
00807 for (uint i=0; i<d->fieldsExpanded->count(); i++) {
00808 QueryColumnInfo *ci = (*d->fieldsExpanded)[i];
00809
00810
00811 if (!columnsAlreadyFound[ci->aliasOrName()]) {
00812 columnsAlreadyFound.insert(ci->aliasOrName(), (char*)1);
00813 result.insert(uniqueListCount++, ci);
00814 }
00815 }
00816 result.resize(uniqueListCount);
00817 return result;
00818 }
00819
00820 void QuerySchema::computeFieldsExpanded()
00821 {
00822 if (d->fieldsExpanded) {
00823
00824
00825 return;
00826 }
00827
00828
00829
00830
00831
00832
00833
00834
00835 QueryColumnInfo::List list;
00836 int i = 0;
00837 int fieldPosition = 0;
00838 for (Field *f = m_fields.first(); f; f = m_fields.next(), fieldPosition++) {
00839 if (f->isQueryAsterisk()) {
00840 if (static_cast<QueryAsterisk*>(f)->isSingleTableAsterisk()) {
00841 Field::List *ast_fields = static_cast<QueryAsterisk*>(f)->table()->fields();
00842 for (Field *ast_f = ast_fields->first(); ast_f; ast_f=ast_fields->next()) {
00843
00844 list.append( new QueryColumnInfo(ast_f, QCString(),
00845 isColumnVisible(fieldPosition))
00846 );
00847
00848 }
00849 }
00850 else {
00851 for (TableSchema *table = d->tables.first(); table; table = d->tables.next()) {
00852
00853 Field::List *tab_fields = table->fields();
00854 for (Field *tab_f = tab_fields->first(); tab_f; tab_f = tab_fields->next()) {
00856
00857
00858 list.append( new QueryColumnInfo(tab_f, QCString(),
00859 isColumnVisible(fieldPosition))
00860 );
00861 }
00862 }
00863 }
00864 }
00865 else {
00866
00867
00868 list.append(
00869 new QueryColumnInfo(f, columnAlias(fieldPosition), isColumnVisible(fieldPosition)) );
00870
00871 }
00872 }
00873
00874 if (!d->fieldsExpanded) {
00875 d->fieldsExpanded = new QueryColumnInfo::Vector( list.count() );
00876 d->fieldsExpanded->setAutoDelete(true);
00877 d->fieldsOrder = new QMap<QueryColumnInfo*,int>();
00878 }
00879 else {
00880 d->fieldsExpanded->clear();
00881 d->fieldsExpanded->resize( list.count() );
00882 d->fieldsOrder->clear();
00883 }
00884
00885
00886
00887
00888
00889
00890 d->columnInfosByName.clear();
00891 QueryColumnInfo::ListIterator it(list);
00892 for (i=0; it.current(); ++it, i++)
00893 {
00894 d->fieldsExpanded->insert(i,it.current());
00895 d->fieldsOrder->insert(it.current(),i);
00896
00897 if (!it.current()->alias.isEmpty()) {
00898
00899 if (!d->columnInfosByName[ it.current()->alias ])
00900 d->columnInfosByName.insert( it.current()->alias, it.current() );
00901 }
00902 else {
00903
00904 if (!d->columnInfosByName[ it.current()->field->name() ])
00905 d->columnInfosByName.insert( it.current()->field->name(), it.current() );
00906 QString tableAndName( it.current()->field->table()->name() + "." + it.current()->field->name() );
00907 if (!d->columnInfosByName[ tableAndName ])
00908 d->columnInfosByName.insert( tableAndName, it.current() );
00909 }
00910 }
00911
00912
00913 }
00914
00915 QMap<QueryColumnInfo*,int> QuerySchema::fieldsOrder()
00916 {
00917 if (!d->fieldsOrder)
00918 computeFieldsExpanded();
00919 return *d->fieldsOrder;
00920 }
00921
00922 QValueVector<int> QuerySchema::pkeyFieldsOrder()
00923 {
00924 if (d->pkeyFieldsOrder)
00925 return *d->pkeyFieldsOrder;
00926
00927 TableSchema *tbl = masterTable();
00928 if (!tbl || !tbl->primaryKey())
00929 return QValueVector<int>();
00930
00931
00932 IndexSchema *pkey = tbl->primaryKey();
00933 d->pkeyFieldsOrder = new QValueVector<int>( pkey->fieldCount(), -1 );
00934
00935 const uint fCount = fieldsExpanded().count();
00936 d->pkeyFieldsCount = 0;
00937 for (uint i = 0; i<fCount; i++) {
00938 QueryColumnInfo *fi = d->fieldsExpanded->at(i);
00939 const int fieldIndex = fi->field->table()==tbl ? pkey->indexOf(fi->field) : -1;
00940 if (fieldIndex!=-1
00941 && d->pkeyFieldsOrder->at(fieldIndex)==-1 )
00942 {
00943 KexiDBDbg << "QuerySchema::pkeyFieldsOrder(): FIELD " << fi->field->name()
00944 << " IS IN PKEY AT POSITION #" << fieldIndex << endl;
00945
00946 (*d->pkeyFieldsOrder)[fieldIndex]=i;
00947 d->pkeyFieldsCount++;
00948
00949 }
00950 }
00951 KexiDBDbg << "QuerySchema::pkeyFieldsOrder(): " << d->pkeyFieldsCount
00952 << " OUT OF " << pkey->fieldCount() << " PKEY'S FIELDS FOUND IN QUERY " << name() << endl;
00953 return *d->pkeyFieldsOrder;
00954 }
00955
00956 uint QuerySchema::pkeyFieldsCount()
00957 {
00958 (void)pkeyFieldsOrder();
00959 return d->pkeyFieldsCount;
00960 }
00961
00962 Relationship* QuerySchema::addRelationship( Field *field1, Field *field2 )
00963 {
00964
00965 Relationship *r = new Relationship(this, field1, field2);
00966 if (r->isEmpty()) {
00967 delete r;
00968 return 0;
00969 }
00970
00971 d->relations.append( r );
00972 return r;
00973 }
00974
00975 QueryColumnInfo::List* QuerySchema::autoIncrementFields()
00976 {
00977 if (!d->autoincFields) {
00978 d->autoincFields = new QueryColumnInfo::List();
00979 }
00980 TableSchema *mt = masterTable();
00981 if (!mt) {
00982 KexiDBWarn << "QuerySchema::autoIncrementFields(): no master table!" << endl;
00983 return d->autoincFields;
00984 }
00985 if (d->autoincFields->isEmpty()) {
00986 QueryColumnInfo::Vector fexp = fieldsExpanded();
00987 for (int i=0; i<(int)fexp.count(); i++) {
00988 QueryColumnInfo *fi = fexp[i];
00989 if (fi->field->table() == mt && fi->field->isAutoIncrement()) {
00990 d->autoincFields->append( fi );
00991 }
00992 }
00993 }
00994 return d->autoincFields;
00995 }
00996
00997 QString QuerySchema::sqlColumnsList(QueryColumnInfo::List* infolist, Driver *driver)
00998 {
00999 if (!infolist)
01000 return QString::null;
01001 QString result;
01002 result.reserve(256);
01003 QueryColumnInfo::ListIterator it( *infolist );
01004 bool start = true;
01005 for (; it.current(); ++it) {
01006 if (!start)
01007 result += ",";
01008 else
01009 start = false;
01010 result += driver->escapeIdentifier( it.current()->field->name() );
01011 }
01012 return result;
01013 }
01014
01015 QString QuerySchema::autoIncrementSQLFieldsList(Driver *driver)
01016 {
01017 if ((Driver *)d->lastUsedDriverForAutoIncrementSQLFieldsList != driver
01018 || d->autoIncrementSQLFieldsList.isEmpty())
01019 {
01020 d->autoIncrementSQLFieldsList = QuerySchema::sqlColumnsList( autoIncrementFields(), driver );
01021 d->lastUsedDriverForAutoIncrementSQLFieldsList = driver;
01022 }
01023 return d->autoIncrementSQLFieldsList;
01024 }
01025
01026 void QuerySchema::setWhereExpression(BaseExpr *expr)
01027 {
01028 delete d->whereExpr;
01029 d->whereExpr = expr;
01030 }
01031
01032 void QuerySchema::addToWhereExpression(KexiDB::Field *field, const QVariant& value, int relation)
01033 {
01034 int token;
01035 if (value.isNull())
01036 token = SQL_NULL;
01037 else if (field->isIntegerType()) {
01038 token = INTEGER_CONST;
01039 }
01040 else if (field->isFPNumericType()) {
01041 token = REAL_CONST;
01042 }
01043 else {
01044 token = CHARACTER_STRING_LITERAL;
01046 }
01047
01048 BinaryExpr * newExpr = new BinaryExpr(
01049 KexiDBExpr_Relational,
01050 new ConstExpr( token, value ),
01051 relation,
01052 new VariableExpr((field->table() ? (field->table()->name()+".") : QString::null)+field->name())
01053 );
01054 if (d->whereExpr) {
01055 d->whereExpr = new BinaryExpr(
01056 KexiDBExpr_Logical,
01057 d->whereExpr,
01058 AND,
01059 newExpr
01060 );
01061 }
01062 else {
01063 d->whereExpr = newExpr;
01064 }
01065 }
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075
01076
01077
01078
01080
01081
01082
01083 BaseExpr *QuerySchema::whereExpression() const
01084 {
01085 return d->whereExpr;
01086 }
01087
01088 void QuerySchema::setOrderByColumnList(const QStringList& columnNames)
01089 {
01090 Q_UNUSED(columnNames);
01092
01093
01094
01095
01096
01097 }
01098
01100 void QuerySchema::setOrderByColumnList(const QString& column1, const QString& column2,
01101 const QString& column3, const QString& column4, const QString& column5)
01102 {
01103 Q_UNUSED(column1);
01104 Q_UNUSED(column2);
01105 Q_UNUSED(column3);
01106 Q_UNUSED(column4);
01107 Q_UNUSED(column5);
01110 }
01111
01112 QueryColumnInfo::Vector QuerySchema::orderByColumnList() const
01113 {
01114 return d->orderByColumnList ? *d->orderByColumnList: QueryColumnInfo::Vector();
01115 }
01116
01117
01118
01119
01120
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 QueryAsterisk::QueryAsterisk( QuerySchema *query, TableSchema *table )
01176 :Field()
01177 ,m_table(table)
01178 {
01179 assert(query);
01180 m_parent = query;
01181 setType(Field::Asterisk);
01182 }
01183
01184 QueryAsterisk::~QueryAsterisk()
01185 {
01186 }
01187
01188 void QueryAsterisk::setTable(TableSchema *table)
01189 {
01190 KexiDBDbg << "QueryAsterisk::setTable()" << endl;
01191 m_table=table;
01192 }
01193
01194 QString QueryAsterisk::debugString()
01195 {
01196 QString dbg;
01197 if (isAllTableAsterisk()) {
01198 dbg += "ALL-TABLES ASTERISK (*) ON TABLES(";
01199 TableSchema *table;
01200 QString table_names;
01201 TableSchema::List *tables = query()->tables();
01202 for ( table = tables->first(); table; table = tables->next() ) {
01203 if (!table_names.isEmpty())
01204 table_names += ", ";
01205 table_names += table->name();
01206 }
01207 dbg += (table_names + ")");
01208 }
01209 else {
01210 dbg += ("SINGLE-TABLE ASTERISK (" + table()->name() + ".*)");
01211 }
01212 return dbg;
01213 }
01214