/***** * * 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 "toconf.h" #include "toconnection.h" #include "tohighlightedtext.h" #include "tomain.h" #include "tosql.h" #include "totool.h" #include #include #include #include #include #include #include // A little magic to get lrefresh to work and get a check on qApp #undef QT_TRANSLATE_NOOP #define QT_TRANSLATE_NOOP(x,y) QTRANS(x,y) #define TO_DEBUGOUT(x) fprintf(stderr,(const char *)x); // Connection provider implementation std::map *toConnectionProvider::Providers; std::map *toConnectionProvider::Types; static int NumberFormat; static int NumberDecimals; void toConnectionProvider::checkAlloc(void) { if (!Providers) Providers = new std::map; } void toConnectionProvider::addProvider(const QCString &provider) { checkAlloc(); Provider = provider; (*Providers)[Provider] = this; } toConnectionProvider::toConnectionProvider(const QCString &provider, bool add ) { Provider = provider; if (add ) addProvider(provider); if (!Types) Types = new std::map; (*Types)[provider] = this; } std::list toConnectionProvider::providedOptions(const QCString &) { std::list ret; return ret; } void toConnectionProvider::removeProvider(const QCString &provider) { std::map::iterator i = Providers->find(provider); if (i != Providers->end()) Providers->erase(i); } toConnectionProvider::~toConnectionProvider() { try { if (!Provider.isEmpty()) removeProvider(Provider); std::map::iterator i = Types->find(Provider); if (i != Types->end()) Types->erase(i); } catch (...) {} } std::list toConnectionProvider::providedHosts(const QCString &) { std::list ret; return ret; } std::list toConnectionProvider::providers() { std::list ret; if (!Providers) return ret; for (std::map::iterator i = Providers->begin();i != Providers->end();i++) ret.insert(ret.end(), (*i).first); return ret; } void toConnectionProvider::initializeAll(void) { if (Types) for (std::map::iterator i = Types->begin(); i != Types->end();i++) (*i).second->initialize(); } toConnectionProvider &toConnectionProvider::fetchProvider(const QCString &provider) { checkAlloc(); std::map::iterator i = Providers->find(provider); if (i == Providers->end()) throw QT_TRANSLATE_NOOP("toConnectionProvider", "Tried to fetch unknown provider %1").arg(provider); return *((*i).second); } std::list toConnectionProvider::options(const QCString &provider) { return fetchProvider(provider).providedOptions(provider); } QWidget *toConnectionProvider::configurationTab(const QCString &provider, QWidget *parent) { return fetchProvider(provider).providerConfigurationTab(provider, parent); } toConnection::connectionImpl *toConnectionProvider::connection(const QCString &provider, toConnection *conn) { return fetchProvider(provider).provideConnection(provider, conn); } std::list toConnectionProvider::hosts(const QCString &provider) { return fetchProvider(provider).providedHosts(provider); } std::list toConnectionProvider::databases(const QCString &provider, const QString &host, const QString &user, const QString &pwd) { return fetchProvider(provider).providedDatabases(provider, host, user, pwd); } const QString &toConnectionProvider::config(const QCString &tag, const QCString &def) { QCString str = Provider; str.append(":"); str.append(tag); return toTool::globalConfig(str, def); } void toConnectionProvider::setConfig(const QCString &tag, const QCString &def) { QCString str = Provider; str.append(":"); str.append(tag); toTool::globalSetConfig(str, def); } QWidget *toConnectionProvider::providerConfigurationTab(const QCString &, QWidget *) { return NULL; } // Query value implementation toQValue::toQValue(int i) { Type = intType; Value.Int = i; } toQValue::toQValue(double i) { Type = doubleType; Value.Double = i; } toQValue::toQValue(const toQValue ©) { Type = copy.Type; switch (Type) { case intType: Value.Int = copy.Value.Int; break; case doubleType: Value.Double = copy.Value.Double; break; case stringType: Value.String = new QString(*copy.Value.String); break; case binaryType: Value.Array = new QByteArray(*copy.Value.Array); break; case nullType: break; } } const toQValue &toQValue::operator = (const toQValue ©) { if (Type == stringType) delete Value.String; else if (Type == binaryType) delete Value.Array; Type = copy.Type; switch (Type) { case intType: Value.Int = copy.Value.Int; break; case doubleType: Value.Double = copy.Value.Double; break; case stringType: Value.String = new QString(*copy.Value.String); break; case binaryType: Value.Array = new QByteArray(*copy.Value.Array); break; case nullType: break; } return *this; } bool toQValue::operator == (const toQValue &val) const { if (isNull() && val.isNull()) return true; if (val.Type != Type) return false; switch (Type) { case intType: return (val.Value.Int == Value.Int); case doubleType: return (val.Value.Double == Value.Double); case stringType: return (*val.Value.String) == (*Value.String); case binaryType: return (*val.Value.Array) == (*Value.Array); case nullType: break; } return false; // Should never get here } toQValue::toQValue(const QString &str) { Type = stringType; Value.String = new QString(str); } toQValue::toQValue(void) { Type = nullType; } toQValue::~toQValue() { if (Type == stringType) delete Value.String; else if (Type == binaryType) delete Value.Array; } bool toQValue::isInt(void) const { return Type == intType; } bool toQValue::isDouble(void) const { return Type == doubleType; } bool toQValue::isString(void) const { return Type == stringType; } bool toQValue::isBinary(void) const { return Type == binaryType; } bool toQValue::isNull(void) const { if (Type == nullType) return true; if (Type == stringType && Value.String->isNull()) return true; return false; } const QByteArray &toQValue::toByteArray() const { if (Type != binaryType) throw qApp->translate("toQValue", "Tried to convert non binary value to binary"); return *Value.Array; } static char HexString[] = "0123456789ABCDEF"; QCString toQValue::utf8(void) const { switch (Type) { case nullType: { QCString ret; return ret; } case intType: { QCString ret; ret.setNum(Value.Int); return ret; } case doubleType: { QCString ret; if (Value.Double != int(Value.Double)) { ret.setNum(Value.Double); return ret; } char buf[100]; switch (NumberFormat) { default: ret.setNum(Value.Double); break; case 1: sprintf(buf, "%E", Value.Double); ret = buf; break; case 2: sprintf(buf, "%0.*f", NumberDecimals, Value.Double); ret = buf; break; } return ret; } case stringType: return Value.String->utf8(); case binaryType: { QCString ret(Value.Array->size()*2 + 1); for (unsigned int i = 0;i < Value.Array->size();i++) { unsigned char c = (unsigned char)Value.Array->at(i); ret.at(i*2) = HexString[(c / 16) % 16]; ret.at(i*2 + 1) = HexString[c % 16]; } ret.at(Value.Array->size()*2) = 0; return ret; } } throw qApp->translate("toQValue", "Unknown type of query value"); } int toQValue::toInt(void) const { switch (Type) { case nullType: return 0; case intType: return Value.Int; case doubleType: return int(Value.Double); case stringType: return Value.String->toInt(); case binaryType: throw qApp->translate("toQValue", "Can't transform binary value to int"); } throw qApp->translate("toQValue", "Unknown type of query value"); } double toQValue::toDouble(void) const { switch (Type) { case nullType: return 0; case intType: return double(Value.Int); case doubleType: return Value.Double; case stringType: return Value.String->toDouble(); case binaryType: throw qApp->translate("toQValue", "Can't transform binary value to double"); } throw qApp->translate("toQValue", "Unknown type of query value"); } void toQValue::setNumberFormat(int format, int decimals) { NumberFormat = format; NumberDecimals = decimals; } QString toQValue::formatNumber(double number) { if (number == int(number)) return QString::number(number); switch (NumberFormat) { case 1: { char buf[100]; sprintf(buf, "%E", number); return buf; } case 2: { char buf[100]; sprintf(buf, "%0.*f", NumberDecimals, number); return buf; } default: return QString::number(number); } } int toQValue::numberFormat(void) { return NumberFormat; } int toQValue::numberDecimals(void) { return NumberDecimals; } toQValue toQValue::createBinary(const QByteArray &arr) { toQValue ret; ret.Type = binaryType; ret.Value.Array = new QByteArray(arr); return ret; } toQValue toQValue::createFromHex(const QCString &hex) { QByteArray arr((hex.length() + 1) / 2); for (unsigned int i = 0;i < hex.length();i += 2) { int num; char c = hex.at(i); if (c >= 'a') num = c - 'a'; else if (c >= 'A') num = c - 'A'; else num = c - '0'; num <<= 4; c = hex.at(i + 1); if (c >= 'a') num += c - 'a'; else if (c >= 'A') num += c - 'A'; else num += c - '0'; arr.at(i / 2) = num; } return createBinary(arr); } toQValue toQValue::createFromHex(const QString &hex) { QByteArray arr((hex.length() + 1) / 2); for (unsigned int i = 0;i < hex.length();i += 2) { int num; char c = hex.at(i); if (c >= 'a') num = c - 'a'; else if (c >= 'A') num = c - 'A'; else num = c - '0'; num <<= 4; c = hex.at(i + 1); if (c >= 'a') num += c - 'a'; else if (c >= 'A') num += c - 'A'; else num += c - '0'; arr.at(i / 2) = num; } return createBinary(arr); } toQValue::operator QString() const { switch (Type) { case nullType: return QString::null; case doubleType: return formatNumber(Value.Double); case intType: return QString::number(Value.Int); case stringType: return *Value.String; case binaryType: { QString ret; for (unsigned int i = 0;i < Value.Array->size();i++) { unsigned char c = (unsigned char)Value.Array->at(i); ret += HexString[(c / 16) % 16]; ret += HexString[c % 16]; } return ret; } } throw qApp->translate("toQValue", "Unknown type of query value"); } // toQuery implementation toQuery::toQuery(toConnection &conn, const toSQL &sql, const QString &arg1, const QString &arg2, const QString &arg3, const QString &arg4, const QString &arg5, const QString &arg6, const QString &arg7, const QString &arg8, const QString &arg9) : Connection(conn), ConnectionSub(conn.mainConnection()), SQL(sql(Connection)) { Mode = Normal; int numArgs; if (!arg9.isNull()) numArgs = 9; else if (!arg8.isNull()) numArgs = 8; else if (!arg7.isNull()) numArgs = 7; else if (!arg6.isNull()) numArgs = 6; else if (!arg5.isNull()) numArgs = 5; else if (!arg4.isNull()) numArgs = 4; else if (!arg3.isNull()) numArgs = 3; else if (!arg2.isNull()) numArgs = 2; else if (!arg1.isNull()) numArgs = 1; else numArgs = 0; if (numArgs > 0) Params.insert(Params.end(), arg1); if (numArgs > 1) Params.insert(Params.end(), arg2); if (numArgs > 2) Params.insert(Params.end(), arg3); if (numArgs > 3) Params.insert(Params.end(), arg4); if (numArgs > 4) Params.insert(Params.end(), arg5); if (numArgs > 5) Params.insert(Params.end(), arg6); if (numArgs > 6) Params.insert(Params.end(), arg7); if (numArgs > 7) Params.insert(Params.end(), arg8); if (numArgs > 8) Params.insert(Params.end(), arg9); toBusy busy; try { Query = NULL; Query = conn.Connection->createQuery(this, ConnectionSub); Query->execute(); } catch (...) { delete Query; Query = NULL; Connection.freeConnection(ConnectionSub); throw; } ConnectionSub->setQuery(this); } toQuery::toQuery(toConnection &conn, const QString &sql, const QString &arg1, const QString &arg2, const QString &arg3, const QString &arg4, const QString &arg5, const QString &arg6, const QString &arg7, const QString &arg8, const QString &arg9) : Connection(conn), ConnectionSub(conn.mainConnection()), SQL(sql.utf8()) { Mode = Normal; int numArgs; if (!arg9.isNull()) numArgs = 9; else if (!arg8.isNull()) numArgs = 8; else if (!arg7.isNull()) numArgs = 7; else if (!arg6.isNull()) numArgs = 6; else if (!arg5.isNull()) numArgs = 5; else if (!arg4.isNull()) numArgs = 4; else if (!arg3.isNull()) numArgs = 3; else if (!arg2.isNull()) numArgs = 2; else if (!arg1.isNull()) numArgs = 1; else numArgs = 0; if (numArgs > 0) Params.insert(Params.end(), arg1); if (numArgs > 1) Params.insert(Params.end(), arg2); if (numArgs > 2) Params.insert(Params.end(), arg3); if (numArgs > 3) Params.insert(Params.end(), arg4); if (numArgs > 4) Params.insert(Params.end(), arg5); if (numArgs > 5) Params.insert(Params.end(), arg6); if (numArgs > 6) Params.insert(Params.end(), arg7); if (numArgs > 7) Params.insert(Params.end(), arg8); if (numArgs > 8) Params.insert(Params.end(), arg9); toBusy busy; try { Query = NULL; Query = conn.Connection->createQuery(this, ConnectionSub); Query->execute(); } catch (...) { delete Query; Query = NULL; Connection.freeConnection(ConnectionSub); throw; } ConnectionSub->setQuery(this); } toQuery::toQuery(toConnection &conn, const toSQL &sql, const toQList ¶ms) : Connection(conn), ConnectionSub(conn.mainConnection()), Params(params), SQL(sql(conn)) { Mode = Normal; toBusy busy; try { Query = NULL; Query = conn.Connection->createQuery(this, ConnectionSub); Query->execute(); } catch (...) { delete Query; Query = NULL; Connection.freeConnection(ConnectionSub); throw; } ConnectionSub->setQuery(this); } toQuery::toQuery(toConnection &conn, const QString &sql, const toQList ¶ms) : Connection(conn), ConnectionSub(conn.mainConnection()), Params(params), SQL(sql.utf8()) { Mode = Normal; toBusy busy; try { Query = NULL; Query = conn.Connection->createQuery(this, ConnectionSub); Query->execute(); } catch (...) { delete Query; Query = NULL; Connection.freeConnection(ConnectionSub); throw; } ConnectionSub->setQuery(this); } toQuery::toQuery(toConnection &conn, queryMode mode, const toSQL &sql, const toQList ¶ms) : Connection(conn), Params(params), SQL(sql(conn)) { Mode = mode; switch (Mode) { case Normal: case All: ConnectionSub = conn.mainConnection(); break; case Background: ConnectionSub = conn.backgroundConnection(); break; case Long: ConnectionSub = conn.longConnection(); break; } toBusy busy; try { Query = NULL; Query = conn.Connection->createQuery(this, ConnectionSub); Query->execute(); } catch (...) { delete Query; Query = NULL; Connection.freeConnection(ConnectionSub); throw; } ConnectionSub->setQuery(this); } toQuery::toQuery(toConnection &conn, queryMode mode, const QString &sql, const toQList ¶ms) : Connection(conn), Params(params), SQL(sql.utf8()) { Mode = mode; switch (Mode) { case Normal: case All: ConnectionSub = conn.mainConnection(); break; case Background: ConnectionSub = conn.backgroundConnection(); break; case Long: ConnectionSub = conn.longConnection(); break; } toBusy busy; try { Query = NULL; Query = conn.Connection->createQuery(this, ConnectionSub); Query->execute(); } catch (...) { delete Query; Query = NULL; Connection.freeConnection(ConnectionSub); throw; } ConnectionSub->setQuery(this); } toQuery::toQuery(toConnection &conn, queryMode mode) : Connection(conn) { Mode = mode; switch (Mode) { case Normal: case All: ConnectionSub = conn.mainConnection(); break; case Background: ConnectionSub = conn.backgroundConnection(); break; case Long: ConnectionSub = conn.longConnection(); break; } toBusy busy; try { Query = NULL; Query = conn.Connection->createQuery(this, ConnectionSub); } catch (...) { delete Query; Query = NULL; throw; } ConnectionSub->setQuery(this); } void toQuery::execute(const toSQL &sql, const toQList ¶ms) { toBusy busy; SQL = sql(Connection); Params = params; Query->execute(); } void toQuery::execute(const QString &sql, const toQList ¶ms) { toBusy busy; SQL = sql.utf8(); Params = params; Query->execute(); } toQuery::~toQuery() { toBusy busy; delete Query; try { if (ConnectionSub->query() == this) ConnectionSub->setQuery(NULL); Connection.freeConnection(ConnectionSub); } catch (...) {} } bool toQuery::eof(void) { if (Mode == All) { if (Query->eof()) { Connection.Lock.lock(); bool found = false; try { std::list &cons = Connection.connections(); for (std::list::iterator i = cons.begin();i != cons.end();i++) { if (*i == ConnectionSub) { i++; if (i != cons.end()) { ConnectionSub = *i; Connection.Lock.unlock(); found = true; delete Query; Query = NULL; Query = connection().Connection->createQuery(this, ConnectionSub); Query->execute(); Connection.Lock.lock(); } break; } } Connection.Lock.unlock(); } catch (...) {} } } return Query->eof(); } toQList toQuery::readQuery(toConnection &conn, const toSQL &sql, toQList ¶ms) { toBusy busy; toQuery query(conn, sql, params); toQList ret; while (!query.eof()) ret.insert(ret.end(), query.readValue()); return ret; } toQList toQuery::readQuery(toConnection &conn, const QString &sql, toQList ¶ms) { toBusy busy; toQuery query(conn, sql, params); toQList ret; while (!query.eof()) ret.insert(ret.end(), query.readValue()); return ret; } toQList toQuery::readQuery(toConnection &conn, const toSQL &sql, const QString &arg1, const QString &arg2, const QString &arg3, const QString &arg4, const QString &arg5, const QString &arg6, const QString &arg7, const QString &arg8, const QString &arg9) { toBusy busy; toQuery query(conn, sql, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); toQList ret; while (!query.eof()) ret.insert(ret.end(), query.readValue()); return ret; } toQList toQuery::readQuery(toConnection &conn, const QString &sql, const QString &arg1, const QString &arg2, const QString &arg3, const QString &arg4, const QString &arg5, const QString &arg6, const QString &arg7, const QString &arg8, const QString &arg9) { toBusy busy; toQuery query(conn, sql, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); toQList ret; while (!query.eof()) ret.insert(ret.end(), query.readValue()); return ret; } toQList toQuery::readQueryNull(toConnection &conn, const toSQL &sql, toQList ¶ms) { toBusy busy; toQuery query(conn, sql, params); toQList ret; while (!query.eof()) ret.insert(ret.end(), query.readValueNull()); return ret; } toQList toQuery::readQueryNull(toConnection &conn, const QString &sql, toQList ¶ms) { toBusy busy; toQuery query(conn, sql, params); toQList ret; while (!query.eof()) ret.insert(ret.end(), query.readValueNull()); return ret; } toQList toQuery::readQueryNull(toConnection &conn, const toSQL &sql, const QString &arg1, const QString &arg2, const QString &arg3, const QString &arg4, const QString &arg5, const QString &arg6, const QString &arg7, const QString &arg8, const QString &arg9) { toBusy busy; toQuery query(conn, sql, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); toQList ret; while (!query.eof()) ret.insert(ret.end(), query.readValueNull()); return ret; } toQList toQuery::readQueryNull(toConnection &conn, const QString &sql, const QString &arg1, const QString &arg2, const QString &arg3, const QString &arg4, const QString &arg5, const QString &arg6, const QString &arg7, const QString &arg8, const QString &arg9) { toBusy busy; toQuery query(conn, sql, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); toQList ret; while (!query.eof()) ret.insert(ret.end(), query.readValueNull()); return ret; } toQValue toQuery::readValue(void) { toBusy busy; if (Connection.Abort) throw qApp->translate("toQuery", "Query aborted"); if (Mode == All) eof(); return toNull(Query->readValue()); } toQValue toQuery::readValueNull(void) { toBusy busy; if (Connection.Abort) throw qApp->translate("toQuery", "Query aborted"); if (Mode == All) eof(); return Query->readValue(); } void toQuery::cancel(void) { Query->cancel(); } // toConnection implementation void toConnection::addConnection(void) { toBusy busy; toConnectionSub *sub = Connection->createConnection(); toLocker lock (Lock) ; Connections.insert(Connections.end(), sub); toQList params; for (std::list::iterator i = InitStrings.begin();i != InitStrings.end();i++) { try { Connection->execute(sub, (*i).utf8(), params); } TOCATCH } } toConnection::toConnection(const QCString &provider, const QString &user, const QString &password, const QString &host, const QString &database, const std::set &options, bool cache) : Provider(provider), User(user), Password(password), Host(host), Database(database), Options(options) { BackgroundConnection = NULL; BackgroundCount = 0; Connection = toConnectionProvider::connection(Provider, this); addConnection(); Version = Connection->version(mainConnection()); NeedCommit = Abort = false; ReadingCache = false; if (cache) { if (toTool::globalConfig(CONF_OBJECT_CACHE, DEFAULT_OBJECT_CACHE).toInt() == 1) readObjects(); } else { ReadingValues.up(); ReadingValues.up(); } } toConnection::toConnection(const toConnection &conn) : Provider(conn.Provider), User(conn.User), Password(conn.Password), Host(conn.Host), Database(conn.Database), Options(conn.Options) { BackgroundConnection = NULL; BackgroundCount = 0; Connection = toConnectionProvider::connection(Provider, this); addConnection(); Version = Connection->version(mainConnection()); ReadingValues.up(); ReadingValues.up(); ReadingCache = false; NeedCommit = Abort = false; } std::list toConnection::running(void) { toBusy busy; toLocker lock (Lock) ; std::list ret; toConnectionSub *sub = (*(Connections.begin())); if (sub && sub->query()) ret.insert(ret.end(), sub->query()->sql()); if (BackgroundConnection && BackgroundConnection->query()) ret.insert(ret.end(), BackgroundConnection->query()->sql()); for (std::list::const_iterator i = Running.begin();i != Running.end();i++) { sub = *i; if (sub && sub->query()) ret.insert(ret.end(), sub->query()->sql()); } return ret; } void toConnection::cancelAll(void) { toBusy busy; toLocker lock (Lock) ; for (std::list::iterator i = Running.begin();i != Running.end();i++) (*i)->cancel(); } toConnection::~toConnection() { toBusy busy; { toLocker lock (Lock) ; for_each(Widgets.begin(), Widgets.end(), DeleteObject()); { for (std::list::iterator i = Running.begin();i != Running.end();i++) try { (*i)->cancel(); } catch (...) {} } } Abort = true; if (ReadingCache) { ReadingValues.down(); ReadingValues.down(); } for (std::list::iterator i = Connections.begin();i != Connections.end();i++) { try { Connection->closeConnection(*i); } catch (...) {} } delete Connection; } toConnectionSub *toConnection::mainConnection() { if (Connection->handleMultipleQueries()) { toLocker lock (Lock) ; return (*(Connections.begin())); } else { return longConnection(); } } toConnectionSub *toConnection::backgroundConnection() { if (!Connection->handleMultipleQueries()) return longConnection(); if (toTool::globalConfig(CONF_BKGND_CONNECT, "").isEmpty()) return mainConnection(); Lock.lock(); if (!BackgroundConnection) { Lock.unlock(); toConnectionSub *tmp = longConnection(); Lock.lock(); BackgroundConnection = tmp; BackgroundCount = 0; } BackgroundCount++; Lock.unlock(); return BackgroundConnection; } toConnectionSub *toConnection::longConnection() { Lock.lock(); bool multiple = Connection->handleMultipleQueries(); if ((multiple && Connections.size() == 1) || (!multiple && Connections.empty())) { Lock.unlock(); addConnection(); } else Lock.unlock(); toLocker lock (Lock) ; std::list::iterator i = Connections.begin(); if (multiple) i++; toConnectionSub *ret = (*i); Connections.erase(i); Running.insert(Running.end(), ret); return ret; } void toConnection::freeConnection(toConnectionSub *sub) { toLocker lock (Lock) ; if (sub == BackgroundConnection) { BackgroundCount--; if (BackgroundCount > 0) return ; BackgroundConnection = NULL; } { for (std::list::iterator i = Running.begin();i != Running.end();i++) { if (*i == sub) { Running.erase(i); break; } } } { for (std::list::iterator i = Connections.begin();i != Connections.end();i++) { if (*i == sub) return ; } } Connections.insert(Connections.end(), sub); } void toConnection::commit(void) { toBusy busy; toLocker lock (Lock) ; for (std::list::iterator i = Connections.begin();i != Connections.end();i++) Connection->commit(*i); while (Connections.size() > 2) { std::list::iterator i = Connections.begin(); i++; delete (*i); Connections.erase(i); } setNeedCommit(false); } void toConnection::rollback(void) { toBusy busy; toLocker lock (Lock) ; for (std::list::iterator i = Connections.begin();i != Connections.end();i++) { Connection->rollback(*i); } while (Connections.size() > 2) { std::list::iterator i = Connections.begin(); i++; delete (*i); Connections.erase(i); } setNeedCommit(false); } void toConnection::delWidget(QObject *widget) { for (std::list::iterator i = Widgets.begin();i != Widgets.end();i++) { if ((*i) == widget) { Widgets.erase(i); break; } } } bool toConnection::closeWidgets(void) { for (std::list::iterator i = Widgets.begin();i != Widgets.end();i = Widgets.begin()) { if ((*i)->inherits("QWidget")) { QWidget * widget = static_cast(*i); if (!widget->close(true)) return false; } else delete *i; std::list::iterator nextI = Widgets.begin(); if (i == nextI) throw qApp->translate("toConnection", "All tool widgets need to have autodelete flag set"); } return true; } QString toConnection::description(bool version) const { QString ret(User); ret += QString::fromLatin1("@"); ret += Database; if (!Host.isEmpty() && Host != "SQL*Net") { ret += QString::fromLatin1("."); ret += Host; } if (version) { if (!Version.isEmpty()) { ret += QString::fromLatin1(" ["); ret += QString::fromLatin1(Version); ret += QString::fromLatin1("]"); } } return ret; } void toConnection::addInit(const QString &sql) { delInit(sql); InitStrings.insert(InitStrings.end(), sql); } void toConnection::delInit(const QString &sql) { std::list::iterator i = InitStrings.begin(); while (i != InitStrings.end()) { if ((*i) == sql) i = InitStrings.erase(i); else i++; } } const std::list toConnection::initStrings() const { return InitStrings; } void toConnection::parse(const QString &sql) { toBusy busy; Connection->parse(mainConnection(), sql.utf8()); } void toConnection::parse(const toSQL &sql) { toBusy busy; Connection->parse(mainConnection(), toSQL::sql(sql, *this)); } void toConnection::execute(const toSQL &sql, toQList ¶ms) { toBusy busy; Connection->execute(mainConnection(), toSQL::sql(sql, *this), params); } void toConnection::execute(const QString &sql, toQList ¶ms) { toBusy busy; Connection->execute(mainConnection(), sql.utf8(), params); } void toConnection::execute(const toSQL &sql, const QString &arg1, const QString &arg2, const QString &arg3, const QString &arg4, const QString &arg5, const QString &arg6, const QString &arg7, const QString &arg8, const QString &arg9) { int numArgs; if (!arg9.isNull()) numArgs = 9; else if (!arg8.isNull()) numArgs = 8; else if (!arg7.isNull()) numArgs = 7; else if (!arg6.isNull()) numArgs = 6; else if (!arg5.isNull()) numArgs = 5; else if (!arg4.isNull()) numArgs = 4; else if (!arg3.isNull()) numArgs = 3; else if (!arg2.isNull()) numArgs = 2; else if (!arg1.isNull()) numArgs = 1; else numArgs = 0; toQList args; if (numArgs > 0) args.insert(args.end(), arg1); if (numArgs > 1) args.insert(args.end(), arg2); if (numArgs > 2) args.insert(args.end(), arg3); if (numArgs > 3) args.insert(args.end(), arg4); if (numArgs > 4) args.insert(args.end(), arg5); if (numArgs > 5) args.insert(args.end(), arg6); if (numArgs > 6) args.insert(args.end(), arg7); if (numArgs > 7) args.insert(args.end(), arg8); if (numArgs > 8) args.insert(args.end(), arg9); toBusy busy; Connection->execute(mainConnection(), toSQL::sql(sql, *this), args); } void toConnection::execute(const QString &sql, const QString &arg1, const QString &arg2, const QString &arg3, const QString &arg4, const QString &arg5, const QString &arg6, const QString &arg7, const QString &arg8, const QString &arg9) { int numArgs; if (!arg9.isNull()) numArgs = 9; else if (!arg8.isNull()) numArgs = 8; else if (!arg7.isNull()) numArgs = 7; else if (!arg6.isNull()) numArgs = 6; else if (!arg5.isNull()) numArgs = 5; else if (!arg4.isNull()) numArgs = 4; else if (!arg3.isNull()) numArgs = 3; else if (!arg2.isNull()) numArgs = 2; else if (!arg1.isNull()) numArgs = 1; else numArgs = 0; toQList args; if (numArgs > 0) args.insert(args.end(), arg1); if (numArgs > 1) args.insert(args.end(), arg2); if (numArgs > 2) args.insert(args.end(), arg3); if (numArgs > 3) args.insert(args.end(), arg4); if (numArgs > 4) args.insert(args.end(), arg5); if (numArgs > 5) args.insert(args.end(), arg6); if (numArgs > 6) args.insert(args.end(), arg7); if (numArgs > 7) args.insert(args.end(), arg8); if (numArgs > 8) args.insert(args.end(), arg9); toBusy busy; Connection->execute(mainConnection(), sql.utf8(), args); } void toConnection::allExecute(const toSQL &sql, toQList ¶ms) { toBusy busy; toLocker lock (Lock) ; for (std::list::iterator i = Connections.begin();i != Connections.end();i++) { try { Connection->execute(*i, toSQL::sql(sql, *this), params); } TOCATCH } } void toConnection::allExecute(const QString &sql, toQList ¶ms) { toBusy busy; toLocker lock (Lock) ; for (std::list::iterator i = Connections.begin();i != Connections.end();i++) { try { Connection->execute(*i, sql.utf8(), params); } TOCATCH } } void toConnection::allExecute(const toSQL &sql, const QString &arg1, const QString &arg2, const QString &arg3, const QString &arg4, const QString &arg5, const QString &arg6, const QString &arg7, const QString &arg8, const QString &arg9) { int numArgs; if (!arg9.isNull()) numArgs = 9; else if (!arg8.isNull()) numArgs = 8; else if (!arg7.isNull()) numArgs = 7; else if (!arg6.isNull()) numArgs = 6; else if (!arg5.isNull()) numArgs = 5; else if (!arg4.isNull()) numArgs = 4; else if (!arg3.isNull()) numArgs = 3; else if (!arg2.isNull()) numArgs = 2; else if (!arg1.isNull()) numArgs = 1; else numArgs = 0; toQList args; if (numArgs > 0) args.insert(args.end(), arg1); if (numArgs > 1) args.insert(args.end(), arg2); if (numArgs > 2) args.insert(args.end(), arg3); if (numArgs > 3) args.insert(args.end(), arg4); if (numArgs > 4) args.insert(args.end(), arg5); if (numArgs > 5) args.insert(args.end(), arg6); if (numArgs > 6) args.insert(args.end(), arg7); if (numArgs > 7) args.insert(args.end(), arg8); if (numArgs > 8) args.insert(args.end(), arg9); toBusy busy; toLocker lock (Lock) ; for (std::list::iterator i = Connections.begin();i != Connections.end();i++) { try { Connection->execute(*i, toSQL::sql(sql, *this), args); } TOCATCH } } void toConnection::allExecute(const QString &sql, const QString &arg1, const QString &arg2, const QString &arg3, const QString &arg4, const QString &arg5, const QString &arg6, const QString &arg7, const QString &arg8, const QString &arg9) { int numArgs; if (!arg9.isNull()) numArgs = 9; else if (!arg8.isNull()) numArgs = 8; else if (!arg7.isNull()) numArgs = 7; else if (!arg6.isNull()) numArgs = 6; else if (!arg5.isNull()) numArgs = 5; else if (!arg4.isNull()) numArgs = 4; else if (!arg3.isNull()) numArgs = 3; else if (!arg2.isNull()) numArgs = 2; else if (!arg1.isNull()) numArgs = 1; else numArgs = 0; toQList args; if (numArgs > 0) args.insert(args.end(), arg1); if (numArgs > 1) args.insert(args.end(), arg2); if (numArgs > 2) args.insert(args.end(), arg3); if (numArgs > 3) args.insert(args.end(), arg4); if (numArgs > 4) args.insert(args.end(), arg5); if (numArgs > 5) args.insert(args.end(), arg6); if (numArgs > 6) args.insert(args.end(), arg7); if (numArgs > 7) args.insert(args.end(), arg8); if (numArgs > 8) args.insert(args.end(), arg9); toBusy busy; toLocker lock (Lock) ; for (std::list::iterator i = Connections.begin();i != Connections.end();i++) { try { Connection->execute(*i, sql.utf8(), args); } TOCATCH } } const QCString &toConnection::provider(void) const { return Provider; } QString toConnection::cacheDir() { QString home = QDir::homeDirPath(); QString dirname = toTool::globalConfig(CONF_CACHE_DIR, ""); if (dirname.isEmpty()) { #ifdef WIN32 if (getenv("TEMP")) dirname = QString(getenv("TEMP")); else #endif dirname = QString(home); #ifdef TOAD dirname += "/.toad_cache"; #else dirname += "/.tora_cache"; #endif } return dirname; } QString toConnection::cacheFile() { QString dbname (description(false).stripWhiteSpace()); return (cacheDir() + "/" + dbname).simplifyWhiteSpace(); } bool toConnection::loadDiskCache() { if (toTool::globalConfig(CONF_CACHE_DISK, DEFAULT_CACHE_DISK).isEmpty()) return false; toConnection::objectName *cur = 0; int objCounter = 0; int synCounter = 0; QString filename = cacheFile(); QFile file(filename); if (!QFile::exists(filename)) return false; QFileInfo fi(file); QDateTime today; if (fi.lastModified().addDays(toTool::globalConfig(CONF_CACHE_TIMEOUT, DEFAULT_CACHE_TIMEOUT).toInt()) < today) return false; /** read in all data */ if (!file.open(IO_ReadOnly)) return false; QString data = file.readAll(); /** build cache lists */ QStringList records = QStringList::split("\x1D", data, true); for ( QStringList::Iterator i = records.begin(); i != records.end(); i++) { objCounter++; QStringList record = QStringList::split("\x1E", (*i), true); QStringList::Iterator rec = record.begin(); cur = new objectName; (*cur).Owner = (*rec); rec++; (*cur).Name = (*rec); rec++; (*cur).Type = (*rec); rec++; (*cur).Comment = (*rec); rec++; QStringList slist = QStringList::split("\x1F", (*rec), false); for (QStringList::Iterator s = slist.begin(); s != slist.end(); s++) { SynonymMap[(*s)] = (*cur); (*cur).Synonyms.insert((*cur).Synonyms.end(), (*s)); synCounter++; } ObjectNames.insert(ObjectNames.end(), (*cur)); delete cur; cur = 0; } return true; } void toConnection::writeDiskCache() { QString text; long objCounter = 0; long synCounter = 0; if (toTool::globalConfig(CONF_CACHE_DISK, DEFAULT_CACHE_DISK).isEmpty()) return ; QString filename(cacheFile()); /** check pathnames and create */ QString dirname(cacheDir()); QDir dir; dir.setPath(dirname); if (!dir.exists(dirname)) dir.mkdir(dirname); /** build record to write out */ QStringList record; QStringList records; QStringList recordSynonym; for (std::list::iterator i = ObjectNames.begin();i != ObjectNames.end();i++) { record.clear(); record.append((*i).Owner); record.append((*i).Name); record.append((*i).Type); record.append((*i).Comment); for (std::list::iterator s = (*i).Synonyms.begin();s != (*i).Synonyms.end();s++) { recordSynonym.append((*s)); synCounter++; } record.append(recordSynonym.join("\x1F")); recordSynonym.clear(); objCounter++; records.append(record.join("\x1E")); } /** open file */ QFile file(filename); file.open( IO_ReadWrite | IO_Truncate ); QTextStream t (&file); t << records.join("\x1D"); file.flush(); file.close(); } void toConnection::cacheObjects::run() { bool diskloaded = false; try { diskloaded = Connection.loadDiskCache(); if (!diskloaded) { Connection.ObjectNames = Connection.Connection->objectNames(); } Connection.ObjectNames.sort(); Connection.ReadingValues.up(); if (!diskloaded) { Connection.SynonymMap = Connection.Connection->synonymMap(Connection.ObjectNames); Connection.writeDiskCache(); } } catch (...) { if (Connection.ReadingValues.getValue() == 0) Connection.ReadingValues.up(); } Connection.ReadingValues.up(); } void toConnection::readObjects(void) { if (toTool::globalConfig(CONF_OBJECT_CACHE, DEFAULT_OBJECT_CACHE).toInt() == 3) { ReadingCache = false; return ; } if (!ReadingCache) { ReadingCache = true; try { (new toThread(new cacheObjects(*this)))->start(); } catch (...) { ReadingCache = false; } } } void toConnection::rereadCache(void) { if (toTool::globalConfig(CONF_OBJECT_CACHE, DEFAULT_OBJECT_CACHE).toInt() == 3) { ColumnCache.clear(); return ; } if (ReadingValues.getValue() < 2 && ReadingCache) { toStatusMessage(qApp->translate("toConnection", "Not done caching objects, can not clear unread cache")); return ; } ReadingCache = false; while (ReadingValues.getValue() > 0) ReadingValues.down(); ObjectNames.clear(); ColumnCache.clear(); SynonymMap.clear(); /** delete cache file to force reload */ QString filename(cacheFile()); if (QFile::exists(filename)) QFile::remove (filename); readObjects(); } QString toConnection::quote(const QString &name) { return Connection->quote(name); } QString toConnection::unQuote(const QString &name) { return Connection->unQuote(name); } bool toConnection::cacheAvailable(bool synonyms, bool block, bool need) { if (toTool::globalConfig(CONF_OBJECT_CACHE, DEFAULT_OBJECT_CACHE).toInt() == 3) return true; if (!ReadingCache) { if (!need) return true; if (toTool::globalConfig(CONF_OBJECT_CACHE, DEFAULT_OBJECT_CACHE).toInt() == 2 && !block) return true; readObjects(); toMainWidget()->checkCaching(); } if (ReadingValues.getValue() == 0 || (ReadingValues.getValue() == 1 && synonyms == true)) { if (block) { toBusy busy; if (toThread::mainThread()) { QProgressDialog waiting(qApp->translate("toConnection", "Waiting for object caching to be completed.\n" "Canceling this dialog will probably leave some list of\n" "database objects empty."), qApp->translate("toConnection", "Cancel"), 10, toMainWidget(), "progress", true); waiting.setCaption(qApp->translate("toConnection", "Waiting for object cache")); int num = 1; int waitVal = (synonyms ? 2 : 1); do { qApp->processEvents(); toThread::msleep(100); waiting.setProgress((++num) % 10); if (waiting.wasCancelled()) return false; } while (ReadingValues.getValue() < waitVal); } ReadingValues.down(); if (synonyms) { ReadingValues.down(); ReadingValues.up(); } ReadingValues.up(); } else return false; } return true; } std::list &toConnection::objects(bool block) { if (!cacheAvailable(false, block)) { toStatusMessage(qApp->translate("toConnection", "Not done caching objects"), false, false); static std::list ret; return ret; } return ObjectNames; } void toConnection::addIfNotExists(toConnection::objectName &obj) { if (!cacheAvailable(true, false)) { toStatusMessage(qApp->translate("toConnection", "Not done caching objects"), false, false); return ; } std::list::iterator i = ObjectNames.begin(); while (i != ObjectNames.end() && (*i) < obj) i++; if (i != ObjectNames.end() && *i == obj) // Already exists, don't add return ; ObjectNames.insert(i, obj); } std::map &toConnection::synonyms(bool block) { if (!cacheAvailable(true, block)) { toStatusMessage(qApp->translate("toConnection", "Not done caching objects"), false, false); static std::map ret; return ret; } return SynonymMap; } const toConnection::objectName &toConnection::realName(const QString &object, QString &synonym, bool block) { if (!cacheAvailable(true, block)) throw qApp->translate("toConnection", "Not done caching objects"); QString name; QString owner; QString q = QString::fromLatin1("\""); QString c = QString::fromLatin1("."); bool quote = false; for (unsigned int pos = 0;pos < object.length();pos++) { if (object.at(pos) == q) { quote = !quote; } else { if (!quote && object.at(pos) == c) { owner = name; name = QString::null; } else name += object.at(pos); } } QString uo = owner.upper(); QString un = name.upper(); synonym = QString::null; for (std::list::iterator i = ObjectNames.begin();i != ObjectNames.end();i++) { if (owner.isEmpty()) { if (((*i).Name == un || (*i).Name == name) && ((*i).Owner == user().upper() || (*i).Owner == database())) return *i; } else if (((*i).Name == un || (*i).Name == name) && ((*i).Owner == uo || (*i).Owner == owner)) return *i; } if (owner.isEmpty()) { std::map::iterator i = SynonymMap.find(name); if (i == SynonymMap.end() && un != name) { i = SynonymMap.find(un); synonym = un; } else synonym = name; if (i != SynonymMap.end()) { return (*i).second; } } throw qApp->translate("toConnection", "Object %1 not available for %2").arg(object).arg(user()); } const toConnection::objectName &toConnection::realName(const QString &object, bool block) { QString dummy; return realName(object, dummy, block); } toQDescList &toConnection::columns(const objectName &object, bool nocache) { std::map::iterator i = ColumnCache.find(object); if (i == ColumnCache.end() || nocache) { ColumnCache[object] = Connection->columnDesc(object); } return ColumnCache[object]; } bool toConnection::objectName::operator < (const objectName &nam) const { if (Owner < nam.Owner || (Owner.isNull() && !nam.Owner.isNull())) return true; if (Owner > nam.Owner || (!Owner.isNull() && nam.Owner.isNull())) return false; if (Name < nam.Name || (Name.isNull() && !nam.Name.isNull())) return true; if (Name > nam.Name || (!Name.isNull() && nam.Name.isNull())) return false; if (Type < nam.Type) return true; return false; } bool toConnection::objectName::operator == (const objectName &nam) const { return Owner == nam.Owner && Name == nam.Name && Type == nam.Type; } toSyntaxAnalyzer &toConnection::connectionImpl::analyzer() { return toSyntaxAnalyzer::defaultAnalyzer(); } toSyntaxAnalyzer &toConnection::analyzer() { return Connection->analyzer(); } std::list toConnection::connectionImpl::objectNames(void) { std::list ret; return ret; } std::map toConnection::connectionImpl::synonymMap(std::list &) { std::map ret; return ret; } toQDescList toConnection::connectionImpl::columnDesc(const objectName &) { toQDescList ret; return ret; } void toConnection::connectionImpl::parse(toConnectionSub *, const QCString &) { throw qApp->translate("toConnection", "Parse only not implemented for this type of connection"); }