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 "lookupfieldschema.h"
00037 #include "parser/parser.h"
00038
00039 #include <kexiutils/utils.h>
00040 #include <kexiutils/identifier.h>
00041
00042 #include <qdir.h>
00043 #include <qfileinfo.h>
00044 #include <qguardedptr.h>
00045 #include <qdom.h>
00046
00047 #include <klocale.h>
00048 #include <kdebug.h>
00049
00050 #define KEXIDB_EXTENDED_TABLE_SCHEMA_VERSION 1
00051
00052
00053
00054 namespace KexiDB {
00055
00056 Connection::SelectStatementOptions::SelectStatementOptions()
00057 : identifierEscaping(Driver::EscapeDriver|Driver::EscapeAsNecessary)
00058 , alsoRetrieveROWID(false)
00059 {
00060 }
00061
00062 Connection::SelectStatementOptions::~SelectStatementOptions()
00063 {
00064 }
00065
00066
00067
00068 ConnectionInternal::ConnectionInternal(Connection *conn)
00069 : connection(conn)
00070 {
00071 }
00072
00073 ConnectionInternal::~ConnectionInternal()
00074 {
00075 }
00076
00077
00079 class ConnectionPrivate
00080 {
00081 public:
00082 ConnectionPrivate(Connection* const conn, ConnectionData &conn_data)
00083 : conn(conn)
00084 , conn_data(&conn_data)
00085 , tableSchemaChangeListeners(101)
00086 , m_parser(0)
00087 , tables_byname(101, false)
00088 , queries_byname(101, false)
00089 , kexiDBSystemTables(101)
00090 , dont_remove_transactions(false)
00091 , skip_databaseExists_check_in_useDatabase(false)
00092 , default_trans_started_inside(false)
00093 , isConnected(false)
00094 , autoCommit(true)
00095 {
00096 tableSchemaChangeListeners.setAutoDelete(true);
00097 obsoleteQueries.setAutoDelete(true);
00098
00099 tables.setAutoDelete(true);
00100 tables_byname.setAutoDelete(false);
00101 kexiDBSystemTables.setAutoDelete(true);
00102 queries.setAutoDelete(true);
00103 queries_byname.setAutoDelete(false);
00104
00105
00106 tables.resize(101);
00107 queries.resize(101);
00108 }
00109 ~ConnectionPrivate()
00110 {
00111 delete m_parser;
00112 }
00113
00114 void errorInvalidDBContents(const QString& details) {
00115 conn->setError( ERR_INVALID_DATABASE_CONTENTS, i18n("Invalid database contents. ")+details);
00116 }
00117
00118 QString strItIsASystemObject() const {
00119 return i18n("It is a system object.");
00120 }
00121
00122 inline Parser *parser() { return m_parser ? m_parser : (m_parser = new Parser(conn)); }
00123
00124 Connection* const conn;
00125 QGuardedPtr<ConnectionData> conn_data;
00126
00131 Transaction default_trans;
00132 QValueList<Transaction> transactions;
00133
00134 QPtrDict< QPtrList<Connection::TableSchemaChangeListenerInterface> > tableSchemaChangeListeners;
00135
00138 QPtrList<QuerySchema> obsoleteQueries;
00139
00140
00142 KexiDB::ServerVersionInfo serverVersion;
00143
00145 KexiDB::DatabaseVersionInfo databaseVersion;
00146
00147 Parser *m_parser;
00148
00150 QIntDict<TableSchema> tables;
00151 QDict<TableSchema> tables_byname;
00152 QIntDict<QuerySchema> queries;
00153 QDict<QuerySchema> queries_byname;
00154
00156 QPtrDict<TableSchema> kexiDBSystemTables;
00157
00159 DatabaseProperties* dbProperties;
00160
00161 QString availableDatabaseName;
00162 QString usedDatabase;
00163
00166 bool dont_remove_transactions : 1;
00167
00170 bool skip_databaseExists_check_in_useDatabase : 1;
00171
00180 bool default_trans_started_inside : 1;
00181
00182 bool isConnected : 1;
00183
00184 bool autoCommit : 1;
00185
00187 bool readOnly : 1;
00188 };
00189
00190 }
00191
00192
00193 using namespace KexiDB;
00194
00196 QStringList KexiDB_kexiDBSystemTableNames;
00197
00198 Connection::Connection( Driver *driver, ConnectionData &conn_data )
00199 : QObject()
00200 ,KexiDB::Object()
00201 ,d(new ConnectionPrivate(this, conn_data))
00202 ,m_driver(driver)
00203 ,m_destructor_started(false)
00204 {
00205 d->dbProperties = new DatabaseProperties(this);
00206 m_cursors.setAutoDelete(true);
00207
00208
00209 m_cursors.resize(101);
00210
00211 m_sql.reserve(0x4000);
00212 }
00213
00214 void Connection::destroy()
00215 {
00216 disconnect();
00217
00218 m_driver->d->connections.take( this );
00219 }
00220
00221 Connection::~Connection()
00222 {
00223 m_destructor_started = true;
00224
00225 delete d->dbProperties;
00226 delete d;
00227 d = 0;
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238 }
00239
00240 ConnectionData* Connection::data() const
00241 {
00242 return d->conn_data;
00243 }
00244
00245 bool Connection::connect()
00246 {
00247 clearError();
00248 if (d->isConnected) {
00249 setError(ERR_ALREADY_CONNECTED, i18n("Connection already established.") );
00250 return false;
00251 }
00252
00253 d->serverVersion.clear();
00254 if (!(d->isConnected = drv_connect(d->serverVersion))) {
00255 setError(m_driver->isFileDriver() ?
00256 i18n("Could not open \"%1\" project file.").arg(QDir::convertSeparators(d->conn_data->fileName()))
00257 : i18n("Could not connect to \"%1\" database server.").arg(d->conn_data->serverInfoString()) );
00258 }
00259 return d->isConnected;
00260 }
00261
00262 bool Connection::isDatabaseUsed() const
00263 {
00264 return !d->usedDatabase.isEmpty() && d->isConnected && drv_isDatabaseUsed();
00265 }
00266
00267 void Connection::clearError()
00268 {
00269 Object::clearError();
00270 m_sql = QString::null;
00271 }
00272
00273 bool Connection::disconnect()
00274 {
00275 clearError();
00276 if (!d->isConnected)
00277 return true;
00278
00279 if (!closeDatabase())
00280 return false;
00281
00282 bool ok = drv_disconnect();
00283 if (ok)
00284 d->isConnected = false;
00285 return ok;
00286 }
00287
00288 bool Connection::isConnected() const
00289 {
00290 return d->isConnected;
00291 }
00292
00293 bool Connection::checkConnected()
00294 {
00295 if (d->isConnected) {
00296 clearError();
00297 return true;
00298 }
00299 setError(ERR_NO_CONNECTION, i18n("Not connected to the database server.") );
00300 return false;
00301 }
00302
00303 bool Connection::checkIsDatabaseUsed()
00304 {
00305 if (isDatabaseUsed()) {
00306 clearError();
00307 return true;
00308 }
00309 setError(ERR_NO_DB_USED, i18n("Currently no database is used.") );
00310 return false;
00311 }
00312
00313 QStringList Connection::databaseNames(bool also_system_db)
00314 {
00315 KexiDBDbg << "Connection::databaseNames("<<also_system_db<<")"<< endl;
00316 if (!checkConnected())
00317 return QStringList();
00318
00319 QString tmpdbName;
00320
00321 if (!useTemporaryDatabaseIfNeeded(tmpdbName))
00322 return QStringList();
00323
00324 QStringList list, non_system_list;
00325
00326 bool ret = drv_getDatabasesList( list );
00327
00328 if (!tmpdbName.isEmpty()) {
00329
00330 if (!closeDatabase())
00331 return QStringList();
00332 }
00333
00334 if (!ret)
00335 return QStringList();
00336
00337 if (also_system_db)
00338 return list;
00339
00340 for (QStringList::ConstIterator it = list.constBegin(); it!=list.constEnd(); ++it) {
00341 KexiDBDbg << "Connection::databaseNames(): " << *it << endl;
00342 if (!m_driver->isSystemDatabaseName(*it)) {
00343 KexiDBDbg << "add " << *it << endl;
00344 non_system_list << (*it);
00345 }
00346 }
00347 return non_system_list;
00348 }
00349
00350 bool Connection::drv_getDatabasesList( QStringList &list )
00351 {
00352 list.clear();
00353 return true;
00354 }
00355
00356 bool Connection::drv_databaseExists( const QString &dbName, bool ignoreErrors )
00357 {
00358 QStringList list = databaseNames(true);
00359 if (error()) {
00360 return false;
00361 }
00362
00363 if (list.find( dbName )==list.end()) {
00364 if (!ignoreErrors)
00365 setError(ERR_OBJECT_NOT_FOUND, i18n("The database \"%1\" does not exist.").arg(dbName));
00366 return false;
00367 }
00368
00369 return true;
00370 }
00371
00372 bool Connection::databaseExists( const QString &dbName, bool ignoreErrors )
00373 {
00374
00375 if (!checkConnected())
00376 return false;
00377 clearError();
00378
00379 if (m_driver->isFileDriver()) {
00380
00381
00382 QFileInfo file(d->conn_data->fileName());
00383 if (!file.exists() || ( !file.isFile() && !file.isSymLink()) ) {
00384 if (!ignoreErrors)
00385 setError(ERR_OBJECT_NOT_FOUND, i18n("Database file \"%1\" does not exist.")
00386 .arg(QDir::convertSeparators(d->conn_data->fileName())) );
00387 return false;
00388 }
00389 if (!file.isReadable()) {
00390 if (!ignoreErrors)
00391 setError(ERR_ACCESS_RIGHTS, i18n("Database file \"%1\" is not readable.")
00392 .arg(QDir::convertSeparators(d->conn_data->fileName())) );
00393 return false;
00394 }
00395 if (!file.isWritable()) {
00396 if (!ignoreErrors)
00397 setError(ERR_ACCESS_RIGHTS, i18n("Database file \"%1\" is not writable.")
00398 .arg(QDir::convertSeparators(d->conn_data->fileName())) );
00399 return false;
00400 }
00401 return true;
00402 }
00403
00404 QString tmpdbName;
00405
00406 const bool orig_skip_databaseExists_check_in_useDatabase = d->skip_databaseExists_check_in_useDatabase;
00407 d->skip_databaseExists_check_in_useDatabase = true;
00408 bool ret = useTemporaryDatabaseIfNeeded(tmpdbName);
00409 d->skip_databaseExists_check_in_useDatabase = orig_skip_databaseExists_check_in_useDatabase;
00410 if (!ret)
00411 return false;
00412
00413 ret = drv_databaseExists(dbName, ignoreErrors);
00414
00415 if (!tmpdbName.isEmpty()) {
00416
00417 if (!closeDatabase())
00418 return false;
00419 }
00420
00421 return ret;
00422 }
00423
00424 #define createDatabase_CLOSE \
00425 { if (!closeDatabase()) { \
00426 setError(i18n("Database \"%1\" created but could not be closed after creation.").arg(dbName) ); \
00427 return false; \
00428 } }
00429
00430 #define createDatabase_ERROR \
00431 { createDatabase_CLOSE; return false; }
00432
00433
00434 bool Connection::createDatabase( const QString &dbName )
00435 {
00436 if (!checkConnected())
00437 return false;
00438
00439 if (databaseExists( dbName )) {
00440 setError(ERR_OBJECT_EXISTS, i18n("Database \"%1\" already exists.").arg(dbName) );
00441 return false;
00442 }
00443 if (m_driver->isSystemDatabaseName( dbName )) {
00444 setError(ERR_SYSTEM_NAME_RESERVED,
00445 i18n("Cannot create database \"%1\". This name is reserved for system database.").arg(dbName) );
00446 return false;
00447 }
00448 if (m_driver->isFileDriver()) {
00449
00450 d->conn_data->setFileName( dbName );
00451 }
00452
00453 QString tmpdbName;
00454
00455 if (!useTemporaryDatabaseIfNeeded(tmpdbName))
00456 return false;
00457
00458
00459 if (!drv_createDatabase( dbName )) {
00460 setError(i18n("Error creating database \"%1\" on the server.").arg(dbName) );
00461 closeDatabase();
00462 return false;
00463 }
00464
00465 if (!tmpdbName.isEmpty()) {
00466
00467 if (!closeDatabase())
00468 return false;
00469 }
00470
00471 if (!tmpdbName.isEmpty() || !m_driver->d->isDBOpenedAfterCreate) {
00472
00473 if (!useDatabase( dbName, false )) {
00474 setError(i18n("Database \"%1\" created but could not be opened.").arg(dbName) );
00475 return false;
00476 }
00477 }
00478 else {
00479
00480 d->usedDatabase = dbName;
00481 }
00482
00483 Transaction trans;
00484 if (m_driver->transactionsSupported()) {
00485 trans = beginTransaction();
00486 if (!trans.active())
00487 return false;
00488 }
00489
00490
00491
00492
00493
00494 if (!setupKexiDBSystemSchema())
00495 return false;
00496
00497
00498 for (QPtrDictIterator<TableSchema> it(d->kexiDBSystemTables); it.current(); ++it) {
00499 if (!drv_createTable( it.current()->name() ))
00500 createDatabase_ERROR;
00501 }
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519 TableSchema *t_db = tableSchema("kexi__db");
00520 if (!t_db)
00521 createDatabase_ERROR;
00522 if ( !insertRecord(*t_db, "kexidb_major_ver", KexiDB::version().major)
00523 || !insertRecord(*t_db, "kexidb_minor_ver", KexiDB::version().minor))
00524 createDatabase_ERROR;
00525
00526 if (trans.active() && !commitTransaction(trans))
00527 createDatabase_ERROR;
00528
00529 createDatabase_CLOSE;
00530 return true;
00531 }
00532
00533 #undef createDatabase_CLOSE
00534 #undef createDatabase_ERROR
00535
00536 bool Connection::useDatabase( const QString &dbName, bool kexiCompatible, bool *cancelled, MessageHandler* msgHandler )
00537 {
00538 if (cancelled)
00539 *cancelled = false;
00540 KexiDBDbg << "Connection::useDatabase(" << dbName << "," << kexiCompatible <<")" << endl;
00541 if (!checkConnected())
00542 return false;
00543
00544 if (dbName.isEmpty())
00545 return false;
00546 QString my_dbName = dbName;
00547
00548
00549
00550
00551
00552 if (d->usedDatabase == my_dbName)
00553 return true;
00554
00555 if (!d->skip_databaseExists_check_in_useDatabase) {
00556 if (!databaseExists(my_dbName, false ))
00557 return false;
00558 }
00559
00560 if (!d->usedDatabase.isEmpty() && !closeDatabase())
00561 return false;
00562
00563 d->usedDatabase = "";
00564
00565 if (!drv_useDatabase( my_dbName, cancelled, msgHandler )) {
00566 if (cancelled && *cancelled)
00567 return false;
00568 QString msg(i18n("Opening database \"%1\" failed.").arg( my_dbName ));
00569 if (error())
00570 setError( this, msg );
00571 else
00572 setError( msg );
00573 return false;
00574 }
00575
00576
00577 if (!setupKexiDBSystemSchema())
00578 return false;
00579
00580 if (kexiCompatible && my_dbName.lower()!=anyAvailableDatabaseName().lower()) {
00581
00582 int num;
00583 bool ok;
00584
00585 num = d->dbProperties->value("kexidb_major_ver").toInt(&ok);
00586 if (!ok)
00587 return false;
00588 d->databaseVersion.major = num;
00589
00590
00591
00592
00593
00594 num = d->dbProperties->value("kexidb_minor_ver").toInt(&ok);
00595 if (!ok)
00596 return false;
00597 d->databaseVersion.minor = num;
00598
00599
00600
00601
00602
00603
00604 #if 0 //this is already checked in DriverManagerInternal::lookupDrivers()
00605
00606 if (m_driver->versionMajor()!=KexiDB::versionMajor()) {
00607 setError(ERR_INCOMPAT_DATABASE_VERSION,
00608 i18n("Database version (%1) does not match Kexi application's version (%2)")
00609 .arg( QString("%1.%2").arg(versionMajor()).arg(versionMinor()) )
00610 .arg( QString("%1.%2").arg(KexiDB::versionMajor()).arg(KexiDB::versionMinor()) ) );
00611 return false;
00612 }
00613 if (m_driver->versionMinor()!=KexiDB::versionMinor()) {
00614
00615
00616 }
00617 #endif
00618 }
00619 d->usedDatabase = my_dbName;
00620 return true;
00621 }
00622
00623 bool Connection::closeDatabase()
00624 {
00625 if (d->usedDatabase.isEmpty())
00626 return true;
00627 if (!checkConnected())
00628 return true;
00629
00630 bool ret = true;
00631
00633 if (m_driver->transactionsSupported()) {
00634
00635 QValueList<Transaction>::ConstIterator it;
00636 d->dont_remove_transactions=true;
00637 for (it=d->transactions.constBegin(); it!= d->transactions.constEnd(); ++it) {
00638 if (!rollbackTransaction(*it)) {
00639 ret = false;
00640 }
00641 else {
00642 KexiDBDbg << "Connection::closeDatabase(): transaction rolled back!" << endl;
00643 KexiDBDbg << "Connection::closeDatabase(): trans.refcount==" <<
00644 ((*it).m_data ? QString::number((*it).m_data->refcount) : "(null)") << endl;
00645 }
00646 }
00647 d->dont_remove_transactions=false;
00648 d->transactions.clear();
00649 }
00650
00651
00652 m_cursors.clear();
00653
00654 d->tables.clear();
00655 d->kexiDBSystemTables.clear();
00656 d->queries.clear();
00657
00658 if (!drv_closeDatabase())
00659 return false;
00660
00661 d->usedDatabase = "";
00662
00663 return ret;
00664 }
00665
00666 QString Connection::currentDatabase() const
00667 {
00668 return d->usedDatabase;
00669 }
00670
00671 bool Connection::useTemporaryDatabaseIfNeeded(QString &tmpdbName)
00672 {
00673 if (!m_driver->isFileDriver() && m_driver->beh->USING_DATABASE_REQUIRED_TO_CONNECT
00674 && !isDatabaseUsed()) {
00675
00676 tmpdbName = anyAvailableDatabaseName();
00677 if (tmpdbName.isEmpty()) {
00678 setError(ERR_NO_DB_USED, i18n("Cannot find any database for temporary connection.") );
00679 return false;
00680 }
00681 const bool orig_skip_databaseExists_check_in_useDatabase = d->skip_databaseExists_check_in_useDatabase;
00682 d->skip_databaseExists_check_in_useDatabase = true;
00683 bool ret = useDatabase(tmpdbName, false);
00684 d->skip_databaseExists_check_in_useDatabase = orig_skip_databaseExists_check_in_useDatabase;
00685 if (!ret) {
00686 setError(errorNum(),
00687 i18n("Error during starting temporary connection using \"%1\" database name.")
00688 .arg(tmpdbName) );
00689 return false;
00690 }
00691 }
00692 return true;
00693 }
00694
00695 bool Connection::dropDatabase( const QString &dbName )
00696 {
00697 if (!checkConnected())
00698 return false;
00699
00700 QString dbToDrop;
00701 if (dbName.isEmpty() && d->usedDatabase.isEmpty()) {
00702 if (!m_driver->isFileDriver()
00703 || (m_driver->isFileDriver() && d->conn_data->fileName().isEmpty()) ) {
00704 setError(ERR_NO_NAME_SPECIFIED, i18n("Cannot drop database - name not specified.") );
00705 return false;
00706 }
00707
00708 dbToDrop = d->conn_data->fileName();
00709 }
00710 else {
00711 if (dbName.isEmpty()) {
00712 dbToDrop = d->usedDatabase;
00713 } else {
00714 if (m_driver->isFileDriver())
00715 dbToDrop = QFileInfo(dbName).absFilePath();
00716 else
00717 dbToDrop = dbName;
00718 }
00719 }
00720
00721 if (dbToDrop.isEmpty()) {
00722 setError(ERR_NO_NAME_SPECIFIED, i18n("Cannot delete database - name not specified.") );
00723 return false;
00724 }
00725
00726 if (m_driver->isSystemDatabaseName( dbToDrop )) {
00727 setError(ERR_SYSTEM_NAME_RESERVED, i18n("Cannot delete system database \"%1\".").arg(dbToDrop) );
00728 return false;
00729 }
00730
00731 if (isDatabaseUsed() && d->usedDatabase == dbToDrop) {
00732
00733 if (!closeDatabase())
00734 return false;
00735 }
00736
00737 QString tmpdbName;
00738
00739 if (!useTemporaryDatabaseIfNeeded(tmpdbName))
00740 return false;
00741
00742
00743 bool ret = drv_dropDatabase( dbToDrop );
00744
00745 if (!tmpdbName.isEmpty()) {
00746
00747 if (!closeDatabase())
00748 return false;
00749 }
00750 return ret;
00751 }
00752
00753 QStringList Connection::objectNames(int objType, bool* ok)
00754 {
00755 QStringList list;
00756
00757 if (!checkIsDatabaseUsed()) {
00758 if(ok)
00759 *ok = false;
00760 return list;
00761 }
00762
00763 QString sql;
00764 if (objType==KexiDB::AnyObjectType)
00765 sql = "SELECT o_name FROM kexi__objects";
00766 else
00767 sql = QString::fromLatin1("SELECT o_name FROM kexi__objects WHERE o_type=%1").arg(objType);
00768
00769 Cursor *c = executeQuery(sql);
00770 if (!c) {
00771 if(ok)
00772 *ok = false;
00773 return list;
00774 }
00775
00776 for (c->moveFirst(); !c->eof(); c->moveNext()) {
00777 QString name = c->value(0).toString();
00778 if (KexiUtils::isIdentifier( name )) {
00779 list.append(name);
00780 }
00781 }
00782
00783 if (!deleteCursor(c)) {
00784 if(ok)
00785 *ok = false;
00786 return list;
00787 }
00788
00789 if(ok)
00790 *ok = true;
00791 return list;
00792 }
00793
00794 QStringList Connection::tableNames(bool also_system_tables)
00795 {
00796 bool ok = true;
00797 QStringList list = objectNames(TableObjectType, &ok);
00798 if (also_system_tables && ok) {
00799 list += Connection::kexiDBSystemTableNames();
00800 }
00801 return list;
00802 }
00803
00805 const QStringList& Connection::kexiDBSystemTableNames()
00806 {
00807 if (KexiDB_kexiDBSystemTableNames.isEmpty()) {
00808 KexiDB_kexiDBSystemTableNames
00809 << "kexi__objects"
00810 << "kexi__objectdata"
00811 << "kexi__fields"
00812
00813
00814
00815 << "kexi__db"
00816 ;
00817 }
00818 return KexiDB_kexiDBSystemTableNames;
00819 }
00820
00821 KexiDB::ServerVersionInfo* Connection::serverVersion() const
00822 {
00823 return isConnected() ? &d->serverVersion : 0;
00824 }
00825
00826 KexiDB::DatabaseVersionInfo* Connection::databaseVersion() const
00827 {
00828 return isDatabaseUsed() ? &d->databaseVersion : 0;
00829 }
00830
00831 DatabaseProperties& Connection::databaseProperties()
00832 {
00833 return *d->dbProperties;
00834 }
00835
00836 QValueList<int> Connection::tableIds()
00837 {
00838 return objectIds(KexiDB::TableObjectType);
00839 }
00840
00841 QValueList<int> Connection::queryIds()
00842 {
00843 return objectIds(KexiDB::QueryObjectType);
00844 }
00845
00846 QValueList<int> Connection::objectIds(int objType)
00847 {
00848 QValueList<int> list;
00849
00850 if (!checkIsDatabaseUsed())
00851 return list;
00852
00853 Cursor *c = executeQuery(
00854 QString::fromLatin1("SELECT o_id, o_name FROM kexi__objects WHERE o_type=%1").arg(objType));
00855 if (!c)
00856 return list;
00857 for (c->moveFirst(); !c->eof(); c->moveNext())
00858 {
00859 QString tname = c->value(1).toString();
00860 if (KexiUtils::isIdentifier( tname )) {
00861 list.append(c->value(0).toInt());
00862 }
00863 }
00864
00865 deleteCursor(c);
00866
00867 return list;
00868 }
00869
00870 QString Connection::createTableStatement( const KexiDB::TableSchema& tableSchema ) const
00871 {
00872
00873 QString sql;
00874 sql.reserve(4096);
00875 sql = "CREATE TABLE " + escapeIdentifier(tableSchema.name()) + " (";
00876 bool first=true;
00877 Field::ListIterator it( tableSchema.m_fields );
00878 Field *field;
00879 for (;(field = it.current())!=0; ++it) {
00880 if (first)
00881 first = false;
00882 else
00883 sql += ", ";
00884 QString v = escapeIdentifier(field->name()) + " ";
00885 const bool autoinc = field->isAutoIncrement();
00886 const bool pk = field->isPrimaryKey() || (autoinc && m_driver->beh->AUTO_INCREMENT_REQUIRES_PK);
00887
00888 if (autoinc && m_driver->beh->SPECIAL_AUTO_INCREMENT_DEF) {
00889 if (pk)
00890 v += m_driver->beh->AUTO_INCREMENT_TYPE + " " + m_driver->beh->AUTO_INCREMENT_PK_FIELD_OPTION;
00891 else
00892 v += m_driver->beh->AUTO_INCREMENT_TYPE + " " + m_driver->beh->AUTO_INCREMENT_FIELD_OPTION;
00893 }
00894 else {
00895 if (autoinc && !m_driver->beh->AUTO_INCREMENT_TYPE.isEmpty())
00896 v += m_driver->beh->AUTO_INCREMENT_TYPE;
00897 else
00898 v += m_driver->sqlTypeName(field->type(), field->precision());
00899
00900 if (field->isUnsigned())
00901 v += (" " + m_driver->beh->UNSIGNED_TYPE_KEYWORD);
00902
00903 if (field->isFPNumericType() && field->precision()>0) {
00904 if (field->scale()>0)
00905 v += QString::fromLatin1("(%1,%2)").arg(field->precision()).arg(field->scale());
00906 else
00907 v += QString::fromLatin1("(%1)").arg(field->precision());
00908 }
00909 else if (field->type()==Field::Text && field->length()>0)
00910 v += QString::fromLatin1("(%1)").arg(field->length());
00911
00912 if (autoinc)
00913 v += (" " +
00914 (pk ? m_driver->beh->AUTO_INCREMENT_PK_FIELD_OPTION : m_driver->beh->AUTO_INCREMENT_FIELD_OPTION));
00915 else
00916
00917 if (pk)
00918 v += " PRIMARY KEY";
00919 if (!pk && field->isUniqueKey())
00920 v += " UNIQUE";
00922 if (!autoinc && !pk && field->isNotNull())
00923 v += " NOT NULL";
00924 if (field->defaultValue().isValid()) {
00925 QString valToSQL( m_driver->valueToSQL( field, field->defaultValue() ) );
00926 if (!valToSQL.isEmpty())
00927 v += QString::fromLatin1(" DEFAULT ") + valToSQL;
00928 }
00929 }
00930 sql += v;
00931 }
00932 sql += ")";
00933 return sql;
00934 }
00935
00936
00937 #define C_A(a) , const QVariant& c ## a
00938
00939 #define V_A0 m_driver->valueToSQL( tableSchema.field(0), c0 )
00940 #define V_A(a) +","+m_driver->valueToSQL( \
00941 tableSchema.field(a) ? tableSchema.field(a)->type() : Field::Text, c ## a )
00942
00943
00944
00945
00946
00947 #define C_INS_REC(args, vals) \
00948 bool Connection::insertRecord(KexiDB::TableSchema &tableSchema args) {\
00949 return executeSQL( \
00950 QString("INSERT INTO ") + escapeIdentifier(tableSchema.name()) + " VALUES (" + vals + ")" \
00951 ); \
00952 }
00953
00954 #define C_INS_REC_ALL \
00955 C_INS_REC( C_A(0), V_A0 ) \
00956 C_INS_REC( C_A(0) C_A(1), V_A0 V_A(1) ) \
00957 C_INS_REC( C_A(0) C_A(1) C_A(2), V_A0 V_A(1) V_A(2) ) \
00958 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) ) \
00959 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) ) \
00960 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) ) \
00961 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) ) \
00962 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) )
00963
00964 C_INS_REC_ALL
00965
00966 #undef V_A0
00967 #undef V_A
00968 #undef C_INS_REC
00969
00970 #define V_A0 value += m_driver->valueToSQL( flist->first(), c0 );
00971 #define V_A( a ) value += ("," + m_driver->valueToSQL( flist->next(), c ## a ));
00972
00973
00974
00975 #define C_INS_REC(args, vals) \
00976 bool Connection::insertRecord(FieldList& fields args) \
00977 { \
00978 QString value; \
00979 Field::List *flist = fields.fields(); \
00980 vals \
00981 return executeSQL( \
00982 QString("INSERT INTO ") + \
00983 ((fields.fields()->first() && fields.fields()->first()->table()) ? \
00984 escapeIdentifier(fields.fields()->first()->table()->name()) : \
00985 "??") \
00986 + "(" + fields.sqlFieldsList(m_driver) + ") VALUES (" + value + ")" \
00987 ); \
00988 }
00989
00990 C_INS_REC_ALL
00991
00992 #undef C_A
00993 #undef V_A
00994 #undef V_ALAST
00995 #undef C_INS_REC
00996 #undef C_INS_REC_ALL
00997
00998 bool Connection::insertRecord(TableSchema &tableSchema, QValueList<QVariant>& values)
00999 {
01000
01001 Field::List *fields = tableSchema.fields();
01002 Field *f = fields->first();
01003
01004
01005 m_sql = QString::null;
01006 QValueList<QVariant>::ConstIterator it = values.constBegin();
01007
01008 while (f && (it!=values.end())) {
01009 if (m_sql.isEmpty())
01010 m_sql = QString("INSERT INTO ") +
01011 escapeIdentifier(tableSchema.name()) +
01012 " VALUES (";
01013 else
01014 m_sql += ",";
01015 m_sql += m_driver->valueToSQL( f, *it );
01016
01017 ++it;
01018 f=fields->next();
01019 }
01020 m_sql += ")";
01021
01022
01023 return executeSQL(m_sql);
01024 }
01025
01026 bool Connection::insertRecord(FieldList& fields, QValueList<QVariant>& values)
01027 {
01028
01029 Field::List *flist = fields.fields();
01030 Field *f = flist->first();
01031 if (!f)
01032 return false;
01033
01034
01035 m_sql = QString::null;
01036 QValueList<QVariant>::ConstIterator it = values.constBegin();
01037
01038 while (f && (it!=values.constEnd())) {
01039 if (m_sql.isEmpty())
01040 m_sql = QString("INSERT INTO ") +
01041 escapeIdentifier(flist->first()->table()->name()) + "(" +
01042 fields.sqlFieldsList(m_driver) + ") VALUES (";
01043 else
01044 m_sql += ",";
01045 m_sql += m_driver->valueToSQL( f, *it );
01046
01047 ++it;
01048 f=flist->next();
01049 }
01050 m_sql += ")";
01051
01052 return executeSQL(m_sql);
01053 }
01054
01055 bool Connection::executeSQL( const QString& statement )
01056 {
01057 m_sql = statement;
01058 if (!drv_executeSQL( m_sql )) {
01059 m_errMsg = QString::null;
01060 m_errorSql = statement;
01061 setError(this, ERR_SQL_EXECUTION_ERROR, i18n("Error while executing SQL statement."));
01062 return false;
01063 }
01064 return true;
01065 }
01066
01067 QString Connection::selectStatement( KexiDB::QuerySchema& querySchema,
01068 const QValueList<QVariant>& params,
01069 const SelectStatementOptions& options) const
01070 {
01071
01072
01073
01074
01075
01076 if (!querySchema.statement().isEmpty())
01077 return querySchema.statement();
01078
01081 Field *f;
01082 uint number = 0;
01083 bool singleTable = querySchema.tables()->count() <= 1;
01084 if (singleTable) {
01085
01086 for (Field::ListIterator it = querySchema.fieldsIterator(); (f = it.current()); ++it, number++) {
01087 if (querySchema.isColumnVisible(number) && f->table() && f->table()->lookupFieldSchema( *f )) {
01088
01089 singleTable = false;
01090 break;
01091 }
01092 }
01093 }
01094
01095 QString sql;
01096 sql.reserve(4096);
01097
01098 QString s_additional_joins;
01099 QString s_additional_fields;
01100 uint internalUniqueTableAliasNumber = 0;
01101 uint internalUniqueQueryAliasNumber = 0;
01102 number = 0;
01103 QPtrList<QuerySchema> subqueries_for_lookup_data;
01104 QString kexidb_subquery_prefix("__kexidb_subquery_");
01105 for (Field::ListIterator it = querySchema.fieldsIterator(); (f = it.current()); ++it, number++) {
01106 if (querySchema.isColumnVisible(number)) {
01107 if (!sql.isEmpty())
01108 sql += QString::fromLatin1(", ");
01109
01110 if (f->isQueryAsterisk()) {
01111 if (!singleTable && static_cast<QueryAsterisk*>(f)->isSingleTableAsterisk())
01112 sql += escapeIdentifier(f->table()->name(), options.identifierEscaping) +
01113 QString::fromLatin1(".*");
01114 else
01115 sql += QString::fromLatin1("*");
01116 }
01117 else {
01118 if (f->isExpression()) {
01119 sql += f->expression()->toString();
01120 }
01121 else {
01122 if (!f->table())
01123 return QString::null;
01124
01125 QString tableName;
01126 int tablePosition = querySchema.tableBoundToColumn(number);
01127 if (tablePosition>=0)
01128 tableName = querySchema.tableAlias(tablePosition);
01129 if (tableName.isEmpty())
01130 tableName = f->table()->name();
01131
01132 if (!singleTable) {
01133 sql += (escapeIdentifier(tableName, options.identifierEscaping) + ".");
01134 }
01135 sql += escapeIdentifier(f->name(), options.identifierEscaping);
01136 }
01137 QString aliasString = QString(querySchema.columnAlias(number));
01138 if (!aliasString.isEmpty())
01139 sql += (QString::fromLatin1(" AS ") + aliasString);
01141 }
01142 LookupFieldSchema *lookupFieldSchema = f->table() ? f->table()->lookupFieldSchema( *f ) : 0;
01143 if (lookupFieldSchema && lookupFieldSchema->boundColumn()>=0) {
01144
01145
01146
01147
01148 LookupFieldSchema::RowSource& rowSource = lookupFieldSchema->rowSource();
01149 if (rowSource.type()==LookupFieldSchema::RowSource::Table) {
01150 TableSchema *lookupTable = querySchema.connection()->tableSchema( rowSource.name() );
01151 FieldList* visibleColumns = 0;
01152 Field *boundField = 0;
01153 if (lookupTable
01154 && (uint)lookupFieldSchema->boundColumn() < lookupTable->fieldCount()
01155 && (visibleColumns = lookupTable->subList( lookupFieldSchema->visibleColumns() ))
01156 && (boundField = lookupTable->field( lookupFieldSchema->boundColumn() )))
01157 {
01158
01159 if (!s_additional_joins.isEmpty())
01160 s_additional_joins += QString::fromLatin1(" ");
01161 QString internalUniqueTableAlias( QString("__kexidb_") + lookupTable->name() + "_"
01162 + QString::number(internalUniqueTableAliasNumber++) );
01163 s_additional_joins += QString("LEFT OUTER JOIN %1 AS %2 ON %3.%4=%5.%6")
01164 .arg(escapeIdentifier(lookupTable->name(), options.identifierEscaping))
01165 .arg(internalUniqueTableAlias)
01166 .arg(escapeIdentifier(f->table()->name(), options.identifierEscaping))
01167 .arg(escapeIdentifier(f->name(), options.identifierEscaping))
01168 .arg(internalUniqueTableAlias)
01169 .arg(escapeIdentifier(boundField->name(), options.identifierEscaping));
01170
01171
01172
01173 #if 0
01174 if (!querySchema.table( visibleField->table()->name() )) {
01175
01176
01177
01178
01179
01180
01181 }
01182 #endif
01183 if (!s_additional_fields.isEmpty())
01184 s_additional_fields += QString::fromLatin1(", ");
01185
01186
01189 s_additional_fields += visibleColumns->sqlFieldsList(
01190 driver(), " || ' ' || ", internalUniqueTableAlias, options.identifierEscaping);
01191 }
01192 delete visibleColumns;
01193 }
01194 else if (rowSource.type()==LookupFieldSchema::RowSource::Query) {
01195 QuerySchema *lookupQuery = querySchema.connection()->querySchema( rowSource.name() );
01196 if (!lookupQuery) {
01197 KexiDBWarn << "Connection::selectStatement(): !lookupQuery" << endl;
01198 return QString::null;
01199 }
01200 const QueryColumnInfo::Vector fieldsExpanded( lookupQuery->fieldsExpanded() );
01201 if ((uint)lookupFieldSchema->boundColumn() >= fieldsExpanded.count()) {
01202 KexiDBWarn << "Connection::selectStatement(): (uint)lookupFieldSchema->boundColumn() >= fieldsExpanded.count()" << endl;
01203 return QString::null;
01204 }
01205 QueryColumnInfo *boundColumnInfo = fieldsExpanded.at( lookupFieldSchema->boundColumn() );
01206 if (!boundColumnInfo) {
01207 KexiDBWarn << "Connection::selectStatement(): !boundColumnInfo" << endl;
01208 return QString::null;
01209 }
01210 Field *boundField = boundColumnInfo->field;
01211 if (!boundField) {
01212 KexiDBWarn << "Connection::selectStatement(): !boundField" << endl;
01213 return QString::null;
01214 }
01215
01216 if (!s_additional_joins.isEmpty())
01217 s_additional_joins += QString::fromLatin1(" ");
01218 QString internalUniqueQueryAlias(
01219 kexidb_subquery_prefix + lookupQuery->name() + "_"
01220 + QString::number(internalUniqueQueryAliasNumber++) );
01221 s_additional_joins += QString("LEFT OUTER JOIN (%1) AS %2 ON %3.%4=%5.%6")
01222 .arg(selectStatement( *lookupQuery, params, options ))
01223 .arg(internalUniqueQueryAlias)
01224 .arg(escapeIdentifier(f->table()->name(), options.identifierEscaping))
01225 .arg(escapeIdentifier(f->name(), options.identifierEscaping))
01226 .arg(internalUniqueQueryAlias)
01227 .arg(escapeIdentifier(boundColumnInfo->aliasOrName(), options.identifierEscaping));
01228
01229 if (!s_additional_fields.isEmpty())
01230 s_additional_fields += QString::fromLatin1(", ");
01231 const QValueList<uint> visibleColumns( lookupFieldSchema->visibleColumns() );
01232 QString expression;
01233 foreach (QValueList<uint>::ConstIterator, visibleColumnsIt, visibleColumns) {
01236 if (fieldsExpanded.count() <= (*visibleColumnsIt)) {
01237 KexiDBWarn << "Connection::selectStatement(): fieldsExpanded.count() <= (*visibleColumnsIt) : "
01238 << fieldsExpanded.count() << " <= " << *visibleColumnsIt << endl;
01239 return QString::null;
01240 }
01241 if (!expression.isEmpty())
01242 expression += " || ' ' || ";
01243 expression += (internalUniqueQueryAlias + "." +
01244 escapeIdentifier(fieldsExpanded[*visibleColumnsIt]->aliasOrName(),
01245 options.identifierEscaping));
01246 }
01247 s_additional_fields += expression;
01248
01249 }
01250 else {
01251 KexiDBWarn << "Connection::selectStatement(): unsupported row source type "
01252 << rowSource.typeName() << endl;
01253 return false;
01254 }
01255 }
01256 }
01257 }
01258
01259
01260 if (!s_additional_fields.isEmpty())
01261 sql += (QString::fromLatin1(", ") + s_additional_fields);
01262
01263 if (options.alsoRetrieveROWID) {
01264 QString s;
01265 if (!sql.isEmpty())
01266 s = QString::fromLatin1(", ");
01267 if (querySchema.masterTable())
01268 s += (escapeIdentifier(querySchema.masterTable()->name())+".");
01269 s += m_driver->beh->ROW_ID_FIELD_NAME;
01270 sql += s;
01271 }
01272
01273 sql.prepend("SELECT ");
01274 TableSchema::List* tables = querySchema.tables();
01275 if ((tables && !tables->isEmpty()) || !subqueries_for_lookup_data.isEmpty()) {
01276 sql += QString::fromLatin1(" FROM ");
01277 QString s_from;
01278 if (tables) {
01279 TableSchema *table;
01280 number = 0;
01281 for (TableSchema::ListIterator it(*tables); (table = it.current());
01282 ++it, number++)
01283 {
01284 if (!s_from.isEmpty())
01285 s_from += QString::fromLatin1(", ");
01286 s_from += escapeIdentifier(table->name(), options.identifierEscaping);
01287 QString aliasString = QString(querySchema.tableAlias(number));
01288 if (!aliasString.isEmpty())
01289 s_from += (QString::fromLatin1(" AS ") + aliasString);
01290 }
01291
01292
01293
01294
01295
01296 }
01297
01298 uint subqueries_for_lookup_data_counter = 0;
01299 for (QPtrListIterator<QuerySchema> it(subqueries_for_lookup_data);
01300 subqueries_for_lookup_data.current(); ++it, subqueries_for_lookup_data_counter++)
01301 {
01302 if (!s_from.isEmpty())
01303 s_from += QString::fromLatin1(", ");
01304 s_from += QString::fromLatin1("(");
01305 s_from += selectStatement( *it.current(), params, options );
01306 s_from += QString::fromLatin1(") AS %1%2")
01307 .arg(kexidb_subquery_prefix).arg(subqueries_for_lookup_data_counter);
01308 }
01309 sql += s_from;
01310 }
01311 QString s_where;
01312 s_where.reserve(4096);
01313
01314
01315 if (!s_additional_joins.isEmpty()) {
01316 sql += QString::fromLatin1(" ") + s_additional_joins + QString::fromLatin1(" ");
01317 }
01318
01319
01320
01321
01322 Relationship *rel;
01323 bool wasWhere = false;
01324 for (Relationship::ListIterator it(*querySchema.relationships()); (rel = it.current()); ++it) {
01325 if (s_where.isEmpty()) {
01326 wasWhere = true;
01327 }
01328 else
01329 s_where += QString::fromLatin1(" AND ");
01330 Field::Pair *pair;
01331 QString s_where_sub;
01332 for (QPtrListIterator<Field::Pair> p_it(*rel->fieldPairs()); (pair = p_it.current()); ++p_it) {
01333 if (!s_where_sub.isEmpty())
01334 s_where_sub += QString::fromLatin1(" AND ");
01335 s_where_sub += (
01336 escapeIdentifier(pair->first->table()->name(), options.identifierEscaping) +
01337 QString::fromLatin1(".") +
01338 escapeIdentifier(pair->first->name(), options.identifierEscaping) +
01339 QString::fromLatin1(" = ") +
01340 escapeIdentifier(pair->second->table()->name(), options.identifierEscaping) +
01341 QString::fromLatin1(".") +
01342 escapeIdentifier(pair->second->name(), options.identifierEscaping));
01343 }
01344 if (rel->fieldPairs()->count()>1) {
01345 s_where_sub.prepend("(");
01346 s_where_sub += QString::fromLatin1(")");
01347 }
01348 s_where += s_where_sub;
01349 }
01350
01351 if (querySchema.whereExpression()) {
01352 QuerySchemaParameterValueListIterator paramValuesIt(*m_driver, params);
01353 QuerySchemaParameterValueListIterator *paramValuesItPtr = params.isEmpty() ? 0 : ¶mValuesIt;
01354 if (wasWhere) {
01355
01356 s_where = "(" + s_where + ") AND (" + querySchema.whereExpression()->toString(paramValuesItPtr) + ")";
01357 }
01358 else {
01359 s_where = querySchema.whereExpression()->toString(paramValuesItPtr);
01360 }
01361 }
01362 if (!s_where.isEmpty())
01363 sql += QString::fromLatin1(" WHERE ") + s_where;
01365
01366
01367
01368 QString orderByString(
01369 querySchema.orderByColumnList().toSQLString(!singleTable,
01370 driver(), options.identifierEscaping) );
01371 const QValueVector<int> pkeyFieldsOrder( querySchema.pkeyFieldsOrder() );
01372 if (orderByString.isEmpty() && !pkeyFieldsOrder.isEmpty()) {
01373
01374 OrderByColumnList automaticPKOrderBy;
01375 const QueryColumnInfo::Vector fieldsExpanded( querySchema.fieldsExpanded() );
01376 foreach (QValueVector<int>::ConstIterator, it, pkeyFieldsOrder) {
01377 if ((*it) < 0)
01378 continue;
01379 if ((*it) >= (int)fieldsExpanded.count()) {
01380 KexiDBWarn << "Connection::selectStatement(): ORDER BY: (*it) >= fieldsExpanded.count() - "
01381 << (*it) << " >= " << fieldsExpanded.count() << endl;
01382 continue;
01383 }
01384 QueryColumnInfo *ci = fieldsExpanded[ *it ];
01385 automaticPKOrderBy.appendColumn( *ci );
01386 }
01387 orderByString = automaticPKOrderBy.toSQLString(!singleTable,
01388 driver(), options.identifierEscaping);
01389 }
01390 if (!orderByString.isEmpty())
01391 sql += (" ORDER BY " + orderByString);
01392
01393
01394 return sql;
01395 }
01396
01397 QString Connection::selectStatement( KexiDB::TableSchema& tableSchema,
01398 const SelectStatementOptions& options) const
01399 {
01400 return selectStatement( *tableSchema.query(), options );
01401 }
01402
01403 Field* Connection::findSystemFieldName(KexiDB::FieldList* fieldlist)
01404 {
01405 Field *f = fieldlist->fields()->first();
01406 while (f) {
01407 if (m_driver->isSystemFieldName( f->name() ))
01408 return f;
01409 f = fieldlist->fields()->next();
01410 }
01411 return 0;
01412 }
01413
01414 Q_ULLONG Connection::lastInsertedAutoIncValue(const QString& aiFieldName, const QString& tableName,
01415 Q_ULLONG* ROWID)
01416 {
01417 Q_ULLONG row_id = drv_lastInsertRowID();
01418 if (ROWID)
01419 *ROWID = row_id;
01420 if (m_driver->beh->ROW_ID_FIELD_RETURNS_LAST_AUTOINCREMENTED_VALUE) {
01421 return row_id;
01422 }
01423 RowData rdata;
01424 if (row_id<=0 || true!=querySingleRecord(
01425 QString::fromLatin1("SELECT ") + tableName + QString::fromLatin1(".") + aiFieldName + QString::fromLatin1(" FROM ") + tableName
01426 + QString::fromLatin1(" WHERE ") + m_driver->beh->ROW_ID_FIELD_NAME + QString::fromLatin1("=") + QString::number(row_id), rdata))
01427 {
01428
01429 return (Q_ULLONG)-1;
01430 }
01431 return rdata[0].toULongLong();
01432 }
01433
01434 Q_ULLONG Connection::lastInsertedAutoIncValue(const QString& aiFieldName,
01435 const KexiDB::TableSchema& table, Q_ULLONG* ROWID)
01436 {
01437 return lastInsertedAutoIncValue(aiFieldName,table.name(), ROWID);
01438 }
01439
01441 static FieldList* createFieldListForKexi__Fields(TableSchema *kexi__fieldsSchema)
01442 {
01443 if (!kexi__fieldsSchema)
01444 return 0;
01445 return kexi__fieldsSchema->subList(
01446 "t_id",
01447 "f_type",
01448 "f_name",
01449 "f_length",
01450 "f_precision",
01451 "f_constraints",
01452 "f_options",
01453 "f_default",
01454 "f_order",
01455 "f_caption",
01456 "f_help"
01457 );
01458 }
01459
01461 void buildValuesForKexi__Fields(QValueList<QVariant>& vals, Field* f)
01462 {
01463 vals.clear();
01464 vals
01465 << QVariant(f->table()->id())
01466 << QVariant(f->type())
01467 << QVariant(f->name())
01468 << QVariant(f->isFPNumericType() ? f->scale() : f->length())
01469 << QVariant(f->isFPNumericType() ? f->precision() : 0)
01470 << QVariant(f->constraints())
01471 << QVariant(f->options())
01472
01473
01474 << (f->defaultValue().isNull()
01475 ? QVariant() : QVariant(KexiDB::variantToString( f->defaultValue() )))
01476 << QVariant(f->order())
01477 << QVariant(f->caption())
01478 << QVariant(f->description());
01479 }
01480
01481 bool Connection::storeMainFieldSchema(Field *field)
01482 {
01483 if (!field || !field->table())
01484 return false;
01485 FieldList *fl = createFieldListForKexi__Fields(d->tables_byname["kexi__fields"]);
01486 if (!fl)
01487 return false;
01488
01489 QValueList<QVariant> vals;
01490 buildValuesForKexi__Fields(vals, field);
01491 QValueList<QVariant>::ConstIterator valsIt = vals.constBegin();
01492 Field *f;
01493 bool first = true;
01494 QString sql = "UPDATE kexi__fields SET ";
01495 for (Field::ListIterator it( fl->fieldsIterator() ); (f = it.current()); ++it, ++valsIt) {
01496 sql.append( (first ? QString::null : QString(", ")) +
01497 f->name() + "=" + m_driver->valueToSQL( f, *valsIt ) );
01498 if (first)
01499 first = false;
01500 }
01501 delete fl;
01502
01503 sql.append(QString(" WHERE t_id=") + QString::number( field->table()->id() )
01504 + " AND f_name=" + m_driver->valueToSQL( Field::Text, field->name() ) );
01505 return executeSQL( sql );
01506 }
01507
01508 #define createTable_ERR \
01509 { KexiDBDbg << "Connection::createTable(): ERROR!" <<endl; \
01510 setError(this, i18n("Creating table failed.")); \
01511 rollbackAutoCommitTransaction(tg.transaction()); \
01512 return false; }
01513
01514
01516
01523 bool Connection::createTable( KexiDB::TableSchema* tableSchema, bool replaceExisting )
01524 {
01525 if (!tableSchema || !checkIsDatabaseUsed())
01526 return false;
01527
01528
01529 if (tableSchema->fieldCount()<1) {
01530 clearError();
01531 setError(ERR_CANNOT_CREATE_EMPTY_OBJECT, i18n("Cannot create table without fields."));
01532 return false;
01533 }
01534 const bool internalTable = dynamic_cast<InternalTableSchema*>(tableSchema);
01535
01536 const QString &tableName = tableSchema->name().lower();
01537
01538 if (!internalTable) {
01539 if (m_driver->isSystemObjectName( tableName )) {
01540 clearError();
01541 setError(ERR_SYSTEM_NAME_RESERVED, i18n("System name \"%1\" cannot be used as table name.")
01542 .arg(tableSchema->name()));
01543 return false;
01544 }
01545
01546 Field *sys_field = findSystemFieldName(tableSchema);
01547 if (sys_field) {
01548 clearError();
01549 setError(ERR_SYSTEM_NAME_RESERVED,
01550 i18n("System name \"%1\" cannot be used as one of fields in \"%2\" table.")
01551 .arg(sys_field->name()).arg(tableName));
01552 return false;
01553 }
01554 }
01555
01556 bool previousSchemaStillKept = false;
01557
01558 KexiDB::TableSchema *existingTable = 0;
01559 if (replaceExisting) {
01560
01561 existingTable = d->tables_byname[tableName];
01562 if (existingTable) {
01563 if (existingTable == tableSchema) {
01564 clearError();
01565 setError(ERR_OBJECT_EXISTS,
01566 i18n("Could not create the same table \"%1\" twice.").arg(tableSchema->name()) );
01567 return false;
01568 }
01569
01570 if (existingTable->id()>0)
01571 tableSchema->m_id = existingTable->id();
01572 previousSchemaStillKept = true;
01573 if (!dropTable( existingTable, false ))
01574 return false;
01575 }
01576 }
01577 else {
01578 if (this->tableSchema( tableSchema->name() ) != 0) {
01579 clearError();
01580 setError(ERR_OBJECT_EXISTS, i18n("Table \"%1\" already exists.").arg(tableSchema->name()) );
01581 return false;
01582 }
01583 }
01584
01585
01586
01587
01588
01589
01590
01591 TransactionGuard tg;
01592 if (!beginAutoCommitTransaction(tg))
01593 return false;
01594
01595 if (!drv_createTable(*tableSchema))
01596 createTable_ERR;
01597
01598
01599 if (!internalTable) {
01600
01601 if (!storeObjectSchemaData( *tableSchema, true ))
01602 createTable_ERR;
01603
01604 TableSchema *ts = d->tables_byname["kexi__fields"];
01605 if (!ts)
01606 return false;
01607
01608 if (!KexiDB::deleteRow(*this, ts, "t_id", tableSchema->id()))
01609 return false;
01610
01611 FieldList *fl = createFieldListForKexi__Fields(d->tables_byname["kexi__fields"]);
01612 if (!fl)
01613 return false;
01614
01615
01616 Field *f;
01617 for (Field::ListIterator it( *tableSchema->fields() ); (f = it.current()); ++it) {
01618 QValueList<QVariant> vals;
01619 buildValuesForKexi__Fields(vals, f);
01620 if (!insertRecord(*fl, vals ))
01621 createTable_ERR;
01622 }
01623 delete fl;
01624
01625 if (!storeExtendedTableSchemaData(*tableSchema))
01626 createTable_ERR;
01627 }
01628
01629
01630
01631
01632
01633
01634
01635
01636
01637 bool res = commitAutoCommitTransaction(tg.transaction());
01638
01639 if (res) {
01640 if (internalTable) {
01641
01642 insertInternalTableSchema(tableSchema);
01643 }
01644 else {
01645 if (previousSchemaStillKept) {
01646
01647 removeTableSchemaInternal(tableSchema);
01648 }
01649
01650 d->tables.insert(tableSchema->id(), tableSchema);
01651 d->tables_byname.insert(tableSchema->name().lower(), tableSchema);
01652 }
01653
01654 tableSchema->m_conn = this;
01655 }
01656 return res;
01657 }
01658
01659 void Connection::removeTableSchemaInternal(TableSchema *tableSchema)
01660 {
01661 d->tables_byname.remove(tableSchema->name());
01662 d->tables.remove(tableSchema->id());
01663 }
01664
01665 bool Connection::removeObject( uint objId )
01666 {
01667 clearError();
01668
01669 if (!KexiDB::deleteRow(*this, d->tables_byname["kexi__objects"], "o_id", objId)
01670 || !KexiDB::deleteRow(*this, d->tables_byname["kexi__objectdata"], "o_id", objId)) {
01671 setError(ERR_DELETE_SERVER_ERROR, i18n("Could not remove object's data."));
01672 return false;
01673 }
01674 return true;
01675 }
01676
01677 bool Connection::drv_dropTable( const QString& name )
01678 {
01679 m_sql = "DROP TABLE " + escapeIdentifier(name);
01680 return executeSQL(m_sql);
01681 }
01682
01684
01690 tristate Connection::dropTable( KexiDB::TableSchema* tableSchema )
01691 {
01692 return dropTable( tableSchema, true );
01693 }
01694
01695 tristate Connection::dropTable( KexiDB::TableSchema* tableSchema, bool alsoRemoveSchema)
01696 {
01697
01698 clearError();
01699 if (!tableSchema)
01700 return false;
01701
01702 QString errmsg(i18n("Table \"%1\" cannot be removed.\n"));
01703
01704 if (tableSchema->id() < 0
01705 || this->tableSchema(tableSchema->name())!=tableSchema
01706 || this->tableSchema(tableSchema->id())!=tableSchema)
01707 {
01708 setError(ERR_OBJECT_NOT_FOUND, errmsg.arg(tableSchema->name())
01709 +i18n("Unexpected name or identifier."));
01710 return false;
01711 }
01712
01713 tristate res = closeAllTableSchemaChangeListeners(*tableSchema);
01714 if (true!=res)
01715 return res;
01716
01717
01718 if (m_driver->isSystemObjectName( tableSchema->name() )) {
01719 setError(ERR_SYSTEM_NAME_RESERVED, errmsg.arg(tableSchema->name()) + d->strItIsASystemObject());
01720 return false;
01721 }
01722
01723 TransactionGuard tg;
01724 if (!beginAutoCommitTransaction(tg))
01725 return false;
01726
01727
01728 if (drv_containsTable(tableSchema->name())) {
01729 if (!drv_dropTable(tableSchema->name()))
01730 return false;
01731 }
01732
01733 TableSchema *ts = d->tables_byname["kexi__fields"];
01734 if (!KexiDB::deleteRow(*this, ts, "t_id", tableSchema->id()))
01735 return false;
01736
01737
01738 if (!removeObject( tableSchema->id() )) {
01739 return false;
01740 }
01741
01742 if (alsoRemoveSchema) {
01744 tristate res = removeDataBlock( tableSchema->id(), "extended_schema");
01745 if (!res)
01746 return false;
01747 removeTableSchemaInternal(tableSchema);
01748 }
01749 return commitAutoCommitTransaction(tg.transaction());
01750 }
01751
01752 tristate Connection::dropTable( const QString& table )
01753 {
01754 clearError();
01755 TableSchema* ts = tableSchema( table );
01756 if (!ts) {
01757 setError(ERR_OBJECT_NOT_FOUND, i18n("Table \"%1\" does not exist.")
01758 .arg(table));
01759 return false;
01760 }
01761 return dropTable(ts);
01762 }
01763
01764 tristate Connection::alterTable( TableSchema& tableSchema, TableSchema& newTableSchema )
01765 {
01766 clearError();
01767 tristate res = closeAllTableSchemaChangeListeners(tableSchema);
01768 if (true!=res)
01769 return res;
01770
01771 if (&tableSchema == &newTableSchema) {
01772 setError(ERR_OBJECT_THE_SAME, i18n("Could not alter table \"%1\" using the same table.")
01773 .arg(tableSchema.name()));
01774 return false;
01775 }
01776
01777
01778 bool ok, empty;
01779 #if 0//TODO ucomment:
01780 empty = isEmpty( tableSchema, ok ) && ok;
01781 #else
01782 empty = true;
01783 #endif
01784 if (empty) {
01785 ok = createTable(&newTableSchema, true);
01786 }
01787 return ok;
01788 }
01789
01790 bool Connection::alterTableName(TableSchema& tableSchema, const QString& newName, bool replace)
01791 {
01792 clearError();
01793 if (&tableSchema!=d->tables[tableSchema.id()]) {
01794 setError(ERR_OBJECT_NOT_FOUND, i18n("Unknown table \"%1\"").arg(tableSchema.name()));
01795 return false;
01796 }
01797 if (newName.isEmpty() || !KexiUtils::isIdentifier(newName)) {
01798 setError(ERR_INVALID_IDENTIFIER, i18n("Invalid table name \"%1\"").arg(newName));
01799 return false;
01800 }
01801 const QString oldTableName = tableSchema.name();
01802 const QString newTableName = newName.lower().stripWhiteSpace();
01803 if (oldTableName.lower().stripWhiteSpace() == newTableName) {
01804 setError(ERR_OBJECT_THE_SAME, i18n("Could rename table \"%1\" using the same name.")
01805 .arg(newTableName));
01806 return false;
01807 }
01808
01809
01810
01811 TableSchema *tableToReplace = this->tableSchema( newName );
01812 const bool destTableExists = tableToReplace != 0;
01813 const int origID = destTableExists ? tableToReplace->id() : -1;
01814 if (!replace && destTableExists) {
01815 setError(ERR_OBJECT_EXISTS,
01816 i18n("Could not rename table \"%1\" to \"%2\". Table \"%3\" already exists.")
01817 .arg(tableSchema.name()).arg(newName).arg(newName));
01818 return false;
01819 }
01820
01821
01822 #define alterTableName_ERR \
01823 tableSchema.setName(oldTableName) //restore old name
01824
01825 TransactionGuard tg;
01826 if (!beginAutoCommitTransaction(tg))
01827 return false;
01828
01829
01830 if (destTableExists) {
01831 if (!replace) {
01832 return false;
01833 }
01834 if (!dropTable( newName )) {
01835 return false;
01836 }
01837
01838
01839 if (!executeSQL(QString::fromLatin1("UPDATE kexi__objects SET o_id=%1 WHERE o_id=%2 AND o_type=%3")
01840 .arg(origID).arg(tableSchema.id()).arg((int)TableObjectType)))
01841 {
01842 return false;
01843 }
01844 if (!executeSQL(QString::fromLatin1("UPDATE kexi__fields SET t_id=%1 WHERE t_id=%2")
01845 .arg(origID).arg(tableSchema.id())))
01846 {
01847 return false;
01848 }
01849 d->tables.take(tableSchema.id());
01850 d->tables.insert(origID, &tableSchema);
01851
01852 tableSchema.m_id = origID;
01853 }
01854
01855 if (!drv_alterTableName(tableSchema, newTableName)) {
01856 alterTableName_ERR;
01857 return false;
01858 }
01859
01860
01861
01862 if (!executeSQL(QString::fromLatin1("UPDATE kexi__objects SET o_name=%1 WHERE o_id=%2")
01863 .arg(m_driver->escapeString(tableSchema.name())).arg(tableSchema.id())))
01864 {
01865 alterTableName_ERR;
01866 return false;
01867 }
01868
01869
01870
01871 tableSchema.setName(oldTableName);
01872
01873 if (!commitAutoCommitTransaction(tg.transaction())) {
01874 alterTableName_ERR;
01875 return false;
01876 }
01877
01878
01879 d->tables_byname.take(tableSchema.name());
01880 tableSchema.setName(newTableName);
01881 d->tables_byname.insert(tableSchema.name(), &tableSchema);
01882 return true;
01883 }
01884
01885 bool Connection::drv_alterTableName(TableSchema& tableSchema, const QString& newName)
01886 {
01887 const QString oldTableName = tableSchema.name();
01888 tableSchema.setName(newName);
01889
01890 if (!executeSQL(QString::fromLatin1("ALTER TABLE %1 RENAME TO %2")
01891 .arg(escapeIdentifier(oldTableName)).arg(escapeIdentifier(newName))))
01892 {
01893 tableSchema.setName(oldTableName);
01894 return false;
01895 }
01896 return true;
01897 }
01898
01899 bool Connection::dropQuery( KexiDB::QuerySchema* querySchema )
01900 {
01901 clearError();
01902 if (!querySchema)
01903 return false;
01904
01905 TransactionGuard tg;
01906 if (!beginAutoCommitTransaction(tg))
01907 return false;
01908
01909
01910
01911
01912
01913
01914
01915
01916
01917
01918
01919
01920
01921
01922 if (!removeObject( querySchema->id() )) {
01923 return false;
01924 }
01925
01926
01927 d->queries_byname.remove(querySchema->name());
01928 d->queries.remove(querySchema->id());
01929
01930 return commitAutoCommitTransaction(tg.transaction());
01931 }
01932
01933 bool Connection::dropQuery( const QString& query )
01934 {
01935 clearError();
01936 QuerySchema* qs = querySchema( query );
01937 if (!qs) {
01938 setError(ERR_OBJECT_NOT_FOUND, i18n("Query \"%1\" does not exist.")
01939 .arg(query));
01940 return false;
01941 }
01942 return dropQuery(qs);
01943 }
01944
01945 bool Connection::drv_createTable( const KexiDB::TableSchema& tableSchema )
01946 {
01947 m_sql = createTableStatement(tableSchema);
01948 KexiDBDbg<<"******** "<<m_sql<<endl;
01949 return executeSQL(m_sql);
01950 }
01951
01952 bool Connection::drv_createTable( const QString& tableSchemaName )
01953 {
01954 TableSchema *ts = d->tables_byname[tableSchemaName];
01955 if (!ts)
01956 return false;
01957 return drv_createTable(*ts);
01958 }
01959
01960 bool Connection::beginAutoCommitTransaction(TransactionGuard &tg)
01961 {
01962 if ((m_driver->d->features & Driver::IgnoreTransactions)
01963 || !d->autoCommit)
01964 {
01965 tg.setTransaction( Transaction() );
01966 return true;
01967 }
01968
01969
01970
01971 if (m_driver->d->features & Driver::SingleTransactions) {
01972 if (d->default_trans_started_inside)
01973 if (!commitTransaction(d->default_trans, true)) {
01974 tg.setTransaction( Transaction() );
01975 return false;
01976 }
01977
01978 d->default_trans_started_inside = d->default_trans.isNull();
01979 if (!d->default_trans_started_inside) {
01980 tg.setTransaction( d->default_trans );
01981 tg.doNothing();
01982 return true;
01983 }
01984 }
01985 else if (!(m_driver->d->features & Driver::MultipleTransactions)) {
01986 tg.setTransaction( Transaction() );
01987 return true;
01988 }
01989 tg.setTransaction( beginTransaction() );
01990 return !error();
01991 }
01992
01993 bool Connection::commitAutoCommitTransaction(const Transaction& trans)
01994 {
01995 if (m_driver->d->features & Driver::IgnoreTransactions)
01996 return true;
01997 if (trans.isNull() || !m_driver->transactionsSupported())
01998 return true;
01999 if (m_driver->d->features & Driver::SingleTransactions) {
02000 if (!d->default_trans_started_inside)
02001 return true;
02002 }
02003 return commitTransaction(trans, true);
02004 }
02005
02006 bool Connection::rollbackAutoCommitTransaction(const Transaction& trans)
02007 {
02008 if (trans.isNull() || !m_driver->transactionsSupported())
02009 return true;
02010 return rollbackTransaction(trans);
02011 }
02012
02013 #define SET_ERR_TRANS_NOT_SUPP \
02014 { setError(ERR_UNSUPPORTED_DRV_FEATURE, \
02015 i18n("Transactions are not supported for \"%1\" driver.").arg(m_driver->name() )); }
02016
02017 #define SET_BEGIN_TR_ERROR \
02018 { if (!error()) \
02019 setError(ERR_ROLLBACK_OR_COMMIT_TRANSACTION, i18n("Begin transaction failed")); }
02020
02021 Transaction Connection::beginTransaction()
02022 {
02023 if (!checkIsDatabaseUsed())
02024 return Transaction::null;
02025 Transaction trans;
02026 if (m_driver->d->features & Driver::IgnoreTransactions) {
02027
02028
02029 trans.m_data = new TransactionData(this);
02030 d->transactions.append(trans);
02031 return trans;
02032 }
02033 if (m_driver->d->features & Driver::SingleTransactions) {
02034 if (d->default_trans.active()) {
02035 setError(ERR_TRANSACTION_ACTIVE, i18n("Transaction already started.") );
02036 return Transaction::null;
02037 }
02038 if (!(trans.m_data = drv_beginTransaction())) {
02039 SET_BEGIN_TR_ERROR;
02040 return Transaction::null;
02041 }
02042 d->default_trans = trans;
02043 d->transactions.append(trans);
02044 return d->default_trans;
02045 }
02046 if (m_driver->d->features & Driver::MultipleTransactions) {
02047 if (!(trans.m_data = drv_beginTransaction())) {
02048 SET_BEGIN_TR_ERROR;
02049 return Transaction::null;
02050 }
02051 d->transactions.append(trans);
02052 return trans;
02053 }
02054
02055 SET_ERR_TRANS_NOT_SUPP;
02056 return Transaction::null;
02057 }
02058
02059 bool Connection::commitTransaction(const Transaction trans, bool ignore_inactive)
02060 {
02061 if (!isDatabaseUsed())
02062 return false;
02063
02064
02065 if ( !m_driver->transactionsSupported()
02066 && !(m_driver->d->features & Driver::IgnoreTransactions))
02067 {
02068 SET_ERR_TRANS_NOT_SUPP;
02069 return false;
02070 }
02071 Transaction t = trans;
02072 if (!t.active()) {
02073 if (!d->default_trans.active()) {
02074 if (ignore_inactive)
02075 return true;
02076 clearError();
02077 setError(ERR_NO_TRANSACTION_ACTIVE, i18n("Transaction not started.") );
02078 return false;
02079 }
02080 t = d->default_trans;
02081 d->default_trans = Transaction::null;
02082 }
02083 bool ret = true;
02084 if (! (m_driver->d->features & Driver::IgnoreTransactions) )
02085 ret = drv_commitTransaction(t.m_data);
02086 if (t.m_data)
02087 t.m_data->m_active = false;
02088 if (!d->dont_remove_transactions)
02089 d->transactions.remove(t);
02090 if (!ret && !error())
02091 setError(ERR_ROLLBACK_OR_COMMIT_TRANSACTION, i18n("Error on commit transaction"));
02092 return ret;
02093 }
02094
02095 bool Connection::rollbackTransaction(const Transaction trans, bool ignore_inactive)
02096 {
02097 if (!isDatabaseUsed())
02098 return false;
02099
02100
02101 if ( !m_driver->transactionsSupported()
02102 && !(m_driver->d->features & Driver::IgnoreTransactions))
02103 {
02104 SET_ERR_TRANS_NOT_SUPP;
02105 return false;
02106 }
02107 Transaction t = trans;
02108 if (!t.active()) {
02109 if (!d->default_trans.active()) {
02110 if (ignore_inactive)
02111 return true;
02112 clearError();
02113 setError(ERR_NO_TRANSACTION_ACTIVE, i18n("Transaction not started.") );
02114 return false;
02115 }
02116 t = d->default_trans;
02117 d->default_trans = Transaction::null;
02118 }
02119 bool ret = true;
02120 if (! (m_driver->d->features & Driver::IgnoreTransactions) )
02121 ret = drv_rollbackTransaction(t.m_data);
02122 if (t.m_data)
02123 t.m_data->m_active = false;
02124 if (!d->dont_remove_transactions)
02125 d->transactions.remove(t);
02126 if (!ret && !error())
02127 setError(ERR_ROLLBACK_OR_COMMIT_TRANSACTION, i18n("Error on rollback transaction"));
02128 return ret;
02129 }
02130
02131 #undef SET_ERR_TRANS_NOT_SUPP
02132 #undef SET_BEGIN_TR_ERROR
02133
02134
02135
02136
02137
02138
02139 Transaction& Connection::defaultTransaction() const
02140 {
02141 return d->default_trans;
02142 }
02143
02144 void Connection::setDefaultTransaction(const Transaction& trans)
02145 {
02146 if (!isDatabaseUsed())
02147 return;
02148
02149
02150 if ( !(m_driver->d->features & Driver::IgnoreTransactions)
02151 && (!trans.active() || !m_driver->transactionsSupported()) )
02152 {
02153 return;
02154 }
02155 d->default_trans = trans;
02156 }
02157
02158 const QValueList<Transaction>& Connection::transactions()
02159 {
02160 return d->transactions;
02161 }
02162
02163 bool Connection::autoCommit() const
02164 {
02165 return d->autoCommit;
02166 }
02167
02168 bool Connection::setAutoCommit(bool on)
02169 {
02170 if (d->autoCommit == on || m_driver->d->features & Driver::IgnoreTransactions)
02171 return true;
02172 if (!drv_setAutoCommit(on))
02173 return false;
02174 d->autoCommit = on;
02175 return true;
02176 }
02177
02178 TransactionData* Connection::drv_beginTransaction()
02179 {
02180 QString old_sql = m_sql;
02181 if (!executeSQL( "BEGIN" ))
02182 return 0;
02183 return new TransactionData(this);
02184 }
02185
02186 bool Connection::drv_commitTransaction(TransactionData *)
02187 {
02188 return executeSQL( "COMMIT" );
02189 }
02190
02191 bool Connection::drv_rollbackTransaction(TransactionData *)
02192 {
02193 return executeSQL( "ROLLBACK" );
02194 }
02195
02196 bool Connection::drv_setAutoCommit(bool )
02197 {
02198 return true;
02199 }
02200
02201 Cursor* Connection::executeQuery( const QString& statement, uint cursor_options )
02202 {
02203 if (statement.isEmpty())
02204 return 0;
02205 Cursor *c = prepareQuery( statement, cursor_options );
02206 if (!c)
02207 return 0;
02208 if (!c->open()) {
02209 setError(c);
02210 delete c;
02211 return 0;
02212 }
02213 return c;
02214 }
02215
02216 Cursor* Connection::executeQuery( QuerySchema& query, const QValueList<QVariant>& params,
02217 uint cursor_options )
02218 {
02219 Cursor *c = prepareQuery( query, params, cursor_options );
02220 if (!c)
02221 return 0;
02222 if (!c->open()) {
02223 setError(c);
02224 delete c;
02225 return 0;
02226 }
02227 return c;
02228 }
02229
02230 Cursor* Connection::executeQuery( QuerySchema& query, uint cursor_options )
02231 {
02232 return executeQuery(query, QValueList<QVariant>(), cursor_options);
02233 }
02234
02235 Cursor* Connection::executeQuery( TableSchema& table, uint cursor_options )
02236 {
02237 return executeQuery( *table.query(), cursor_options );
02238 }
02239
02240 Cursor* Connection::prepareQuery( TableSchema& table, uint cursor_options )
02241 {
02242 return prepareQuery( *table.query(), cursor_options );
02243 }
02244
02245 Cursor* Connection::prepareQuery( QuerySchema& query, const QValueList<QVariant>& params,
02246 uint cursor_options )
02247 {
02248 Cursor* cursor = prepareQuery(query, cursor_options);
02249 if (cursor)
02250 cursor->setQueryParameters(params);
02251 return cursor;
02252 }
02253
02254 bool Connection::deleteCursor(Cursor *cursor)
02255 {
02256 if (!cursor)
02257 return false;
02258 if (cursor->connection()!=this) {
02259 KexiDBWarn << "Connection::deleteCursor(): Cannot delete the cursor not owned by the same connection!" << endl;
02260 return false;
02261 }
02262 const bool ret = cursor->close();
02263 delete cursor;
02264 return ret;
02265 }
02266
02267 bool Connection::setupObjectSchemaData( const RowData &data, SchemaData &sdata )
02268 {
02269
02270
02271
02272
02273
02274
02275
02276
02277
02278
02279
02280
02281 bool ok;
02282 sdata.m_id = data[0].toInt(&ok);
02283 if (!ok) {
02284 return false;
02285 }
02286 sdata.m_name = data[2].toString();
02287 if (!KexiUtils::isIdentifier( sdata.m_name )) {
02288 setError(ERR_INVALID_IDENTIFIER, i18n("Invalid object name \"%1\"").arg(sdata.m_name));
02289 return false;
02290 }
02291 sdata.m_caption = data[3].toString();
02292 sdata.m_desc = data[4].toString();
02293
02294
02295 return true;
02296 }
02297
02298 tristate Connection::loadObjectSchemaData( int objectID, SchemaData &sdata )
02299 {
02300 RowData data;
02301 if (true!=querySingleRecord(QString::fromLatin1(
02302 "SELECT o_id, o_type, o_name, o_caption, o_desc FROM kexi__objects WHERE o_id=%1")
02303 .arg(objectID), data))
02304 return cancelled;
02305 return setupObjectSchemaData( data, sdata );
02306 }
02307
02308 tristate Connection::loadObjectSchemaData( int objectType, const QString& objectName, SchemaData &sdata )
02309 {
02310 RowData data;
02311 if (true!=querySingleRecord(QString::fromLatin1("SELECT o_id, o_type, o_name, o_caption, o_desc "
02312 "FROM kexi__objects WHERE o_type=%1 AND lower(o_name)=%2")
02313 .arg(objectType).arg(m_driver->valueToSQL(Field::Text, objectName.lower())), data))
02314 return cancelled;
02315 return setupObjectSchemaData( data, sdata );
02316 }
02317
02318 bool Connection::storeObjectSchemaData( SchemaData &sdata, bool newObject )
02319 {
02320 TableSchema *ts = d->tables_byname["kexi__objects"];
02321 if (!ts)
02322 return false;
02323 if (newObject) {
02324 int existingID;
02325 if (true == querySingleNumber(QString::fromLatin1(
02326 "SELECT o_id FROM kexi__objects WHERE o_type=%1 AND lower(o_name)=%2")
02327 .arg(sdata.type()).arg(m_driver->valueToSQL(Field::Text, sdata.name().lower())), existingID))
02328 {
02329
02330
02331 sdata.m_id = existingID;
02332 newObject = false;
02333 }
02334 }
02335 if (newObject) {
02336 FieldList *fl;
02337 bool ok;
02338 if (sdata.id()<=0) {
02339 fl = ts->subList("o_type", "o_name", "o_caption", "o_desc");
02340 ok = fl!=0;
02341 if (ok && !insertRecord(*fl, QVariant(sdata.type()), QVariant(sdata.name()),
02342 QVariant(sdata.caption()), QVariant(sdata.description()) ))
02343 ok = false;
02344 delete fl;
02345 if (!ok)
02346 return false;
02347
02349 int obj_id = (int)lastInsertedAutoIncValue("o_id",*ts);
02350 KexiDBDbg << "######## NEW obj_id == " << obj_id << endl;
02351 if (obj_id<=0)
02352 return false;
02353 sdata.m_id = obj_id;
02354 return true;
02355 } else {
02356 fl = ts->subList("o_id", "o_type", "o_name", "o_caption", "o_desc");
02357 ok = fl!=0;
02358 if (ok && !insertRecord(*fl, QVariant(sdata.id()), QVariant(sdata.type()), QVariant(sdata.name()),
02359 QVariant(sdata.caption()), QVariant(sdata.description()) ))
02360 ok = false;
02361 delete fl;
02362 return ok;
02363 }
02364 }
02365
02366 return executeSQL(QString("UPDATE kexi__objects SET o_type=%2, o_caption=%3, o_desc=%4 WHERE o_id=%1")
02367 .arg(sdata.id()).arg(sdata.type())
02368 .arg(m_driver->valueToSQL(KexiDB::Field::Text, sdata.caption()))
02369 .arg(m_driver->valueToSQL(KexiDB::Field::Text, sdata.description())) );
02370 }
02371
02372 tristate Connection::querySingleRecordInternal(RowData &data, const QString* sql, QuerySchema* query,
02373 bool addLimitTo1)
02374 {
02375 Q_ASSERT(sql || query);
02377 if (sql)
02378 m_sql = addLimitTo1 ? (*sql + " LIMIT 1") : *sql;
02379 KexiDB::Cursor *cursor;
02380 if (!(cursor = sql ? executeQuery( m_sql ) : executeQuery( *query ))) {
02381 KexiDBWarn << "Connection::querySingleRecord(): !executeQuery() " << m_sql << endl;
02382 return false;
02383 }
02384 if (!cursor->moveFirst() || cursor->eof()) {
02385 const tristate result = cursor->error() ? false : cancelled;
02386 KexiDBWarn << "Connection::querySingleRecord(): !cursor->moveFirst() || cursor->eof() m_sql=" << m_sql << endl;
02387 setError(cursor);
02388 deleteCursor(cursor);
02389 return result;
02390 }
02391 cursor->storeCurrentRow(data);
02392 return deleteCursor(cursor);
02393 }
02394
02395 tristate Connection::querySingleRecord(const QString& sql, RowData &data, bool addLimitTo1)
02396 {
02397 return querySingleRecordInternal(data, &sql, 0, addLimitTo1);
02398 }
02399
02400 tristate Connection::querySingleRecord(QuerySchema& query, RowData &data, bool addLimitTo1)
02401 {
02402 return querySingleRecordInternal(data, 0, &query, addLimitTo1);
02403 }
02404
02405 bool Connection::checkIfColumnExists(Cursor *cursor, uint column)
02406 {
02407 if (column >= cursor->fieldCount()) {
02408 setError(ERR_CURSOR_RECORD_FETCHING, i18n("Column %1 does not exist for the query.").arg(column));
02409 return false;
02410 }
02411 return true;
02412 }
02413
02414 tristate Connection::querySingleString(const QString& sql, QString &value, uint column, bool addLimitTo1)
02415 {
02416 KexiDB::Cursor *cursor;
02417 m_sql = addLimitTo1 ? (sql + " LIMIT 1") : sql;
02418 if (!(cursor = executeQuery( m_sql ))) {
02419 KexiDBWarn << "Connection::querySingleRecord(): !executeQuery() " << m_sql << endl;
02420 return false;
02421 }
02422 if (!cursor->moveFirst() || cursor->eof()) {
02423 const tristate result = cursor->error() ? false : cancelled;
02424 KexiDBWarn << "Connection::querySingleRecord(): !cursor->moveFirst() || cursor->eof() " << m_sql << endl;
02425 deleteCursor(cursor);
02426 return result;
02427 }
02428 if (!checkIfColumnExists(cursor, column)) {
02429 deleteCursor(cursor);
02430 return false;
02431 }
02432 value = cursor->value(column).toString();
02433 return deleteCursor(cursor);
02434 }
02435
02436 tristate Connection::querySingleNumber(const QString& sql, int &number, uint column, bool addLimitTo1)
02437 {
02438 static QString str;
02439 static bool ok;
02440 const tristate result = querySingleString(sql, str, column, addLimitTo1);
02441 if (result!=true)
02442 return result;
02443 number = str.toInt(&ok);
02444 return ok;
02445 }
02446
02447 bool Connection::queryStringList(const QString& sql, QStringList& list, uint column)
02448 {
02449 KexiDB::Cursor *cursor;
02450 clearError();
02451 m_sql = sql;
02452 if (!(cursor = executeQuery( m_sql ))) {
02453 KexiDBWarn << "Connection::queryStringList(): !executeQuery() " << m_sql << endl;
02454 return false;
02455 }
02456 cursor->moveFirst();
02457 if (cursor->error()) {
02458 setError(cursor);
02459 deleteCursor(cursor);
02460 return false;
02461 }
02462 if (!cursor->eof() && !checkIfColumnExists(cursor, column)) {
02463 deleteCursor(cursor);
02464 return false;
02465 }
02466 list.clear();
02467 while (!cursor->eof()) {
02468 list.append( cursor->value(column).toString() );
02469 if (!cursor->moveNext() && cursor->error()) {
02470 setError(cursor);
02471 deleteCursor(cursor);
02472 return false;
02473 }
02474 }
02475 return deleteCursor(cursor);
02476 }
02477
02478 bool Connection::resultExists(const QString& sql, bool &success, bool addLimitTo1)
02479 {
02480 KexiDB::Cursor *cursor;
02481
02482 if (m_driver->beh->SELECT_1_SUBQUERY_SUPPORTED) {
02483
02484 if (addLimitTo1 && sql.left(6).upper() == "SELECT")
02485 m_sql = QString("SELECT 1 FROM (") + sql + ") LIMIT 1";
02486 else
02487 m_sql = sql;
02488 }
02489 else {
02490 if (addLimitTo1 && sql.left(6).upper() == "SELECT")
02491 m_sql = sql + " LIMIT 1";
02492 else
02493 m_sql = sql;
02494 }
02495 if (!(cursor = executeQuery( m_sql ))) {
02496 KexiDBWarn << "Connection::querySingleRecord(): !executeQuery() " << m_sql << endl;
02497 success = false;
02498 return false;
02499 }
02500 if (!cursor->moveFirst() || cursor->eof()) {
02501 success = !cursor->error();
02502 KexiDBWarn << "Connection::querySingleRecord(): !cursor->moveFirst() || cursor->eof() " << m_sql << endl;
02503 setError(cursor);
02504 deleteCursor(cursor);
02505 return false;
02506 }
02507 success = deleteCursor(cursor);
02508 return true;
02509 }
02510
02511 bool Connection::isEmpty( TableSchema& table, bool &success )
02512 {
02513 return !resultExists( selectStatement( *table.query() ), success );
02514 }
02515
02517 static void createExtendedTableSchemaMainElementIfNeeded(
02518 QDomDocument& doc, QDomElement& extendedTableSchemaMainEl,
02519 bool& extendedTableSchemaStringIsEmpty)
02520 {
02521 if (!extendedTableSchemaStringIsEmpty)
02522 return;
02523
02524 extendedTableSchemaMainEl = doc.createElement("EXTENDED_TABLE_SCHEMA");
02525 doc.appendChild( extendedTableSchemaMainEl );
02526 extendedTableSchemaMainEl.setAttribute("version", QString::number(KEXIDB_EXTENDED_TABLE_SCHEMA_VERSION));
02527 extendedTableSchemaStringIsEmpty = false;
02528 }
02529
02531 static void createExtendedTableSchemaFieldElementIfNeeded(QDomDocument& doc,
02532 QDomElement& extendedTableSchemaMainEl, const QString& fieldName, QDomElement& extendedTableSchemaFieldEl,
02533 bool append = true)
02534 {
02535 if (!extendedTableSchemaFieldEl.isNull())
02536 return;
02537 extendedTableSchemaFieldEl = doc.createElement("field");
02538 if (append)
02539 extendedTableSchemaMainEl.appendChild( extendedTableSchemaFieldEl );
02540 extendedTableSchemaFieldEl.setAttribute("name", fieldName);
02541 }
02542
02549 static void addFieldPropertyToExtendedTableSchemaData(
02550 Field *f, const char* propertyName, const QVariant& propertyValue,
02551 QDomDocument& doc, QDomElement& extendedTableSchemaMainEl,
02552 QDomElement& extendedTableSchemaFieldEl,
02553 bool& extendedTableSchemaStringIsEmpty,
02554 bool custom = false )
02555 {
02556 createExtendedTableSchemaMainElementIfNeeded(doc,
02557 extendedTableSchemaMainEl, extendedTableSchemaStringIsEmpty);
02558 createExtendedTableSchemaFieldElementIfNeeded(
02559 doc, extendedTableSchemaMainEl, f->name(), extendedTableSchemaFieldEl);
02560
02561
02562 QDomElement extendedTableSchemaFieldPropertyEl = doc.createElement("property");
02563 extendedTableSchemaFieldEl.appendChild( extendedTableSchemaFieldPropertyEl );
02564 if (custom)
02565 extendedTableSchemaFieldPropertyEl.setAttribute("custom", "true");
02566 extendedTableSchemaFieldPropertyEl.setAttribute("name", propertyName);
02567 QDomElement extendedTableSchemaFieldPropertyValueEl;
02568 switch (propertyValue.type()) {
02569 case QVariant::String:
02570 extendedTableSchemaFieldPropertyValueEl = doc.createElement("string");
02571 break;
02572 case QVariant::CString:
02573 extendedTableSchemaFieldPropertyValueEl = doc.createElement("cstring");
02574 break;
02575 case QVariant::Int:
02576 case QVariant::Double:
02577 case QVariant::UInt:
02578 case QVariant::LongLong:
02579 case QVariant::ULongLong:
02580 extendedTableSchemaFieldPropertyValueEl = doc.createElement("number");
02581 break;
02582 case QVariant::Bool:
02583 extendedTableSchemaFieldPropertyValueEl = doc.createElement("bool");
02584 break;
02585 default:
02587 KexiDBFatal << "addFieldPropertyToExtendedTableSchemaData(): impl. error" << endl;
02588 }
02589 extendedTableSchemaFieldPropertyEl.appendChild( extendedTableSchemaFieldPropertyValueEl );
02590 extendedTableSchemaFieldPropertyValueEl.appendChild(
02591 doc.createTextNode( propertyValue.toString() ) );
02592 }
02593
02594 bool Connection::storeExtendedTableSchemaData(TableSchema& tableSchema)
02595 {
02597 QDomDocument doc("EXTENDED_TABLE_SCHEMA");
02598 QDomElement extendedTableSchemaMainEl;
02599 bool extendedTableSchemaStringIsEmpty = true;
02600
02601
02602 Field *f;
02603 for (Field::ListIterator it( *tableSchema.fields() ); (f = it.current()); ++it) {
02604 QDomElement extendedTableSchemaFieldEl;
02605 if (f->visibleDecimalPlaces()>=0 && KexiDB::supportsVisibleDecimalPlacesProperty(f->type())) {
02606 addFieldPropertyToExtendedTableSchemaData(
02607 f, "visibleDecimalPlaces", f->visibleDecimalPlaces(), doc,
02608 extendedTableSchemaMainEl, extendedTableSchemaFieldEl,
02609 extendedTableSchemaStringIsEmpty );
02610 }
02611
02612
02613
02614 const Field::CustomPropertiesMap customProperties(f->customProperties());
02615 foreach( Field::CustomPropertiesMap::ConstIterator, itCustom, customProperties ) {
02616 addFieldPropertyToExtendedTableSchemaData(
02617 f, itCustom.key(), itCustom.data(), doc,
02618 extendedTableSchemaMainEl, extendedTableSchemaFieldEl, extendedTableSchemaStringIsEmpty,
02619 true );
02620 }
02621
02622 LookupFieldSchema *lookupFieldSchema = tableSchema.lookupFieldSchema( *f );
02623 if (lookupFieldSchema) {
02624 createExtendedTableSchemaFieldElementIfNeeded(
02625 doc, extendedTableSchemaMainEl, f->name(), extendedTableSchemaFieldEl, false);
02626 LookupFieldSchema::saveToDom(*lookupFieldSchema, doc, extendedTableSchemaFieldEl);
02627
02628 if (extendedTableSchemaFieldEl.hasChildNodes()) {
02629
02630 createExtendedTableSchemaMainElementIfNeeded(doc, extendedTableSchemaMainEl,
02631 extendedTableSchemaStringIsEmpty);
02632 extendedTableSchemaMainEl.appendChild( extendedTableSchemaFieldEl );
02633 }
02634 }
02635 }
02636
02637
02638 if (extendedTableSchemaStringIsEmpty) {
02639 #ifdef KEXI_DEBUG_GUI
02640 KexiUtils::addAlterTableActionDebug(QString("** Extended table schema REMOVED."));
02641 #endif
02642 if (!removeDataBlock( tableSchema.id(), "extended_schema"))
02643 return false;
02644 }
02645 else {
02646 #ifdef KEXI_DEBUG_GUI
02647 KexiUtils::addAlterTableActionDebug(QString("** Extended table schema set to:\n")+doc.toString(4));
02648 #endif
02649 if (!storeDataBlock( tableSchema.id(), doc.toString(1), "extended_schema" ))
02650 return false;
02651 }
02652 return true;
02653 }
02654
02655 bool Connection::loadExtendedTableSchemaData(TableSchema& tableSchema)
02656 {
02657 #define loadExtendedTableSchemaData_ERR \
02658 { setError(i18n("Error while loading extended table schema information.")); \
02659 return false; }
02660 #define loadExtendedTableSchemaData_ERR2(details) \
02661 { setError(i18n("Error while loading extended table schema information."), details); \
02662 return false; }
02663 #define loadExtendedTableSchemaData_ERR3(data) \
02664 { setError(i18n("Error while loading extended table schema information."), \
02665 i18n("Invalid XML data: ") + data.left(1024) ); \
02666 return false; }
02667
02668
02669 QString extendedTableSchemaString;
02670 tristate res = loadDataBlock( tableSchema.id(), extendedTableSchemaString, "extended_schema" );
02671 if (!res)
02672 loadExtendedTableSchemaData_ERR;
02673
02674
02675 #ifdef KEXIDB_LOOKUP_FIELD_TEST
02676
02677 if (tableSchema.name()=="cars") {
02678 LookupFieldSchema *lookupFieldSchema = new LookupFieldSchema();
02679 lookupFieldSchema->rowSource().setType(LookupFieldSchema::RowSource::Table);
02680 lookupFieldSchema->rowSource().setName("persons");
02681 lookupFieldSchema->setBoundColumn(0);
02682 lookupFieldSchema->setVisibleColumn(3);
02683 tableSchema.setLookupFieldSchema( "owner", lookupFieldSchema );
02684 }
02685
02686 #endif
02687
02688 if (extendedTableSchemaString.isEmpty())
02689 return true;
02690
02691 QDomDocument doc;
02692 QString errorMsg;
02693 int errorLine, errorColumn;
02694 if (!doc.setContent( extendedTableSchemaString, &errorMsg, &errorLine, &errorColumn ))
02695 loadExtendedTableSchemaData_ERR2( i18n("Error in XML data: \"%1\" in line %2, column %3.\nXML data: ")
02696 .arg(errorMsg).arg(errorLine).arg(errorColumn) + extendedTableSchemaString.left(1024));
02697
02699
02700 if (doc.doctype().name()!="EXTENDED_TABLE_SCHEMA")
02701 loadExtendedTableSchemaData_ERR3( extendedTableSchemaString );
02702
02703 QDomElement docEl = doc.documentElement();
02704 if (docEl.tagName()!="EXTENDED_TABLE_SCHEMA")
02705 loadExtendedTableSchemaData_ERR3( extendedTableSchemaString );
02706
02707 for (QDomNode n = docEl.firstChild(); !n.isNull(); n = n.nextSibling()) {
02708 QDomElement fieldEl = n.toElement();
02709 if (fieldEl.tagName()=="field") {
02710 Field *f = tableSchema.field( fieldEl.attribute("name") );
02711 if (f) {
02712
02714 for (QDomNode propNode = fieldEl.firstChild();
02715 !propNode.isNull(); propNode = propNode.nextSibling())
02716 {
02717 QDomElement propEl = propNode.toElement();
02718 bool ok;
02719 int intValue;
02720 if (propEl.tagName()=="property") {
02721 QCString propertyName = propEl.attribute("name").latin1();
02722 if (propEl.attribute("custom")=="true") {
02723
02724 f->setCustomProperty(propertyName,
02725 KexiDB::loadPropertyValueFromDom( propEl.firstChild() ));
02726 }
02727 else if (propertyName == "visibleDecimalPlaces"
02728 && KexiDB::supportsVisibleDecimalPlacesProperty(f->type()))
02729 {
02730 intValue = KexiDB::loadIntPropertyValueFromDom( propEl.firstChild(), &ok );
02731 if (ok)
02732 f->setVisibleDecimalPlaces(intValue);
02733 }
02735 }
02736 else if (propEl.tagName()=="lookup-column") {
02737 LookupFieldSchema *lookupFieldSchema = LookupFieldSchema::loadFromDom(propEl);
02738 if (lookupFieldSchema)
02739 lookupFieldSchema->debug();
02740 tableSchema.setLookupFieldSchema( f->name(), lookupFieldSchema );
02741 }
02742 }
02743 }
02744 else {
02745 KexiDBWarn << "Connection::loadExtendedTableSchemaData(): no such field \""
02746 << fieldEl.attribute("name") << "\" in table \"" << tableSchema.name() << "\"" << endl;
02747 }
02748 }
02749 }
02750
02751 return true;
02752 }
02753
02754 KexiDB::Field* Connection::setupField( const RowData &data )
02755 {
02756 bool ok = true;
02757 int f_int_type = data.at(1).toInt(&ok);
02758 if (f_int_type<=Field::InvalidType || f_int_type>Field::LastType)
02759 ok = false;
02760 if (!ok)
02761 return 0;
02762 Field::Type f_type = (Field::Type)f_int_type;
02763 int f_len = QMAX( 0, data.at(3).toInt(&ok) );
02764 if (!ok)
02765 return 0;
02766 int f_prec = data.at(4).toInt(&ok);
02767 if (!ok)
02768 return 0;
02769 int f_constr = data.at(5).toInt(&ok);
02770 if (!ok)
02771 return 0;
02772 int f_opts = data.at(6).toInt(&ok);
02773 if (!ok)
02774 return 0;
02775
02776 if (!KexiUtils::isIdentifier( data.at(2).toString() )) {
02777 setError(ERR_INVALID_IDENTIFIER, i18n("Invalid object name \"%1\"")
02778 .arg( data.at(2).toString() ));
02779 ok = false;
02780 return 0;
02781 }
02782
02783 Field *f = new Field(
02784 data.at(2).toString(), f_type, f_constr, f_opts, f_len, f_prec );
02785
02786 f->setDefaultValue( KexiDB::stringToVariant(data.at(7).toString(), Field::variantType( f_type ), ok) );
02787 if (!ok) {
02788 KexiDBWarn << "Connection::setupTableSchema() problem with KexiDB::stringToVariant("
02789 << data.at(7).toString() << ")" << endl;
02790 }
02791 ok = true;
02792
02793 f->m_caption = data.at(9).toString();
02794 f->m_desc = data.at(10).toString();
02795 return f;
02796 }
02797
02798 KexiDB::TableSchema* Connection::setupTableSchema( const RowData &data )
02799 {
02800 TableSchema *t = new TableSchema( this );
02801 if (!setupObjectSchemaData( data, *t )) {
02802 delete t;
02803 return 0;
02804 }
02805
02806 KexiDB::Cursor *cursor;
02807 if (!(cursor = executeQuery(
02808 QString::fromLatin1("SELECT t_id, f_type, f_name, f_length, f_precision, f_constraints, "
02809 "f_options, f_default, f_order, f_caption, f_help"
02810 " FROM kexi__fields WHERE t_id=%1 ORDER BY f_order").arg(t->m_id) )))
02811 {
02812 delete t;
02813 return 0;
02814 }
02815 if (!cursor->moveFirst()) {
02816 if (!cursor->error() && cursor->eof()) {
02817 setError(i18n("Table has no fields defined."));
02818 }
02819 deleteCursor(cursor);
02820 delete t;
02821 return 0;
02822 }
02823
02824
02825 RowData fieldData;
02826 bool ok = true;
02827 while (!cursor->eof()) {
02828
02829 cursor->storeCurrentRow(fieldData);
02830 Field *f = setupField(fieldData);
02831 if (!f) {
02832 ok = false;
02833 break;
02834 }
02835 t->addField(f);
02836 cursor->moveNext();
02837 }
02838
02839 if (!ok) {
02840 deleteCursor(cursor);
02841 delete t;
02842 return 0;
02843 }
02844
02845 if (!deleteCursor(cursor)) {
02846 delete t;
02847 return 0;
02848 }
02849
02850 if (!loadExtendedTableSchemaData(*t)) {
02851 delete t;
02852 return 0;
02853 }
02854
02855 d->tables.insert(t->m_id, t);
02856 d->tables_byname.insert(t->m_name.lower(), t);
02857 return t;
02858 }
02859
02860 TableSchema* Connection::tableSchema( const QString& tableName )
02861 {
02862 QString m_tableName = tableName.lower();
02863 TableSchema *t = d->tables_byname[m_tableName];
02864 if (t)
02865 return t;
02866
02867 RowData data;
02868 if (true!=querySingleRecord(QString::fromLatin1(
02869 "SELECT o_id, o_type, o_name, o_caption, o_desc FROM kexi__objects WHERE lower(o_name)='%1' AND o_type=%2")
02870 .arg(m_tableName).arg(KexiDB::TableObjectType), data))
02871 return 0;
02872
02873 return setupTableSchema(data);
02874 }
02875
02876 TableSchema* Connection::tableSchema( int tableId )
02877 {
02878 TableSchema *t = d->tables[tableId];
02879 if (t)
02880 return t;
02881
02882 RowData data;
02883 if (true!=querySingleRecord(QString::fromLatin1(
02884 "SELECT o_id, o_type, o_name, o_caption, o_desc FROM kexi__objects WHERE o_id=%1")
02885 .arg(tableId), data))
02886 return 0;
02887
02888 return setupTableSchema(data);
02889 }
02890
02891 tristate Connection::loadDataBlock( int objectID, QString &dataString, const QString& dataID )
02892 {
02893 if (objectID<=0)
02894 return false;
02895 return querySingleString(
02896 QString("SELECT o_data FROM kexi__objectdata WHERE o_id=") + QString::number(objectID)
02897 + " AND " + KexiDB::sqlWhere(m_driver, KexiDB::Field::Text, "o_sub_id", dataID),
02898 dataString );
02899 }
02900
02901 bool Connection::storeDataBlock( int objectID, const QString &dataString, const QString& dataID )
02902 {
02903 if (objectID<=0)
02904 return false;
02905 QString sql(QString::fromLatin1("SELECT kexi__objectdata.o_id FROM kexi__objectdata WHERE o_id=%1").arg(objectID));
02906 QString sql_sub( KexiDB::sqlWhere(m_driver, KexiDB::Field::Text, "o_sub_id", dataID) );
02907
02908 bool ok, exists;
02909 exists = resultExists(sql + " and " + sql_sub, ok);
02910 if (!ok)
02911 return false;
02912 if (exists) {
02913 return executeSQL( "UPDATE kexi__objectdata SET o_data="
02914 + m_driver->valueToSQL( KexiDB::Field::LongText, dataString )
02915 + " WHERE o_id=" + QString::number(objectID) + " AND " + sql_sub );
02916 }
02917 return executeSQL(
02918 QString::fromLatin1("INSERT INTO kexi__objectdata (o_id, o_data, o_sub_id) VALUES (")
02919 + QString::number(objectID) +"," + m_driver->valueToSQL( KexiDB::Field::LongText, dataString )
02920 + "," + m_driver->valueToSQL( KexiDB::Field::Text, dataID ) + ")" );
02921 }
02922
02923 bool Connection::removeDataBlock( int objectID, const QString& dataID)
02924 {
02925 if (objectID<=0)
02926 return false;
02927 if (dataID.isEmpty())
02928 return KexiDB::deleteRow(*this, "kexi__objectdata", "o_id", QString::number(objectID));
02929 else
02930 return KexiDB::deleteRow(*this, "kexi__objectdata",
02931 "o_id", KexiDB::Field::Integer, objectID, "o_sub_id", KexiDB::Field::Text, dataID);
02932 }
02933
02934 KexiDB::QuerySchema* Connection::setupQuerySchema( const RowData &data )
02935 {
02936 bool ok = true;
02937 const int objID = data[0].toInt(&ok);
02938 if (!ok)
02939 return false;
02940 QString sqlText;
02941 if (!loadDataBlock( objID, sqlText, "sql" )) {
02942 setError(ERR_OBJECT_NOT_FOUND,
02943 i18n("Could not find definition for query \"%1\". Removing this query is recommended.")
02944 .arg(data[2].toString()));
02945 return 0;
02946 }
02947 d->parser()->parse( sqlText );
02948 KexiDB::QuerySchema *query = d->parser()->query();
02949
02950 if (!query) {
02951 setError(ERR_SQL_PARSE_ERROR,
02952 i18n("<p>Could not load definition for query \"%1\". "
02953 "SQL statement for this query is invalid:<br><tt>%2</tt></p>\n"
02954 "<p>You can open this query in Text View and correct it.</p>").arg(data[2].toString())
02955 .arg(d->parser()->statement()));
02956 return 0;
02957 }
02958 if (!setupObjectSchemaData( data, *query )) {
02959 delete query;
02960 return 0;
02961 }
02962 d->queries.insert(query->m_id, query);
02963 d->queries_byname.insert(query->m_name, query);
02964 return query;
02965 }
02966
02967 QuerySchema* Connection::querySchema( const QString& queryName )
02968 {
02969 QString m_queryName = queryName.lower();
02970 QuerySchema *q = d->queries_byname[m_queryName];
02971 if (q)
02972 return q;
02973
02974 RowData data;
02975 if (true!=querySingleRecord(QString::fromLatin1(
02976 "SELECT o_id, o_type, o_name, o_caption, o_desc FROM kexi__objects WHERE lower(o_name)='%1' AND o_type=%2")
02977 .arg(m_queryName).arg(KexiDB::QueryObjectType), data))
02978 return 0;
02979
02980 return setupQuerySchema(data);
02981 }
02982
02983 QuerySchema* Connection::querySchema( int queryId )
02984 {
02985 QuerySchema *q = d->queries[queryId];
02986 if (q)
02987 return q;
02988
02989 clearError();
02990 RowData data;
02991 if (true!=querySingleRecord(QString::fromLatin1(
02992 "SELECT o_id, o_type, o_name, o_caption, o_desc FROM kexi__objects WHERE o_id=%1").arg(queryId), data))
02993 return 0;
02994
02995 return setupQuerySchema(data);
02996 }
02997
02998 bool Connection::setQuerySchemaObsolete( const QString& queryName )
02999 {
03000 QuerySchema* oldQuery = querySchema( queryName );
03001 if (!oldQuery)
03002 return false;
03003 d->obsoleteQueries.append(oldQuery);
03004 d->queries_byname.take(queryName);
03005 d->queries.take(oldQuery->id());
03006 return true;
03007 }
03008
03009 TableSchema* Connection::newKexiDBSystemTableSchema(const QString& tsname)
03010 {
03011 TableSchema *ts = new TableSchema(tsname.lower());
03012 insertInternalTableSchema( ts );
03013 return ts;
03014 }
03015
03016 bool Connection::isInternalTableSchema(const QString& tableName)
03017 {
03018 return (d->kexiDBSystemTables[ d->tables_byname[tableName] ])
03019
03020
03021 || tableName=="kexi__final" || tableName=="kexi__useractions";
03022 }
03023
03024 void Connection::insertInternalTableSchema(TableSchema *tableSchema)
03025 {
03026 tableSchema->setKexiDBSystem(true);
03027 d->kexiDBSystemTables.insert(tableSchema, tableSchema);
03028 d->tables_byname.insert(tableSchema->name(), tableSchema);
03029 }
03030
03032 bool Connection::setupKexiDBSystemSchema()
03033 {
03034 if (!d->kexiDBSystemTables.isEmpty())
03035 return true;
03036
03037 TableSchema *t_objects = newKexiDBSystemTableSchema("kexi__objects");
03038 t_objects->addField( new Field("o_id", Field::Integer, Field::PrimaryKey | Field::AutoInc, Field::Unsigned) )
03039 .addField( new Field("o_type", Field::Byte, 0, Field::Unsigned) )
03040 .addField( new Field("o_name", Field::Text) )
03041 .addField( new Field("o_caption", Field::Text ) )
03042 .addField( new Field("o_desc", Field::LongText ) );
03043
03044 t_objects->debug();
03045
03046 TableSchema *t_objectdata = newKexiDBSystemTableSchema("kexi__objectdata");
03047 t_objectdata->addField( new Field("o_id", Field::Integer, Field::NotNull, Field::Unsigned) )
03048 .addField( new Field("o_data", Field::LongText) )
03049 .addField( new Field("o_sub_id", Field::Text) );
03050
03051 TableSchema *t_fields = newKexiDBSystemTableSchema("kexi__fields");
03052 t_fields->addField( new Field("t_id", Field::Integer, 0, Field::Unsigned) )
03053 .addField( new Field("f_type", Field::Byte, 0, Field::Unsigned) )
03054 .addField( new Field("f_name", Field::Text ) )
03055 .addField( new Field("f_length", Field::Integer ) )
03056 .addField( new Field("f_precision", Field::Integer ) )
03057 .addField( new Field("f_constraints", Field::Integer ) )
03058 .addField( new Field("f_options", Field::Integer ) )
03059 .addField( new Field("f_default", Field::Text ) )
03060
03061 .addField( new Field("f_order", Field::Integer ) )
03062 .addField( new Field("f_caption", Field::Text ) )
03063 .addField( new Field("f_help", Field::LongText ) );
03064
03065
03066
03067
03068
03069
03070
03071
03072
03073
03074
03075
03076
03077
03078
03079
03080
03081
03082 TableSchema *t_db = newKexiDBSystemTableSchema("kexi__db");
03083 t_db->addField( new Field("db_property", Field::Text, Field::NoConstraints, Field::NoOptions, 32 ) )
03084 .addField( new Field("db_value", Field::LongText ) );
03085
03086
03087
03088
03089
03090
03091
03092
03093
03094
03095
03096
03097
03098
03099
03100
03101
03102
03103
03104
03105
03106
03107
03108
03109 return true;
03110 }
03111
03112 void Connection::removeMe(TableSchema *ts)
03113 {
03114 if (ts && !m_destructor_started) {
03115 d->tables.take(ts->id());
03116 d->tables_byname.take(ts->name());
03117 }
03118 }
03119
03120 QString Connection::anyAvailableDatabaseName()
03121 {
03122 if (!d->availableDatabaseName.isEmpty()) {
03123 return d->availableDatabaseName;
03124 }
03125 return m_driver->beh->ALWAYS_AVAILABLE_DATABASE_NAME;
03126 }
03127
03128 void Connection::setAvailableDatabaseName(const QString& dbName)
03129 {
03130 d->availableDatabaseName = dbName;
03131 }
03132
03134 inline void updateRowDataWithNewValues(QuerySchema &query, RowData& data, KexiDB::RowEditBuffer::DBMap& b,
03135 QMap<QueryColumnInfo*,int>& columnsOrderExpanded)
03136 {
03137 columnsOrderExpanded = query.columnsOrder(QuerySchema::ExpandedList);
03138 QMap<QueryColumnInfo*,int>::ConstIterator columnsOrderExpandedIt;
03139 for (KexiDB::RowEditBuffer::DBMap::ConstIterator it=b.constBegin();it!=b.constEnd();++it) {
03140 columnsOrderExpandedIt = columnsOrderExpanded.find( it.key() );
03141 if (columnsOrderExpandedIt == columnsOrderExpanded.constEnd()) {
03142 KexiDBWarn << "(Connection) updateRowDataWithNewValues(): \"now also assign new value in memory\" step "
03143 "- could not find item '" << it.key()->aliasOrName() << "'" << endl;
03144 continue;
03145 }
03146 data[ columnsOrderExpandedIt.data() ] = it.data();
03147 }
03148 }
03149
03150 bool Connection::updateRow(QuerySchema &query, RowData& data, RowEditBuffer& buf, bool useROWID)
03151 {
03152
03153
03154
03155 KexiDBDbg << "Connection::updateRow.." << endl;
03156 clearError();
03157
03158 if (buf.dbBuffer().isEmpty()) {
03159 KexiDBDbg << " -- NO CHANGES DATA!" << endl;
03160 return true;
03161 }
03162 TableSchema *mt = query.masterTable();
03163 if (!mt) {
03164 KexiDBWarn << " -- NO MASTER TABLE!" << endl;
03165 setError(ERR_UPDATE_NO_MASTER_TABLE,
03166 i18n("Could not update row because there is no master table defined."));
03167 return false;
03168 }
03169 IndexSchema *pkey = (mt->primaryKey() && !mt->primaryKey()->fields()->isEmpty()) ? mt->primaryKey() : 0;
03170 if (!useROWID && !pkey) {
03171 KexiDBWarn << " -- NO MASTER TABLE's PKEY!" << endl;
03172 setError(ERR_UPDATE_NO_MASTER_TABLES_PKEY,
03173 i18n("Could not update row because master table has no primary key defined."));
03175 return false;
03176 }
03177
03178 m_sql = "UPDATE " + escapeIdentifier(mt->name()) + " SET ";
03179 QString sqlset, sqlwhere;
03180 sqlset.reserve(1024);
03181 sqlwhere.reserve(1024);
03182 KexiDB::RowEditBuffer::DBMap b = buf.dbBuffer();
03183 for (KexiDB::RowEditBuffer::DBMap::ConstIterator it=b.constBegin();it!=b.constEnd();++it) {
03184 if (it.key()->field->table()!=mt)
03185 continue;
03186 if (!sqlset.isEmpty())
03187 sqlset+=",";
03188 sqlset += (escapeIdentifier(it.key()->field->name()) + "=" +
03189 m_driver->valueToSQL(it.key()->field,it.data()));
03190 }
03191 if (pkey) {
03192 const QValueVector<int> pkeyFieldsOrder( query.pkeyFieldsOrder() );
03193 KexiDBDbg << pkey->fieldCount() << " ? " << query.pkeyFieldsCount() << endl;
03194 if (pkey->fieldCount() != query.pkeyFieldsCount()) {
03195 KexiDBWarn << " -- NO ENTIRE MASTER TABLE's PKEY SPECIFIED!" << endl;
03196 setError(ERR_UPDATE_NO_ENTIRE_MASTER_TABLES_PKEY,
03197 i18n("Could not update row because it does not contain entire master table's primary key."));
03198 return false;
03199 }
03200 if (!pkey->fields()->isEmpty()) {
03201 uint i=0;
03202 for (Field::ListIterator it = pkey->fieldsIterator(); it.current(); i++, ++it) {
03203 if (!sqlwhere.isEmpty())
03204 sqlwhere+=" AND ";
03205 QVariant val = data[ pkeyFieldsOrder[i] ];
03206 if (val.isNull() || !val.isValid()) {
03207 setError(ERR_UPDATE_NULL_PKEY_FIELD,
03208 i18n("Primary key's field \"%1\" cannot be empty.").arg(it.current()->name()));
03209
03210 return false;
03211 }
03212 sqlwhere += ( escapeIdentifier(it.current()->name()) + "=" +
03213 m_driver->valueToSQL( it.current(), val ) );
03214 }
03215 }
03216 }
03217 else {
03218 sqlwhere = ( escapeIdentifier(m_driver->beh->ROW_ID_FIELD_NAME) + "="
03219 + m_driver->valueToSQL(Field::BigInteger, data[data.size()-1]));
03220 }
03221 m_sql += (sqlset + " WHERE " + sqlwhere);
03222 KexiDBDbg << " -- SQL == " << ((m_sql.length() > 400) ? (m_sql.left(400)+"[.....]") : m_sql) << endl;
03223
03224 if (!executeSQL(m_sql)) {
03225 setError(ERR_UPDATE_SERVER_ERROR, i18n("Row updating on the server failed."));
03226 return false;
03227 }
03228
03229 QMap<QueryColumnInfo*,int> columnsOrderExpanded;
03230 updateRowDataWithNewValues(query, data, b, columnsOrderExpanded);
03231 return true;
03232 }
03233
03234 bool Connection::insertRow(QuerySchema &query, RowData& data, RowEditBuffer& buf, bool getROWID)
03235 {
03236
03237 KexiDBDbg << "Connection::updateRow.." << endl;
03238 clearError();
03239
03240
03241
03242
03243
03244 TableSchema *mt = query.masterTable();
03245 if (!mt) {
03246 KexiDBWarn << " -- NO MASTER TABLE!" << endl;
03247 setError(ERR_INSERT_NO_MASTER_TABLE,
03248 i18n("Could not insert row because there is no master table defined."));
03249 return false;
03250 }
03251 IndexSchema *pkey = (mt->primaryKey() && !mt->primaryKey()->fields()->isEmpty()) ? mt->primaryKey() : 0;
03252 if (!getROWID && !pkey)
03253 KexiDBWarn << " -- WARNING: NO MASTER TABLE's PKEY" << endl;
03254
03255 QString sqlcols, sqlvals;
03256 sqlcols.reserve(1024);
03257 sqlvals.reserve(1024);
03258
03259
03260 m_sql = "INSERT INTO " + escapeIdentifier(mt->name()) + " (";
03261 KexiDB::RowEditBuffer::DBMap b = buf.dbBuffer();
03262
03263
03264 const QueryColumnInfo::Vector fieldsExpanded( query.fieldsExpanded( QuerySchema::Unique ) );
03265 for (uint i=0; i<fieldsExpanded.count(); i++) {
03266 QueryColumnInfo *ci = fieldsExpanded.at(i);
03267 if (ci->field && KexiDB::isDefaultValueAllowed(ci->field)
03268 && !ci->field->defaultValue().isNull()
03269 && !b.contains( ci ))
03270 {
03271 KexiDBDbg << "Connection::insertRow(): adding default value '" << ci->field->defaultValue().toString()
03272 << "' for column '" << ci->field->name() << "'" << endl;
03273 b.insert( ci, ci->field->defaultValue() );
03274 }
03275 }
03276
03277 if (b.isEmpty()) {
03278
03279 if (!getROWID && !pkey) {
03280 KexiDBWarn << "MASTER TABLE's PKEY REQUIRED FOR INSERTING EMPTY ROWS: INSERT CANCELLED" << endl;
03281 setError(ERR_INSERT_NO_MASTER_TABLES_PKEY,
03282 i18n("Could not insert row because master table has no primary key defined."));
03283 return false;
03284 }
03285 if (pkey) {
03286 const QValueVector<int> pkeyFieldsOrder( query.pkeyFieldsOrder() );
03287
03288 if (pkey->fieldCount() != query.pkeyFieldsCount()) {
03289 KexiDBWarn << "NO ENTIRE MASTER TABLE's PKEY SPECIFIED!" << endl;
03290 setError(ERR_INSERT_NO_ENTIRE_MASTER_TABLES_PKEY,
03291 i18n("Could not insert row because it does not contain entire master table's primary key.")
03292 .arg(query.name()));
03293 return false;
03294 }
03295 }
03296
03297 Field *anyField = mt->anyNonPKField();
03298 if (!anyField) {
03299 if (!pkey) {
03300 KexiDBWarn << "WARNING: NO FIELD AVAILABLE TO SET IT TO NULL" << endl;
03301 return false;
03302 }
03303 else {
03304
03305 anyField = pkey->fields()->first();
03306 }
03307 }
03308 sqlcols += escapeIdentifier(anyField->name());
03309 sqlvals += m_driver->valueToSQL(anyField,QVariant());
03310 }
03311 else {
03312
03313 for (KexiDB::RowEditBuffer::DBMap::ConstIterator it=b.constBegin();it!=b.constEnd();++it) {
03314 if (it.key()->field->table()!=mt)
03315 continue;
03316 if (!sqlcols.isEmpty()) {
03317 sqlcols+=",";
03318 sqlvals+=",";
03319 }
03320 sqlcols += escapeIdentifier(it.key()->field->name());
03321 sqlvals += m_driver->valueToSQL(it.key()->field,it.data());
03322 }
03323 }
03324 m_sql += (sqlcols + ") VALUES (" + sqlvals + ")");
03325
03326
03327 bool res = executeSQL(m_sql);
03328
03329 if (!res) {
03330 setError(ERR_INSERT_SERVER_ERROR, i18n("Row inserting on the server failed."));
03331 return false;
03332 }
03333
03334 QMap<QueryColumnInfo*,int> columnsOrderExpanded;
03335 updateRowDataWithNewValues(query, data, b, columnsOrderExpanded);
03336
03337
03338 QueryColumnInfo::List *aif_list = query.autoIncrementFields();
03339 Q_ULLONG ROWID = 0;
03340 if (pkey && !aif_list->isEmpty()) {
03342 QueryColumnInfo *id_columnInfo = aif_list->first();
03344 Q_ULLONG last_id = lastInsertedAutoIncValue(
03345 id_columnInfo->field->name(), id_columnInfo->field->table()->name(), &ROWID);
03346 if (last_id==(Q_ULLONG)-1 || last_id<=0) {
03349 return false;
03350 }
03351 RowData aif_data;
03352 QString getAutoIncForInsertedValue = QString::fromLatin1("SELECT ")
03353 + query.autoIncrementSQLFieldsList(m_driver)
03354 + QString::fromLatin1(" FROM ")
03355 + escapeIdentifier(id_columnInfo->field->table()->name())
03356 + QString::fromLatin1(" WHERE ")
03357 + escapeIdentifier(id_columnInfo->field->name()) + "="
03358 + QString::number(last_id);
03359 if (true!=querySingleRecord(getAutoIncForInsertedValue, aif_data)) {
03361 return false;
03362 }
03363 QueryColumnInfo::ListIterator ci_it(*aif_list);
03364 QueryColumnInfo *ci;
03365 for (uint i=0; (ci = ci_it.current()); ++ci_it, i++) {
03366
03367
03368 ( data[ columnsOrderExpanded[ ci ] ] = aif_data[i] ).cast( ci->field->variantType() );
03369 }
03370 }
03371 else {
03372 ROWID = drv_lastInsertRowID();
03373
03374 if (m_driver->beh->ROW_ID_FIELD_RETURNS_LAST_AUTOINCREMENTED_VALUE) {
03375 KexiDBWarn << "Connection::insertRow(): m_driver->beh->ROW_ID_FIELD_RETURNS_LAST_AUTOINCREMENTED_VALUE" << endl;
03376 return false;
03377 }
03378 }
03379 if (getROWID && data.size() > fieldsExpanded.size()) {
03380
03381 data[data.size()-1] = ROWID;
03382 }
03383 return true;
03384 }
03385
03386 bool Connection::deleteRow(QuerySchema &query, RowData& data, bool useROWID)
03387 {
03388
03389 KexiDBWarn << "Connection::deleteRow.." << endl;
03390 clearError();
03391 TableSchema *mt = query.masterTable();
03392 if (!mt) {
03393 KexiDBWarn << " -- NO MASTER TABLE!" << endl;
03394 setError(ERR_DELETE_NO_MASTER_TABLE,
03395 i18n("Could not delete row because there is no master table defined.")
03396 .arg(query.name()));
03397 return false;
03398 }
03399 IndexSchema *pkey = (mt->primaryKey() && !mt->primaryKey()->fields()->isEmpty()) ? mt->primaryKey() : 0;
03400
03402 if (!useROWID && !pkey) {
03403 KexiDBWarn << " -- WARNING: NO MASTER TABLE's PKEY" << endl;
03404 setError(ERR_DELETE_NO_MASTER_TABLES_PKEY,
03405 i18n("Could not delete row because there is no primary key for master table defined."));
03406 return false;
03407 }
03408
03409
03410 m_sql = "DELETE FROM " + escapeIdentifier(mt->name()) + " WHERE ";
03411 QString sqlwhere;
03412 sqlwhere.reserve(1024);
03413
03414 if (pkey) {
03415 const QValueVector<int> pkeyFieldsOrder( query.pkeyFieldsOrder() );
03416 KexiDBDbg << pkey->fieldCount() << " ? " << query.pkeyFieldsCount() << endl;
03417 if (pkey->fieldCount() != query.pkeyFieldsCount()) {
03418 KexiDBWarn << " -- NO ENTIRE MASTER TABLE's PKEY SPECIFIED!" << endl;
03419 setError(ERR_DELETE_NO_ENTIRE_MASTER_TABLES_PKEY,
03420 i18n("Could not delete row because it does not contain entire master table's primary key."));
03421 return false;
03422 }
03423 uint i=0;
03424 for (Field::ListIterator it = pkey->fieldsIterator(); it.current(); i++, ++it) {
03425 if (!sqlwhere.isEmpty())
03426 sqlwhere+=" AND ";
03427 QVariant val = data[ pkeyFieldsOrder[i] ];
03428 if (val.isNull() || !val.isValid()) {
03429 setError(ERR_DELETE_NULL_PKEY_FIELD, i18n("Primary key's field \"%1\" cannot be empty.")
03430 .arg(it.current()->name()));
03431
03432 return false;
03433 }
03434 sqlwhere += ( escapeIdentifier(it.current()->name()) + "=" +
03435 m_driver->valueToSQL( it.current(), val ) );
03436 }
03437 }
03438 else {
03439 sqlwhere = ( escapeIdentifier(m_driver->beh->ROW_ID_FIELD_NAME) + "="
03440 + m_driver->valueToSQL(Field::BigInteger, data[data.size()-1]));
03441 }
03442 m_sql += sqlwhere;
03443 KexiDBDbg << " -- SQL == " << m_sql << endl;
03444
03445 if (!executeSQL(m_sql)) {
03446 setError(ERR_DELETE_SERVER_ERROR, i18n("Row deletion on the server failed."));
03447 return false;
03448 }
03449 return true;
03450 }
03451
03452 bool Connection::deleteAllRows(QuerySchema &query)
03453 {
03454 clearError();
03455 TableSchema *mt = query.masterTable();
03456 if (!mt) {
03457 KexiDBWarn << " -- NO MASTER TABLE!" << endl;
03458 return false;
03459 }
03460 IndexSchema *pkey = mt->primaryKey();
03461 if (!pkey || pkey->fields()->isEmpty())
03462 KexiDBWarn << "Connection::deleteAllRows -- WARNING: NO MASTER TABLE's PKEY" << endl;
03463
03464 m_sql = "DELETE FROM " + escapeIdentifier(mt->name());
03465
03466 KexiDBDbg << " -- SQL == " << m_sql << endl;
03467
03468 if (!executeSQL(m_sql)) {
03469 setError(ERR_DELETE_SERVER_ERROR, i18n("Row deletion on the server failed."));
03470 return false;
03471 }
03472 return true;
03473 }
03474
03475 void Connection::registerForTableSchemaChanges(TableSchemaChangeListenerInterface& listener,
03476 TableSchema &schema)
03477 {
03478 QPtrList<TableSchemaChangeListenerInterface>* listeners = d->tableSchemaChangeListeners[&schema];
03479 if (!listeners) {
03480 listeners = new QPtrList<TableSchemaChangeListenerInterface>();
03481 d->tableSchemaChangeListeners.insert(&schema, listeners);
03482 }
03483
03484 if (listeners->findRef( &listener )==-1)
03485 listeners->append( &listener );
03486 }
03487
03488 void Connection::unregisterForTableSchemaChanges(TableSchemaChangeListenerInterface& listener,
03489 TableSchema &schema)
03490 {
03491 QPtrList<TableSchemaChangeListenerInterface>* listeners = d->tableSchemaChangeListeners[&schema];
03492 if (!listeners)
03493 return;
03494
03495 listeners->remove( &listener );
03496 }
03497
03498 void Connection::unregisterForTablesSchemaChanges(TableSchemaChangeListenerInterface& listener)
03499 {
03500 for (QPtrDictIterator< QPtrList<TableSchemaChangeListenerInterface> > it(d->tableSchemaChangeListeners);
03501 it.current(); ++it)
03502 {
03503 if (-1!=it.current()->find(&listener))
03504 it.current()->take();
03505 }
03506 }
03507
03508 QPtrList<Connection::TableSchemaChangeListenerInterface>*
03509 Connection::tableSchemaChangeListeners(TableSchema& tableSchema) const
03510 {
03511 KexiDBDbg << d->tableSchemaChangeListeners.count() << endl;
03512 return d->tableSchemaChangeListeners[&tableSchema];
03513 }
03514
03515 tristate Connection::closeAllTableSchemaChangeListeners(TableSchema& tableSchema)
03516 {
03517 QPtrList<Connection::TableSchemaChangeListenerInterface> *listeners = d->tableSchemaChangeListeners[&tableSchema];
03518 if (!listeners)
03519 return true;
03520 QPtrListIterator<KexiDB::Connection::TableSchemaChangeListenerInterface> tmpListeners(*listeners);
03521 tristate res = true;
03522
03523 for (QPtrListIterator<KexiDB::Connection::TableSchemaChangeListenerInterface> it(tmpListeners);
03524 it.current() && res==true; ++it)
03525 {
03526 res = it.current()->closeListener();
03527 }
03528 return res;
03529 }
03530
03531
03532
03533
03534
03535
03536
03537
03538 void Connection::setReadOnly(bool set)
03539 {
03540 if (d->isConnected)
03541 return;
03542 d->readOnly = set;
03543 }
03544
03545 bool Connection::isReadOnly() const
03546 {
03547 return d->readOnly;
03548 }
03549
03550 #include "connection.moc"