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 v += QString::fromLatin1(" DEFAULT ") + m_driver->valueToSQL( field, field->defaultValue() );
00926 }
00927 sql += v;
00928 }
00929 sql += ")";
00930 return sql;
00931 }
00932
00933
00934 #define C_A(a) , const QVariant& c ## a
00935
00936 #define V_A0 m_driver->valueToSQL( tableSchema.field(0), c0 )
00937 #define V_A(a) +","+m_driver->valueToSQL( \
00938 tableSchema.field(a) ? tableSchema.field(a)->type() : Field::Text, c ## a )
00939
00940
00941
00942
00943
00944 #define C_INS_REC(args, vals) \
00945 bool Connection::insertRecord(KexiDB::TableSchema &tableSchema args) {\
00946 return executeSQL( \
00947 QString("INSERT INTO ") + escapeIdentifier(tableSchema.name()) + " VALUES (" + vals + ")" \
00948 ); \
00949 }
00950
00951 #define C_INS_REC_ALL \
00952 C_INS_REC( C_A(0), V_A0 ) \
00953 C_INS_REC( C_A(0) C_A(1), V_A0 V_A(1) ) \
00954 C_INS_REC( C_A(0) C_A(1) C_A(2), V_A0 V_A(1) V_A(2) ) \
00955 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) ) \
00956 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) ) \
00957 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) ) \
00958 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) ) \
00959 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) )
00960
00961 C_INS_REC_ALL
00962
00963 #undef V_A0
00964 #undef V_A
00965 #undef C_INS_REC
00966
00967 #define V_A0 value += m_driver->valueToSQL( flist->first(), c0 );
00968 #define V_A( a ) value += ("," + m_driver->valueToSQL( flist->next(), c ## a ));
00969
00970
00971
00972 #define C_INS_REC(args, vals) \
00973 bool Connection::insertRecord(FieldList& fields args) \
00974 { \
00975 QString value; \
00976 Field::List *flist = fields.fields(); \
00977 vals \
00978 return executeSQL( \
00979 QString("INSERT INTO ") + \
00980 ((fields.fields()->first() && fields.fields()->first()->table()) ? \
00981 escapeIdentifier(fields.fields()->first()->table()->name()) : \
00982 "??") \
00983 + "(" + fields.sqlFieldsList(m_driver) + ") VALUES (" + value + ")" \
00984 ); \
00985 }
00986
00987 C_INS_REC_ALL
00988
00989 #undef C_A
00990 #undef V_A
00991 #undef V_ALAST
00992 #undef C_INS_REC
00993 #undef C_INS_REC_ALL
00994
00995 bool Connection::insertRecord(TableSchema &tableSchema, QValueList<QVariant>& values)
00996 {
00997
00998 Field::List *fields = tableSchema.fields();
00999 Field *f = fields->first();
01000
01001
01002 m_sql = QString::null;
01003 QValueList<QVariant>::ConstIterator it = values.constBegin();
01004
01005 while (f && (it!=values.end())) {
01006 if (m_sql.isEmpty())
01007 m_sql = QString("INSERT INTO ") +
01008 escapeIdentifier(tableSchema.name()) +
01009 " VALUES (";
01010 else
01011 m_sql += ",";
01012 m_sql += m_driver->valueToSQL( f, *it );
01013
01014 ++it;
01015 f=fields->next();
01016 }
01017 m_sql += ")";
01018
01019
01020 return executeSQL(m_sql);
01021 }
01022
01023 bool Connection::insertRecord(FieldList& fields, QValueList<QVariant>& values)
01024 {
01025
01026 Field::List *flist = fields.fields();
01027 Field *f = flist->first();
01028 if (!f)
01029 return false;
01030
01031
01032 m_sql = QString::null;
01033 QValueList<QVariant>::ConstIterator it = values.constBegin();
01034
01035 while (f && (it!=values.constEnd())) {
01036 if (m_sql.isEmpty())
01037 m_sql = QString("INSERT INTO ") +
01038 escapeIdentifier(flist->first()->table()->name()) + "(" +
01039 fields.sqlFieldsList(m_driver) + ") VALUES (";
01040 else
01041 m_sql += ",";
01042 m_sql += m_driver->valueToSQL( f, *it );
01043
01044 ++it;
01045 f=flist->next();
01046 }
01047 m_sql += ")";
01048
01049 return executeSQL(m_sql);
01050 }
01051
01052 bool Connection::executeSQL( const QString& statement )
01053 {
01054 m_sql = statement;
01055 if (!drv_executeSQL( m_sql )) {
01056 m_errMsg = QString::null;
01057 m_errorSql = statement;
01058 setError(this, ERR_SQL_EXECUTION_ERROR, i18n("Error while executing SQL statement."));
01059 return false;
01060 }
01061 return true;
01062 }
01063
01064 QString Connection::selectStatement( KexiDB::QuerySchema& querySchema,
01065 const QValueList<QVariant>& params,
01066 const SelectStatementOptions& options) const
01067 {
01068
01069
01070
01071
01072
01073 if (!querySchema.statement().isEmpty())
01074 return querySchema.statement();
01075
01078 Field *f;
01079 uint number = 0;
01080 bool singleTable = querySchema.tables()->count() <= 1;
01081 if (singleTable) {
01082
01083 for (Field::ListIterator it = querySchema.fieldsIterator(); (f = it.current()); ++it, number++) {
01084 if (querySchema.isColumnVisible(number) && f->table() && f->table()->lookupFieldSchema( *f )) {
01085
01086 singleTable = false;
01087 break;
01088 }
01089 }
01090 }
01091
01092 QString sql;
01093
01094 QString s_additional_joins;
01095 QString s_additional_fields;
01096 sql.reserve(4096);
01097 number = 0;
01098 for (Field::ListIterator it = querySchema.fieldsIterator(); (f = it.current()); ++it, number++) {
01099 if (querySchema.isColumnVisible(number)) {
01100 if (!sql.isEmpty())
01101 sql += QString::fromLatin1(", ");
01102
01103 if (f->isQueryAsterisk()) {
01104 if (!singleTable && static_cast<QueryAsterisk*>(f)->isSingleTableAsterisk())
01105 sql += escapeIdentifier(f->table()->name(), options.identifierEscaping) +
01106 QString::fromLatin1(".*");
01107 else
01108 sql += QString::fromLatin1("*");
01109 }
01110 else {
01111 if (f->isExpression()) {
01112 sql += f->expression()->toString();
01113 }
01114 else {
01115 if (!f->table())
01116 return QString::null;
01117
01118 QString tableName;
01119 int tablePosition = querySchema.tableBoundToColumn(number);
01120 if (tablePosition>=0)
01121 tableName = querySchema.tableAlias(tablePosition);
01122 if (tableName.isEmpty())
01123 tableName = f->table()->name();
01124
01125 if (!singleTable) {
01126 sql += (escapeIdentifier(tableName, options.identifierEscaping) + ".");
01127 }
01128 sql += escapeIdentifier(f->name(), options.identifierEscaping);
01129 }
01130 QString aliasString = QString(querySchema.columnAlias(number));
01131 if (!aliasString.isEmpty())
01132 sql += (QString::fromLatin1(" AS ") + aliasString);
01134 }
01135 LookupFieldSchema *lookupFieldSchema = f->table() ? f->table()->lookupFieldSchema( *f ) : 0;
01136 if (lookupFieldSchema) {
01137
01138
01139
01140
01141 LookupFieldSchema::RowSource& rowSource = lookupFieldSchema->rowSource();
01142 if (rowSource.type()==LookupFieldSchema::RowSource::Table) {
01143 TableSchema *lookupTable = querySchema.connection()->tableSchema( rowSource.name() );
01144 Field *visibleField = 0;
01145 Field *boundField = 0;
01146 if (lookupTable && lookupFieldSchema->boundColumn()>=0
01147 && (uint)lookupFieldSchema->boundColumn() < lookupTable->fieldCount()
01148 && (visibleField = lookupTable->field( lookupFieldSchema->visibleColumn()))
01149 && (boundField = lookupTable->field( lookupFieldSchema->boundColumn() )))
01150 {
01151
01152 if (!s_additional_joins.isEmpty())
01153 s_additional_joins += QString::fromLatin1(" ");
01154 s_additional_joins += QString("LEFT OUTER JOIN %1 ON %2.%3=%4.%5")
01155 .arg(escapeIdentifier(lookupTable->name(), options.identifierEscaping))
01156 .arg(escapeIdentifier(f->table()->name(), options.identifierEscaping))
01157 .arg(escapeIdentifier(f->name(), options.identifierEscaping))
01158 .arg(escapeIdentifier(lookupTable->name(), options.identifierEscaping))
01159 .arg(escapeIdentifier(boundField->name(), options.identifierEscaping));
01160
01161
01162 if (!querySchema.findTableField( visibleField->table()->name()+"."+visibleField->name() )) {
01163 if (!querySchema.table( visibleField->table()->name() )) {
01164
01165
01166
01167
01168
01169
01170 }
01171 if (!s_additional_fields.isEmpty())
01172 s_additional_fields += QString::fromLatin1(", ");
01173 s_additional_fields += (escapeIdentifier(visibleField->table()->name(), options.identifierEscaping) + "."
01174 + escapeIdentifier(visibleField->name(), options.identifierEscaping));
01175 }
01176 }
01177 }
01178 }
01179 }
01180 }
01181
01182
01183 if (!s_additional_fields.isEmpty())
01184 sql += (QString::fromLatin1(", ") + s_additional_fields);
01185
01186 if (options.alsoRetrieveROWID) {
01187 QString s;
01188 if (!sql.isEmpty())
01189 s = QString::fromLatin1(", ");
01190 if (querySchema.masterTable())
01191 s += (escapeIdentifier(querySchema.masterTable()->name())+".");
01192 s += m_driver->beh->ROW_ID_FIELD_NAME;
01193 sql += s;
01194 }
01195
01196 sql.prepend("SELECT ");
01197 TableSchema::List* tables = querySchema.tables();
01198 if (tables && !tables->isEmpty()) {
01199 sql += QString::fromLatin1(" FROM ");
01200 QString s_from;
01201 TableSchema *table;
01202 number = 0;
01203 for (TableSchema::ListIterator it(*tables); (table = it.current());
01204 ++it, number++)
01205 {
01206 if (!s_from.isEmpty())
01207 s_from += QString::fromLatin1(", ");
01208 s_from += escapeIdentifier(table->name(), options.identifierEscaping);
01209 QString aliasString = QString(querySchema.tableAlias(number));
01210 if (!aliasString.isEmpty())
01211 s_from += (QString::fromLatin1(" AS ") + aliasString);
01212 }
01213
01214
01215
01216
01217
01218 sql += s_from;
01219 }
01220 QString s_where;
01221 s_where.reserve(4096);
01222
01223
01224 if (!s_additional_joins.isEmpty()) {
01225 sql += QString::fromLatin1(" ") + s_additional_joins + QString::fromLatin1(" ");
01226 }
01227
01228
01229
01230
01231 Relationship *rel;
01232 bool wasWhere = false;
01233 for (Relationship::ListIterator it(*querySchema.relationships()); (rel = it.current()); ++it) {
01234 if (s_where.isEmpty()) {
01235 wasWhere = true;
01236 }
01237 else
01238 s_where += QString::fromLatin1(" AND ");
01239 Field::Pair *pair;
01240 QString s_where_sub;
01241 for (QPtrListIterator<Field::Pair> p_it(*rel->fieldPairs()); (pair = p_it.current()); ++p_it) {
01242 if (!s_where_sub.isEmpty())
01243 s_where_sub += QString::fromLatin1(" AND ");
01244 s_where_sub += (
01245 escapeIdentifier(pair->first->table()->name(), options.identifierEscaping) +
01246 QString::fromLatin1(".") +
01247 escapeIdentifier(pair->first->name(), options.identifierEscaping) +
01248 QString::fromLatin1(" = ") +
01249 escapeIdentifier(pair->second->table()->name(), options.identifierEscaping) +
01250 QString::fromLatin1(".") +
01251 escapeIdentifier(pair->second->name(), options.identifierEscaping));
01252 }
01253 if (rel->fieldPairs()->count()>1) {
01254 s_where_sub.prepend("(");
01255 s_where_sub += QString::fromLatin1(")");
01256 }
01257 s_where += s_where_sub;
01258 }
01259
01260 if (querySchema.whereExpression()) {
01261 QuerySchemaParameterValueListIterator paramValuesIt(*m_driver, params);
01262 QuerySchemaParameterValueListIterator *paramValuesItPtr = params.isEmpty() ? 0 : ¶mValuesIt;
01263 if (wasWhere) {
01264
01265 s_where = "(" + s_where + ") AND (" + querySchema.whereExpression()->toString(paramValuesItPtr) + ")";
01266 }
01267 else {
01268 s_where = querySchema.whereExpression()->toString(paramValuesItPtr);
01269 }
01270 }
01271 if (!s_where.isEmpty())
01272 sql += QString::fromLatin1(" WHERE ") + s_where;
01274
01275
01276
01277 QString orderByString( querySchema.orderByColumnList().toSQLString(!singleTable) );
01278 if (!orderByString.isEmpty())
01279 sql += (" ORDER BY " + orderByString);
01280
01281
01282 return sql;
01283 }
01284
01285 QString Connection::selectStatement( KexiDB::TableSchema& tableSchema,
01286 const SelectStatementOptions& options) const
01287 {
01288 return selectStatement( *tableSchema.query(), options );
01289 }
01290
01291 Field* Connection::findSystemFieldName(KexiDB::FieldList* fieldlist)
01292 {
01293 Field *f = fieldlist->fields()->first();
01294 while (f) {
01295 if (m_driver->isSystemFieldName( f->name() ))
01296 return f;
01297 f = fieldlist->fields()->next();
01298 }
01299 return 0;
01300 }
01301
01302 Q_ULLONG Connection::lastInsertedAutoIncValue(const QString& aiFieldName, const QString& tableName,
01303 Q_ULLONG* ROWID)
01304 {
01305 Q_ULLONG row_id = drv_lastInsertRowID();
01306 if (ROWID)
01307 *ROWID = row_id;
01308 if (m_driver->beh->ROW_ID_FIELD_RETURNS_LAST_AUTOINCREMENTED_VALUE) {
01309 return row_id;
01310 }
01311 RowData rdata;
01312 if (row_id<=0 || true!=querySingleRecord(
01313 QString::fromLatin1("SELECT ") + tableName + QString::fromLatin1(".") + aiFieldName + QString::fromLatin1(" FROM ") + tableName
01314 + QString::fromLatin1(" WHERE ") + m_driver->beh->ROW_ID_FIELD_NAME + QString::fromLatin1("=") + QString::number(row_id), rdata))
01315 {
01316
01317 return (Q_ULLONG)-1;
01318 }
01319 return rdata[0].toULongLong();
01320 }
01321
01322 Q_ULLONG Connection::lastInsertedAutoIncValue(const QString& aiFieldName,
01323 const KexiDB::TableSchema& table, Q_ULLONG* ROWID)
01324 {
01325 return lastInsertedAutoIncValue(aiFieldName,table.name(), ROWID);
01326 }
01327
01329 static FieldList* createFieldListForKexi__Fields(TableSchema *kexi__fieldsSchema)
01330 {
01331 if (!kexi__fieldsSchema)
01332 return 0;
01333 return kexi__fieldsSchema->subList(
01334 "t_id",
01335 "f_type",
01336 "f_name",
01337 "f_length",
01338 "f_precision",
01339 "f_constraints",
01340 "f_options",
01341 "f_default",
01342 "f_order",
01343 "f_caption",
01344 "f_help"
01345 );
01346 }
01347
01349 void buildValuesForKexi__Fields(QValueList<QVariant>& vals, Field* f)
01350 {
01351 vals.clear();
01352 vals
01353 << QVariant(f->table()->id())
01354 << QVariant(f->type())
01355 << QVariant(f->name())
01356 << QVariant(f->isFPNumericType() ? f->scale() : f->length())
01357 << QVariant(f->isFPNumericType() ? f->precision() : 0)
01358 << QVariant(f->constraints())
01359 << QVariant(f->options())
01360
01361
01362 << (f->defaultValue().isNull()
01363 ? QVariant() : QVariant(KexiDB::variantToString( f->defaultValue() )))
01364 << QVariant(f->order())
01365 << QVariant(f->caption())
01366 << QVariant(f->description());
01367 }
01368
01369 bool Connection::storeMainFieldSchema(Field *field)
01370 {
01371 if (!field || !field->table())
01372 return false;
01373 FieldList *fl = createFieldListForKexi__Fields(d->tables_byname["kexi__fields"]);
01374 if (!fl)
01375 return false;
01376
01377 QValueList<QVariant> vals;
01378 buildValuesForKexi__Fields(vals, field);
01379 QValueList<QVariant>::ConstIterator valsIt = vals.constBegin();
01380 Field *f;
01381 bool first = true;
01382 QString sql = "UPDATE kexi__fields SET ";
01383 for (Field::ListIterator it( fl->fieldsIterator() ); (f = it.current()); ++it, ++valsIt) {
01384 sql.append( (first ? QString::null : QString(", ")) +
01385 f->name() + "=" + m_driver->valueToSQL( f, *valsIt ) );
01386 if (first)
01387 first = false;
01388 }
01389 delete fl;
01390
01391 sql.append(QString(" WHERE t_id=") + QString::number( field->table()->id() )
01392 + " AND f_name=" + m_driver->valueToSQL( Field::Text, field->name() ) );
01393 return executeSQL( sql );
01394 }
01395
01396 #define createTable_ERR \
01397 { KexiDBDbg << "Connection::createTable(): ERROR!" <<endl; \
01398 setError(this, i18n("Creating table failed.")); \
01399 rollbackAutoCommitTransaction(tg.transaction()); \
01400 return false; }
01401
01402
01404
01411 bool Connection::createTable( KexiDB::TableSchema* tableSchema, bool replaceExisting )
01412 {
01413 if (!tableSchema || !checkIsDatabaseUsed())
01414 return false;
01415
01416
01417 if (tableSchema->fieldCount()<1) {
01418 clearError();
01419 setError(ERR_CANNOT_CREATE_EMPTY_OBJECT, i18n("Cannot create table without fields."));
01420 return false;
01421 }
01422 const bool internalTable = dynamic_cast<InternalTableSchema*>(tableSchema);
01423
01424 const QString &tableName = tableSchema->name().lower();
01425
01426 if (!internalTable) {
01427 if (m_driver->isSystemObjectName( tableName )) {
01428 clearError();
01429 setError(ERR_SYSTEM_NAME_RESERVED, i18n("System name \"%1\" cannot be used as table name.")
01430 .arg(tableSchema->name()));
01431 return false;
01432 }
01433
01434 Field *sys_field = findSystemFieldName(tableSchema);
01435 if (sys_field) {
01436 clearError();
01437 setError(ERR_SYSTEM_NAME_RESERVED,
01438 i18n("System name \"%1\" cannot be used as one of fields in \"%2\" table.")
01439 .arg(sys_field->name()).arg(tableName));
01440 return false;
01441 }
01442 }
01443
01444 bool previousSchemaStillKept = false;
01445
01446 KexiDB::TableSchema *existingTable = 0;
01447 if (replaceExisting) {
01448
01449 existingTable = d->tables_byname[tableName];
01450 if (existingTable) {
01451 if (existingTable == tableSchema) {
01452 clearError();
01453 setError(ERR_OBJECT_EXISTS,
01454 i18n("Could not create the same table \"%1\" twice.").arg(tableSchema->name()) );
01455 return false;
01456 }
01457
01458 if (existingTable->id()>0)
01459 tableSchema->m_id = existingTable->id();
01460 previousSchemaStillKept = true;
01461 if (!dropTable( existingTable, false ))
01462 return false;
01463 }
01464 }
01465 else {
01466 if (this->tableSchema( tableSchema->name() ) != 0) {
01467 clearError();
01468 setError(ERR_OBJECT_EXISTS, i18n("Table \"%1\" already exists.").arg(tableSchema->name()) );
01469 return false;
01470 }
01471 }
01472
01473
01474
01475
01476
01477
01478
01479 TransactionGuard tg;
01480 if (!beginAutoCommitTransaction(tg))
01481 return false;
01482
01483 if (!drv_createTable(*tableSchema))
01484 createTable_ERR;
01485
01486
01487 if (!internalTable) {
01488
01489 if (!storeObjectSchemaData( *tableSchema, true ))
01490 createTable_ERR;
01491
01492 TableSchema *ts = d->tables_byname["kexi__fields"];
01493 if (!ts)
01494 return false;
01495
01496 if (!KexiDB::deleteRow(*this, ts, "t_id", tableSchema->id()))
01497 return false;
01498
01499 FieldList *fl = createFieldListForKexi__Fields(d->tables_byname["kexi__fields"]);
01500 if (!fl)
01501 return false;
01502
01503
01504 Field *f;
01505 for (Field::ListIterator it( *tableSchema->fields() ); (f = it.current()); ++it) {
01506 QValueList<QVariant> vals;
01507 buildValuesForKexi__Fields(vals, f);
01508 if (!insertRecord(*fl, vals ))
01509 createTable_ERR;
01510 }
01511 delete fl;
01512
01513 if (!storeExtendedTableSchemaData(*tableSchema))
01514 createTable_ERR;
01515 }
01516
01517
01518
01519
01520
01521
01522
01523
01524
01525 bool res = commitAutoCommitTransaction(tg.transaction());
01526
01527 if (res) {
01528 if (internalTable) {
01529
01530 insertInternalTableSchema(tableSchema);
01531 }
01532 else {
01533 if (previousSchemaStillKept) {
01534
01535 removeTableSchemaInternal(tableSchema);
01536 }
01537
01538 d->tables.insert(tableSchema->id(), tableSchema);
01539 d->tables_byname.insert(tableSchema->name().lower(), tableSchema);
01540 }
01541
01542 tableSchema->m_conn = this;
01543 }
01544 return res;
01545 }
01546
01547 void Connection::removeTableSchemaInternal(TableSchema *tableSchema)
01548 {
01549 d->tables_byname.remove(tableSchema->name());
01550 d->tables.remove(tableSchema->id());
01551 }
01552
01553 bool Connection::removeObject( uint objId )
01554 {
01555 clearError();
01556
01557 if (!KexiDB::deleteRow(*this, d->tables_byname["kexi__objects"], "o_id", objId)
01558 || !KexiDB::deleteRow(*this, d->tables_byname["kexi__objectdata"], "o_id", objId)) {
01559 setError(ERR_DELETE_SERVER_ERROR, i18n("Could not remove object's data."));
01560 return false;
01561 }
01562 return true;
01563 }
01564
01565 bool Connection::drv_dropTable( const QString& name )
01566 {
01567 m_sql = "DROP TABLE " + escapeIdentifier(name);
01568 return executeSQL(m_sql);
01569 }
01570
01572
01578 tristate Connection::dropTable( KexiDB::TableSchema* tableSchema )
01579 {
01580 return dropTable( tableSchema, true );
01581 }
01582
01583 tristate Connection::dropTable( KexiDB::TableSchema* tableSchema, bool alsoRemoveSchema)
01584 {
01585
01586 clearError();
01587 if (!tableSchema)
01588 return false;
01589
01590 QString errmsg(i18n("Table \"%1\" cannot be removed.\n"));
01591
01592 if (tableSchema->id() < 0
01593 || this->tableSchema(tableSchema->name())!=tableSchema
01594 || this->tableSchema(tableSchema->id())!=tableSchema)
01595 {
01596 setError(ERR_OBJECT_NOT_FOUND, errmsg.arg(tableSchema->name())
01597 +i18n("Unexpected name or identifier."));
01598 return false;
01599 }
01600
01601 tristate res = closeAllTableSchemaChangeListeners(*tableSchema);
01602 if (true!=res)
01603 return res;
01604
01605
01606 if (m_driver->isSystemObjectName( tableSchema->name() )) {
01607 setError(ERR_SYSTEM_NAME_RESERVED, errmsg.arg(tableSchema->name()) + d->strItIsASystemObject());
01608 return false;
01609 }
01610
01611 TransactionGuard tg;
01612 if (!beginAutoCommitTransaction(tg))
01613 return false;
01614
01615
01616 if (drv_containsTable(tableSchema->name())) {
01617 if (!drv_dropTable(tableSchema->name()))
01618 return false;
01619 }
01620
01621 TableSchema *ts = d->tables_byname["kexi__fields"];
01622 if (!KexiDB::deleteRow(*this, ts, "t_id", tableSchema->id()))
01623 return false;
01624
01625
01626 if (!removeObject( tableSchema->id() )) {
01627 return false;
01628 }
01629
01630 if (alsoRemoveSchema) {
01632 tristate res = removeDataBlock( tableSchema->id(), "extended_schema");
01633 if (!res)
01634 return false;
01635 removeTableSchemaInternal(tableSchema);
01636 }
01637 return commitAutoCommitTransaction(tg.transaction());
01638 }
01639
01640 tristate Connection::dropTable( const QString& table )
01641 {
01642 clearError();
01643 TableSchema* ts = tableSchema( table );
01644 if (!ts) {
01645 setError(ERR_OBJECT_NOT_FOUND, i18n("Table \"%1\" does not exist.")
01646 .arg(table));
01647 return false;
01648 }
01649 return dropTable(ts);
01650 }
01651
01652 tristate Connection::alterTable( TableSchema& tableSchema, TableSchema& newTableSchema )
01653 {
01654 clearError();
01655 tristate res = closeAllTableSchemaChangeListeners(tableSchema);
01656 if (true!=res)
01657 return res;
01658
01659 if (&tableSchema == &newTableSchema) {
01660 setError(ERR_OBJECT_THE_SAME, i18n("Could not alter table \"%1\" using the same table.")
01661 .arg(tableSchema.name()));
01662 return false;
01663 }
01664
01665
01666 bool ok, empty;
01667 #if 0//TODO ucomment:
01668 empty = isEmpty( tableSchema, ok ) && ok;
01669 #else
01670 empty = true;
01671 #endif
01672 if (empty) {
01673 ok = createTable(&newTableSchema, true);
01674 }
01675 return ok;
01676 }
01677
01678 bool Connection::alterTableName(TableSchema& tableSchema, const QString& newName, bool replace)
01679 {
01680 clearError();
01681 if (&tableSchema!=d->tables[tableSchema.id()]) {
01682 setError(ERR_OBJECT_NOT_FOUND, i18n("Unknown table \"%1\"").arg(tableSchema.name()));
01683 return false;
01684 }
01685 if (newName.isEmpty() || !KexiUtils::isIdentifier(newName)) {
01686 setError(ERR_INVALID_IDENTIFIER, i18n("Invalid table name \"%1\"").arg(newName));
01687 return false;
01688 }
01689 const QString oldTableName = tableSchema.name();
01690 const QString newTableName = newName.lower().stripWhiteSpace();
01691 if (oldTableName.lower().stripWhiteSpace() == newTableName) {
01692 setError(ERR_OBJECT_THE_SAME, i18n("Could rename table \"%1\" using the same name.")
01693 .arg(newTableName));
01694 return false;
01695 }
01696
01697
01698
01699 TableSchema *tableToReplace = this->tableSchema( newName );
01700 const bool destTableExists = tableToReplace != 0;
01701 const int origID = destTableExists ? tableToReplace->id() : -1;
01702 if (!replace && destTableExists) {
01703 setError(ERR_OBJECT_EXISTS,
01704 i18n("Could not rename table \"%1\" to \"%2\". Table \"%3\" already exists.")
01705 .arg(tableSchema.name()).arg(newName).arg(newName));
01706 return false;
01707 }
01708
01709
01710 #define alterTableName_ERR \
01711 tableSchema.setName(oldTableName) //restore old name
01712
01713 TransactionGuard tg;
01714 if (!beginAutoCommitTransaction(tg))
01715 return false;
01716
01717
01718 if (destTableExists) {
01719 if (!replace) {
01720 return false;
01721 }
01722 if (!dropTable( newName )) {
01723 return false;
01724 }
01725
01726
01727 if (!executeSQL(QString::fromLatin1("UPDATE kexi__objects SET o_id=%1 WHERE o_id=%2 AND o_type=%3")
01728 .arg(origID).arg(tableSchema.id()).arg((int)TableObjectType)))
01729 {
01730 return false;
01731 }
01732 if (!executeSQL(QString::fromLatin1("UPDATE kexi__fields SET t_id=%1 WHERE t_id=%2")
01733 .arg(origID).arg(tableSchema.id())))
01734 {
01735 return false;
01736 }
01737 d->tables.take(tableSchema.id());
01738 d->tables.insert(origID, &tableSchema);
01739
01740 tableSchema.m_id = origID;
01741 }
01742
01743 if (!drv_alterTableName(tableSchema, newTableName)) {
01744 alterTableName_ERR;
01745 return false;
01746 }
01747
01748
01749
01750 if (!executeSQL(QString::fromLatin1("UPDATE kexi__objects SET o_name=%1 WHERE o_id=%2")
01751 .arg(m_driver->escapeString(tableSchema.name())).arg(tableSchema.id())))
01752 {
01753 alterTableName_ERR;
01754 return false;
01755 }
01756
01757
01758
01759 tableSchema.setName(oldTableName);
01760
01761 if (!commitAutoCommitTransaction(tg.transaction())) {
01762 alterTableName_ERR;
01763 return false;
01764 }
01765
01766
01767 d->tables_byname.take(tableSchema.name());
01768 tableSchema.setName(newTableName);
01769 d->tables_byname.insert(tableSchema.name(), &tableSchema);
01770 return true;
01771 }
01772
01773 bool Connection::drv_alterTableName(TableSchema& tableSchema, const QString& newName)
01774 {
01775 const QString oldTableName = tableSchema.name();
01776 tableSchema.setName(newName);
01777
01778 if (!executeSQL(QString::fromLatin1("ALTER TABLE %1 RENAME TO %2")
01779 .arg(escapeIdentifier(oldTableName)).arg(escapeIdentifier(newName))))
01780 {
01781 tableSchema.setName(oldTableName);
01782 return false;
01783 }
01784 return true;
01785 }
01786
01787 bool Connection::dropQuery( KexiDB::QuerySchema* querySchema )
01788 {
01789 clearError();
01790 if (!querySchema)
01791 return false;
01792
01793 TransactionGuard tg;
01794 if (!beginAutoCommitTransaction(tg))
01795 return false;
01796
01797
01798
01799
01800
01801
01802
01803
01804
01805
01806
01807
01808
01809
01810 if (!removeObject( querySchema->id() )) {
01811 return false;
01812 }
01813
01814
01815 d->queries_byname.remove(querySchema->name());
01816 d->queries.remove(querySchema->id());
01817
01818 return commitAutoCommitTransaction(tg.transaction());
01819 }
01820
01821 bool Connection::dropQuery( const QString& query )
01822 {
01823 clearError();
01824 QuerySchema* qs = querySchema( query );
01825 if (!qs) {
01826 setError(ERR_OBJECT_NOT_FOUND, i18n("Query \"%1\" does not exist.")
01827 .arg(query));
01828 return false;
01829 }
01830 return dropQuery(qs);
01831 }
01832
01833 bool Connection::drv_createTable( const KexiDB::TableSchema& tableSchema )
01834 {
01835 m_sql = createTableStatement(tableSchema);
01836 KexiDBDbg<<"******** "<<m_sql<<endl;
01837 return executeSQL(m_sql);
01838 }
01839
01840 bool Connection::drv_createTable( const QString& tableSchemaName )
01841 {
01842 TableSchema *ts = d->tables_byname[tableSchemaName];
01843 if (!ts)
01844 return false;
01845 return drv_createTable(*ts);
01846 }
01847
01848 bool Connection::beginAutoCommitTransaction(TransactionGuard &tg)
01849 {
01850 if ((m_driver->d->features & Driver::IgnoreTransactions)
01851 || !d->autoCommit)
01852 {
01853 tg.setTransaction( Transaction() );
01854 return true;
01855 }
01856
01857
01858
01859 if (m_driver->d->features & Driver::SingleTransactions) {
01860 if (d->default_trans_started_inside)
01861 if (!commitTransaction(d->default_trans, true)) {
01862 tg.setTransaction( Transaction() );
01863 return false;
01864 }
01865
01866 d->default_trans_started_inside = d->default_trans.isNull();
01867 if (!d->default_trans_started_inside) {
01868 tg.setTransaction( d->default_trans );
01869 tg.doNothing();
01870 return true;
01871 }
01872 }
01873 else if (!(m_driver->d->features & Driver::MultipleTransactions)) {
01874 tg.setTransaction( Transaction() );
01875 return true;
01876 }
01877 tg.setTransaction( beginTransaction() );
01878 return !error();
01879 }
01880
01881 bool Connection::commitAutoCommitTransaction(const Transaction& trans)
01882 {
01883 if (m_driver->d->features & Driver::IgnoreTransactions)
01884 return true;
01885 if (trans.isNull() || !m_driver->transactionsSupported())
01886 return true;
01887 if (m_driver->d->features & Driver::SingleTransactions) {
01888 if (!d->default_trans_started_inside)
01889 return true;
01890 }
01891 return commitTransaction(trans, true);
01892 }
01893
01894 bool Connection::rollbackAutoCommitTransaction(const Transaction& trans)
01895 {
01896 if (trans.isNull() || !m_driver->transactionsSupported())
01897 return true;
01898 return rollbackTransaction(trans);
01899 }
01900
01901 #define SET_ERR_TRANS_NOT_SUPP \
01902 { setError(ERR_UNSUPPORTED_DRV_FEATURE, \
01903 i18n("Transactions are not supported for \"%1\" driver.").arg(m_driver->name() )); }
01904
01905 #define SET_BEGIN_TR_ERROR \
01906 { if (!error()) \
01907 setError(ERR_ROLLBACK_OR_COMMIT_TRANSACTION, i18n("Begin transaction failed")); }
01908
01909 Transaction Connection::beginTransaction()
01910 {
01911 if (!checkIsDatabaseUsed())
01912 return Transaction::null;
01913 Transaction trans;
01914 if (m_driver->d->features & Driver::IgnoreTransactions) {
01915
01916
01917 trans.m_data = new TransactionData(this);
01918 d->transactions.append(trans);
01919 return trans;
01920 }
01921 if (m_driver->d->features & Driver::SingleTransactions) {
01922 if (d->default_trans.active()) {
01923 setError(ERR_TRANSACTION_ACTIVE, i18n("Transaction already started.") );
01924 return Transaction::null;
01925 }
01926 if (!(trans.m_data = drv_beginTransaction())) {
01927 SET_BEGIN_TR_ERROR;
01928 return Transaction::null;
01929 }
01930 d->default_trans = trans;
01931 d->transactions.append(trans);
01932 return d->default_trans;
01933 }
01934 if (m_driver->d->features & Driver::MultipleTransactions) {
01935 if (!(trans.m_data = drv_beginTransaction())) {
01936 SET_BEGIN_TR_ERROR;
01937 return Transaction::null;
01938 }
01939 d->transactions.append(trans);
01940 return trans;
01941 }
01942
01943 SET_ERR_TRANS_NOT_SUPP;
01944 return Transaction::null;
01945 }
01946
01947 bool Connection::commitTransaction(const Transaction trans, bool ignore_inactive)
01948 {
01949 if (!isDatabaseUsed())
01950 return false;
01951
01952
01953 if ( !m_driver->transactionsSupported()
01954 && !(m_driver->d->features & Driver::IgnoreTransactions))
01955 {
01956 SET_ERR_TRANS_NOT_SUPP;
01957 return false;
01958 }
01959 Transaction t = trans;
01960 if (!t.active()) {
01961 if (!d->default_trans.active()) {
01962 if (ignore_inactive)
01963 return true;
01964 clearError();
01965 setError(ERR_NO_TRANSACTION_ACTIVE, i18n("Transaction not started.") );
01966 return false;
01967 }
01968 t = d->default_trans;
01969 d->default_trans = Transaction::null;
01970 }
01971 bool ret = true;
01972 if (! (m_driver->d->features & Driver::IgnoreTransactions) )
01973 ret = drv_commitTransaction(t.m_data);
01974 if (t.m_data)
01975 t.m_data->m_active = false;
01976 if (!d->dont_remove_transactions)
01977 d->transactions.remove(t);
01978 if (!ret && !error())
01979 setError(ERR_ROLLBACK_OR_COMMIT_TRANSACTION, i18n("Error on commit transaction"));
01980 return ret;
01981 }
01982
01983 bool Connection::rollbackTransaction(const Transaction trans, bool ignore_inactive)
01984 {
01985 if (!isDatabaseUsed())
01986 return false;
01987
01988
01989 if ( !m_driver->transactionsSupported()
01990 && !(m_driver->d->features & Driver::IgnoreTransactions))
01991 {
01992 SET_ERR_TRANS_NOT_SUPP;
01993 return false;
01994 }
01995 Transaction t = trans;
01996 if (!t.active()) {
01997 if (!d->default_trans.active()) {
01998 if (ignore_inactive)
01999 return true;
02000 clearError();
02001 setError(ERR_NO_TRANSACTION_ACTIVE, i18n("Transaction not started.") );
02002 return false;
02003 }
02004 t = d->default_trans;
02005 d->default_trans = Transaction::null;
02006 }
02007 bool ret = true;
02008 if (! (m_driver->d->features & Driver::IgnoreTransactions) )
02009 ret = drv_rollbackTransaction(t.m_data);
02010 if (t.m_data)
02011 t.m_data->m_active = false;
02012 if (!d->dont_remove_transactions)
02013 d->transactions.remove(t);
02014 if (!ret && !error())
02015 setError(ERR_ROLLBACK_OR_COMMIT_TRANSACTION, i18n("Error on rollback transaction"));
02016 return ret;
02017 }
02018
02019 #undef SET_ERR_TRANS_NOT_SUPP
02020 #undef SET_BEGIN_TR_ERROR
02021
02022
02023
02024
02025
02026
02027 Transaction& Connection::defaultTransaction() const
02028 {
02029 return d->default_trans;
02030 }
02031
02032 void Connection::setDefaultTransaction(const Transaction& trans)
02033 {
02034 if (!isDatabaseUsed())
02035 return;
02036
02037
02038 if ( !(m_driver->d->features & Driver::IgnoreTransactions)
02039 && (!trans.active() || !m_driver->transactionsSupported()) )
02040 {
02041 return;
02042 }
02043 d->default_trans = trans;
02044 }
02045
02046 const QValueList<Transaction>& Connection::transactions()
02047 {
02048 return d->transactions;
02049 }
02050
02051 bool Connection::autoCommit() const
02052 {
02053 return d->autoCommit;
02054 }
02055
02056 bool Connection::setAutoCommit(bool on)
02057 {
02058 if (d->autoCommit == on || m_driver->d->features & Driver::IgnoreTransactions)
02059 return true;
02060 if (!drv_setAutoCommit(on))
02061 return false;
02062 d->autoCommit = on;
02063 return true;
02064 }
02065
02066 TransactionData* Connection::drv_beginTransaction()
02067 {
02068 QString old_sql = m_sql;
02069 if (!executeSQL( "BEGIN" ))
02070 return 0;
02071 return new TransactionData(this);
02072 }
02073
02074 bool Connection::drv_commitTransaction(TransactionData *)
02075 {
02076 return executeSQL( "COMMIT" );
02077 }
02078
02079 bool Connection::drv_rollbackTransaction(TransactionData *)
02080 {
02081 return executeSQL( "ROLLBACK" );
02082 }
02083
02084 bool Connection::drv_setAutoCommit(bool )
02085 {
02086 return true;
02087 }
02088
02089 Cursor* Connection::executeQuery( const QString& statement, uint cursor_options )
02090 {
02091 if (statement.isEmpty())
02092 return 0;
02093 Cursor *c = prepareQuery( statement, cursor_options );
02094 if (!c)
02095 return 0;
02096 if (!c->open()) {
02097 setError(c);
02098 delete c;
02099 return 0;
02100 }
02101 return c;
02102 }
02103
02104 Cursor* Connection::executeQuery( QuerySchema& query, const QValueList<QVariant>& params,
02105 uint cursor_options )
02106 {
02107 Cursor *c = prepareQuery( query, params, cursor_options );
02108 if (!c)
02109 return 0;
02110 if (!c->open()) {
02111 setError(c);
02112 delete c;
02113 return 0;
02114 }
02115 return c;
02116 }
02117
02118 Cursor* Connection::executeQuery( QuerySchema& query, uint cursor_options )
02119 {
02120 return executeQuery(query, QValueList<QVariant>(), cursor_options);
02121 }
02122
02123 Cursor* Connection::executeQuery( TableSchema& table, uint cursor_options )
02124 {
02125 return executeQuery( *table.query(), cursor_options );
02126 }
02127
02128 Cursor* Connection::prepareQuery( TableSchema& table, uint cursor_options )
02129 {
02130 return prepareQuery( *table.query(), cursor_options );
02131 }
02132
02133 Cursor* Connection::prepareQuery( QuerySchema& query, const QValueList<QVariant>& params,
02134 uint cursor_options )
02135 {
02136 Cursor* cursor = prepareQuery(query, cursor_options);
02137 if (cursor)
02138 cursor->setQueryParameters(params);
02139 return cursor;
02140 }
02141
02142 bool Connection::deleteCursor(Cursor *cursor)
02143 {
02144 if (!cursor)
02145 return false;
02146 if (cursor->connection()!=this) {
02147 KexiDBWarn << "Connection::deleteCursor(): Cannot delete the cursor not owned by the same connection!" << endl;
02148 return false;
02149 }
02150 const bool ret = cursor->close();
02151 delete cursor;
02152 return ret;
02153 }
02154
02155 bool Connection::setupObjectSchemaData( const RowData &data, SchemaData &sdata )
02156 {
02157
02158
02159
02160
02161
02162
02163
02164
02165
02166
02167
02168
02169 bool ok;
02170 sdata.m_id = data[0].toInt(&ok);
02171 if (!ok) {
02172 return false;
02173 }
02174 sdata.m_name = data[2].toString();
02175 if (!KexiUtils::isIdentifier( sdata.m_name )) {
02176 setError(ERR_INVALID_IDENTIFIER, i18n("Invalid object name \"%1\"").arg(sdata.m_name));
02177 return false;
02178 }
02179 sdata.m_caption = data[3].toString();
02180 sdata.m_desc = data[4].toString();
02181
02182
02183 return true;
02184 }
02185
02186 tristate Connection::loadObjectSchemaData( int objectID, SchemaData &sdata )
02187 {
02188 RowData data;
02189 if (true!=querySingleRecord(QString::fromLatin1(
02190 "SELECT o_id, o_type, o_name, o_caption, o_desc FROM kexi__objects where o_id=%1")
02191 .arg(objectID), data))
02192 return cancelled;
02193 return setupObjectSchemaData( data, sdata );
02194 }
02195
02196 tristate Connection::loadObjectSchemaData( int objectType, const QString& objectName, SchemaData &sdata )
02197 {
02198 RowData data;
02199 if (true!=querySingleRecord(QString::fromLatin1("SELECT o_id, o_type, o_name, o_caption, o_desc "
02200 "FROM kexi__objects WHERE o_type=%1 AND lower(o_name)=%2")
02201 .arg(objectType).arg(m_driver->valueToSQL(Field::Text, objectName.lower())), data))
02202 return cancelled;
02203 return setupObjectSchemaData( data, sdata );
02204 }
02205
02206 bool Connection::storeObjectSchemaData( SchemaData &sdata, bool newObject )
02207 {
02208 TableSchema *ts = d->tables_byname["kexi__objects"];
02209 if (!ts)
02210 return false;
02211 if (newObject) {
02212 int existingID;
02213 if (true == querySingleNumber(QString::fromLatin1(
02214 "SELECT o_id FROM kexi__objects WHERE o_type=%1 AND lower(o_name)=%2")
02215 .arg(sdata.type()).arg(m_driver->valueToSQL(Field::Text, sdata.name().lower())), existingID))
02216 {
02217
02218
02219 sdata.m_id = existingID;
02220 newObject = false;
02221 }
02222 }
02223 if (newObject) {
02224 FieldList *fl;
02225 bool ok;
02226 if (sdata.id()<=0) {
02227 fl = ts->subList("o_type", "o_name", "o_caption", "o_desc");
02228 ok = fl!=0;
02229 if (ok && !insertRecord(*fl, QVariant(sdata.type()), QVariant(sdata.name()),
02230 QVariant(sdata.caption()), QVariant(sdata.description()) ))
02231 ok = false;
02232 delete fl;
02233 if (!ok)
02234 return false;
02235
02237 int obj_id = (int)lastInsertedAutoIncValue("o_id",*ts);
02238 KexiDBDbg << "######## NEW obj_id == " << obj_id << endl;
02239 if (obj_id<=0)
02240 return false;
02241 sdata.m_id = obj_id;
02242 return true;
02243 } else {
02244 fl = ts->subList("o_id", "o_type", "o_name", "o_caption", "o_desc");
02245 ok = fl!=0;
02246 if (ok && !insertRecord(*fl, QVariant(sdata.id()), QVariant(sdata.type()), QVariant(sdata.name()),
02247 QVariant(sdata.caption()), QVariant(sdata.description()) ))
02248 ok = false;
02249 delete fl;
02250 return ok;
02251 }
02252 }
02253
02254 return executeSQL(QString("UPDATE kexi__objects SET o_type=%2, o_caption=%3, o_desc=%4 WHERE o_id=%1")
02255 .arg(sdata.id()).arg(sdata.type())
02256 .arg(m_driver->valueToSQL(KexiDB::Field::Text, sdata.caption()))
02257 .arg(m_driver->valueToSQL(KexiDB::Field::Text, sdata.description())) );
02258 }
02259
02260 tristate Connection::querySingleRecordInternal(RowData &data, const QString* sql, QuerySchema* query,
02261 bool addLimitTo1)
02262 {
02263 Q_ASSERT(sql || query);
02265 if (sql)
02266 m_sql = addLimitTo1 ? (*sql + " LIMIT 1") : *sql;
02267 KexiDB::Cursor *cursor;
02268 if (!(cursor = sql ? executeQuery( m_sql ) : executeQuery( *query ))) {
02269 KexiDBWarn << "Connection::querySingleRecord(): !executeQuery() " << m_sql << endl;
02270 return false;
02271 }
02272 if (!cursor->moveFirst() || cursor->eof()) {
02273 const tristate result = cursor->error() ? false : cancelled;
02274 KexiDBWarn << "Connection::querySingleRecord(): !cursor->moveFirst() || cursor->eof() m_sql=" << m_sql << endl;
02275 setError(cursor);
02276 deleteCursor(cursor);
02277 return result;
02278 }
02279 cursor->storeCurrentRow(data);
02280 return deleteCursor(cursor);
02281 }
02282
02283 tristate Connection::querySingleRecord(const QString& sql, RowData &data, bool addLimitTo1)
02284 {
02285 return querySingleRecordInternal(data, &sql, 0, addLimitTo1);
02286 }
02287
02288 tristate Connection::querySingleRecord(QuerySchema& query, RowData &data, bool addLimitTo1)
02289 {
02290 return querySingleRecordInternal(data, 0, &query, addLimitTo1);
02291 }
02292
02293 bool Connection::checkIfColumnExists(Cursor *cursor, uint column)
02294 {
02295 if (column >= cursor->fieldCount()) {
02296 setError(ERR_CURSOR_RECORD_FETCHING, i18n("Column %1 does not exist for the query.").arg(column));
02297 return false;
02298 }
02299 return true;
02300 }
02301
02302 tristate Connection::querySingleString(const QString& sql, QString &value, uint column, bool addLimitTo1)
02303 {
02304 KexiDB::Cursor *cursor;
02305 m_sql = addLimitTo1 ? (sql + " LIMIT 1") : sql;
02306 if (!(cursor = executeQuery( m_sql ))) {
02307 KexiDBWarn << "Connection::querySingleRecord(): !executeQuery() " << m_sql << endl;
02308 return false;
02309 }
02310 if (!cursor->moveFirst() || cursor->eof()) {
02311 const tristate result = cursor->error() ? false : cancelled;
02312 KexiDBWarn << "Connection::querySingleRecord(): !cursor->moveFirst() || cursor->eof() " << m_sql << endl;
02313 deleteCursor(cursor);
02314 return result;
02315 }
02316 if (!checkIfColumnExists(cursor, column)) {
02317 deleteCursor(cursor);
02318 return false;
02319 }
02320 value = cursor->value(column).toString();
02321 return deleteCursor(cursor);
02322 }
02323
02324 tristate Connection::querySingleNumber(const QString& sql, int &number, uint column, bool addLimitTo1)
02325 {
02326 static QString str;
02327 static bool ok;
02328 const tristate result = querySingleString(sql, str, column, addLimitTo1);
02329 if (result!=true)
02330 return result;
02331 number = str.toInt(&ok);
02332 return ok;
02333 }
02334
02335 bool Connection::queryStringList(const QString& sql, QStringList& list, uint column)
02336 {
02337 KexiDB::Cursor *cursor;
02338 clearError();
02339 m_sql = sql;
02340 if (!(cursor = executeQuery( m_sql ))) {
02341 KexiDBWarn << "Connection::queryStringList(): !executeQuery() " << m_sql << endl;
02342 return false;
02343 }
02344 if (!checkIfColumnExists(cursor, column)) {
02345 deleteCursor(cursor);
02346 return false;
02347 }
02348 cursor->moveFirst();
02349 if (cursor->error()) {
02350 setError(cursor);
02351 deleteCursor(cursor);
02352 return false;
02353 }
02354 list.clear();
02355 while (!cursor->eof()) {
02356 list.append( cursor->value(column).toString() );
02357 if (!cursor->moveNext() && cursor->error()) {
02358 setError(cursor);
02359 deleteCursor(cursor);
02360 return false;
02361 }
02362 }
02363 return deleteCursor(cursor);
02364 }
02365
02366 bool Connection::resultExists(const QString& sql, bool &success, bool addLimitTo1)
02367 {
02368 KexiDB::Cursor *cursor;
02369
02370 if (m_driver->beh->SELECT_1_SUBQUERY_SUPPORTED) {
02371
02372 if (addLimitTo1 && sql.left(6).upper() == "SELECT")
02373 m_sql = QString("SELECT 1 FROM (") + sql + ") LIMIT 1";
02374 else
02375 m_sql = sql;
02376 }
02377 else {
02378 if (addLimitTo1 && sql.left(6).upper() == "SELECT")
02379 m_sql = sql + " LIMIT 1";
02380 else
02381 m_sql = sql;
02382 }
02383 if (!(cursor = executeQuery( m_sql ))) {
02384 KexiDBWarn << "Connection::querySingleRecord(): !executeQuery() " << m_sql << endl;
02385 success = false;
02386 return false;
02387 }
02388 if (!cursor->moveFirst() || cursor->eof()) {
02389 success = !cursor->error();
02390 KexiDBWarn << "Connection::querySingleRecord(): !cursor->moveFirst() || cursor->eof() " << m_sql << endl;
02391 setError(cursor);
02392 deleteCursor(cursor);
02393 return false;
02394 }
02395 success = deleteCursor(cursor);
02396 return true;
02397 }
02398
02399 bool Connection::isEmpty( TableSchema& table, bool &success )
02400 {
02401 return !resultExists( selectStatement( *table.query() ), success );
02402 }
02403
02404 int Connection::resultCount(const QString& sql)
02405 {
02406 int count = -1;
02407 m_sql = QString::fromLatin1("SELECT COUNT() FROM (") + sql + ")";
02408 querySingleNumber(m_sql, count);
02409 return count;
02410 }
02411
02413 static void createExtendedTableSchemaMainElementIfNeeded(
02414 QDomDocument& doc, QDomElement& extendedTableSchemaMainEl,
02415 bool& extendedTableSchemaStringIsEmpty)
02416 {
02417 if (!extendedTableSchemaStringIsEmpty)
02418 return;
02419
02420 extendedTableSchemaMainEl = doc.createElement("EXTENDED_TABLE_SCHEMA");
02421 doc.appendChild( extendedTableSchemaMainEl );
02422 extendedTableSchemaMainEl.setAttribute("version", QString::number(KEXIDB_EXTENDED_TABLE_SCHEMA_VERSION));
02423 extendedTableSchemaStringIsEmpty = false;
02424 }
02425
02427 static void createExtendedTableSchemaFieldElementIfNeeded(QDomDocument& doc,
02428 QDomElement& extendedTableSchemaMainEl, const QString& fieldName, QDomElement& extendedTableSchemaFieldEl)
02429 {
02430 if (!extendedTableSchemaFieldEl.isNull())
02431 return;
02432 extendedTableSchemaFieldEl = doc.createElement("field");
02433 extendedTableSchemaMainEl.appendChild( extendedTableSchemaFieldEl );
02434 extendedTableSchemaFieldEl.setAttribute("name", fieldName);
02435 }
02436
02443 static void addFieldPropertyToExtendedTableSchemaData(
02444 Field *f, const char* propertyName, const QVariant& propertyValue,
02445 QDomDocument& doc, QDomElement& extendedTableSchemaMainEl,
02446 QDomElement& extendedTableSchemaFieldEl,
02447 bool& extendedTableSchemaStringIsEmpty,
02448 bool custom = false )
02449 {
02450 createExtendedTableSchemaMainElementIfNeeded(doc,
02451 extendedTableSchemaMainEl, extendedTableSchemaStringIsEmpty);
02452 createExtendedTableSchemaFieldElementIfNeeded(
02453 doc, extendedTableSchemaMainEl, f->name(), extendedTableSchemaFieldEl);
02454
02455
02456 QDomElement extendedTableSchemaFieldPropertyEl = doc.createElement("property");
02457 extendedTableSchemaFieldEl.appendChild( extendedTableSchemaFieldPropertyEl );
02458 if (custom)
02459 extendedTableSchemaFieldPropertyEl.setAttribute("custom", "true");
02460 extendedTableSchemaFieldPropertyEl.setAttribute("name", propertyName);
02461 QDomElement extendedTableSchemaFieldPropertyValueEl;
02462 switch (propertyValue.type()) {
02463 case QVariant::String:
02464 extendedTableSchemaFieldPropertyValueEl = doc.createElement("string");
02465 break;
02466 case QVariant::CString:
02467 extendedTableSchemaFieldPropertyValueEl = doc.createElement("cstring");
02468 break;
02469 case QVariant::Int:
02470 case QVariant::Double:
02471 case QVariant::UInt:
02472 case QVariant::LongLong:
02473 case QVariant::ULongLong:
02474 extendedTableSchemaFieldPropertyValueEl = doc.createElement("number");
02475 break;
02476 case QVariant::Bool:
02477 extendedTableSchemaFieldPropertyValueEl = doc.createElement("bool");
02478 break;
02479 default:
02481 KexiDBFatal << "addFieldPropertyToExtendedTableSchemaData(): impl. error" << endl;
02482 }
02483 extendedTableSchemaFieldPropertyEl.appendChild( extendedTableSchemaFieldPropertyValueEl );
02484 extendedTableSchemaFieldPropertyValueEl.appendChild(
02485 doc.createTextNode( propertyValue.toString() ) );
02486 }
02487
02488 bool Connection::storeExtendedTableSchemaData(TableSchema& tableSchema)
02489 {
02491 QDomDocument doc("EXTENDED_TABLE_SCHEMA");
02492 QDomElement extendedTableSchemaMainEl;
02493 bool extendedTableSchemaStringIsEmpty = true;
02494
02495
02496 Field *f;
02497 for (Field::ListIterator it( *tableSchema.fields() ); (f = it.current()); ++it) {
02498 QDomElement extendedTableSchemaFieldEl;
02499 if (f->visibleDecimalPlaces()>=0 && KexiDB::supportsVisibleDecimalPlacesProperty(f->type())) {
02500 addFieldPropertyToExtendedTableSchemaData(
02501 f, "visibleDecimalPlaces", f->visibleDecimalPlaces(), doc,
02502 extendedTableSchemaMainEl, extendedTableSchemaFieldEl,
02503 extendedTableSchemaStringIsEmpty );
02504 }
02505
02506
02507
02508 const Field::CustomPropertiesMap customProperties(f->customProperties());
02509 foreach( Field::CustomPropertiesMap::ConstIterator, itCustom, customProperties ) {
02510 addFieldPropertyToExtendedTableSchemaData(
02511 f, itCustom.key(), itCustom.data(), doc,
02512 extendedTableSchemaMainEl, extendedTableSchemaFieldEl, extendedTableSchemaStringIsEmpty,
02513 true );
02514 }
02515
02516 LookupFieldSchema *lookupFieldSchema = tableSchema.lookupFieldSchema( *f );
02517 if (lookupFieldSchema) {
02518 createExtendedTableSchemaMainElementIfNeeded(doc, extendedTableSchemaMainEl,
02519 extendedTableSchemaStringIsEmpty);
02520 createExtendedTableSchemaFieldElementIfNeeded(
02521 doc, extendedTableSchemaMainEl, f->name(), extendedTableSchemaFieldEl);
02522 LookupFieldSchema::saveToDom(*lookupFieldSchema, doc, extendedTableSchemaFieldEl);
02523 }
02524 }
02525
02526
02527 if (extendedTableSchemaStringIsEmpty) {
02528 #ifdef KEXI_DEBUG_GUI
02529 KexiUtils::addAlterTableActionDebug(QString("** Extended table schema REMOVED."));
02530 #endif
02531 if (!removeDataBlock( tableSchema.id(), "extended_schema"))
02532 return false;
02533 }
02534 else {
02535 #ifdef KEXI_DEBUG_GUI
02536 KexiUtils::addAlterTableActionDebug(QString("** Extended table schema set to:\n")+doc.toString(4));
02537 #endif
02538 if (!storeDataBlock( tableSchema.id(), doc.toString(1), "extended_schema" ))
02539 return false;
02540 }
02541 return true;
02542 }
02543
02544 bool Connection::loadExtendedTableSchemaData(TableSchema& tableSchema)
02545 {
02546 #define loadExtendedTableSchemaData_ERR \
02547 { setError(i18n("Error while loading extended table schema information.")); \
02548 return false; }
02549 #define loadExtendedTableSchemaData_ERR2(details) \
02550 { setError(i18n("Error while loading extended table schema information."), details); \
02551 return false; }
02552 #define loadExtendedTableSchemaData_ERR3(data) \
02553 { setError(i18n("Error while loading extended table schema information."), \
02554 i18n("Invalid XML data: ") + data.left(1024) ); \
02555 return false; }
02556
02557
02558 QString extendedTableSchemaString;
02559 tristate res = loadDataBlock( tableSchema.id(), extendedTableSchemaString, "extended_schema" );
02560 if (!res)
02561 loadExtendedTableSchemaData_ERR;
02562
02563
02564 #ifdef KEXIDB_LOOKUP_FIELD_TEST
02565
02566 if (tableSchema.name()=="cars") {
02567 LookupFieldSchema *lookupFieldSchema = new LookupFieldSchema();
02568 lookupFieldSchema->rowSource().setType(LookupFieldSchema::RowSource::Table);
02569 lookupFieldSchema->rowSource().setName("persons");
02570 lookupFieldSchema->setBoundColumn(0);
02571 lookupFieldSchema->setVisibleColumn(3);
02572 tableSchema.setLookupFieldSchema( "owner", lookupFieldSchema );
02573 }
02574
02575 #endif
02576
02577 if (extendedTableSchemaString.isEmpty())
02578 return true;
02579
02580 QDomDocument doc;
02581 QString errorMsg;
02582 int errorLine, errorColumn;
02583 if (!doc.setContent( extendedTableSchemaString, &errorMsg, &errorLine, &errorColumn ))
02584 loadExtendedTableSchemaData_ERR2( i18n("Error in XML data: \"%1\" in line %2, column %3.\nXML data: ")
02585 .arg(errorMsg).arg(errorLine).arg(errorColumn) + extendedTableSchemaString.left(1024));
02586
02588
02589 if (doc.doctype().name()!="EXTENDED_TABLE_SCHEMA")
02590 loadExtendedTableSchemaData_ERR3( extendedTableSchemaString );
02591
02592 QDomElement docEl = doc.documentElement();
02593 if (docEl.tagName()!="EXTENDED_TABLE_SCHEMA")
02594 loadExtendedTableSchemaData_ERR3( extendedTableSchemaString );
02595
02596 for (QDomNode n = docEl.firstChild(); !n.isNull(); n = n.nextSibling()) {
02597 QDomElement fieldEl = n.toElement();
02598 if (fieldEl.tagName()=="field") {
02599 Field *f = tableSchema.field( fieldEl.attribute("name") );
02600 if (f) {
02601
02603 for (QDomNode propNode = fieldEl.firstChild();
02604 !propNode.isNull(); propNode = propNode.nextSibling())
02605 {
02606 QDomElement propEl = propNode.toElement();
02607 bool ok;
02608 int intValue;
02609 if (propEl.tagName()=="property") {
02610 QCString propertyName = propEl.attribute("name").latin1();
02611 if (propEl.attribute("custom")=="true") {
02612
02613 f->setCustomProperty(propertyName,
02614 KexiDB::loadPropertyValueFromDom( propEl.firstChild() ));
02615 }
02616 else if (propertyName == "visibleDecimalPlaces"
02617 && KexiDB::supportsVisibleDecimalPlacesProperty(f->type()))
02618 {
02619 intValue = KexiDB::loadIntPropertyValueFromDom( propEl.firstChild(), &ok );
02620 if (ok)
02621 f->setVisibleDecimalPlaces(intValue);
02622 }
02624 }
02625 else if (propEl.tagName()=="lookup-column") {
02626 LookupFieldSchema *lookupFieldSchema = LookupFieldSchema::loadFromDom(propEl);
02627 tableSchema.setLookupFieldSchema( f->name(), lookupFieldSchema );
02628 }
02629 }
02630 }
02631 else {
02632 KexiDBWarn << "Connection::loadExtendedTableSchemaData(): no such field \""
02633 << fieldEl.attribute("name") << "\" in table \"" << tableSchema.name() << "\"" << endl;
02634 }
02635 }
02636 }
02637
02638 return true;
02639 }
02640
02641 KexiDB::TableSchema* Connection::setupTableSchema( const RowData &data )
02642 {
02643 TableSchema *t = new TableSchema( this );
02644 if (!setupObjectSchemaData( data, *t )) {
02645 delete t;
02646 return 0;
02647 }
02648
02649
02650
02651
02652
02653 KexiDB::Cursor *cursor;
02654 if (!(cursor = executeQuery(
02655 QString::fromLatin1("SELECT t_id, f_type, f_name, f_length, f_precision, f_constraints, "
02656 "f_options, f_default, f_order, f_caption, f_help"
02657 " FROM kexi__fields WHERE t_id=%1 ORDER BY f_order").arg(t->m_id) )))
02658 {
02659 delete t;
02660 return 0;
02661 }
02662 if (!cursor->moveFirst()) {
02663 if (!cursor->error() && cursor->eof()) {
02664 setError(i18n("Table has no fields defined."));
02665 }
02666 deleteCursor(cursor);
02667 delete t;
02668 return 0;
02669 }
02670
02671
02672 bool ok;
02673 while (!cursor->eof()) {
02674
02675
02676 int f_int_type = cursor->value(1).toInt(&ok);
02677 if (f_int_type<=Field::InvalidType || f_int_type>Field::LastType)
02678 ok = false;
02679 if (!ok)
02680 break;
02681 Field::Type f_type = (Field::Type)f_int_type;
02682 int f_len = QMAX( 0, cursor->value(3).toInt(&ok) );
02683 if (!ok)
02684 break;
02685 int f_prec = cursor->value(4).toInt(&ok);
02686 if (!ok)
02687 break;
02688 int f_constr = cursor->value(5).toInt(&ok);
02689 if (!ok)
02690 break;
02691 int f_opts = cursor->value(6).toInt(&ok);
02692 if (!ok)
02693 break;
02694
02695 if (!KexiUtils::isIdentifier( cursor->value(2).asString() )) {
02696 setError(ERR_INVALID_IDENTIFIER, i18n("Invalid object name \"%1\"")
02697 .arg( cursor->value(2).asString() ));
02698 ok=false;
02699 break;
02700 }
02701
02702 Field *f = new Field(
02703 cursor->value(2).asString(), f_type, f_constr, f_opts, f_len, f_prec );
02704
02705 f->setDefaultValue( KexiDB::stringToVariant(cursor->value(7).toString(), Field::variantType( f_type ), ok) );
02706 if (!ok) {
02707 KexiDBWarn << "Connection::setupTableSchema() problem with KexiDB::stringToVariant("
02708 << cursor->value(7).toString() << ")" << endl;
02709 }
02710 ok = true;
02711
02712 f->m_caption = cursor->value(9).asString();
02713 f->m_desc = cursor->value(10).asString();
02714 t->addField(f);
02715 cursor->moveNext();
02716 }
02717
02718 if (!ok) {
02719 deleteCursor(cursor);
02720 delete t;
02721 return 0;
02722 }
02723
02724 if (!deleteCursor(cursor)) {
02725 delete t;
02726 return 0;
02727 }
02728
02729 if (!loadExtendedTableSchemaData(*t)) {
02730 delete t;
02731 return 0;
02732 }
02733
02734 d->tables.insert(t->m_id, t);
02735 d->tables_byname.insert(t->m_name.lower(), t);
02736 return t;
02737 }
02738
02739 TableSchema* Connection::tableSchema( const QString& tableName )
02740 {
02741 QString m_tableName = tableName.lower();
02742 TableSchema *t = d->tables_byname[m_tableName];
02743 if (t)
02744 return t;
02745
02746 RowData data;
02747 if (true!=querySingleRecord(QString::fromLatin1(
02748 "SELECT o_id, o_type, o_name, o_caption, o_desc FROM kexi__objects WHERE lower(o_name)='%1' AND o_type=%2")
02749 .arg(m_tableName).arg(KexiDB::TableObjectType), data))
02750 return 0;
02751
02752 return setupTableSchema(data);
02753 }
02754
02755 TableSchema* Connection::tableSchema( int tableId )
02756 {
02757 TableSchema *t = d->tables[tableId];
02758 if (t)
02759 return t;
02760
02761 RowData data;
02762 if (true!=querySingleRecord(QString::fromLatin1(
02763 "SELECT o_id, o_type, o_name, o_caption, o_desc FROM kexi__objects WHERE o_id=%1")
02764 .arg(tableId), data))
02765 return 0;
02766
02767 return setupTableSchema(data);
02768 }
02769
02770 tristate Connection::loadDataBlock( int objectID, QString &dataString, const QString& dataID )
02771 {
02772 if (objectID<=0)
02773 return false;
02774 return querySingleString(
02775 QString("SELECT o_data FROM kexi__objectdata WHERE o_id=") + QString::number(objectID)
02776 + " AND " + KexiDB::sqlWhere(m_driver, KexiDB::Field::Text, "o_sub_id", dataID),
02777 dataString );
02778 }
02779
02780 bool Connection::storeDataBlock( int objectID, const QString &dataString, const QString& dataID )
02781 {
02782 if (objectID<=0)
02783 return false;
02784 QString sql(QString::fromLatin1("SELECT kexi__objectdata.o_id FROM kexi__objectdata WHERE o_id=%1").arg(objectID));
02785 QString sql_sub( KexiDB::sqlWhere(m_driver, KexiDB::Field::Text, "o_sub_id", dataID) );
02786
02787 bool ok, exists;
02788 exists = resultExists(sql + " and " + sql_sub, ok);
02789 if (!ok)
02790 return false;
02791 if (exists) {
02792 return executeSQL( "UPDATE kexi__objectdata SET o_data="
02793 + m_driver->valueToSQL( KexiDB::Field::LongText, dataString )
02794 + " WHERE o_id=" + QString::number(objectID) + " AND " + sql_sub );
02795 }
02796 return executeSQL(
02797 QString::fromLatin1("INSERT INTO kexi__objectdata (o_id, o_data, o_sub_id) VALUES (")
02798 + QString::number(objectID) +"," + m_driver->valueToSQL( KexiDB::Field::LongText, dataString )
02799 + "," + m_driver->valueToSQL( KexiDB::Field::Text, dataID ) + ")" );
02800 }
02801
02802 bool Connection::removeDataBlock( int objectID, const QString& dataID)
02803 {
02804 if (objectID<=0)
02805 return false;
02806 if (dataID.isEmpty())
02807 return KexiDB::deleteRow(*this, "kexi__objectdata", "o_id", QString::number(objectID));
02808 else
02809 return KexiDB::deleteRow(*this, "kexi__objectdata",
02810 "o_id", KexiDB::Field::Integer, objectID, "o_sub_id", KexiDB::Field::Text, dataID);
02811 }
02812
02813 KexiDB::QuerySchema* Connection::setupQuerySchema( const RowData &data )
02814 {
02815 bool ok = true;
02816 const int objID = data[0].toInt(&ok);
02817 if (!ok)
02818 return false;
02819 QString sqlText;
02820 if (!loadDataBlock( objID, sqlText, "sql" )) {
02821 setError(ERR_OBJECT_NOT_FOUND,
02822 i18n("Could not find definition for query \"%1\". Removing this query is recommended.")
02823 .arg(data[2].toString()));
02824 return 0;
02825 }
02826 d->parser()->parse( sqlText );
02827 KexiDB::QuerySchema *query = d->parser()->query();
02828
02829 if (!query) {
02830 setError(ERR_SQL_PARSE_ERROR,
02831 i18n("<p>Could not load definition for query \"%1\". "
02832 "SQL statement for this query is invalid:<br><tt>%2</tt></p>\n"
02833 "<p>You can open this query in Text View and correct it.</p>").arg(data[2].toString())
02834 .arg(d->parser()->statement()));
02835 return 0;
02836 }
02837 if (!setupObjectSchemaData( data, *query )) {
02838 delete query;
02839 return 0;
02840 }
02841 d->queries.insert(query->m_id, query);
02842 d->queries_byname.insert(query->m_name, query);
02843 return query;
02844 }
02845
02846 QuerySchema* Connection::querySchema( const QString& queryName )
02847 {
02848 QString m_queryName = queryName.lower();
02849 QuerySchema *q = d->queries_byname[m_queryName];
02850 if (q)
02851 return q;
02852
02853 RowData data;
02854 if (true!=querySingleRecord(QString::fromLatin1(
02855 "SELECT o_id, o_type, o_name, o_caption, o_desc FROM kexi__objects WHERE lower(o_name)='%1' AND o_type=%2")
02856 .arg(m_queryName).arg(KexiDB::QueryObjectType), data))
02857 return 0;
02858
02859 return setupQuerySchema(data);
02860 }
02861
02862 QuerySchema* Connection::querySchema( int queryId )
02863 {
02864 QuerySchema *q = d->queries[queryId];
02865 if (q)
02866 return q;
02867
02868 clearError();
02869 RowData data;
02870 if (true!=querySingleRecord(QString::fromLatin1(
02871 "SELECT o_id, o_type, o_name, o_caption, o_desc FROM kexi__objects WHERE o_id=%1").arg(queryId), data))
02872 return 0;
02873
02874 return setupQuerySchema(data);
02875 }
02876
02877 bool Connection::setQuerySchemaObsolete( const QString& queryName )
02878 {
02879 QuerySchema* oldQuery = querySchema( queryName );
02880 if (!oldQuery)
02881 return false;
02882 d->obsoleteQueries.append(oldQuery);
02883 d->queries_byname.take(queryName);
02884 d->queries.take(oldQuery->id());
02885 return true;
02886 }
02887
02888 TableSchema* Connection::newKexiDBSystemTableSchema(const QString& tsname)
02889 {
02890 TableSchema *ts = new TableSchema(tsname.lower());
02891 insertInternalTableSchema( ts );
02892 return ts;
02893 }
02894
02895 bool Connection::isInternalTableSchema(const QString& tableName)
02896 {
02897 return (d->kexiDBSystemTables[ d->tables_byname[tableName] ])
02898
02899
02900 || tableName=="kexi__final" || tableName=="kexi__useractions";
02901 }
02902
02903 void Connection::insertInternalTableSchema(TableSchema *tableSchema)
02904 {
02905 tableSchema->setKexiDBSystem(true);
02906 d->kexiDBSystemTables.insert(tableSchema, tableSchema);
02907 d->tables_byname.insert(tableSchema->name(), tableSchema);
02908 }
02909
02911 bool Connection::setupKexiDBSystemSchema()
02912 {
02913 if (!d->kexiDBSystemTables.isEmpty())
02914 return true;
02915
02916 TableSchema *t_objects = newKexiDBSystemTableSchema("kexi__objects");
02917 t_objects->addField( new Field("o_id", Field::Integer, Field::PrimaryKey | Field::AutoInc, Field::Unsigned) )
02918 .addField( new Field("o_type", Field::Byte, 0, Field::Unsigned) )
02919 .addField( new Field("o_name", Field::Text) )
02920 .addField( new Field("o_caption", Field::Text ) )
02921 .addField( new Field("o_desc", Field::LongText ) );
02922
02923 t_objects->debug();
02924
02925 TableSchema *t_objectdata = newKexiDBSystemTableSchema("kexi__objectdata");
02926 t_objectdata->addField( new Field("o_id", Field::Integer, Field::NotNull, Field::Unsigned) )
02927 .addField( new Field("o_data", Field::LongText) )
02928 .addField( new Field("o_sub_id", Field::Text) );
02929
02930 TableSchema *t_fields = newKexiDBSystemTableSchema("kexi__fields");
02931 t_fields->addField( new Field("t_id", Field::Integer, 0, Field::Unsigned) )
02932 .addField( new Field("f_type", Field::Byte, 0, Field::Unsigned) )
02933 .addField( new Field("f_name", Field::Text ) )
02934 .addField( new Field("f_length", Field::Integer ) )
02935 .addField( new Field("f_precision", Field::Integer ) )
02936 .addField( new Field("f_constraints", Field::Integer ) )
02937 .addField( new Field("f_options", Field::Integer ) )
02938 .addField( new Field("f_default", Field::Text ) )
02939
02940 .addField( new Field("f_order", Field::Integer ) )
02941 .addField( new Field("f_caption", Field::Text ) )
02942 .addField( new Field("f_help", Field::LongText ) );
02943
02944
02945
02946
02947
02948
02949
02950
02951
02952
02953
02954
02955
02956
02957
02958
02959
02960
02961 TableSchema *t_db = newKexiDBSystemTableSchema("kexi__db");
02962 t_db->addField( new Field("db_property", Field::Text, Field::NoConstraints, Field::NoOptions, 32 ) )
02963 .addField( new Field("db_value", Field::LongText ) );
02964
02965
02966
02967
02968
02969
02970
02971
02972
02973
02974
02975
02976
02977
02978
02979
02980
02981
02982
02983
02984
02985
02986
02987
02988 return true;
02989 }
02990
02991 void Connection::removeMe(TableSchema *ts)
02992 {
02993 if (ts && !m_destructor_started) {
02994 d->tables.take(ts->id());
02995 d->tables_byname.take(ts->name());
02996 }
02997 }
02998
02999 QString Connection::anyAvailableDatabaseName()
03000 {
03001 if (!d->availableDatabaseName.isEmpty()) {
03002 return d->availableDatabaseName;
03003 }
03004 return m_driver->beh->ALWAYS_AVAILABLE_DATABASE_NAME;
03005 }
03006
03007 void Connection::setAvailableDatabaseName(const QString& dbName)
03008 {
03009 d->availableDatabaseName = dbName;
03010 }
03011
03013 inline void updateRowDataWithNewValues(QuerySchema &query, RowData& data, KexiDB::RowEditBuffer::DBMap& b,
03014 QMap<QueryColumnInfo*,int>& columnsOrderExpanded)
03015 {
03016 columnsOrderExpanded = query.columnsOrder(QuerySchema::ExpandedList);
03017 QMap<QueryColumnInfo*,int>::ConstIterator columnsOrderExpandedIt;
03018 for (KexiDB::RowEditBuffer::DBMap::ConstIterator it=b.constBegin();it!=b.constEnd();++it) {
03019 columnsOrderExpandedIt = columnsOrderExpanded.find( it.key() );
03020 if (columnsOrderExpandedIt == columnsOrderExpanded.constEnd()) {
03021 KexiDBWarn << "(Connection) updateRowDataWithNewValues(): \"now also assign new value in memory\" step "
03022 "- could not find item '" << it.key()->aliasOrName() << "'" << endl;
03023 continue;
03024 }
03025 data[ columnsOrderExpandedIt.data() ] = it.data();
03026 }
03027 }
03028
03029 bool Connection::updateRow(QuerySchema &query, RowData& data, RowEditBuffer& buf, bool useROWID)
03030 {
03031
03032
03033
03034 KexiDBDbg << "Connection::updateRow.." << endl;
03035 clearError();
03036
03037 if (buf.dbBuffer().isEmpty()) {
03038 KexiDBDbg << " -- NO CHANGES DATA!" << endl;
03039 return true;
03040 }
03041 TableSchema *mt = query.masterTable();
03042 if (!mt) {
03043 KexiDBWarn << " -- NO MASTER TABLE!" << endl;
03044 setError(ERR_UPDATE_NO_MASTER_TABLE,
03045 i18n("Could not update row because there is no master table defined."));
03046 return false;
03047 }
03048 IndexSchema *pkey = (mt->primaryKey() && !mt->primaryKey()->fields()->isEmpty()) ? mt->primaryKey() : 0;
03049 if (!useROWID && !pkey) {
03050 KexiDBWarn << " -- NO MASTER TABLE's PKEY!" << endl;
03051 setError(ERR_UPDATE_NO_MASTER_TABLES_PKEY,
03052 i18n("Could not update row because master table has no primary key defined."));
03054 return false;
03055 }
03056
03057 m_sql = "UPDATE " + escapeIdentifier(mt->name()) + " SET ";
03058 QString sqlset, sqlwhere;
03059 sqlset.reserve(1024);
03060 sqlwhere.reserve(1024);
03061 KexiDB::RowEditBuffer::DBMap b = buf.dbBuffer();
03062 for (KexiDB::RowEditBuffer::DBMap::ConstIterator it=b.constBegin();it!=b.constEnd();++it) {
03063 if (it.key()->field->table()!=mt)
03064 continue;
03065 if (!sqlset.isEmpty())
03066 sqlset+=",";
03067 sqlset += (escapeIdentifier(it.key()->field->name()) + "=" +
03068 m_driver->valueToSQL(it.key()->field,it.data()));
03069 }
03070 if (pkey) {
03071 QValueVector<int> pkeyFieldsOrder = query.pkeyFieldsOrder();
03072 KexiDBDbg << pkey->fieldCount() << " ? " << query.pkeyFieldsCount() << endl;
03073 if (pkey->fieldCount() != query.pkeyFieldsCount()) {
03074 KexiDBWarn << " -- NO ENTIRE MASTER TABLE's PKEY SPECIFIED!" << endl;
03075 setError(ERR_UPDATE_NO_ENTIRE_MASTER_TABLES_PKEY,
03076 i18n("Could not update row because it does not contain entire master table's primary key."));
03077 return false;
03078 }
03079 if (!pkey->fields()->isEmpty()) {
03080 uint i=0;
03081 for (Field::ListIterator it = pkey->fieldsIterator(); it.current(); i++, ++it) {
03082 if (!sqlwhere.isEmpty())
03083 sqlwhere+=" AND ";
03084 QVariant val = data[ pkeyFieldsOrder[i] ];
03085 if (val.isNull() || !val.isValid()) {
03086 setError(ERR_UPDATE_NULL_PKEY_FIELD,
03087 i18n("Primary key's field \"%1\" cannot be empty.").arg(it.current()->name()));
03088
03089 return false;
03090 }
03091 sqlwhere += ( escapeIdentifier(it.current()->name()) + "=" +
03092 m_driver->valueToSQL( it.current(), val ) );
03093 }
03094 }
03095 }
03096 else {
03097 sqlwhere = ( escapeIdentifier(m_driver->beh->ROW_ID_FIELD_NAME) + "="
03098 + m_driver->valueToSQL(Field::BigInteger, data[data.size()-1]));
03099 }
03100 m_sql += (sqlset + " WHERE " + sqlwhere);
03101 KexiDBDbg << " -- SQL == " << ((m_sql.length() > 400) ? (m_sql.left(400)+"[.....]") : m_sql) << endl;
03102
03103 if (!executeSQL(m_sql)) {
03104 setError(ERR_UPDATE_SERVER_ERROR, i18n("Row updating on the server failed."));
03105 return false;
03106 }
03107
03108 QMap<QueryColumnInfo*,int> columnsOrderExpanded;
03109 updateRowDataWithNewValues(query, data, b, columnsOrderExpanded);
03110 return true;
03111 }
03112
03113 bool Connection::insertRow(QuerySchema &query, RowData& data, RowEditBuffer& buf, bool getROWID)
03114 {
03115
03116 KexiDBDbg << "Connection::updateRow.." << endl;
03117 clearError();
03118
03119
03120
03121
03122
03123 TableSchema *mt = query.masterTable();
03124 if (!mt) {
03125 KexiDBWarn << " -- NO MASTER TABLE!" << endl;
03126 setError(ERR_INSERT_NO_MASTER_TABLE,
03127 i18n("Could not insert row because there is no master table defined."));
03128 return false;
03129 }
03130 IndexSchema *pkey = (mt->primaryKey() && !mt->primaryKey()->fields()->isEmpty()) ? mt->primaryKey() : 0;
03131 if (!getROWID && !pkey)
03132 KexiDBWarn << " -- WARNING: NO MASTER TABLE's PKEY" << endl;
03133
03134 QString sqlcols, sqlvals;
03135 sqlcols.reserve(1024);
03136 sqlvals.reserve(1024);
03137
03138
03139 m_sql = "INSERT INTO " + escapeIdentifier(mt->name()) + " (";
03140 KexiDB::RowEditBuffer::DBMap b = buf.dbBuffer();
03141
03142
03143 const QueryColumnInfo::Vector fieldsExpanded( query.fieldsExpanded( QuerySchema::Unique ) );
03144 for (uint i=0; i<fieldsExpanded.count(); i++) {
03145 QueryColumnInfo *ci = fieldsExpanded.at(i);
03146 if (ci->field && KexiDB::isDefaultValueAllowed(ci->field)
03147 && !ci->field->defaultValue().isNull()
03148 && !b.contains( ci ))
03149 {
03150 KexiDBDbg << "Connection::insertRow(): adding default value '" << ci->field->defaultValue().toString()
03151 << "' for column '" << ci->field->name() << "'" << endl;
03152 b.insert( ci, ci->field->defaultValue() );
03153 }
03154 }
03155
03156 if (b.isEmpty()) {
03157
03158 if (!getROWID && !pkey) {
03159 KexiDBWarn << "MASTER TABLE's PKEY REQUIRED FOR INSERTING EMPTY ROWS: INSERT CANCELLED" << endl;
03160 setError(ERR_INSERT_NO_MASTER_TABLES_PKEY,
03161 i18n("Could not insert row because master table has no primary key defined."));
03162 return false;
03163 }
03164 if (pkey) {
03165 QValueVector<int> pkeyFieldsOrder = query.pkeyFieldsOrder();
03166
03167 if (pkey->fieldCount() != query.pkeyFieldsCount()) {
03168 KexiDBWarn << "NO ENTIRE MASTER TABLE's PKEY SPECIFIED!" << endl;
03169 setError(ERR_INSERT_NO_ENTIRE_MASTER_TABLES_PKEY,
03170 i18n("Could not insert row because it does not contain entire master table's primary key.")
03171 .arg(query.name()));
03172 return false;
03173 }
03174 }
03175
03176 Field *anyField = mt->anyNonPKField();
03177 if (!anyField) {
03178 if (!pkey) {
03179 KexiDBWarn << "WARNING: NO FIELD AVAILABLE TO SET IT TO NULL" << endl;
03180 return false;
03181 }
03182 else {
03183
03184 anyField = pkey->fields()->first();
03185 }
03186 }
03187 sqlcols += escapeIdentifier(anyField->name());
03188 sqlvals += m_driver->valueToSQL(anyField,QVariant());
03189 }
03190 else {
03191
03192 for (KexiDB::RowEditBuffer::DBMap::ConstIterator it=b.constBegin();it!=b.constEnd();++it) {
03193 if (it.key()->field->table()!=mt)
03194 continue;
03195 if (!sqlcols.isEmpty()) {
03196 sqlcols+=",";
03197 sqlvals+=",";
03198 }
03199 sqlcols += escapeIdentifier(it.key()->field->name());
03200 sqlvals += m_driver->valueToSQL(it.key()->field,it.data());
03201 }
03202 }
03203 m_sql += (sqlcols + ") VALUES (" + sqlvals + ")");
03204
03205
03206 bool res = executeSQL(m_sql);
03207
03208 if (!res) {
03209 setError(ERR_INSERT_SERVER_ERROR, i18n("Row inserting on the server failed."));
03210 return false;
03211 }
03212
03213 QMap<QueryColumnInfo*,int> columnsOrderExpanded;
03214 updateRowDataWithNewValues(query, data, b, columnsOrderExpanded);
03215
03216
03217 QueryColumnInfo::List *aif_list = query.autoIncrementFields();
03218 Q_ULLONG ROWID = 0;
03219 if (pkey && !aif_list->isEmpty()) {
03221 QueryColumnInfo *id_columnInfo = aif_list->first();
03223 Q_ULLONG last_id = lastInsertedAutoIncValue(
03224 id_columnInfo->field->name(), id_columnInfo->field->table()->name(), &ROWID);
03225 if (last_id==(Q_ULLONG)-1 || last_id<=0) {
03228 return false;
03229 }
03230 RowData aif_data;
03231 QString getAutoIncForInsertedValue = QString::fromLatin1("SELECT ")
03232 + query.autoIncrementSQLFieldsList(m_driver)
03233 + QString::fromLatin1(" FROM ")
03234 + escapeIdentifier(id_columnInfo->field->table()->name())
03235 + QString::fromLatin1(" WHERE ")
03236 + escapeIdentifier(id_columnInfo->field->name()) + "="
03237 + QString::number(last_id);
03238 if (true!=querySingleRecord(getAutoIncForInsertedValue, aif_data)) {
03240 return false;
03241 }
03242 QueryColumnInfo::ListIterator ci_it(*aif_list);
03243 QueryColumnInfo *ci;
03244 for (uint i=0; (ci = ci_it.current()); ++ci_it, i++) {
03245
03246
03247 ( data[ columnsOrderExpanded[ ci ] ] = aif_data[i] ).cast( ci->field->variantType() );
03248 }
03249 }
03250 else {
03251 ROWID = drv_lastInsertRowID();
03252
03253 if (m_driver->beh->ROW_ID_FIELD_RETURNS_LAST_AUTOINCREMENTED_VALUE) {
03254 KexiDBWarn << "Connection::insertRow(): m_driver->beh->ROW_ID_FIELD_RETURNS_LAST_AUTOINCREMENTED_VALUE" << endl;
03255 return false;
03256 }
03257 }
03258 if (getROWID && data.size() > fieldsExpanded.size()) {
03259
03260 data[data.size()-1] = ROWID;
03261 }
03262 return true;
03263 }
03264
03265 bool Connection::deleteRow(QuerySchema &query, RowData& data, bool useROWID)
03266 {
03267
03268 KexiDBWarn << "Connection::deleteRow.." << endl;
03269 clearError();
03270 TableSchema *mt = query.masterTable();
03271 if (!mt) {
03272 KexiDBWarn << " -- NO MASTER TABLE!" << endl;
03273 setError(ERR_DELETE_NO_MASTER_TABLE,
03274 i18n("Could not delete row because there is no master table defined.")
03275 .arg(query.name()));
03276 return false;
03277 }
03278 IndexSchema *pkey = (mt->primaryKey() && !mt->primaryKey()->fields()->isEmpty()) ? mt->primaryKey() : 0;
03279
03281 if (!useROWID && !pkey) {
03282 KexiDBWarn << " -- WARNING: NO MASTER TABLE's PKEY" << endl;
03283 setError(ERR_DELETE_NO_MASTER_TABLES_PKEY,
03284 i18n("Could not delete row because there is no primary key for master table defined."));
03285 return false;
03286 }
03287
03288
03289 m_sql = "DELETE FROM " + escapeIdentifier(mt->name()) + " WHERE ";
03290 QString sqlwhere;
03291 sqlwhere.reserve(1024);
03292
03293 if (pkey) {
03294 QValueVector<int> pkeyFieldsOrder = query.pkeyFieldsOrder();
03295 KexiDBDbg << pkey->fieldCount() << " ? " << query.pkeyFieldsCount() << endl;
03296 if (pkey->fieldCount() != query.pkeyFieldsCount()) {
03297 KexiDBWarn << " -- NO ENTIRE MASTER TABLE's PKEY SPECIFIED!" << endl;
03298 setError(ERR_DELETE_NO_ENTIRE_MASTER_TABLES_PKEY,
03299 i18n("Could not delete row because it does not contain entire master table's primary key."));
03300 return false;
03301 }
03302 uint i=0;
03303 for (Field::ListIterator it = pkey->fieldsIterator(); it.current(); i++, ++it) {
03304 if (!sqlwhere.isEmpty())
03305 sqlwhere+=" AND ";
03306 QVariant val = data[ pkeyFieldsOrder[i] ];
03307 if (val.isNull() || !val.isValid()) {
03308 setError(ERR_DELETE_NULL_PKEY_FIELD, i18n("Primary key's field \"%1\" cannot be empty.")
03309 .arg(it.current()->name()));
03310
03311 return false;
03312 }
03313 sqlwhere += ( escapeIdentifier(it.current()->name()) + "=" +
03314 m_driver->valueToSQL( it.current(), val ) );
03315 }
03316 }
03317 else {
03318 sqlwhere = ( escapeIdentifier(m_driver->beh->ROW_ID_FIELD_NAME) + "="
03319 + m_driver->valueToSQL(Field::BigInteger, data[data.size()-1]));
03320 }
03321 m_sql += sqlwhere;
03322 KexiDBDbg << " -- SQL == " << m_sql << endl;
03323
03324 if (!executeSQL(m_sql)) {
03325 setError(ERR_DELETE_SERVER_ERROR, i18n("Row deletion on the server failed."));
03326 return false;
03327 }
03328 return true;
03329 }
03330
03331 bool Connection::deleteAllRows(QuerySchema &query)
03332 {
03333 clearError();
03334 TableSchema *mt = query.masterTable();
03335 if (!mt) {
03336 KexiDBWarn << " -- NO MASTER TABLE!" << endl;
03337 return false;
03338 }
03339 IndexSchema *pkey = mt->primaryKey();
03340 if (!pkey || pkey->fields()->isEmpty())
03341 KexiDBWarn << "Connection::deleteAllRows -- WARNING: NO MASTER TABLE's PKEY" << endl;
03342
03343 m_sql = "DELETE FROM " + escapeIdentifier(mt->name());
03344
03345 KexiDBDbg << " -- SQL == " << m_sql << endl;
03346
03347 if (!executeSQL(m_sql)) {
03348 setError(ERR_DELETE_SERVER_ERROR, i18n("Row deletion on the server failed."));
03349 return false;
03350 }
03351 return true;
03352 }
03353
03354 void Connection::registerForTableSchemaChanges(TableSchemaChangeListenerInterface& listener,
03355 TableSchema &schema)
03356 {
03357 QPtrList<TableSchemaChangeListenerInterface>* listeners = d->tableSchemaChangeListeners[&schema];
03358 if (!listeners) {
03359 listeners = new QPtrList<TableSchemaChangeListenerInterface>();
03360 d->tableSchemaChangeListeners.insert(&schema, listeners);
03361 }
03362
03363 if (listeners->findRef( &listener )==-1)
03364 listeners->append( &listener );
03365 }
03366
03367 void Connection::unregisterForTableSchemaChanges(TableSchemaChangeListenerInterface& listener,
03368 TableSchema &schema)
03369 {
03370 QPtrList<TableSchemaChangeListenerInterface>* listeners = d->tableSchemaChangeListeners[&schema];
03371 if (!listeners)
03372 return;
03373
03374 listeners->remove( &listener );
03375 }
03376
03377 void Connection::unregisterForTablesSchemaChanges(TableSchemaChangeListenerInterface& listener)
03378 {
03379 for (QPtrDictIterator< QPtrList<TableSchemaChangeListenerInterface> > it(d->tableSchemaChangeListeners);
03380 it.current(); ++it)
03381 {
03382 if (-1!=it.current()->find(&listener))
03383 it.current()->take();
03384 }
03385 }
03386
03387 QPtrList<Connection::TableSchemaChangeListenerInterface>*
03388 Connection::tableSchemaChangeListeners(TableSchema& tableSchema) const
03389 {
03390 KexiDBDbg << d->tableSchemaChangeListeners.count() << endl;
03391 return d->tableSchemaChangeListeners[&tableSchema];
03392 }
03393
03394 tristate Connection::closeAllTableSchemaChangeListeners(TableSchema& tableSchema)
03395 {
03396 QPtrList<Connection::TableSchemaChangeListenerInterface> *listeners = d->tableSchemaChangeListeners[&tableSchema];
03397 if (!listeners)
03398 return true;
03399 QPtrListIterator<KexiDB::Connection::TableSchemaChangeListenerInterface> tmpListeners(*listeners);
03400 tristate res = true;
03401
03402 for (QPtrListIterator<KexiDB::Connection::TableSchemaChangeListenerInterface> it(tmpListeners);
03403 it.current() && res==true; ++it)
03404 {
03405 res = it.current()->closeListener();
03406 }
03407 return res;
03408 }
03409
03410
03411
03412
03413
03414
03415
03416
03417 void Connection::setReadOnly(bool set)
03418 {
03419 if (d->isConnected)
03420 return;
03421 d->readOnly = set;
03422 }
03423
03424 bool Connection::isReadOnly() const
03425 {
03426 return d->readOnly;
03427 }
03428
03429 #include "connection.moc"