/***** * * TOra - An Oracle Toolkit for DBA's and developers * Copyright (C) 2003-2005 Quest Software, Inc * Portions Copyright (C) 2005 Other Contributors * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; only version 2 of * the License is valid for this program. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * As a special exception, you have permission to link this program * with the Oracle Client libraries and distribute executables, as long * as you follow the requirements of the GNU GPL in regard to all of the * software in the executable aside from Oracle client libraries. * * Specifically you are not permitted to link this program with the * Qt/UNIX, Qt/Windows or Qt Non Commercial products of TrollTech. * And you are not permitted to distribute binaries compiled against * these libraries without written consent from Quest Software, Inc. * Observe that this does not disallow linking to the Qt Free Edition. * * You may link this product with any GPL'd Qt library such as Qt/Free * * All trademarks belong to their respective owners. * *****/ #include "utils.h" #include "tobrowserindex.h" #include "toconnection.h" #include "toresultcols.h" #include "toextract.h" #include "tomemoeditor.h" #include "tosql.h" #include "totableselect.h" #include #include #include #include #include #include #include #include #include #include #include "tobrowserindex.moc" #include "tobrowserindexui.moc" void toBrowserIndex::modifyIndex(toConnection &conn, const QString &owner, const QString &table, QWidget *parent, const QString &index) { toBrowserIndex dialog(conn, owner, table, index, parent); if (dialog.exec()) { dialog.changeIndex(); dialog.execute(); } } void toBrowserIndex::addIndex(toConnection &conn, const QString &owner, const QString &table, QWidget *parent) { toBrowserIndex dialog(conn, owner, table, QString::null, parent); dialog.addIndex(); if (dialog.exec()) { dialog.changeIndex(); dialog.execute(); } } void toBrowserIndex::execute() { std::list statements = toSQLParse::parse(sql(), connection()); try { QProgressDialog prog(tr("Performing index changes"), tr("Executing index change script"), statements.size(), this, "progress", true); prog.setCaption(tr("Performing index changes")); for (std::list::iterator i = statements.begin();i != statements.end();i++) { QString sql = toSQLParse::indentStatement(*i, connection()); int i = sql.length() - 1; while (i >= 0 && (sql.at(i) == ';' || sql.at(i).isSpace())) i--; if (i >= 0) connection().execute(sql.mid(0, i + 1)); qApp->processEvents(); if (prog.wasCancelled()) throw tr("Cancelled ongoing index modification, indexes might be corrupt"); } } TOCATCH } void toBrowserIndex::registerIndex(const QString &type, const QString &name, std::list::iterator beg, std::list::iterator end) { std::list columns = toExtract::parseColumnDescription(beg, end); QString val; for (std::list::iterator i = columns.begin();i != columns.end();i++) { if (i != columns.begin()) val += ","; val += (*i).Name; } IndexType[name] = type; IndexCols[name] = val; } toBrowserIndex::toBrowserIndex(toConnection &conn, const QString &owner, const QString &table, const QString &index, QWidget *parent, const char *name) : toBrowserIndexUI(parent, name, true), toConnectionWidget(conn, this), Extractor(conn, NULL) { Extractor.setIndexes(true); Extractor.setConstraints(false); Extractor.setPrompt(false); Extractor.setHeading(false); if (toIsMySQL(connection())) Type->insertItem("Fulltext Index"); if (!owner.isEmpty() && !table.isEmpty()) { QString fulltable = conn.quote(owner) + "." + conn.quote(table); TableSelect->setTable(fulltable); describeTable(fulltable); } else if (!owner.isEmpty()) TableSelect->setTable(conn.quote(owner)); connect(TableSelect, SIGNAL(selectTable(const QString &)), this, SLOT(changeTable(const QString &))); for (int i = 0;i < Name->count();i++) if (connection().unQuote(Name->text(i)) == index) { Name->setCurrentItem(Name->count() - 1); break; } } QString toBrowserIndex::table(void) { if (Owner.isEmpty() && Table.isEmpty()) return QString::null; return connection().quote(Owner) + "." + connection().quote(Table); } void toBrowserIndex::describeTable(const QString &table) { try { QStringList parts = QStringList::split(".", table); if (parts.size() > 1) { Owner = connection().unQuote(parts[0]); Table = connection().unQuote(parts[1]); } else { Table = connection().unQuote(table); if (toIsOracle(connection())) Owner = connection().user(); else Owner = connection().database(); } Current = QString::null; if (!table.isEmpty()) { if ( OriginalDescription[table].empty() ) { std::list Objects; Objects.insert(Objects.end(), "TABLE:" + table); NewDescription[table] = Extractor.describe(Objects); } std::list &origDescription = NewDescription[table]; std::list::iterator beg = origDescription.end(); QString lname; QString ltype; QString realtype; IndexType.clear(); IndexCols.clear(); for (std::list::iterator i = origDescription.begin();i != origDescription.end();) { std::list ctx = toExtract::splitDescribe(*i); toShift(ctx); QString type = toShift(ctx); if (type == "INDEX") { QString name = toShift(ctx); if (name != lname) { if (beg != origDescription.end()) registerIndex(realtype, lname, beg, i); beg = i; ltype = type; lname = name; } if (toShift(ctx) == "TYPE") realtype = toShift(ctx); i++; } else { if (beg != origDescription.end()) { registerIndex(realtype, lname, beg, i); beg = origDescription.end(); } i = origDescription.erase(i); // Remove everything that isn't indexes } } if (beg != origDescription.end()) registerIndex(realtype, lname, beg, origDescription.end()); } if ( OriginalDescription[table].empty() ) OriginalDescription[table] = NewDescription[table]; Name->clear(); for (std::map::iterator i = IndexType.begin();i != IndexType.end();i++) Name->insertItem((*i).first); ColList->displayHeader(false); ColList->changeParams(Owner, Table); show(); changeIndex(); } catch (const QString &exc) { toStatusMessage(exc); reject(); } } void toBrowserIndex::saveChanges(void) { if (table().isEmpty()) return ; changeIndex(); std::list migrateTable; for (std::map::iterator i = IndexType.begin();i != IndexType.end();i++) { std::list ctx; toPush(ctx, Owner); toPush(ctx, QString("INDEX")); toPush(ctx, (*i).first); QStringList lst = QStringList::split(",", IndexCols[(*i).first]); for (unsigned int j = 0;j < lst.count();j++) { toExtract::addDescription(migrateTable, ctx, "COLUMN", lst[j]); toExtract::addDescription(migrateTable, ctx, "COLUMN", lst[j], "ORDER", QString::number(j + 1)); } toExtract::addDescription(migrateTable, ctx); toExtract::addDescription(migrateTable, ctx, "ON", Table); toExtract::addDescription(migrateTable, ctx, "TYPE", (*i).second); } NewDescription[table()] = migrateTable; } QString toBrowserIndex::sql() { saveChanges(); std::list origTable; std::list migrateTable; { for (std::map >::iterator i = OriginalDescription.begin();i != OriginalDescription.end();i++) { std::list &cur = (*i).second; for (std::list::iterator j = cur.begin();j != cur.end();j++) toPush(origTable, *j); } } { for (std::map >::iterator i = NewDescription.begin();i != NewDescription.end();i++) { std::list &cur = (*i).second; for (std::list::iterator j = cur.begin();j != cur.end();j++) toPush(migrateTable, *j); } } origTable.sort(); migrateTable.sort(); return Extractor.migrate(origTable, migrateTable); } void toBrowserIndex::displaySQL() { toMemoEditor memo(this, sql(), -1, -1, true, true); memo.exec(); } void toBrowserIndex::addIndex() { if (Table.isEmpty()) return ; bool ok = false; QString name = QInputDialog::getText(tr("Enter new index name"), tr("Enter name of new index."), QLineEdit::Normal, QString::null, &ok, this); if (ok) { Name->insertItem(name); Name->setCurrentItem(Name->count() - 1); IndexType[name] = "Normal Index"; changeIndex(); } } void toBrowserIndex::delIndex() { if (Name->count() > 0) { IndexType.erase(Current); IndexCols.erase(Current); Current = QString::null; Name->removeItem(Name->currentItem()); changeIndex(); } } void toBrowserIndex::changeIndex() { if (!Current.isEmpty()) { QString type = Type->currentText().upper(); if (type == "NORMAL INDEX") type = "INDEX"; IndexType[Current] = type; IndexCols[Current] = Cols->text(); } Current = Name->currentText(); if (Current.isEmpty()) { Cols->setEnabled(false); Type->setEnabled(false); } else { Cols->setEnabled(true); Type->setEnabled(true); Cols->setText(IndexCols[Current]); int i; QString type = IndexType[Current]; if (type == "INDEX") type = "NORMAL INDEX"; for (i = 0;i < Type->count();i++) { if (Type->text(i).upper() == type) { Type->setCurrentItem(i); break; } } if (i == Type->count()) { Type->insertItem(IndexType[Current]); Type->setCurrentItem(Type->count() - 1); } } } void toBrowserIndex::changeTable(const QString &table) { saveChanges(); describeTable(table); }