00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <kexidb/connection.h>
00021
00022 #include "error.h"
00023 #include "connection_p.h"
00024 #include "connectiondata.h"
00025 #include "driver.h"
00026 #include "driver_p.h"
00027 #include "schemadata.h"
00028 #include "tableschema.h"
00029 #include "relationship.h"
00030 #include "transaction.h"
00031 #include "cursor.h"
00032 #include "global.h"
00033 #include "roweditbuffer.h"
00034 #include "utils.h"
00035 #include "dbproperties.h"
00036 #include "parser/parser.h"
00037
00038 #include <kexiutils/utils.h>
00039 #include <kexiutils/identifier.h>
00040
00041 #include <qdir.h>
00042 #include <qfileinfo.h>
00043 #include <qguardedptr.h>
00044
00045 #include <klocale.h>
00046 #include <kdebug.h>
00047
00048 namespace KexiDB {
00049
00050 ConnectionInternal::ConnectionInternal(Connection *conn)
00051 : connection(conn)
00052 {
00053 }
00054
00055 ConnectionInternal::~ConnectionInternal()
00056 {
00057 }
00058
00059
00061 class ConnectionPrivate
00062 {
00063 public:
00064 ConnectionPrivate(Connection *conn)
00065 : conn(conn)
00066 , tableSchemaChangeListeners(101)
00067 , versionMajor(-1)
00068 , versionMinor(-1)
00069 , m_parser(0)
00070 , dont_remove_transactions(false)
00071 , skip_databaseExists_check_in_useDatabase(false)
00072 , default_trans_started_inside(false)
00073 , isConnected(false)
00074 , autoCommit(true)
00075 {
00076 tableSchemaChangeListeners.setAutoDelete(true);
00077 obsoleteQueries.setAutoDelete(true);
00078 }
00079 ~ConnectionPrivate()
00080 {
00081 delete m_parser;
00082 }
00083
00084 void errorInvalidDBContents(const QString& details) {
00085 conn->setError( ERR_INVALID_DATABASE_CONTENTS, i18n("Invalid database contents. ")+details);
00086 }
00087
00088 QString strItIsASystemObject() const {
00089 return i18n("It is a system object.");
00090 }
00091
00092 inline Parser *parser() { return m_parser ? m_parser : (m_parser = new Parser(conn)); }
00093
00094 Connection *conn;
00095
00100 Transaction default_trans;
00101 QValueList<Transaction> transactions;
00102
00103 QPtrDict< QPtrList<Connection::TableSchemaChangeListenerInterface> > tableSchemaChangeListeners;
00104
00107 QPtrList<QuerySchema> obsoleteQueries;
00108
00110 int versionMajor;
00111 int versionMinor;
00112
00113 Parser *m_parser;
00114
00116 DatabaseProperties* dbProperties;
00117
00118 QString availableDatabaseName;
00119
00122 bool dont_remove_transactions : 1;
00123
00126 bool skip_databaseExists_check_in_useDatabase : 1;
00127
00136 bool default_trans_started_inside : 1;
00137
00138 bool isConnected : 1;
00139
00140 bool autoCommit : 1;
00141
00143 bool readOnly : 1;
00144 };
00145
00146 }
00147
00148
00149 using namespace KexiDB;
00150
00152 QStringList KexiDB_kexiDBSystemTableNames;
00153
00154 Connection::Connection( Driver *driver, ConnectionData &conn_data )
00155 : QObject()
00156 ,KexiDB::Object()
00157 ,m_data(&conn_data)
00158 ,m_tables_byname(101, false)
00159 ,m_queries_byname(101, false)
00160 ,m_kexiDBSystemTables(101)
00161 ,d(new ConnectionPrivate(this))
00162 ,m_driver(driver)
00163 ,m_destructor_started(false)
00164 {
00165 d->dbProperties = new DatabaseProperties(this);
00166 m_tables.setAutoDelete(true);
00167 m_tables_byname.setAutoDelete(false);
00168 m_kexiDBSystemTables.setAutoDelete(true);
00169 m_queries.setAutoDelete(true);
00170 m_queries_byname.setAutoDelete(false);
00171 m_cursors.setAutoDelete(true);
00172
00173
00174 m_tables.resize(101);
00175 m_queries.resize(101);
00176 m_cursors.resize(101);
00177
00178 m_sql.reserve(0x4000);
00179 }
00180
00181 void Connection::destroy()
00182 {
00183 disconnect();
00184
00185 m_driver->d->connections.take( this );
00186 }
00187
00188 Connection::~Connection()
00189 {
00190 m_destructor_started = true;
00191
00192 delete d->dbProperties;
00193 delete d;
00194 d = 0;
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205 }
00206
00207 bool Connection::connect()
00208 {
00209 clearError();
00210 if (d->isConnected) {
00211 setError(ERR_ALREADY_CONNECTED, i18n("Connection already established.") );
00212 return false;
00213 }
00214
00215 if (!(d->isConnected = drv_connect())) {
00216 setError(m_driver->isFileDriver() ?
00217 i18n("Could not open \"%1\" project file.").arg(QDir::convertSeparators(m_data->fileName()))
00218 : i18n("Could not connect to \"%1\" database server.").arg(m_data->serverInfoString()) );
00219 }
00220 return d->isConnected;
00221 }
00222
00223 bool Connection::isDatabaseUsed() const
00224 {
00225 return !m_usedDatabase.isEmpty() && d->isConnected && drv_isDatabaseUsed();
00226 }
00227
00228 void Connection::clearError()
00229 {
00230 Object::clearError();
00231 m_sql = QString::null;
00232 }
00233
00234 bool Connection::disconnect()
00235 {
00236 clearError();
00237 if (!d->isConnected)
00238 return true;
00239
00240 if (!closeDatabase())
00241 return false;
00242
00243 bool ok = drv_disconnect();
00244 if (ok)
00245 d->isConnected = false;
00246 return ok;
00247 }
00248
00249 bool Connection::isConnected() const
00250 {
00251 return d->isConnected;
00252 }
00253
00254 bool Connection::checkConnected()
00255 {
00256 if (d->isConnected) {
00257 clearError();
00258 return true;
00259 }
00260 setError(ERR_NO_CONNECTION, i18n("Not connected to the database server.") );
00261 return false;
00262 }
00263
00264 bool Connection::checkIsDatabaseUsed()
00265 {
00266 if (isDatabaseUsed()) {
00267 clearError();
00268 return true;
00269 }
00270 setError(ERR_NO_DB_USED, i18n("Currently no database is used.") );
00271 return false;
00272 }
00273
00274 QStringList Connection::databaseNames(bool also_system_db)
00275 {
00276 KexiDBDbg << "Connection::databaseNames("<<also_system_db<<")"<< endl;
00277 if (!checkConnected())
00278 return QStringList();
00279
00280 QString tmpdbName;
00281
00282 if (!useTemporaryDatabaseIfNeeded(tmpdbName))
00283 return QStringList();
00284
00285 QStringList list, non_system_list;
00286
00287 bool ret = drv_getDatabasesList( list );
00288
00289 if (!tmpdbName.isEmpty()) {
00290
00291 if (!closeDatabase())
00292 return QStringList();
00293 }
00294
00295 if (!ret)
00296 return QStringList();
00297
00298 if (also_system_db)
00299 return list;
00300
00301 for (QStringList::ConstIterator it = list.constBegin(); it!=list.constEnd(); ++it) {
00302 KexiDBDbg << "Connection::databaseNames(): " << *it << endl;
00303 if (!m_driver->isSystemDatabaseName(*it)) {
00304 KexiDBDbg << "add " << *it << endl;
00305 non_system_list << (*it);
00306 }
00307 }
00308 return non_system_list;
00309 }
00310
00311 bool Connection::drv_getDatabasesList( QStringList &list )
00312 {
00313 list.clear();
00314 return true;
00315 }
00316
00317 bool Connection::drv_databaseExists( const QString &dbName, bool ignoreErrors )
00318 {
00319 QStringList list = databaseNames(true);
00320 if (error()) {
00321 return false;
00322 }
00323
00324 if (list.find( dbName )==list.end()) {
00325 if (!ignoreErrors)
00326 setError(ERR_OBJECT_NOT_FOUND, i18n("The database \"%1\" does not exist.").arg(dbName));
00327 return false;
00328 }
00329
00330 return true;
00331 }
00332
00333 bool Connection::databaseExists( const QString &dbName, bool ignoreErrors )
00334 {
00335
00336 if (!checkConnected())
00337 return false;
00338 clearError();
00339
00340 if (m_driver->isFileDriver()) {
00341
00342
00343 QFileInfo file(dbName);
00344 if (!file.exists() || ( !file.isFile() && !file.isSymLink()) ) {
00345 if (!ignoreErrors)
00346 setError(ERR_OBJECT_NOT_FOUND, i18n("Database file \"%1\" does not exist.")
00347 .arg(QDir::convertSeparators(m_data->fileName())) );
00348 return false;
00349 }
00350 if (!file.isReadable()) {
00351 if (!ignoreErrors)
00352 setError(ERR_ACCESS_RIGHTS, i18n("Database file \"%1\" is not readable.")
00353 .arg(QDir::convertSeparators(m_data->fileName())) );
00354 return false;
00355 }
00356 if (!file.isWritable()) {
00357 if (!ignoreErrors)
00358 setError(ERR_ACCESS_RIGHTS, i18n("Database file \"%1\" is not writable.")
00359 .arg(QDir::convertSeparators(m_data->fileName())) );
00360 return false;
00361 }
00362 return true;
00363 }
00364
00365 QString tmpdbName;
00366
00367 const bool orig_skip_databaseExists_check_in_useDatabase = d->skip_databaseExists_check_in_useDatabase;
00368 d->skip_databaseExists_check_in_useDatabase = true;
00369 bool ret = useTemporaryDatabaseIfNeeded(tmpdbName);
00370 d->skip_databaseExists_check_in_useDatabase = orig_skip_databaseExists_check_in_useDatabase;
00371 if (!ret)
00372 return false;
00373
00374 ret = drv_databaseExists(dbName, ignoreErrors);
00375
00376 if (!tmpdbName.isEmpty()) {
00377
00378 if (!closeDatabase())
00379 return false;
00380 }
00381
00382 return ret;
00383 }
00384
00385 #define createDatabase_CLOSE \
00386 { if (!closeDatabase()) { \
00387 setError(i18n("Database \"%1\" created but could not be closed after creation.").arg(dbName) ); \
00388 return false; \
00389 } }
00390
00391 #define createDatabase_ERROR \
00392 { createDatabase_CLOSE; return false; }
00393
00394
00395 bool Connection::createDatabase( const QString &dbName )
00396 {
00397 if (!checkConnected())
00398 return false;
00399
00400 if (databaseExists( dbName )) {
00401 setError(ERR_OBJECT_EXISTS, i18n("Database \"%1\" already exists.").arg(dbName) );
00402 return false;
00403 }
00404 if (m_driver->isSystemDatabaseName( dbName )) {
00405 setError(ERR_SYSTEM_NAME_RESERVED,
00406 i18n("Cannot create database \"%1\". This name is reserved for system database.").arg(dbName) );
00407 return false;
00408 }
00409 if (m_driver->isFileDriver()) {
00410
00411 m_data->setFileName( dbName );
00412 }
00413
00414 QString tmpdbName;
00415
00416 if (!useTemporaryDatabaseIfNeeded(tmpdbName))
00417 return false;
00418
00419
00420 if (!drv_createDatabase( dbName )) {
00421 setError(i18n("Error creating database \"%1\" on the server.").arg(dbName) );
00422 closeDatabase();
00423 return false;
00424 }
00425
00426 if (!tmpdbName.isEmpty()) {
00427
00428 if (!closeDatabase())
00429 return false;
00430 }
00431
00432 if (!tmpdbName.isEmpty() || !m_driver->d->isDBOpenedAfterCreate) {
00433
00434 if (!useDatabase( dbName, false )) {
00435 setError(i18n("Database \"%1\" created but could not be opened.").arg(dbName) );
00436 return false;
00437 }
00438 }
00439 else {
00440
00441 m_usedDatabase = dbName;
00442 }
00443
00444 Transaction trans;
00445 if (m_driver->transactionsSupported()) {
00446 trans = beginTransaction();
00447 if (!trans.active())
00448 return false;
00449 }
00450
00451
00452
00453
00454
00455 if (!setupKexiDBSystemSchema())
00456 return false;
00457
00458
00459 for (QPtrDictIterator<TableSchema> it(m_kexiDBSystemTables); it.current(); ++it) {
00460 if (!drv_createTable( it.current()->name() ))
00461 createDatabase_ERROR;
00462 }
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480 TableSchema *t_db = tableSchema("kexi__db");
00481 if (!t_db)
00482 createDatabase_ERROR;
00483 if ( !insertRecord(*t_db, "kexidb_major_ver", KexiDB::versionMajor())
00484 || !insertRecord(*t_db, "kexidb_minor_ver", KexiDB::versionMinor()))
00485 createDatabase_ERROR;
00486
00487 if (trans.active() && !commitTransaction(trans))
00488 createDatabase_ERROR;
00489
00490 createDatabase_CLOSE;
00491 return true;
00492 }
00493
00494 #undef createDatabase_CLOSE
00495 #undef createDatabase_ERROR
00496
00497 bool Connection::useDatabase( const QString &dbName, bool kexiCompatible, bool *cancelled, MessageHandler* msgHandler )
00498 {
00499 if (cancelled)
00500 *cancelled = false;
00501 KexiDBDbg << "Connection::useDatabase(" << dbName << "," << kexiCompatible <<")" << endl;
00502 if (!checkConnected())
00503 return false;
00504
00505 if (dbName.isEmpty())
00506 return false;
00507 QString my_dbName = dbName;
00508
00509
00510
00511
00512
00513 if (m_usedDatabase == my_dbName)
00514 return true;
00515
00516 if (!d->skip_databaseExists_check_in_useDatabase) {
00517 if (!databaseExists(my_dbName, false ))
00518 return false;
00519 }
00520
00521 if (!m_usedDatabase.isEmpty() && !closeDatabase())
00522 return false;
00523
00524 m_usedDatabase = "";
00525
00526 if (!drv_useDatabase( my_dbName, cancelled, msgHandler )) {
00527 if (cancelled && *cancelled)
00528 return false;
00529 QString msg(i18n("Opening database \"%1\" failed.").arg( my_dbName ));
00530 if (error())
00531 setError( this, msg );
00532 else
00533 setError( msg );
00534 return false;
00535 }
00536
00537
00538 if (!setupKexiDBSystemSchema())
00539 return false;
00540
00541 if (kexiCompatible && my_dbName.lower()!=anyAvailableDatabaseName().lower()) {
00542
00543 int num;
00544 bool ok;
00545
00546 num = d->dbProperties->value("kexidb_major_ver").toInt(&ok);
00547 if (!ok)
00548 return false;
00549 d->versionMajor = num;
00550
00551
00552
00553
00554
00555 num = d->dbProperties->value("kexidb_minor_ver").toInt(&ok);
00556 if (!ok)
00557 return false;
00558 d->versionMinor = num;
00559
00560
00561
00562
00563
00564
00565
00566 if (m_driver->versionMajor()!=KexiDB::versionMajor()) {
00567 setError(ERR_INCOMPAT_DATABASE_VERSION,
00568 i18n("Database version (%1) does not match Kexi application's version (%2)")
00569 .arg( QString("%1.%2").arg(versionMajor()).arg(versionMinor()) )
00570 .arg( QString("%1.%2").arg(KexiDB::versionMajor()).arg(KexiDB::versionMinor()) ) );
00571 return false;
00572 }
00573 if (m_driver->versionMinor()!=KexiDB::versionMinor()) {
00574
00575
00576 }
00577 }
00578 m_usedDatabase = my_dbName;
00579 return true;
00580 }
00581
00582 bool Connection::closeDatabase()
00583 {
00584 if (m_usedDatabase.isEmpty())
00585 return true;
00586 if (!checkConnected())
00587 return true;
00588
00589 bool ret = true;
00590
00592 if (m_driver->transactionsSupported()) {
00593
00594 QValueList<Transaction>::ConstIterator it;
00595 d->dont_remove_transactions=true;
00596 for (it=d->transactions.constBegin(); it!= d->transactions.constEnd(); ++it) {
00597 if (!rollbackTransaction(*it)) {
00598 ret = false;
00599 }
00600 else {
00601 KexiDBDbg << "Connection::closeDatabase(): transaction rolled back!" << endl;
00602 KexiDBDbg << "Connection::closeDatabase(): trans.refcount==" <<
00603 ((*it).m_data ? QString::number((*it).m_data->refcount) : "(null)") << endl;
00604 }
00605 }
00606 d->dont_remove_transactions=false;
00607 d->transactions.clear();
00608 }
00609
00610
00611 m_cursors.clear();
00612
00613 m_tables.clear();
00614 m_kexiDBSystemTables.clear();
00615 m_queries.clear();
00616
00617 if (!drv_closeDatabase())
00618 return false;
00619
00620 m_usedDatabase = "";
00621
00622 return ret;
00623 }
00624
00625 bool Connection::useTemporaryDatabaseIfNeeded(QString &tmpdbName)
00626 {
00627 if (!m_driver->isFileDriver() && m_driver->beh->USING_DATABASE_REQUIRED_TO_CONNECT
00628 && !isDatabaseUsed()) {
00629
00630 tmpdbName = anyAvailableDatabaseName();
00631 if (tmpdbName.isEmpty()) {
00632 setError(ERR_NO_DB_USED, i18n("Cannot find any database for temporary connection.") );
00633 return false;
00634 }
00635 const bool orig_skip_databaseExists_check_in_useDatabase = d->skip_databaseExists_check_in_useDatabase;
00636 d->skip_databaseExists_check_in_useDatabase = true;
00637 bool ret = useDatabase(tmpdbName, false);
00638 d->skip_databaseExists_check_in_useDatabase = orig_skip_databaseExists_check_in_useDatabase;
00639 if (!ret) {
00640 setError(errorNum(),
00641 i18n("Error during starting temporary connection using \"%1\" database name.")
00642 .arg(tmpdbName) );
00643 return false;
00644 }
00645 }
00646 return true;
00647 }
00648
00649 bool Connection::dropDatabase( const QString &dbName )
00650 {
00651 if (!checkConnected())
00652 return false;
00653
00654 QString dbToDrop;
00655 if (dbName.isEmpty() && m_usedDatabase.isEmpty()) {
00656 if (!m_driver->isFileDriver()
00657 || (m_driver->isFileDriver() && m_data->fileName().isEmpty()) ) {
00658 setError(ERR_NO_NAME_SPECIFIED, i18n("Cannot drop database - name not specified.") );
00659 return false;
00660 }
00661
00662 dbToDrop = m_data->fileName();
00663 }
00664 else {
00665 if (dbName.isEmpty()) {
00666 dbToDrop = m_usedDatabase;
00667 } else {
00668 if (m_driver->isFileDriver())
00669 dbToDrop = QFileInfo(dbName).absFilePath();
00670 else
00671 dbToDrop = dbName;
00672 }
00673 }
00674
00675 if (dbToDrop.isEmpty()) {
00676 setError(ERR_NO_NAME_SPECIFIED, i18n("Cannot delete database - name not specified.") );
00677 return false;
00678 }
00679
00680 if (m_driver->isSystemDatabaseName( dbToDrop )) {
00681 setError(ERR_SYSTEM_NAME_RESERVED, i18n("Cannot delete system database \"%1\".").arg(dbToDrop) );
00682 return false;
00683 }
00684
00685 if (isDatabaseUsed() && m_usedDatabase == dbToDrop) {
00686
00687 if (!closeDatabase())
00688 return false;
00689 }
00690
00691 QString tmpdbName;
00692
00693 if (!useTemporaryDatabaseIfNeeded(tmpdbName))
00694 return false;
00695
00696
00697 bool ret = drv_dropDatabase( dbToDrop );
00698
00699 if (!tmpdbName.isEmpty()) {
00700
00701 if (!closeDatabase())
00702 return false;
00703 }
00704 return ret;
00705 }
00706
00707 QStringList Connection::objectNames(int objType, bool* ok)
00708 {
00709 QStringList list;
00710
00711 if (!checkIsDatabaseUsed()) {
00712 if(ok)
00713 *ok = false;
00714 return list;
00715 }
00716
00717 QString sql;
00718 if (objType==KexiDB::AnyObjectType)
00719 sql = "SELECT o_name FROM kexi__objects";
00720 else
00721 sql = QString::fromLatin1("SELECT o_name FROM kexi__objects WHERE o_type=%1").arg(objType);
00722
00723 Cursor *c = executeQuery(sql);
00724 if (!c) {
00725 if(ok)
00726 *ok = false;
00727 return list;
00728 }
00729
00730 for (c->moveFirst(); !c->eof(); c->moveNext()) {
00731 QString name = c->value(0).toString();
00732 if (KexiUtils::isIdentifier( name )) {
00733 list.append(name);
00734 }
00735 }
00736
00737 if (!deleteCursor(c)) {
00738 if(ok)
00739 *ok = false;
00740 return list;
00741 }
00742
00743 if(ok)
00744 *ok = true;
00745 return list;
00746 }
00747
00748 QStringList Connection::tableNames(bool also_system_tables)
00749 {
00750 bool ok = true;
00751 QStringList list = objectNames(TableObjectType, &ok);
00752 if (also_system_tables && ok) {
00753 list += Connection::kexiDBSystemTableNames();
00754 }
00755 return list;
00756 }
00757
00759 const QStringList& Connection::kexiDBSystemTableNames()
00760 {
00761 if (KexiDB_kexiDBSystemTableNames.isEmpty()) {
00762 KexiDB_kexiDBSystemTableNames
00763 << "kexi__objects"
00764 << "kexi__objectdata"
00765 << "kexi__fields"
00766
00767
00768
00769 << "kexi__db"
00770 ;
00771 }
00772 return KexiDB_kexiDBSystemTableNames;
00773 }
00774
00775 int Connection::versionMajor() const
00776 {
00777 return d->versionMinor;
00778 }
00779
00780 int Connection::versionMinor() const
00781 {
00782 return d->versionMinor;
00783 }
00784
00785 DatabaseProperties& Connection::databaseProperties()
00786 {
00787 return *d->dbProperties;
00788 }
00789
00790 QValueList<int> Connection::queryIds()
00791 {
00792 return objectIds(KexiDB::QueryObjectType);
00793 }
00794
00795 QValueList<int> Connection::objectIds(int objType)
00796 {
00797 QValueList<int> list;
00798
00799 if (!checkIsDatabaseUsed())
00800 return list;
00801
00802 Cursor *c = executeQuery(
00803 QString::fromLatin1("SELECT o_id, o_name FROM kexi__objects WHERE o_type=%1").arg(objType));
00804 if (!c)
00805 return list;
00806 for (c->moveFirst(); !c->eof(); c->moveNext())
00807 {
00808 QString tname = c->value(1).toString();
00809 if (KexiUtils::isIdentifier( tname )) {
00810 list.append(c->value(0).toInt());
00811 }
00812 }
00813
00814 deleteCursor(c);
00815
00816 return list;
00817 }
00818
00819 QString Connection::createTableStatement( const KexiDB::TableSchema& tableSchema ) const
00820 {
00821
00822 QString sql;
00823 sql.reserve(4096);
00824 sql = "CREATE TABLE " + escapeIdentifier(tableSchema.name()) + " (";
00825 bool first=true;
00826 Field::ListIterator it( tableSchema.m_fields );
00827 Field *field;
00828 for (;(field = it.current())!=0; ++it) {
00829 if (first)
00830 first = false;
00831 else
00832 sql += ", ";
00833 QString v = escapeIdentifier(field->name()) + " ";
00834 const bool autoinc = field->isAutoIncrement();
00835 const bool pk = field->isPrimaryKey() || (autoinc && m_driver->beh->AUTO_INCREMENT_REQUIRES_PK);
00836
00837 if (autoinc && m_driver->beh->SPECIAL_AUTO_INCREMENT_DEF) {
00838 if (pk)
00839 v += m_driver->beh->AUTO_INCREMENT_TYPE + " " + m_driver->beh->AUTO_INCREMENT_PK_FIELD_OPTION;
00840 else
00841 v += m_driver->beh->AUTO_INCREMENT_TYPE + " " + m_driver->beh->AUTO_INCREMENT_FIELD_OPTION;
00842 }
00843 else {
00844 if (autoinc && !m_driver->beh->AUTO_INCREMENT_TYPE.isEmpty())
00845 v += m_driver->beh->AUTO_INCREMENT_TYPE;
00846 else
00847 v += m_driver->sqlTypeName(field->type(), field->precision());
00848
00849 if (field->isUnsigned())
00850 v += (" " + m_driver->beh->UNSIGNED_TYPE_KEYWORD);
00851
00852 if (field->isFPNumericType() && field->precision()>0) {
00853 if (field->scale()>0)
00854 v += QString::fromLatin1("(%1,%2)").arg(field->precision()).arg(field->scale());
00855 else
00856 v += QString::fromLatin1("(%1)").arg(field->precision());
00857 }
00858 else if (field->type()==Field::Text && field->length()>0)
00859 v += QString::fromLatin1("(%1)").arg(field->length());
00860
00861 if (autoinc)
00862 v += (" " +
00863 (pk ? m_driver->beh->AUTO_INCREMENT_PK_FIELD_OPTION : m_driver->beh->AUTO_INCREMENT_FIELD_OPTION));
00864 else
00865
00866 if (pk)
00867 v += " PRIMARY KEY";
00868 if (!pk && field->isUniqueKey())
00869 v += " UNIQUE";
00871 if (!autoinc && !pk && field->isNotNull())
00872 v += " NOT NULL";
00873 if (field->defaultValue().isValid())
00874 v += QString::fromLatin1(" DEFAULT ") + m_driver->valueToSQL( field, field->defaultValue() );
00875 }
00876 sql += v;
00877 }
00878 sql += ")";
00879 return sql;
00880 }
00881
00882
00883 #define C_A(a) , const QVariant& c ## a
00884
00885 #define V_A0 m_driver->valueToSQL( tableSchema.field(0), c0 )
00886 #define V_A(a) +","+m_driver->valueToSQL( \
00887 tableSchema.field(a) ? tableSchema.field(a)->type() : Field::Text, c ## a )
00888
00889
00890
00891
00892
00893 #define C_INS_REC(args, vals) \
00894 bool Connection::insertRecord(KexiDB::TableSchema &tableSchema args) {\
00895 return executeSQL( \
00896 QString("INSERT INTO ") + escapeIdentifier(tableSchema.name()) + " VALUES (" + vals + ")" \
00897 ); \
00898 }
00899
00900 #define C_INS_REC_ALL \
00901 C_INS_REC( C_A(0), V_A0 ) \
00902 C_INS_REC( C_A(0) C_A(1), V_A0 V_A(1) ) \
00903 C_INS_REC( C_A(0) C_A(1) C_A(2), V_A0 V_A(1) V_A(2) ) \
00904 C_INS_REC( C_A(0) C_A(1) C_A(2) C_A(3), V_A0 V_A(1) V_A(2) V_A(3) ) \
00905 C_INS_REC( C_A(0) C_A(1) C_A(2) C_A(3) C_A(4), V_A0 V_A(1) V_A(2) V_A(3) V_A(4) ) \
00906 C_INS_REC( C_A(0) C_A(1) C_A(2) C_A(3) C_A(4) C_A(5), V_A0 V_A(1) V_A(2) V_A(3) V_A(4) V_A(5) ) \
00907 C_INS_REC( C_A(0) C_A(1) C_A(2) C_A(3) C_A(4) C_A(5) C_A(6), V_A0 V_A(1) V_A(2) V_A(3) V_A(4) V_A(5) V_A(6) ) \
00908 C_INS_REC( C_A(0) C_A(1) C_A(2) C_A(3) C_A(4) C_A(5) C_A(6) C_A(7), V_A0 V_A(1) V_A(2) V_A(3) V_A(4) V_A(5) V_A(6) V_A(7) )
00909
00910 C_INS_REC_ALL
00911
00912 #undef V_A0
00913 #undef V_A
00914 #undef C_INS_REC
00915
00916 #define V_A0 value += m_driver->valueToSQL( flist->first(), c0 );
00917 #define V_A( a ) value += ("," + m_driver->valueToSQL( flist->next(), c ## a ));
00918
00919
00920
00921 #define C_INS_REC(args, vals) \
00922 bool Connection::insertRecord(FieldList& fields args) \
00923 { \
00924 QString value; \
00925 Field::List *flist = fields.fields(); \
00926 vals \
00927 return executeSQL( \
00928 QString("INSERT INTO ") + \
00929 ((fields.fields()->first() && fields.fields()->first()->table()) ? \
00930 escapeIdentifier(fields.fields()->first()->table()->name()) : \
00931 "??") \
00932 + "(" + fields.sqlFieldsList(m_driver) + ") VALUES (" + value + ")" \
00933 ); \
00934 }
00935
00936 C_INS_REC_ALL
00937
00938 #undef C_A
00939 #undef V_A
00940 #undef V_ALAST
00941 #undef C_INS_REC
00942 #undef C_INS_REC_ALL
00943
00944 bool Connection::insertRecord(TableSchema &tableSchema, QValueList<QVariant>& values)
00945 {
00946
00947 Field::List *fields = tableSchema.fields();
00948 Field *f = fields->first();
00949
00950
00951 m_sql = QString::null;
00952 QValueList<QVariant>::ConstIterator it = values.constBegin();
00953
00954 while (f && (it!=values.end())) {
00955 if (m_sql.isEmpty())
00956 m_sql = QString("INSERT INTO ") +
00957 escapeIdentifier(tableSchema.name()) +
00958 " VALUES (";
00959 else
00960 m_sql += ",";
00961 m_sql += m_driver->valueToSQL( f, *it );
00962
00963 ++it;
00964 f=fields->next();
00965 }
00966 m_sql += ")";
00967
00968
00969 return executeSQL(m_sql);
00970 }
00971
00972 bool Connection::insertRecord(FieldList& fields, QValueList<QVariant>& values)
00973 {
00974
00975 Field::List *flist = fields.fields();
00976 Field *f = flist->first();
00977 if (!f)
00978 return false;
00979
00980
00981 m_sql = QString::null;
00982 QValueList<QVariant>::ConstIterator it = values.constBegin();
00983
00984 while (f && (it!=values.constEnd())) {
00985 if (m_sql.isEmpty())
00986 m_sql = QString("INSERT INTO ") +
00987 escapeIdentifier(flist->first()->table()->name()) + "(" +
00988 fields.sqlFieldsList(m_driver) + ") VALUES (";
00989 else
00990 m_sql += ",";
00991 m_sql += m_driver->valueToSQL( f, *it );
00992
00993 ++it;
00994 f=flist->next();
00995 }
00996 m_sql += ")";
00997
00998 return executeSQL(m_sql);
00999 }
01000
01001 bool Connection::executeSQL( const QString& statement )
01002 {
01003 m_sql = statement;
01004 if (!drv_executeSQL( m_sql )) {
01005 m_errMsg = QString::null;
01006 m_errorSql = statement;
01007 setError(this, ERR_SQL_EXECUTION_ERROR, i18n("Error while executing SQL statement."));
01008 return false;
01009 }
01010 return true;
01011 }
01012
01013 QString Connection::selectStatement( KexiDB::QuerySchema& querySchema,
01014 bool alsoRetrieveROWID, int drvEscaping) const
01015 {
01016
01017
01018
01019
01020
01021 if (!querySchema.statement().isEmpty())
01022 return querySchema.statement();
01023
01026 const bool singleTable = querySchema.tables()->count() <= 1;
01027
01028 QString sql;
01029 sql.reserve(4096);
01030
01031 uint number = 0;
01032
01033 Field *f;
01034 for (Field::ListIterator it = querySchema.fieldsIterator(); (f = it.current()); ++it, number++) {
01035 if (querySchema.isColumnVisible(number)) {
01036 if (!sql.isEmpty())
01037 sql += QString::fromLatin1(", ");
01038
01039 if (f->isQueryAsterisk()) {
01040 if (!singleTable && static_cast<QueryAsterisk*>(f)->isSingleTableAsterisk())
01041 sql += escapeIdentifier(f->table()->name(), drvEscaping) +
01042 QString::fromLatin1(".*");
01043 else
01044 sql += QString::fromLatin1("*");
01045 }
01046 else {
01047 if (f->isExpression()) {
01048 sql += f->expression()->toString();
01049 }
01050 else {
01051 if (!f->table())
01052 return QString::null;
01053
01054 QString tableName;
01055 int tablePosition = querySchema.tableBoundToColumn(number);
01056 if (tablePosition>=0)
01057 tableName = querySchema.tableAlias(tablePosition);
01058 if (tableName.isEmpty())
01059 tableName = f->table()->name();
01060
01061 if (!singleTable) {
01062 sql += (escapeIdentifier(tableName, drvEscaping) + ".");
01063 }
01064 sql += escapeIdentifier(f->name(), drvEscaping);
01065 }
01066 QString aliasString = QString(querySchema.columnAlias(number));
01067 if (!aliasString.isEmpty())
01068 sql += (QString::fromLatin1(" AS ") + aliasString);
01070 }
01071 }
01072 }
01073 if (alsoRetrieveROWID) {
01074 QString s;
01075 if (!sql.isEmpty())
01076 s = QString::fromLatin1(", ");
01077 if (querySchema.masterTable())
01078 s += (escapeIdentifier(querySchema.masterTable()->name())+".");
01079 s += m_driver->beh->ROW_ID_FIELD_NAME;
01080 sql += s;
01081 }
01082 sql.prepend("SELECT ");
01083 TableSchema::List* tables = querySchema.tables();
01084 if (tables && !tables->isEmpty()) {
01085 sql += QString::fromLatin1(" FROM ");
01086 QString s_from;
01087 TableSchema *table;
01088 number = 0;
01089 for (TableSchema::ListIterator it(*tables); (table = it.current());
01090 ++it, number++)
01091 {
01092 if (!s_from.isEmpty())
01093 s_from += QString::fromLatin1(", ");
01094 s_from += escapeIdentifier(table->name(), drvEscaping);
01095 QString aliasString = QString(querySchema.tableAlias(number));
01096 if (!aliasString.isEmpty())
01097 s_from += (QString::fromLatin1(" AS ") + aliasString);
01098 }
01099 sql += s_from;
01100 }
01101 QString s_where;
01102 s_where.reserve(4096);
01103
01104
01105
01106 Relationship *rel;
01107 bool wasWhere = false;
01108 for (Relationship::ListIterator it(*querySchema.relationships()); (rel = it.current()); ++it) {
01109 if (s_where.isEmpty()) {
01110 wasWhere = true;
01111 }
01112 else
01113 s_where += QString::fromLatin1(" AND ");
01114 Field::Pair *pair;
01115 QString s_where_sub;
01116 for (QPtrListIterator<Field::Pair> p_it(*rel->fieldPairs()); (pair = p_it.current()); ++p_it) {
01117 if (!s_where_sub.isEmpty())
01118 s_where_sub += QString::fromLatin1(" AND ");
01119 s_where_sub += (
01120 escapeIdentifier(pair->first->table()->name(), drvEscaping) +
01121 QString::fromLatin1(".") +
01122 escapeIdentifier(pair->first->name(), drvEscaping) +
01123 QString::fromLatin1(" = ") +
01124 escapeIdentifier(pair->second->table()->name(), drvEscaping) +
01125 QString::fromLatin1(".") +
01126 escapeIdentifier(pair->second->name(), drvEscaping));
01127 }
01128 if (rel->fieldPairs()->count()>1) {
01129 s_where_sub.prepend("(");
01130 s_where_sub += QString::fromLatin1(")");
01131 }
01132 s_where += s_where_sub;
01133 }
01134
01135 if (querySchema.whereExpression()) {
01136 if (wasWhere) {
01137
01138 s_where = "(" + s_where + ") AND (" + querySchema.whereExpression()->toString() + ")";
01139 }
01140 else {
01141 s_where = querySchema.whereExpression()->toString();
01142 }
01143 }
01144 if (!s_where.isEmpty())
01145 sql += QString::fromLatin1(" WHERE ") + s_where;
01147
01148
01149 return sql;
01150 }
01151
01152 QString Connection::selectStatement( KexiDB::TableSchema& tableSchema ) const
01153 {
01154 return selectStatement( *tableSchema.query() );
01155 }
01156
01157 Field* Connection::findSystemFieldName(KexiDB::FieldList* fieldlist)
01158 {
01159 Field *f = fieldlist->fields()->first();
01160 while (f) {
01161 if (m_driver->isSystemFieldName( f->name() ))
01162 return f;
01163 f = fieldlist->fields()->next();
01164 }
01165 return 0;
01166 }
01167
01168 Q_ULLONG Connection::lastInsertedAutoIncValue(const QString& aiFieldName, const QString& tableName,
01169 Q_ULLONG* ROWID)
01170 {
01171 Q_ULLONG row_id = drv_lastInsertRowID();
01172 if (ROWID)
01173 *ROWID = row_id;
01174 if (m_driver->beh->ROW_ID_FIELD_RETURNS_LAST_AUTOINCREMENTED_VALUE) {
01175 return row_id;
01176 }
01177 RowData rdata;
01178 if (row_id<=0 || true!=querySingleRecord(
01179 QString::fromLatin1("SELECT ") + tableName + QString::fromLatin1(".") + aiFieldName + QString::fromLatin1(" FROM ") + tableName
01180 + QString::fromLatin1(" WHERE ") + m_driver->beh->ROW_ID_FIELD_NAME + QString::fromLatin1("=") + QString::number(row_id), rdata))
01181 {
01182
01183 return (Q_ULLONG)-1;
01184 }
01185 return rdata[0].toULongLong();
01186 }
01187
01188 Q_ULLONG Connection::lastInsertedAutoIncValue(const QString& aiFieldName,
01189 const KexiDB::TableSchema& table, Q_ULLONG* ROWID)
01190 {
01191 return lastInsertedAutoIncValue(aiFieldName,table.name(), ROWID);
01192 }
01193
01194 #define createTable_ERR \
01195 { KexiDBDbg << "Connection::createTable(): ERROR!" <<endl; \
01196 setError(this, i18n("Creating table failed.")); \
01197 rollbackAutoCommitTransaction(tg.transaction()); \
01198 return false; }
01199
01200
01202
01209 bool Connection::createTable( KexiDB::TableSchema* tableSchema, bool replaceExisting )
01210 {
01211 if (!tableSchema || !checkIsDatabaseUsed())
01212 return false;
01213
01214
01215 if (tableSchema->fieldCount()<1) {
01216 clearError();
01217 setError(ERR_CANNOT_CREATE_EMPTY_OBJECT, i18n("Cannot create table without fields."));
01218 return false;
01219 }
01220 const bool internalTable = dynamic_cast<InternalTableSchema*>(tableSchema);
01221
01222 const QString &tableName = tableSchema->name().lower();
01223
01224 if (!internalTable) {
01225 if (m_driver->isSystemObjectName( tableName )) {
01226 clearError();
01227 setError(ERR_SYSTEM_NAME_RESERVED, i18n("System name \"%1\" cannot be used as table name.")
01228 .arg(tableSchema->name()));
01229 return false;
01230 }
01231
01232 Field *sys_field = findSystemFieldName(tableSchema);
01233 if (sys_field) {
01234 clearError();
01235 setError(ERR_SYSTEM_NAME_RESERVED,
01236 i18n("System name \"%1\" cannot be used as one of fields in \"%2\" table.")
01237 .arg(sys_field->name()).arg(tableName));
01238 return false;
01239 }
01240 }
01241
01242 bool previousSchemaStillKept = false;
01243
01244 KexiDB::TableSchema *existingTable = 0;
01245 if (replaceExisting) {
01246
01247 existingTable = m_tables_byname[tableName];
01248 if (existingTable) {
01249 if (existingTable == tableSchema) {
01250 clearError();
01251 setError(ERR_OBJECT_EXISTS,
01252 i18n("Could not create the same table \"%1\" twice.").arg(tableSchema->name()) );
01253 return false;
01254 }
01255
01256 if (existingTable->id()>0)
01257 tableSchema->m_id = existingTable->id();
01258 previousSchemaStillKept = true;
01259 if (!dropTable( existingTable, false ))
01260 return false;
01261 }
01262 }
01263 else {
01264 if (this->tableSchema( tableSchema->name() ) != 0) {
01265 clearError();
01266 setError(ERR_OBJECT_EXISTS, i18n("Table \"%1\" already exists.").arg(tableSchema->name()) );
01267 return false;
01268 }
01269 }
01270
01271
01272
01273
01274
01275
01276
01277 TransactionGuard tg;
01278 if (!beginAutoCommitTransaction(tg))
01279 return false;
01280
01281 if (!drv_createTable(*tableSchema))
01282 createTable_ERR;
01283
01284
01285 if (!internalTable) {
01286
01287 if (!storeObjectSchemaData( *tableSchema, true ))
01288 createTable_ERR;
01289
01290 TableSchema *ts = m_tables_byname["kexi__fields"];
01291 if (!ts)
01292 return false;
01293
01294 if (!KexiDB::deleteRow(*this, ts, "t_id", tableSchema->id()))
01295 return false;
01296
01297 FieldList *fl = ts->subList(
01298 "t_id",
01299 "f_type",
01300 "f_name",
01301 "f_length",
01302 "f_precision",
01303 "f_constraints",
01304 "f_options",
01305 "f_default",
01306 "f_order",
01307 "f_caption",
01308 "f_help"
01309 );
01310 if (!fl)
01311 return false;
01312
01313 Field::List *fields = tableSchema->fields();
01314 Field *f = fields->first();
01315 int order = 0;
01316 while (f) {
01317 QValueList<QVariant> vals;
01318 vals
01319 << QVariant(tableSchema->id())
01320 << QVariant(f->type())
01321 << QVariant(f->name())
01322 << QVariant(f->isFPNumericType() ? f->scale() : f->length())
01323 << QVariant(f->isFPNumericType() ? f->precision() : 0)
01324 << QVariant(f->constraints())
01325 << QVariant(f->options())
01326 << QVariant(f->defaultValue())
01327 << QVariant(f->order())
01328 << QVariant(f->caption())
01329 << QVariant(f->description());
01330
01331 if (!insertRecord(*fl, vals ))
01332 createTable_ERR;
01333
01334 f = fields->next();
01335 order++;
01336 }
01337 delete fl;
01338 }
01339
01340
01341
01342
01343
01344
01345
01346
01347 bool res = commitAutoCommitTransaction(tg.transaction());
01348
01349 if (res) {
01350 if (internalTable) {
01351
01352 insertInternalTableSchema(tableSchema);
01353 }
01354 else {
01355 if (previousSchemaStillKept) {
01356
01357 removeTableSchemaInternal(tableSchema);
01358 }
01359
01360 m_tables.insert(tableSchema->id(), tableSchema);
01361 m_tables_byname.insert(tableSchema->name().lower(), tableSchema);
01362 }
01363
01364 tableSchema->m_conn = this;
01365 }
01366 return res;
01367 }
01368
01369 void Connection::removeTableSchemaInternal(TableSchema *tableSchema)
01370 {
01371 m_tables_byname.remove(tableSchema->name());
01372 m_tables.remove(tableSchema->id());
01373 }
01374
01375 bool Connection::removeObject( uint objId )
01376 {
01377 clearError();
01378
01379 if (!KexiDB::deleteRow(*this, m_tables_byname["kexi__objects"], "o_id", objId)
01380 || !KexiDB::deleteRow(*this, m_tables_byname["kexi__objectdata"], "o_id", objId)) {
01381 setError(ERR_DELETE_SERVER_ERROR, i18n("Could not remove object's data."));
01382 return false;
01383 }
01384 return true;
01385 }
01386
01387 bool Connection::drv_dropTable( const QString& name )
01388 {
01389 m_sql = "DROP TABLE " + escapeIdentifier(name);
01390 return executeSQL(m_sql);
01391 }
01392
01394
01400 tristate Connection::dropTable( KexiDB::TableSchema* tableSchema )
01401 {
01402 return dropTable( tableSchema, true );
01403 }
01404
01405 tristate Connection::dropTable( KexiDB::TableSchema* tableSchema, bool alsoRemoveSchema)
01406 {
01407
01408 clearError();
01409 if (!tableSchema)
01410 return false;
01411
01412 QString errmsg(i18n("Table \"%1\" cannot be removed.\n"));
01413
01414 if (tableSchema->id() < 0
01415 || this->tableSchema(tableSchema->name())!=tableSchema
01416 || this->tableSchema(tableSchema->id())!=tableSchema)
01417 {
01418 setError(ERR_OBJECT_NOT_FOUND, errmsg.arg(tableSchema->name())
01419 +i18n("Unexpected name or identifier."));
01420 return false;
01421 }
01422
01423 tristate res = closeAllTableSchemaChangeListeners(*tableSchema);
01424 if (true!=res)
01425 return res;
01426
01427
01428 if (m_driver->isSystemObjectName( tableSchema->name() )) {
01429 setError(ERR_SYSTEM_NAME_RESERVED, errmsg.arg(tableSchema->name()) + d->strItIsASystemObject());
01430 return false;
01431 }
01432
01433 TransactionGuard tg;
01434 if (!beginAutoCommitTransaction(tg))
01435 return false;
01436
01437
01438 if (drv_containsTable(tableSchema->name())) {
01439 if (!drv_dropTable(tableSchema->name()))
01440 return false;
01441 }
01442
01443 TableSchema *ts = m_tables_byname["kexi__fields"];
01444 if (!KexiDB::deleteRow(*this, ts, "t_id", tableSchema->id()))
01445 return false;
01446
01447
01448 if (!removeObject( tableSchema->id() )) {
01449 return false;
01450 }
01451
01452 if (alsoRemoveSchema) {
01454 removeTableSchemaInternal(tableSchema);
01455 }
01456 return commitAutoCommitTransaction(tg.transaction());
01457 }
01458
01459 tristate Connection::dropTable( const QString& table )
01460 {
01461 clearError();
01462 TableSchema* ts = tableSchema( table );
01463 if (!ts) {
01464 setError(ERR_OBJECT_NOT_FOUND, i18n("Table \"%1\" does not exist.")
01465 .arg(table));
01466 return false;
01467 }
01468 return dropTable(ts);
01469 }
01470
01471 tristate Connection::alterTable( TableSchema& tableSchema, TableSchema& newTableSchema )
01472 {
01473 clearError();
01474 tristate res = closeAllTableSchemaChangeListeners(tableSchema);
01475 if (true!=res)
01476 return res;
01477
01478 if (&tableSchema == &newTableSchema) {
01479 setError(ERR_OBJECT_THE_SAME, i18n("Could not alter table \"%1\" using the same table.")
01480 .arg(tableSchema.name()));
01481 return false;
01482 }
01483
01484
01485 bool ok, empty;
01486 #if 0//TODO ucomment:
01487 empty = isEmpty( tableSchema, ok ) && ok;
01488 #else
01489 empty = true;
01490 #endif
01491 if (empty) {
01492 ok = createTable(&newTableSchema, true);
01493 }
01494 return ok;
01495 }
01496
01497 bool Connection::alterTableName(TableSchema& tableSchema, const QString& newName, bool )
01498 {
01499 clearError();
01500 if (&tableSchema!=m_tables[tableSchema.id()]) {
01501 setError(ERR_OBJECT_NOT_FOUND, i18n("Unknown table \"%1\"").arg(tableSchema.name()));
01502 return false;
01503 }
01504 if (newName.isEmpty() || !KexiUtils::isIdentifier(newName)) {
01505 setError(ERR_INVALID_IDENTIFIER, i18n("Invalid table name \"%1\"").arg(newName));
01506 return false;
01507 }
01508 const QString& newTableName = newName.lower().stripWhiteSpace();
01509 if (tableSchema.name().lower().stripWhiteSpace() == newTableName) {
01510 setError(ERR_OBJECT_THE_SAME, i18n("Could rename table \"%1\" using the same name.")
01511 .arg(newTableName));
01512 return false;
01513 }
01514 const bool res = drv_alterTableName(tableSchema, newTableName);
01515 if (res) {
01516
01517 m_tables_byname.take(tableSchema.name());
01518 tableSchema.setName(newTableName);
01519 m_tables_byname.insert(tableSchema.name(), &tableSchema);
01520 }
01521 return res;
01522 }
01523
01524 bool Connection::drv_alterTableName(TableSchema& tableSchema, const QString& newName,
01525 bool replace)
01526 {
01527
01528
01529
01530 const bool destTableExists = this->tableSchema( newName ) != 0;
01531 if (!replace && destTableExists) {
01532 setError(ERR_OBJECT_EXISTS,
01533 i18n("Could not rename table \"%1\" to \"%2\". Table \"%3\" already exists.")
01534 .arg(tableSchema.name()).arg(newName).arg(newName));
01535 return false;
01536 }
01537
01538
01539
01540
01541 TransactionGuard tg;
01542
01543
01544
01545 if (!beginAutoCommitTransaction(tg))
01546 return false;
01547
01548
01549 if (destTableExists && !drv_dropTable( newName ))
01550 return false;
01551
01552
01553
01554 const QString& oldTableName = tableSchema.name();
01555 tableSchema.setName(newName);
01556
01557
01558 #define drv_alterTableName_ERR \
01559 tableSchema.setName(oldTableName) //restore old name
01560
01561 if (!drv_createTable( tableSchema )) {
01562 drv_alterTableName_ERR;
01563 return false;
01564 }
01565
01566
01567
01568
01569 if (!executeSQL(QString::fromLatin1("INSERT INTO %1 SELECT * FROM %2")
01570 .arg(escapeIdentifier(tableSchema.name())).arg(escapeIdentifier(oldTableName))))
01571 {
01572 drv_alterTableName_ERR;
01573 return false;
01574 }
01575
01576
01577 if (!drv_dropTable( oldTableName )) {
01578 drv_alterTableName_ERR;
01579 return false;
01580 }
01581
01582
01583
01584 if (!executeSQL(QString::fromLatin1("UPDATE kexi__objects SET o_name=%1 WHERE o_id=%2")
01585 .arg(m_driver->escapeString(tableSchema.name())).arg(tableSchema.id())))
01586 {
01587 drv_alterTableName_ERR;
01588 return false;
01589 }
01590
01591
01592 tableSchema.setName(oldTableName);
01593
01594
01595
01596
01597
01598 return commitAutoCommitTransaction(tg.transaction());
01599 }
01600
01601 bool Connection::dropQuery( KexiDB::QuerySchema* querySchema )
01602 {
01603 clearError();
01604 if (!querySchema)
01605 return false;
01606
01607 TransactionGuard tg;
01608 if (!beginAutoCommitTransaction(tg))
01609 return false;
01610
01611
01612
01613
01614
01615
01616
01617
01618
01619
01620
01621
01622
01623
01624 if (!removeObject( querySchema->id() )) {
01625 return false;
01626 }
01627
01628
01629 m_queries_byname.remove(querySchema->name());
01630 m_queries.remove(querySchema->id());
01631
01632 return commitAutoCommitTransaction(tg.transaction());
01633 }
01634
01635 bool Connection::dropQuery( const QString& query )
01636 {
01637 clearError();
01638 QuerySchema* qs = querySchema( query );
01639 if (!qs) {
01640 setError(ERR_OBJECT_NOT_FOUND, i18n("Query \"%1\" does not exist.")
01641 .arg(query));
01642 return false;
01643 }
01644 return dropQuery(qs);
01645 }
01646
01647 bool Connection::drv_createTable( const KexiDB::TableSchema& tableSchema )
01648 {
01649 m_sql = createTableStatement(tableSchema);
01650 KexiDBDbg<<"******** "<<m_sql<<endl;
01651 return executeSQL(m_sql);
01652 }
01653
01654 bool Connection::drv_createTable( const QString& tableSchemaName )
01655 {
01656 TableSchema *ts = m_tables_byname[tableSchemaName];
01657 if (!ts)
01658 return false;
01659 return drv_createTable(*ts);
01660 }
01661
01662 bool Connection::beginAutoCommitTransaction(TransactionGuard &tg)
01663 {
01664 if ((m_driver->d->features & Driver::IgnoreTransactions)
01665 || !d->autoCommit)
01666 {
01667 tg.setTransaction( Transaction() );
01668 return true;
01669 }
01670
01671
01672
01673 if (m_driver->d->features & Driver::SingleTransactions) {
01674 if (d->default_trans_started_inside)
01675 if (!commitTransaction(d->default_trans, true)) {
01676 tg.setTransaction( Transaction() );
01677 return false;
01678 }
01679
01680 d->default_trans_started_inside = d->default_trans.isNull();
01681 if (!d->default_trans_started_inside) {
01682 tg.setTransaction( d->default_trans );
01683 tg.doNothing();
01684 return true;
01685 }
01686 }
01687 else if (!(m_driver->d->features & Driver::MultipleTransactions)) {
01688 tg.setTransaction( Transaction() );
01689 return true;
01690 }
01691 tg.setTransaction( beginTransaction() );
01692 return !error();
01693 }
01694
01695 bool Connection::commitAutoCommitTransaction(const Transaction& trans)
01696 {
01697 if (m_driver->d->features & Driver::IgnoreTransactions)
01698 return true;
01699 if (trans.isNull() || !m_driver->transactionsSupported())
01700 return true;
01701 if (m_driver->d->features & Driver::SingleTransactions) {
01702 if (!d->default_trans_started_inside)
01703 return true;
01704 }
01705 return commitTransaction(trans, true);
01706 }
01707
01708 bool Connection::rollbackAutoCommitTransaction(const Transaction& trans)
01709 {
01710 if (trans.isNull() || !m_driver->transactionsSupported())
01711 return true;
01712 return rollbackTransaction(trans);
01713 }
01714
01715 #define SET_ERR_TRANS_NOT_SUPP \
01716 { setError(ERR_UNSUPPORTED_DRV_FEATURE, \
01717 i18n("Transactions are not supported for \"%1\" driver.").arg(m_driver->name() )); }
01718
01719 #define SET_BEGIN_TR_ERROR \
01720 { if (!error()) \
01721 setError(ERR_ROLLBACK_OR_COMMIT_TRANSACTION, i18n("Begin transaction failed")); }
01722
01723 Transaction Connection::beginTransaction()
01724 {
01725 if (!checkIsDatabaseUsed())
01726 return Transaction::null;
01727 Transaction trans;
01728 if (m_driver->d->features & Driver::IgnoreTransactions) {
01729
01730
01731 trans.m_data = new TransactionData(this);
01732 d->transactions.append(trans);
01733 return trans;
01734 }
01735 if (m_driver->d->features & Driver::SingleTransactions) {
01736 if (d->default_trans.active()) {
01737 setError(ERR_TRANSACTION_ACTIVE, i18n("Transaction already started.") );
01738 return Transaction::null;
01739 }
01740 if (!(trans.m_data = drv_beginTransaction())) {
01741 SET_BEGIN_TR_ERROR;
01742 return Transaction::null;
01743 }
01744 d->default_trans = trans;
01745 d->transactions.append(trans);
01746 return d->default_trans;
01747 }
01748 if (m_driver->d->features & Driver::MultipleTransactions) {
01749 if (!(trans.m_data = drv_beginTransaction())) {
01750 SET_BEGIN_TR_ERROR;
01751 return Transaction::null;
01752 }
01753 d->transactions.append(trans);
01754 return trans;
01755 }
01756
01757 SET_ERR_TRANS_NOT_SUPP;
01758 return Transaction::null;
01759 }
01760
01761 bool Connection::commitTransaction(const Transaction trans, bool ignore_inactive)
01762 {
01763 if (!isDatabaseUsed())
01764 return false;
01765
01766
01767 if ( !m_driver->transactionsSupported()
01768 && !(m_driver->d->features & Driver::IgnoreTransactions))
01769 {
01770 SET_ERR_TRANS_NOT_SUPP;
01771 return false;
01772 }
01773 Transaction t = trans;
01774 if (!t.active()) {
01775 if (!d->default_trans.active()) {
01776 if (ignore_inactive)
01777 return true;
01778 clearError();
01779 setError(ERR_NO_TRANSACTION_ACTIVE, i18n("Transaction not started.") );
01780 return false;
01781 }
01782 t = d->default_trans;
01783 d->default_trans = Transaction::null;
01784 }
01785 bool ret = true;
01786 if (! (m_driver->d->features & Driver::IgnoreTransactions) )
01787 ret = drv_commitTransaction(t.m_data);
01788 if (t.m_data)
01789 t.m_data->m_active = false;
01790 if (!d->dont_remove_transactions)
01791 d->transactions.remove(t);
01792 if (!ret && !error())
01793 setError(ERR_ROLLBACK_OR_COMMIT_TRANSACTION, i18n("Error on commit transaction"));
01794 return ret;
01795 }
01796
01797 bool Connection::rollbackTransaction(const Transaction trans, bool ignore_inactive)
01798 {
01799 if (!isDatabaseUsed())
01800 return false;
01801
01802
01803 if ( !m_driver->transactionsSupported()
01804 && !(m_driver->d->features & Driver::IgnoreTransactions))
01805 {
01806 SET_ERR_TRANS_NOT_SUPP;
01807 return false;
01808 }
01809 Transaction t = trans;
01810 if (!t.active()) {
01811 if (!d->default_trans.active()) {
01812 if (ignore_inactive)
01813 return true;
01814 clearError();
01815 setError(ERR_NO_TRANSACTION_ACTIVE, i18n("Transaction not started.") );
01816 return false;
01817 }
01818 t = d->default_trans;
01819 d->default_trans = Transaction::null;
01820 }
01821 bool ret = true;
01822 if (! (m_driver->d->features & Driver::IgnoreTransactions) )
01823 ret = drv_rollbackTransaction(t.m_data);
01824 if (t.m_data)
01825 t.m_data->m_active = false;
01826 if (!d->dont_remove_transactions)
01827 d->transactions.remove(t);
01828 if (!ret && !error())
01829 setError(ERR_ROLLBACK_OR_COMMIT_TRANSACTION, i18n("Error on rollback transaction"));
01830 return ret;
01831 }
01832
01833 #undef SET_ERR_TRANS_NOT_SUPP
01834 #undef SET_BEGIN_TR_ERROR
01835
01836
01837
01838
01839
01840
01841 Transaction& Connection::defaultTransaction() const
01842 {
01843 return d->default_trans;
01844 }
01845
01846 void Connection::setDefaultTransaction(const Transaction& trans)
01847 {
01848 if (!isDatabaseUsed())
01849 return;
01850
01851
01852 if ( !(m_driver->d->features & Driver::IgnoreTransactions)
01853 && (!trans.active() || !m_driver->transactionsSupported()) )
01854 {
01855 return;
01856 }
01857 d->default_trans = trans;
01858 }
01859
01860 const QValueList<Transaction>& Connection::transactions()
01861 {
01862 return d->transactions;
01863 }
01864
01865 bool Connection::autoCommit() const
01866 {
01867 return d->autoCommit;
01868 }
01869
01870 bool Connection::setAutoCommit(bool on)
01871 {
01872 if (d->autoCommit == on || m_driver->d->features & Driver::IgnoreTransactions)
01873 return true;
01874 if (!drv_setAutoCommit(on))
01875 return false;
01876 d->autoCommit = on;
01877 return true;
01878 }
01879
01880 TransactionData* Connection::drv_beginTransaction()
01881 {
01882 QString old_sql = m_sql;
01883 if (!executeSQL( "BEGIN" ))
01884 return 0;
01885 return new TransactionData(this);
01886 }
01887
01888 bool Connection::drv_commitTransaction(TransactionData *)
01889 {
01890 return executeSQL( "COMMIT" );
01891 }
01892
01893 bool Connection::drv_rollbackTransaction(TransactionData *)
01894 {
01895 return executeSQL( "ROLLBACK" );
01896 }
01897
01898 bool Connection::drv_setAutoCommit(bool )
01899 {
01900 return true;
01901 }
01902
01903 Cursor* Connection::executeQuery( const QString& statement, uint cursor_options )
01904 {
01905 if (statement.isEmpty())
01906 return 0;
01907 Cursor *c = prepareQuery( statement, cursor_options );
01908 if (!c)
01909 return 0;
01910 if (!c->open()) {
01911 setError(c);
01912 delete c;
01913 return 0;
01914 }
01915 return c;
01916 }
01917
01918 Cursor* Connection::executeQuery( QuerySchema& query, uint cursor_options )
01919 {
01920 Cursor *c = prepareQuery( query, cursor_options );
01921 if (!c)
01922 return 0;
01923 if (!c->open()) {
01924 setError(c);
01925 delete c;
01926 return 0;
01927 }
01928 return c;
01929 }
01930
01931 Cursor* Connection::executeQuery( TableSchema& table, uint cursor_options )
01932 {
01933 return executeQuery( *table.query(), cursor_options );
01934 }
01935
01936
01937
01938
01939
01940
01941
01942
01943
01944
01945
01946
01947
01948
01949 Cursor* Connection::prepareQuery( TableSchema& table, uint cursor_options )
01950 {
01951 return prepareQuery( *table.query(), cursor_options );
01952 }
01953
01954 bool Connection::deleteCursor(Cursor *cursor)
01955 {
01956 if (!cursor)
01957 return false;
01958 if (cursor->connection()!=this) {
01959 KexiDBWarn << "Connection::deleteCursor(): Cannot delete the cursor not owned by the same connection!" << endl;
01960 return false;
01961 }
01962 bool ret = cursor->close();
01963 delete cursor;
01964 return ret;
01965 }
01966
01967 bool Connection::setupObjectSchemaData( const RowData &data, SchemaData &sdata )
01968 {
01969
01970
01971
01972
01973
01974
01975
01976
01977
01978
01979
01980
01981 bool ok;
01982 sdata.m_id = data[0].toInt(&ok);
01983 if (!ok) {
01984 return false;
01985 }
01986 sdata.m_name = data[2].toString();
01987 if (!KexiUtils::isIdentifier( sdata.m_name )) {
01988 setError(ERR_INVALID_IDENTIFIER, i18n("Invalid object name \"%1\"").arg(sdata.m_name));
01989 return false;
01990 }
01991 sdata.m_caption = data[3].toString();
01992 sdata.m_desc = data[4].toString();
01993
01994
01995 return true;
01996 }
01997
01998 tristate Connection::loadObjectSchemaData( int objectID, SchemaData &sdata )
01999 {
02000 RowData data;
02001 if (true!=querySingleRecord(QString::fromLatin1(
02002 "SELECT o_id, o_type, o_name, o_caption, o_desc FROM kexi__objects where o_id=%1")
02003 .arg(objectID), data))
02004 return cancelled;
02005 return setupObjectSchemaData( data, sdata );
02006 }
02007
02008 tristate Connection::loadObjectSchemaData( int objectType, const QString& objectName, SchemaData &sdata )
02009 {
02010 RowData data;
02011 if (true!=querySingleRecord(QString::fromLatin1("SELECT o_id, o_type, o_name, o_caption, o_desc "
02012 "FROM kexi__objects WHERE o_type=%1 AND lower(o_name)=%2")
02013 .arg(objectType).arg(m_driver->valueToSQL(Field::Text, objectName.lower())), data))
02014 return cancelled;
02015 return setupObjectSchemaData( data, sdata );
02016 }
02017
02018 bool Connection::storeObjectSchemaData( SchemaData &sdata, bool newObject )
02019 {
02020 TableSchema *ts = m_tables_byname["kexi__objects"];
02021 if (!ts)
02022 return false;
02023 if (newObject) {
02024 int existingID;
02025 if (querySingleNumber(QString::fromLatin1(
02026 "SELECT o_id FROM kexi__objects WHERE o_type=%1 AND lower(o_name)=%2")
02027 .arg(sdata.type()).arg(m_driver->valueToSQL(Field::Text, sdata.name().lower())), existingID))
02028 {
02029
02030
02031 sdata.m_id = existingID;
02032 newObject = false;
02033 }
02034 }
02035 if (newObject) {
02036 FieldList *fl;
02037 bool ok;
02038 if (sdata.id()<=0) {
02039 fl = ts->subList("o_type", "o_name", "o_caption", "o_desc");
02040 ok = fl!=0;
02041 if (ok && !insertRecord(*fl, QVariant(sdata.type()), QVariant(sdata.name()),
02042 QVariant(sdata.caption()), QVariant(sdata.description()) ))
02043 ok = false;
02044 delete fl;
02045 if (!ok)
02046 return false;
02047
02049 int obj_id = (int)lastInsertedAutoIncValue("o_id",*ts);
02050 KexiDBDbg << "######## NEW obj_id == " << obj_id << endl;
02051 if (obj_id<=0)
02052 return false;
02053 sdata.m_id = obj_id;
02054 return true;
02055 } else {
02056 fl = ts->subList("o_id", "o_type", "o_name", "o_caption", "o_desc");
02057 ok = fl!=0;
02058 if (ok && !insertRecord(*fl, QVariant(sdata.id()), QVariant(sdata.type()), QVariant(sdata.name()),
02059 QVariant(sdata.caption()), QVariant(sdata.description()) ))
02060 ok = false;
02061 delete fl;
02062 return ok;
02063 }
02064 }
02065
02066 return executeSQL(QString("UPDATE kexi__objects SET o_type=%2, o_caption=%3, o_desc=%4 WHERE o_id=%1")
02067 .arg(sdata.id()).arg(sdata.type())
02068 .arg(m_driver->valueToSQL(KexiDB::Field::Text, sdata.caption()))
02069 .arg(m_driver->valueToSQL(KexiDB::Field::Text, sdata.description())) );
02070 }
02071
02072 tristate Connection::querySingleRecordInternal(RowData &data, const QString* sql, QuerySchema* query)
02073 {
02074 Q_ASSERT(sql || query);
02076 if (sql)
02077 m_sql = *sql + " LIMIT 1";
02078 KexiDB::Cursor *cursor;
02079 if (!(cursor = sql ? executeQuery( m_sql ) : executeQuery( *query ))) {
02080 KexiDBDbg << "Connection::querySingleRecord(): !executeQuery()" << endl;
02081 return false;
02082 }
02083 if (!cursor->moveFirst() || cursor->eof()) {
02084 const tristate result = cursor->error() ? false : cancelled;
02085 KexiDBDbg << "Connection::querySingleRecord(): !cursor->moveFirst() || cursor->eof()" << endl;
02086 setError(cursor);
02087 deleteCursor(cursor);
02088 return result;
02089 }
02090 cursor->storeCurrentRow(data);
02091 return deleteCursor(cursor);
02092 }
02093
02094 tristate Connection::querySingleRecord(const QString& sql, RowData &data)
02095 {
02096 return querySingleRecordInternal(data, &sql, 0);
02097 }
02098
02099 tristate Connection::querySingleRecord(QuerySchema& query, RowData &data)
02100 {
02101 return querySingleRecordInternal(data, 0, &query);
02102 }
02103
02104 bool Connection::checkIfColumnExists(Cursor *cursor, uint column)
02105 {
02106 if (column >= cursor->fieldCount()) {
02107 setError(ERR_CURSOR_RECORD_FETCHING, i18n("Column %1 does not exist for the query.").arg(column));
02108 return false;
02109 }
02110 return true;
02111 }
02112
02113 tristate Connection::querySingleString(const QString& sql, QString &value, uint column)
02114 {
02115 KexiDB::Cursor *cursor;
02116 m_sql = sql + " LIMIT 1";
02117 if (!(cursor = executeQuery( m_sql ))) {
02118 KexiDBDbg << "Connection::querySingleRecord(): !executeQuery()" << endl;
02119 return false;
02120 }
02121 if (!cursor->moveFirst() || cursor->eof()) {
02122 const tristate result = cursor->error() ? false : cancelled;
02123 KexiDBDbg << "Connection::querySingleRecord(): !cursor->moveFirst() || cursor->eof()" << endl;
02124 deleteCursor(cursor);
02125 return result;
02126 }
02127 if (!checkIfColumnExists(cursor, column)) {
02128 deleteCursor(cursor);
02129 return false;
02130 }
02131 value = cursor->value(column).toString();
02132 return deleteCursor(cursor);
02133 }
02134
02135 tristate Connection::querySingleNumber(const QString& sql, int &number, uint column)
02136 {
02137 static QString str;
02138 static bool ok;
02139 const tristate result = querySingleString(sql, str, column);
02140 if (result!=true)
02141 return result;
02142 number = str.toInt(&ok);
02143 return ok;
02144 }
02145
02146 bool Connection::queryStringList(const QString& sql, QStringList& list, uint column)
02147 {
02148 KexiDB::Cursor *cursor;
02149 clearError();
02150 m_sql = sql;
02151 if (!(cursor = executeQuery( m_sql ))) {
02152 KexiDBDbg << "Connection::queryStringList(): !executeQuery()" << endl;
02153 return false;
02154 }
02155 if (!checkIfColumnExists(cursor, column)) {
02156 deleteCursor(cursor);
02157 return false;
02158 }
02159 cursor->moveFirst();
02160 if (cursor->error()) {
02161 setError(cursor);
02162 deleteCursor(cursor);
02163 return false;
02164 }
02165 list.clear();
02166 while (!cursor->eof()) {
02167 list.append( cursor->value(column).toString() );
02168 if (!cursor->moveNext() && cursor->error()) {
02169 setError(cursor);
02170 deleteCursor(cursor);
02171 return false;
02172 }
02173 }
02174 return deleteCursor(cursor);
02175 }
02176
02177 bool Connection::resultExists(const QString& sql, bool &success)
02178 {
02179 KexiDB::Cursor *cursor;
02180
02181 if (m_driver->beh->SELECT_1_SUBQUERY_SUPPORTED) {
02182
02183 if (sql.left(6).upper() == "SELECT")
02184 m_sql = QString("SELECT 1 FROM (") + sql + ") LIMIT 1";
02185 else
02186 m_sql = sql;
02187 }
02188 else {
02189 if (sql.left(6).upper() == "SELECT")
02190 m_sql = sql + " LIMIT 1";
02191 else
02192 m_sql = sql;
02193 }
02194 if (!(cursor = executeQuery( m_sql ))) {
02195 KexiDBDbg << "Connection::querySingleRecord(): !executeQuery()" << endl;
02196 success = false;
02197 return false;
02198 }
02199 if (!cursor->moveFirst() || cursor->eof()) {
02200 success = !cursor->error();
02201 KexiDBDbg << "Connection::querySingleRecord(): !cursor->moveFirst() || cursor->eof()" << endl;
02202 setError(cursor);
02203 deleteCursor(cursor);
02204 return false;
02205 }
02206 success = deleteCursor(cursor);
02207 return true;
02208 }
02209
02210 bool Connection::isEmpty( TableSchema& table, bool &success )
02211 {
02212 return !resultExists( selectStatement( *table.query() ), success );
02213 }
02214
02215 int Connection::resultCount(const QString& sql)
02216 {
02217 int count = -1;
02218 m_sql = QString::fromLatin1("SELECT COUNT() FROM (") + sql + ")";
02219 querySingleNumber(m_sql, count);
02220 return count;
02221 }
02222
02223 KexiDB::TableSchema* Connection::setupTableSchema( const RowData &data )
02224 {
02225 TableSchema *t = new TableSchema( this );
02226 if (!setupObjectSchemaData( data, *t )) {
02227 delete t;
02228 return 0;
02229 }
02230
02231
02232
02233
02234
02235 KexiDB::Cursor *cursor;
02236 if (!(cursor = executeQuery(
02237 QString::fromLatin1("SELECT t_id, f_type, f_name, f_length, f_precision, f_constraints, "
02238 "f_options, f_default, f_order, f_caption, f_help"
02239 " FROM kexi__fields WHERE t_id=%1 ORDER BY f_order").arg(t->m_id) ))) {
02240 return 0;
02241 }
02242 if (!cursor->moveFirst()) {
02243 if (!cursor->error() && cursor->eof()) {
02244 setError(i18n("Table has no fields defined."));
02245 }
02246 deleteCursor(cursor);
02247 return 0;
02248 }
02249 bool ok;
02250 while (!cursor->eof()) {
02251
02252
02253 int f_type = cursor->value(1).toInt(&ok);
02254 if (!ok)
02255 break;
02256 int f_len = cursor->value(3).toInt(&ok);
02257 if (!ok)
02258 break;
02259 int f_prec = cursor->value(4).toInt(&ok);
02260 if (!ok)
02261 break;
02262 int f_constr = cursor->value(5).toInt(&ok);
02263 if (!ok)
02264 break;
02265 int f_opts = cursor->value(6).toInt(&ok);
02266 if (!ok)
02267 break;
02268
02269 if (!KexiUtils::isIdentifier( cursor->value(2).asString() )) {
02270 setError(ERR_INVALID_IDENTIFIER, i18n("Invalid object name \"%1\"")
02271 .arg( cursor->value(2).asString() ));
02272 ok=false;
02273 break;
02274 }
02275
02276 Field *f = new Field(
02277 cursor->value(2).asString(), (Field::Type)f_type, f_constr, f_len, f_prec, f_opts );
02278 f->setDefaultValue( cursor->value(7).toCString() );
02279 f->m_caption = cursor->value(9).asString();
02280 f->m_desc = cursor->value(10).asString();
02281 t->addField(f);
02282 cursor->moveNext();
02283 }
02284
02285 if (!ok) {
02286 deleteCursor(cursor);
02287 delete t;
02288 return 0;
02289 }
02290
02291 if (!deleteCursor(cursor)) {
02292 delete t;
02293 return 0;
02294 }
02295
02296 m_tables.insert(t->m_id, t);
02297 m_tables_byname.insert(t->m_name.lower(), t);
02298 return t;
02299 }
02300
02301 TableSchema* Connection::tableSchema( const QString& tableName )
02302 {
02303 QString m_tableName = tableName.lower();
02304 TableSchema *t = m_tables_byname[m_tableName];
02305 if (t)
02306 return t;
02307
02308 RowData data;
02309 if (true!=querySingleRecord(QString::fromLatin1(
02310 "SELECT o_id, o_type, o_name, o_caption, o_desc FROM kexi__objects WHERE lower(o_name)='%1' AND o_type=%2")
02311 .arg(m_tableName).arg(KexiDB::TableObjectType), data))
02312 return 0;
02313
02314 return setupTableSchema(data);
02315 }
02316
02317 TableSchema* Connection::tableSchema( int tableId )
02318 {
02319 TableSchema *t = m_tables[tableId];
02320 if (t)
02321 return t;
02322
02323 RowData data;
02324 if (true!=querySingleRecord(QString::fromLatin1(
02325 "SELECT o_id, o_type, o_name, o_caption, o_desc FROM kexi__objects WHERE o_id=%1")
02326 .arg(tableId), data))
02327 return 0;
02328
02329 return setupTableSchema(data);
02330 }
02331
02332 bool Connection::loadDataBlock( int objectID, QString &dataString, const QString& dataID )
02333 {
02334 if (objectID<=0)
02335 return false;
02336 return querySingleString(
02337 QString("SELECT o_data FROM kexi__objectdata WHERE o_id=") + QString::number(objectID)
02338 + " AND " + KexiDB::sqlWhere(m_driver, KexiDB::Field::Text, "o_sub_id", dataID),
02339 dataString );
02340 }
02341
02342 bool Connection::storeDataBlock( int objectID, const QString &dataString, const QString& dataID )
02343 {
02344 if (objectID<=0)
02345 return false;
02346 QString sql(QString::fromLatin1("SELECT kexi__objectdata.o_id FROM kexi__objectdata WHERE o_id=%1").arg(objectID));
02347 QString sql_sub( KexiDB::sqlWhere(m_driver, KexiDB::Field::Text, "o_sub_id", dataID) );
02348
02349 bool ok, exists;
02350 exists = resultExists(sql + " and " + sql_sub, ok);
02351 if (!ok)
02352 return false;
02353 if (exists) {
02354 return executeSQL( "UPDATE kexi__objectdata SET o_data="
02355 + m_driver->valueToSQL( KexiDB::Field::BLOB, dataString )
02356 + " WHERE o_id=" + QString::number(objectID) + " AND " + sql_sub );
02357 }
02358 return executeSQL(
02359 QString::fromLatin1("INSERT INTO kexi__objectdata (o_id, o_data, o_sub_id) VALUES (")
02360 + QString::number(objectID) +"," + m_driver->valueToSQL( KexiDB::Field::BLOB, dataString )
02361 + "," + m_driver->valueToSQL( KexiDB::Field::Text, dataID ) + ")" );
02362 }
02363
02364 bool Connection::removeDataBlock( int objectID, const QString& dataID)
02365 {
02366 if (objectID<=0)
02367 return false;
02368 if (dataID.isEmpty())
02369 return KexiDB::deleteRow(*this, "kexi__objectdata", "o_id", QString::number(objectID));
02370 else
02371 return KexiDB::deleteRow(*this, "kexi__objectdata",
02372 "o_id", KexiDB::Field::Integer, objectID, "o_sub_id", KexiDB::Field::Text, dataID);
02373 }
02374
02375 KexiDB::QuerySchema* Connection::setupQuerySchema( const RowData &data )
02376 {
02377 bool ok = true;
02378 const int objID = data[0].toInt(&ok);
02379 if (!ok)
02380 return false;
02381 QString sqlText;
02382 if (!loadDataBlock( objID, sqlText, "sql" )) {
02383 setError(ERR_OBJECT_NOT_FOUND,
02384 i18n("Could not find definition for query \"%1\". Removing this query is recommended.")
02385 .arg(data[2].toString()));
02386 return 0;
02387 }
02388 d->parser()->parse( sqlText );
02389 KexiDB::QuerySchema *query = d->parser()->query();
02390
02391 if (!query) {
02392 setError(ERR_SQL_PARSE_ERROR,
02393 i18n("<p>Could not load definition for query \"%1\". "
02394 "SQL statement for this query is invalid:<br><tt>%2</tt></p>\n"
02395 "<p>You can open this query in Text View and correct it.</p>").arg(data[2].toString())
02396 .arg(d->parser()->statement()));
02397 return 0;
02398 }
02399 if (!setupObjectSchemaData( data, *query )) {
02400 delete query;
02401 return 0;
02402 }
02403 m_queries.insert(query->m_id, query);
02404 m_queries_byname.insert(query->m_name, query);
02405 return query;
02406 }
02407
02408 QuerySchema* Connection::querySchema( const QString& queryName )
02409 {
02410 QString m_queryName = queryName.lower();
02411 QuerySchema *q = m_queries_byname[m_queryName];
02412 if (q)
02413 return q;
02414
02415 RowData data;
02416 if (true!=querySingleRecord(QString::fromLatin1(
02417 "SELECT o_id, o_type, o_name, o_caption, o_desc FROM kexi__objects WHERE lower(o_name)='%1' AND o_type=%2")
02418 .arg(m_queryName).arg(KexiDB::QueryObjectType), data))
02419 return 0;
02420
02421 return setupQuerySchema(data);
02422 }
02423
02424 QuerySchema* Connection::querySchema( int queryId )
02425 {
02426 QuerySchema *q = m_queries[queryId];
02427 if (q)
02428 return q;
02429
02430 clearError();
02431 RowData data;
02432 if (true!=querySingleRecord(QString::fromLatin1(
02433 "SELECT o_id, o_type, o_name, o_caption, o_desc FROM kexi__objects WHERE o_id=%1").arg(queryId), data))
02434 return 0;
02435
02436 return setupQuerySchema(data);
02437 }
02438
02439 bool Connection::setQuerySchemaObsolete( const QString& queryName )
02440 {
02441 QuerySchema* oldQuery = querySchema( queryName );
02442 if (!oldQuery)
02443 return false;
02444 d->obsoleteQueries.append(oldQuery);
02445 m_queries_byname.take(queryName);
02446 m_queries.take(oldQuery->id());
02447 return true;
02448 }
02449
02450 TableSchema* Connection::newKexiDBSystemTableSchema(const QString& tsname)
02451 {
02452 TableSchema *ts = new TableSchema(tsname.lower());
02453 insertInternalTableSchema( ts );
02454 return ts;
02455 }
02456
02457 bool Connection::isInternalTableSchema(const QString& tableName)
02458 {
02459 return (m_kexiDBSystemTables[ m_tables_byname[tableName] ])
02460
02461
02462 || tableName=="kexi__final" || tableName=="kexi__useractions";
02463 }
02464
02465 void Connection::insertInternalTableSchema(TableSchema *tableSchema)
02466 {
02467 tableSchema->setKexiDBSystem(true);
02468 m_kexiDBSystemTables.insert(tableSchema, tableSchema);
02469 m_tables_byname.insert(tableSchema->name(), tableSchema);
02470 }
02471
02473 bool Connection::setupKexiDBSystemSchema()
02474 {
02475 if (!m_kexiDBSystemTables.isEmpty())
02476 return true;
02477
02478 TableSchema *t_objects = newKexiDBSystemTableSchema("kexi__objects");
02479 t_objects->addField( new Field("o_id", Field::Integer, Field::PrimaryKey | Field::AutoInc, Field::Unsigned) )
02480 .addField( new Field("o_type", Field::Byte, 0, Field::Unsigned) )
02481 .addField( new Field("o_name", Field::Text) )
02482 .addField( new Field("o_caption", Field::Text ) )
02483 .addField( new Field("o_desc", Field::LongText ) );
02484
02485 t_objects->debug();
02486
02487 TableSchema *t_objectdata = newKexiDBSystemTableSchema("kexi__objectdata");
02488 t_objectdata->addField( new Field("o_id", Field::Integer, Field::NotNull, Field::Unsigned) )
02489 .addField( new Field("o_data", Field::BLOB) )
02490 .addField( new Field("o_sub_id", Field::Text) );
02491
02492 TableSchema *t_fields = newKexiDBSystemTableSchema("kexi__fields");
02493 t_fields->addField( new Field("t_id", Field::Integer, 0, Field::Unsigned) )
02494 .addField( new Field("f_type", Field::Byte, 0, Field::Unsigned) )
02495 .addField( new Field("f_name", Field::Text ) )
02496 .addField( new Field("f_length", Field::Integer ) )
02497 .addField( new Field("f_precision", Field::Integer ) )
02498 .addField( new Field("f_constraints", Field::Integer ) )
02499 .addField( new Field("f_options", Field::Integer ) )
02500 .addField( new Field("f_default", Field::Text ) )
02501
02502 .addField( new Field("f_order", Field::Integer ) )
02503 .addField( new Field("f_caption", Field::Text ) )
02504 .addField( new Field("f_help", Field::LongText ) );
02505
02506
02507
02508
02509
02510
02511
02512
02513
02514
02515
02516
02517
02518
02519
02520
02521
02522
02523 TableSchema *t_db = newKexiDBSystemTableSchema("kexi__db");
02524 t_db->addField( new Field("db_property", Field::Text, Field::NoConstraints, Field::NoOptions, 32 ) )
02525 .addField( new Field("db_value", Field::LongText ) );
02526
02527
02528
02529
02530
02531
02532
02533
02534
02535
02536
02537
02538
02539
02540
02541
02542
02543
02544
02545
02546
02547
02548
02549
02550 return true;
02551 }
02552
02553 void Connection::removeMe(TableSchema *ts)
02554 {
02555 if (ts && !m_destructor_started) {
02556 m_tables.take(ts->id());
02557 m_tables.take(ts->id());
02558 m_tables_byname.take(ts->name());
02559 }
02560 }
02561
02562 QString Connection::anyAvailableDatabaseName()
02563 {
02564 if (!d->availableDatabaseName.isEmpty()) {
02565 return d->availableDatabaseName;
02566 }
02567 return m_driver->beh->ALWAYS_AVAILABLE_DATABASE_NAME;
02568 }
02569
02570 void Connection::setAvailableDatabaseName(const QString& dbName)
02571 {
02572 d->availableDatabaseName = dbName;
02573 }
02574
02575 bool Connection::updateRow(QuerySchema &query, RowData& data, RowEditBuffer& buf, bool useROWID)
02576 {
02577
02578
02579
02580 KexiDBDbg << "Connection::updateRow.." << endl;
02581 clearError();
02582
02583 if (buf.dbBuffer().isEmpty()) {
02584 KexiDBDbg << " -- NO CHANGES DATA!" << endl;
02585 return true;
02586 }
02587 TableSchema *mt = query.masterTable();
02588 if (!mt) {
02589 KexiDBWarn << " -- NO MASTER TABLE!" << endl;
02590 setError(ERR_UPDATE_NO_MASTER_TABLE,
02591 i18n("Could not update row because there is no master table defined."));
02592 return false;
02593 }
02594 IndexSchema *pkey = (mt->primaryKey() && !mt->primaryKey()->fields()->isEmpty()) ? mt->primaryKey() : 0;
02595 if (!useROWID && !pkey) {
02596 KexiDBWarn << " -- NO MASTER TABLE's PKEY!" << endl;
02597 setError(ERR_UPDATE_NO_MASTER_TABLES_PKEY,
02598 i18n("Could not update row because master table has no primary key defined."));
02600 return false;
02601 }
02602
02603 m_sql = "UPDATE " + escapeIdentifier(mt->name()) + " SET ";
02604 QString sqlset, sqlwhere;
02605 sqlset.reserve(1024);
02606 sqlwhere.reserve(1024);
02607 KexiDB::RowEditBuffer::DBMap b = buf.dbBuffer();
02608 for (KexiDB::RowEditBuffer::DBMap::ConstIterator it=b.constBegin();it!=b.constEnd();++it) {
02609 if (!sqlset.isEmpty())
02610 sqlset+=",";
02611 sqlset += (escapeIdentifier(it.key()->field->name()) + "=" +
02612 m_driver->valueToSQL(it.key()->field,it.data()));
02613 }
02614 if (pkey) {
02615 QValueVector<int> pkeyFieldsOrder = query.pkeyFieldsOrder();
02616 KexiDBDbg << pkey->fieldCount() << " ? " << query.pkeyFieldsCount() << endl;
02617 if (pkey->fieldCount() != query.pkeyFieldsCount()) {
02618 KexiDBWarn << " -- NO ENTIRE MASTER TABLE's PKEY SPECIFIED!" << endl;
02619 setError(ERR_UPDATE_NO_ENTIRE_MASTER_TABLES_PKEY,
02620 i18n("Could not update row because it does not contain entire master table's primary key."));
02621 return false;
02622 }
02623 if (!pkey->fields()->isEmpty()) {
02624 uint i=0;
02625 for (Field::ListIterator it = pkey->fieldsIterator(); it.current(); i++, ++it) {
02626 if (!sqlwhere.isEmpty())
02627 sqlwhere+=" AND ";
02628 QVariant val = data[ pkeyFieldsOrder[i] ];
02629 if (val.isNull() || !val.isValid()) {
02630 setError(ERR_UPDATE_NULL_PKEY_FIELD,
02631 i18n("Primary key's field \"%1\" cannot be empty.").arg(it.current()->name()));
02632
02633 return false;
02634 }
02635 sqlwhere += ( escapeIdentifier(it.current()->name()) + "=" +
02636 m_driver->valueToSQL( it.current(), val ) );
02637 }
02638 }
02639 }
02640 else {
02641 sqlwhere = ( escapeIdentifier(m_driver->beh->ROW_ID_FIELD_NAME) + "="
02642 + m_driver->valueToSQL(Field::BigInteger, data[data.size()-1]));
02643 }
02644 m_sql += (sqlset + " WHERE " + sqlwhere);
02645 KexiDBDbg << " -- SQL == " << m_sql << endl;
02646
02647 if (!executeSQL(m_sql)) {
02648 setError(ERR_UPDATE_SERVER_ERROR, i18n("Row updating on the server failed."));
02649 return false;
02650 }
02651
02652 QMap<QueryColumnInfo*,int> fieldsOrder = query.fieldsOrder();
02653 QMap<QueryColumnInfo*,int>::ConstIterator fieldsOrderIt;
02654 for (KexiDB::RowEditBuffer::DBMap::ConstIterator it=b.constBegin();it!=b.constEnd();++it) {
02655 fieldsOrderIt = fieldsOrder.find( it.key() );
02656 if (fieldsOrderIt == fieldsOrder.constEnd()) {
02657 KexiDBWarn << "Connection::updateRow(): \"now also assign new value in memory\" step "
02658 "- could not find item '" << it.key()->aliasOrName() << "'" << endl;
02659 continue;
02660 }
02661 data[ fieldsOrderIt.data() ] = it.data();
02662 }
02663 return true;
02664 }
02665
02666 bool Connection::insertRow(QuerySchema &query, RowData& data, RowEditBuffer& buf, bool getROWID)
02667 {
02668
02669 KexiDBDbg << "Connection::updateRow.." << endl;
02670 clearError();
02671
02672
02673
02674
02675
02676 TableSchema *mt = query.masterTable();
02677 if (!mt) {
02678 KexiDBWarn << " -- NO MASTER TABLE!" << endl;
02679 setError(ERR_INSERT_NO_MASTER_TABLE,
02680 i18n("Could not insert row because there is no master table defined."));
02681 return false;
02682 }
02683 IndexSchema *pkey = (mt->primaryKey() && !mt->primaryKey()->fields()->isEmpty()) ? mt->primaryKey() : 0;
02684 if (!getROWID && !pkey)
02685 KexiDBWarn << " -- WARNING: NO MASTER TABLE's PKEY" << endl;
02686
02687 QString sqlcols, sqlvals;
02688 sqlcols.reserve(1024);
02689 sqlvals.reserve(1024);
02690
02691
02692 m_sql = "INSERT INTO " + escapeIdentifier(mt->name()) + " (";
02693 KexiDB::RowEditBuffer::DBMap b = buf.dbBuffer();
02694
02695 if (buf.dbBuffer().isEmpty()) {
02696 if (!getROWID && !pkey) {
02697 KexiDBWarn << " -- WARNING: MASTER TABLE's PKEY REQUIRED FOR INSERTING EMPTY ROWS: INSERT CANCELLED" << endl;
02698 setError(ERR_INSERT_NO_MASTER_TABLES_PKEY,
02699 i18n("Could not insert row because master table has no primary key defined."));
02700 return false;
02701 }
02702 if (pkey) {
02703 QValueVector<int> pkeyFieldsOrder = query.pkeyFieldsOrder();
02704
02705 if (pkey->fieldCount() != query.pkeyFieldsCount()) {
02706 KexiDBWarn << " -- NO ENTIRE MASTER TABLE's PKEY SPECIFIED!" << endl;
02707 setError(ERR_INSERT_NO_ENTIRE_MASTER_TABLES_PKEY,
02708 i18n("Could not insert row because it does not contain entire master table's primary key.")
02709 .arg(query.name()));
02710 return false;
02711 }
02712 }
02713
02714 Field *anyField = mt->anyNonPKField();
02715 if (!anyField) {
02716 if (!pkey) {
02717 KexiDBWarn << " -- WARNING: NO FILED AVAILABLE TO SET IT TO NULL" << endl;
02718 return false;
02719 }
02720 else {
02721
02722 anyField = pkey->fields()->first();
02723 }
02724 }
02725 sqlcols += escapeIdentifier(anyField->name());
02726 sqlvals += m_driver->valueToSQL(anyField,QVariant());
02727 }
02728 else {
02729 for (KexiDB::RowEditBuffer::DBMap::ConstIterator it=b.constBegin();it!=b.constEnd();++it) {
02730 if (!sqlcols.isEmpty()) {
02731 sqlcols+=",";
02732 sqlvals+=",";
02733 }
02734 sqlcols += escapeIdentifier(it.key()->field->name());
02735 sqlvals += m_driver->valueToSQL(it.key()->field,it.data());
02736 }
02737 }
02738 m_sql += (sqlcols + ") VALUES (" + sqlvals + ")");
02739
02740
02741 bool res = executeSQL(m_sql);
02742
02743 if (!res) {
02744 setError(ERR_INSERT_SERVER_ERROR, i18n("Row inserting on the server failed."));
02745 return false;
02746 }
02747
02748 QMap<QueryColumnInfo*,int> fieldsOrder = query.fieldsOrder();
02749 QMap<QueryColumnInfo*,int>::ConstIterator fieldsOrderIt;
02750 for (KexiDB::RowEditBuffer::DBMap::ConstIterator it=b.constBegin();it!=b.constEnd();++it) {
02751 fieldsOrderIt = fieldsOrder.find( it.key() );
02752 if (fieldsOrderIt == fieldsOrder.constEnd()) {
02753 KexiDBWarn << "Connection::insertRow(): \"now also assign new value in memory\" step "
02754 "- could not find item '" << it.key()->aliasOrName() << "'" << endl;
02755 continue;
02756 }
02757 data[ fieldsOrderIt.data() ] = it.data();
02758 }
02759
02760
02761 QueryColumnInfo::List *aif_list = query.autoIncrementFields();
02762 Q_ULLONG ROWID = 0;
02763 if (pkey && !aif_list->isEmpty()) {
02765 QueryColumnInfo *id_fieldinfo = aif_list->first();
02767 Q_ULLONG last_id = lastInsertedAutoIncValue(
02768 id_fieldinfo->field->name(), id_fieldinfo->field->table()->name(), &ROWID);
02769 if (last_id==(Q_ULLONG)-1 || last_id<=0) {
02772 return false;
02773 }
02774 RowData aif_data;
02775 QString getAutoIncForInsertedValue = QString::fromLatin1("SELECT ")
02776 + query.autoIncrementSQLFieldsList(m_driver)
02777 + QString::fromLatin1(" FROM ")
02778 + escapeIdentifier(id_fieldinfo->field->table()->name())
02779 + QString::fromLatin1(" WHERE ")
02780 + escapeIdentifier(id_fieldinfo->field->name()) + "="
02781 + QString::number(last_id);
02782 if (true!=querySingleRecord(getAutoIncForInsertedValue, aif_data)) {
02784 return false;
02785 }
02786 QueryColumnInfo::ListIterator fi_it(*aif_list);
02787 QueryColumnInfo *fi;
02788 for (uint i=0; (fi = fi_it.current()); ++fi_it, i++) {
02789
02790
02791 data[ fieldsOrder[ fi ] ] = aif_data[i];
02792 }
02793 }
02794 else {
02795 ROWID = drv_lastInsertRowID();
02796
02797 if (m_driver->beh->ROW_ID_FIELD_RETURNS_LAST_AUTOINCREMENTED_VALUE) {
02798 KexiDBWarn << "Connection::insertRow(): m_driver->beh->ROW_ID_FIELD_RETURNS_LAST_AUTOINCREMENTED_VALUE" << endl;
02799 return false;
02800 }
02801 }
02802 if (getROWID) {
02803
02804 data[data.size()-1] = ROWID;
02805 }
02806 return true;
02807 }
02808
02809 bool Connection::deleteRow(QuerySchema &query, RowData& data, bool useROWID)
02810 {
02811
02812 KexiDBWarn << "Connection::deleteRow.." << endl;
02813 clearError();
02814 TableSchema *mt = query.masterTable();
02815 if (!mt) {
02816 KexiDBWarn << " -- NO MASTER TABLE!" << endl;
02817 setError(ERR_DELETE_NO_MASTER_TABLE,
02818 i18n("Could not delete row because there is no master table defined.")
02819 .arg(query.name()));
02820 return false;
02821 }
02822 IndexSchema *pkey = (mt->primaryKey() && !mt->primaryKey()->fields()->isEmpty()) ? mt->primaryKey() : 0;
02823
02825 if (!useROWID && !pkey) {
02826 KexiDBWarn << " -- WARNING: NO MASTER TABLE's PKEY" << endl;
02827 setError(ERR_DELETE_NO_MASTER_TABLES_PKEY,
02828 i18n("Could not delete row because there is no primary key for master table defined."));
02829 return false;
02830 }
02831
02832
02833 m_sql = "DELETE FROM " + escapeIdentifier(mt->name()) + " WHERE ";
02834 QString sqlwhere;
02835 sqlwhere.reserve(1024);
02836
02837 if (pkey) {
02838 QValueVector<int> pkeyFieldsOrder = query.pkeyFieldsOrder();
02839 KexiDBDbg << pkey->fieldCount() << " ? " << query.pkeyFieldsCount() << endl;
02840 if (pkey->fieldCount() != query.pkeyFieldsCount()) {
02841 KexiDBWarn << " -- NO ENTIRE MASTER TABLE's PKEY SPECIFIED!" << endl;
02842 setError(ERR_DELETE_NO_ENTIRE_MASTER_TABLES_PKEY,
02843 i18n("Could not delete row because it does not contain entire master table's primary key."));
02844 return false;
02845 }
02846 uint i=0;
02847 for (Field::ListIterator it = pkey->fieldsIterator(); it.current(); i++, ++it) {
02848 if (!sqlwhere.isEmpty())
02849 sqlwhere+=" AND ";
02850 QVariant val = data[ pkeyFieldsOrder[i] ];
02851 if (val.isNull() || !val.isValid()) {
02852 setError(ERR_DELETE_NULL_PKEY_FIELD, i18n("Primary key's field \"%1\" cannot be empty.")
02853 .arg(it.current()->name()));
02854
02855 return false;
02856 }
02857 sqlwhere += ( escapeIdentifier(it.current()->name()) + "=" +
02858 m_driver->valueToSQL( it.current(), val ) );
02859 }
02860 }
02861 else {
02862 sqlwhere = ( escapeIdentifier(m_driver->beh->ROW_ID_FIELD_NAME) + "="
02863 + m_driver->valueToSQL(Field::BigInteger, data[data.size()-1]));
02864 }
02865 m_sql += sqlwhere;
02866 KexiDBDbg << " -- SQL == " << m_sql << endl;
02867
02868 if (!executeSQL(m_sql)) {
02869 setError(ERR_DELETE_SERVER_ERROR, i18n("Row deletion on the server failed."));
02870 return false;
02871 }
02872 return true;
02873 }
02874
02875 bool Connection::deleteAllRows(QuerySchema &query)
02876 {
02877 clearError();
02878 TableSchema *mt = query.masterTable();
02879 if (!mt) {
02880 KexiDBWarn << " -- NO MASTER TABLE!" << endl;
02881 return false;
02882 }
02883 IndexSchema *pkey = mt->primaryKey();
02884 if (!pkey || pkey->fields()->isEmpty())
02885 KexiDBWarn << "Connection::deleteAllRows -- WARNING: NO MASTER TABLE's PKEY" << endl;
02886
02887 m_sql = "DELETE FROM " + escapeIdentifier(mt->name());
02888
02889 KexiDBDbg << " -- SQL == " << m_sql << endl;
02890
02891 if (!executeSQL(m_sql)) {
02892 setError(ERR_DELETE_SERVER_ERROR, i18n("Row deletion on the server failed."));
02893 return false;
02894 }
02895 return true;
02896 }
02897
02898 void Connection::registerForTableSchemaChanges(TableSchemaChangeListenerInterface& listener,
02899 TableSchema &schema)
02900 {
02901 QPtrList<TableSchemaChangeListenerInterface>* listeners = d->tableSchemaChangeListeners[&schema];
02902 if (!listeners) {
02903 listeners = new QPtrList<TableSchemaChangeListenerInterface>();
02904 d->tableSchemaChangeListeners.insert(&schema, listeners);
02905 }
02906
02907 if (listeners->findRef( &listener )==-1)
02908 listeners->append( &listener );
02909 }
02910
02911 void Connection::unregisterForTableSchemaChanges(TableSchemaChangeListenerInterface& listener,
02912 TableSchema &schema)
02913 {
02914 QPtrList<TableSchemaChangeListenerInterface>* listeners = d->tableSchemaChangeListeners[&schema];
02915 if (!listeners)
02916 return;
02917
02918 listeners->remove( &listener );
02919 }
02920
02921 void Connection::unregisterForTablesSchemaChanges(TableSchemaChangeListenerInterface& listener)
02922 {
02923 for (QPtrDictIterator< QPtrList<TableSchemaChangeListenerInterface> > it(d->tableSchemaChangeListeners);
02924 it.current(); ++it)
02925 {
02926 if (-1!=it.current()->find(&listener))
02927 it.current()->take();
02928 }
02929 }
02930
02931 QPtrList<Connection::TableSchemaChangeListenerInterface>*
02932 Connection::tableSchemaChangeListeners(TableSchema& tableSchema) const
02933 {
02934 KexiDBDbg << d->tableSchemaChangeListeners.count() << endl;
02935 return d->tableSchemaChangeListeners[&tableSchema];
02936 }
02937
02938 tristate Connection::closeAllTableSchemaChangeListeners(TableSchema& tableSchema)
02939 {
02940 QPtrList<Connection::TableSchemaChangeListenerInterface> *listeners = d->tableSchemaChangeListeners[&tableSchema];
02941 if (!listeners)
02942 return true;
02943 QPtrListIterator<KexiDB::Connection::TableSchemaChangeListenerInterface> tmpListeners(*listeners);
02944 tristate res = true;
02945
02946 for (QPtrListIterator<KexiDB::Connection::TableSchemaChangeListenerInterface> it(tmpListeners);
02947 it.current() && res==true; ++it)
02948 {
02949 res = it.current()->closeListener();
02950 }
02951 return res;
02952 }
02953
02954
02955
02956
02957
02958
02959
02960
02961 void Connection::setReadOnly(bool set)
02962 {
02963 if (d->isConnected)
02964 return;
02965 d->readOnly = set;
02966 }
02967
02968 bool Connection::isReadOnly() const
02969 {
02970 return d->readOnly;
02971 }
02972
02973 #include "connection.moc"