00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <kexidb/connection.h>
00021
00022 #include "error.h"
00023 #include "connection_p.h"
00024 #include "connectiondata.h"
00025 #include "driver.h"
00026 #include "driver_p.h"
00027 #include "schemadata.h"
00028 #include "tableschema.h"
00029 #include "relationship.h"
00030 #include "transaction.h"
00031 #include "cursor.h"
00032 #include "global.h"
00033 #include "roweditbuffer.h"
00034 #include "utils.h"
00035 #include "dbproperties.h"
00036 #include "lookupfieldschema.h"
00037 #include "parser/parser.h"
00038
00039 #include <kexiutils/utils.h>
00040 #include <kexiutils/identifier.h>
00041
00042 #include <qdir.h>
00043 #include <qfileinfo.h>
00044 #include <qguardedptr.h>
00045 #include <qdom.h>
00046
00047 #include <klocale.h>
00048 #include <kdebug.h>
00049
00050 #define KEXIDB_EXTENDED_TABLE_SCHEMA_VERSION 1
00051
00052
00053
00054 namespace KexiDB {
00055
00056 Connection::SelectStatementOptions::SelectStatementOptions()
00057 : identifierEscaping(Driver::EscapeDriver|Driver::EscapeAsNecessary)
00058 , alsoRetrieveROWID(false)
00059 {
00060 }
00061
00062 Connection::SelectStatementOptions::~SelectStatementOptions()
00063 {
00064 }
00065
00066
00067
00068 ConnectionInternal::ConnectionInternal(Connection *conn)
00069 : connection(conn)
00070 {
00071 }
00072
00073 ConnectionInternal::~ConnectionInternal()
00074 {
00075 }
00076
00077
00079 class ConnectionPrivate
00080 {
00081 public:
00082 ConnectionPrivate(Connection* const conn, ConnectionData &conn_data)
00083 : conn(conn)
00084 , conn_data(&conn_data)
00085 , tableSchemaChangeListeners(101)
00086 , m_parser(0)
00087 , tables_byname(101, false)
00088 , queries_byname(101, false)
00089 , kexiDBSystemTables(101)
00090 , dont_remove_transactions(false)
00091 , skip_databaseExists_check_in_useDatabase(false)
00092 , default_trans_started_inside(false)
00093 , isConnected(false)
00094 , autoCommit(true)
00095 {
00096 tableSchemaChangeListeners.setAutoDelete(true);
00097 obsoleteQueries.setAutoDelete(true);
00098
00099 tables.setAutoDelete(true);
00100 tables_byname.setAutoDelete(false);
00101 kexiDBSystemTables.setAutoDelete(true);
00102 queries.setAutoDelete(true);
00103 queries_byname.setAutoDelete(false);
00104
00105
00106 tables.resize(101);
00107 queries.resize(101);
00108 }
00109 ~ConnectionPrivate()
00110 {
00111 delete m_parser;
00112 }
00113
00114 void errorInvalidDBContents(const QString& details) {
00115 conn->setError( ERR_INVALID_DATABASE_CONTENTS, i18n("Invalid database contents. ")+details);
00116 }
00117
00118 QString strItIsASystemObject() const {
00119 return i18n("It is a system object.");
00120 }
00121
00122 inline Parser *parser() { return m_parser ? m_parser : (m_parser = new Parser(conn)); }
00123
00124 Connection* const conn;
00125 QGuardedPtr<ConnectionData> conn_data;
00126
00131 Transaction default_trans;
00132 QValueList<Transaction> transactions;
00133
00134 QPtrDict< QPtrList<Connection::TableSchemaChangeListenerInterface> > tableSchemaChangeListeners;
00135
00138 QPtrList<QuerySchema> obsoleteQueries;
00139
00140
00142 KexiDB::ServerVersionInfo serverVersion;
00143
00145 KexiDB::DatabaseVersionInfo databaseVersion;
00146
00147 Parser *m_parser;
00148
00150 QIntDict<TableSchema> tables;
00151 QDict<TableSchema> tables_byname;
00152 QIntDict<QuerySchema> queries;
00153 QDict<QuerySchema> queries_byname;
00154
00156 QPtrDict<TableSchema> kexiDBSystemTables;
00157
00159 DatabaseProperties* dbProperties;
00160
00161 QString availableDatabaseName;
00162 QString usedDatabase;
00163
00166 bool dont_remove_transactions : 1;
00167
00170 bool skip_databaseExists_check_in_useDatabase : 1;
00171
00180 bool default_trans_started_inside : 1;
00181
00182 bool isConnected : 1;
00183
00184 bool autoCommit : 1;
00185
00187 bool readOnly : 1;
00188 };
00189
00190 }
00191
00192
00193 using namespace KexiDB;
00194
00196 QStringList KexiDB_kexiDBSystemTableNames;
00197
00198 Connection::Connection( Driver *driver, ConnectionData &conn_data )
00199 : QObject()
00200 ,KexiDB::Object()
00201 ,d(new ConnectionPrivate(this, conn_data))
00202 ,m_driver(driver)
00203 ,m_destructor_started(false)
00204 {
00205 d->dbProperties = new DatabaseProperties(this);
00206 m_cursors.setAutoDelete(true);
00207
00208
00209 m_cursors.resize(101);
00210
00211 m_sql.reserve(0x4000);
00212 }
00213
00214 void Connection::destroy()
00215 {
00216 disconnect();
00217
00218 m_driver->d->connections.take( this );
00219 }
00220
00221 Connection::~Connection()
00222 {
00223 m_destructor_started = true;
00224
00225 delete d->dbProperties;
00226 delete d;
00227 d = 0;
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238 }
00239
00240 ConnectionData* Connection::data() const
00241 {
00242 return d->conn_data;
00243 }
00244
00245 bool Connection::connect()
00246 {
00247 clearError();
00248 if (d->isConnected) {
00249 setError(ERR_ALREADY_CONNECTED, i18n("Connection already established.") );
00250 return false;
00251 }
00252
00253 d->serverVersion.clear();
00254 if (!(d->isConnected = drv_connect(d->serverVersion))) {
00255 setError(m_driver->isFileDriver() ?
00256 i18n("Could not open \"%1\" project file.").arg(QDir::convertSeparators(d->conn_data->fileName()))
00257 : i18n("Could not connect to \"%1\" database server.").arg(d->conn_data->serverInfoString()) );
00258 }
00259 return d->isConnected;
00260 }
00261
00262 bool Connection::isDatabaseUsed() const
00263 {
00264 return !d->usedDatabase.isEmpty() && d->isConnected && drv_isDatabaseUsed();
00265 }
00266
00267 void Connection::clearError()
00268 {
00269 Object::clearError();
00270 m_sql = QString::null;
00271 }
00272
00273 bool Connection::disconnect()
00274 {
00275 clearError();
00276 if (!d->isConnected)
00277 return true;
00278
00279 if (!closeDatabase())
00280 return false;
00281
00282 bool ok = drv_disconnect();
00283 if (ok)
00284 d->isConnected = false;
00285 return ok;
00286 }
00287
00288 bool Connection::isConnected() const
00289 {
00290 return d->isConnected;
00291 }
00292
00293 bool Connection::checkConnected()
00294 {
00295 if (d->isConnected) {
00296 clearError();
00297 return true;
00298 }
00299 setError(ERR_NO_CONNECTION, i18n("Not connected to the database server.") );
00300 return false;
00301 }
00302
00303 bool Connection::checkIsDatabaseUsed()
00304 {
00305 if (isDatabaseUsed()) {
00306 clearError();
00307 return true;
00308 }
00309 setError(ERR_NO_DB_USED, i18n("Currently no database is used.") );
00310 return false;
00311 }
00312
00313 QStringList Connection::databaseNames(bool also_system_db)
00314 {
00315 KexiDBDbg << "Connection::databaseNames("<<also_system_db<<")"<< endl;
00316 if (!checkConnected())
00317 return QStringList();
00318
00319 QString tmpdbName;
00320
00321 if (!useTemporaryDatabaseIfNeeded(tmpdbName))
00322 return QStringList();
00323
00324 QStringList list, non_system_list;
00325
00326 bool ret = drv_getDatabasesList( list );
00327
00328 if (!tmpdbName.isEmpty()) {
00329
00330 if (!closeDatabase())
00331 return QStringList();
00332 }
00333
00334 if (!ret)
00335 return QStringList();
00336
00337 if (also_system_db)
00338 return list;
00339
00340 for (QStringList::ConstIterator it = list.constBegin(); it!=list.constEnd(); ++it) {
00341 KexiDBDbg << "Connection::databaseNames(): " << *it << endl;
00342 if (!m_driver->isSystemDatabaseName(*it)) {
00343 KexiDBDbg << "add " << *it << endl;
00344 non_system_list << (*it);
00345 }
00346 }
00347 return non_system_list;
00348 }
00349
00350 bool Connection::drv_getDatabasesList( QStringList &list )
00351 {
00352 list.clear();
00353 return true;
00354 }
00355
00356 bool Connection::drv_databaseExists( const QString &dbName, bool ignoreErrors )
00357 {
00358 QStringList list = databaseNames(true);
00359 if (error()) {
00360 return false;
00361 }
00362
00363 if (list.find( dbName )==list.end()) {
00364 if (!ignoreErrors)
00365 setError(ERR_OBJECT_NOT_FOUND, i18n("The database \"%1\" does not exist.").arg(dbName));
00366 return false;
00367 }
00368
00369 return true;
00370 }
00371
00372 bool Connection::databaseExists( const QString &dbName, bool ignoreErrors )
00373 {
00374
00375 if (!checkConnected())
00376 return false;
00377 clearError();
00378
00379 if (m_driver->isFileDriver()) {
00380
00381
00382 QFileInfo file(d->conn_data->fileName());
00383 if (!file.exists() || ( !file.isFile() && !file.isSymLink()) ) {
00384 if (!ignoreErrors)
00385 setError(ERR_OBJECT_NOT_FOUND, i18n("Database file \"%1\" does not exist.")
00386 .arg(QDir::convertSeparators(d->conn_data->fileName())) );
00387 return false;
00388 }
00389 if (!file.isReadable()) {
00390 if (!ignoreErrors)
00391 setError(ERR_ACCESS_RIGHTS, i18n("Database file \"%1\" is not readable.")
00392 .arg(QDir::convertSeparators(d->conn_data->fileName())) );
00393 return false;
00394 }
00395 if (!file.isWritable()) {
00396 if (!ignoreErrors)
00397 setError(ERR_ACCESS_RIGHTS, i18n("Database file \"%1\" is not writable.")
00398 .arg(QDir::convertSeparators(d->conn_data->fileName())) );
00399 return false;
00400 }
00401 return true;
00402 }
00403
00404 QString tmpdbName;
00405
00406 const bool orig_skip_databaseExists_check_in_useDatabase = d->skip_databaseExists_check_in_useDatabase;
00407 d->skip_databaseExists_check_in_useDatabase = true;
00408 bool ret = useTemporaryDatabaseIfNeeded(tmpdbName);
00409 d->skip_databaseExists_check_in_useDatabase = orig_skip_databaseExists_check_in_useDatabase;
00410 if (!ret)
00411 return false;
00412
00413 ret = drv_databaseExists(dbName, ignoreErrors);
00414
00415 if (!tmpdbName.isEmpty()) {
00416
00417 if (!closeDatabase())
00418 return false;
00419 }
00420
00421 return ret;
00422 }
00423
00424 #define createDatabase_CLOSE \
00425 { if (!closeDatabase()) { \
00426 setError(i18n("Database \"%1\" created but could not be closed after creation.").arg(dbName) ); \
00427 return false; \
00428 } }
00429
00430 #define createDatabase_ERROR \
00431 { createDatabase_CLOSE; return false; }
00432
00433
00434 bool Connection::createDatabase( const QString &dbName )
00435 {
00436 if (!checkConnected())
00437 return false;
00438
00439 if (databaseExists( dbName )) {
00440 setError(ERR_OBJECT_EXISTS, i18n("Database \"%1\" already exists.").arg(dbName) );
00441 return false;
00442 }
00443 if (m_driver->isSystemDatabaseName( dbName )) {
00444 setError(ERR_SYSTEM_NAME_RESERVED,
00445 i18n("Cannot create database \"%1\". This name is reserved for system database.").arg(dbName) );
00446 return false;
00447 }
00448 if (m_driver->isFileDriver()) {
00449
00450 d->conn_data->setFileName( dbName );
00451 }
00452
00453 QString tmpdbName;
00454
00455 if (!useTemporaryDatabaseIfNeeded(tmpdbName))
00456 return false;
00457
00458
00459 if (!drv_createDatabase( dbName )) {
00460 setError(i18n("Error creating database \"%1\" on the server.").arg(dbName) );
00461 closeDatabase();
00462 return false;
00463 }
00464
00465 if (!tmpdbName.isEmpty()) {
00466
00467 if (!closeDatabase())
00468 return false;
00469 }
00470
00471 if (!tmpdbName.isEmpty() || !m_driver->d->isDBOpenedAfterCreate) {
00472
00473 if (!useDatabase( dbName, false )) {
00474 setError(i18n("Database \"%1\" created but could not be opened.").arg(dbName) );
00475 return false;
00476 }
00477 }
00478 else {
00479
00480 d->usedDatabase = dbName;
00481 }
00482
00483 Transaction trans;
00484 if (m_driver->transactionsSupported()) {
00485 trans = beginTransaction();
00486 if (!trans.active())
00487 return false;
00488 }
00489
00490
00491
00492
00493
00494 if (!setupKexiDBSystemSchema())
00495 return false;
00496
00497
00498 for (QPtrDictIterator<TableSchema> it(d->kexiDBSystemTables); it.current(); ++it) {
00499 if (!drv_createTable( it.current()->name() ))
00500 createDatabase_ERROR;
00501 }
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519 TableSchema *t_db = tableSchema("kexi__db");
00520 if (!t_db)
00521 createDatabase_ERROR;
00522 if ( !insertRecord(*t_db, "kexidb_major_ver", KexiDB::version().major)
00523 || !insertRecord(*t_db, "kexidb_minor_ver", KexiDB::version().minor))
00524 createDatabase_ERROR;
00525
00526 if (trans.active() && !commitTransaction(trans))
00527 createDatabase_ERROR;
00528
00529 createDatabase_CLOSE;
00530 return true;
00531 }
00532
00533 #undef createDatabase_CLOSE
00534 #undef createDatabase_ERROR
00535
00536 bool Connection::useDatabase( const QString &dbName, bool kexiCompatible, bool *cancelled, MessageHandler* msgHandler )
00537 {
00538 if (cancelled)
00539 *cancelled = false;
00540 KexiDBDbg << "Connection::useDatabase(" << dbName << "," << kexiCompatible <<")" << endl;
00541 if (!checkConnected())
00542 return false;
00543
00544 if (dbName.isEmpty())
00545 return false;
00546 QString my_dbName = dbName;
00547
00548
00549
00550
00551
00552 if (d->usedDatabase == my_dbName)
00553 return true;
00554
00555 if (!d->skip_databaseExists_check_in_useDatabase) {
00556 if (!databaseExists(my_dbName, false ))
00557 return false;
00558 }
00559
00560 if (!d->usedDatabase.isEmpty() && !closeDatabase())
00561 return false;
00562
00563 d->usedDatabase = "";
00564
00565 if (!drv_useDatabase( my_dbName, cancelled, msgHandler )) {
00566 if (cancelled && *cancelled)
00567 return false;
00568 QString msg(i18n("Opening database \"%1\" failed.").arg( my_dbName ));
00569 if (error())
00570 setError( this, msg );
00571 else
00572 setError( msg );
00573 return false;
00574 }
00575
00576
00577 if (!setupKexiDBSystemSchema())
00578 return false;
00579
00580 if (kexiCompatible && my_dbName.lower()!=anyAvailableDatabaseName().lower()) {
00581
00582 int num;
00583 bool ok;
00584
00585 num = d->dbProperties->value("kexidb_major_ver").toInt(&ok);
00586 if (!ok)
00587 return false;
00588 d->databaseVersion.major = num;
00589
00590
00591
00592
00593
00594 num = d->dbProperties->value("kexidb_minor_ver").toInt(&ok);
00595 if (!ok)
00596 return false;
00597 d->databaseVersion.minor = num;
00598
00599
00600
00601
00602
00603
00604 #if 0 //this is already checked in DriverManagerInternal::lookupDrivers()
00605
00606 if (m_driver->versionMajor()!=KexiDB::versionMajor()) {
00607 setError(ERR_INCOMPAT_DATABASE_VERSION,
00608 i18n("Database version (%1) does not match Kexi application's version (%2)")
00609 .arg( QString("%1.%2").arg(versionMajor()).arg(versionMinor()) )
00610 .arg( QString("%1.%2").arg(KexiDB::versionMajor()).arg(KexiDB::versionMinor()) ) );
00611 return false;
00612 }
00613 if (m_driver->versionMinor()!=KexiDB::versionMinor()) {
00614
00615
00616 }
00617 #endif
00618 }
00619 d->usedDatabase = my_dbName;
00620 return true;
00621 }
00622
00623 bool Connection::closeDatabase()
00624 {
00625 if (d->usedDatabase.isEmpty())
00626 return true;
00627 if (!checkConnected())
00628 return true;
00629
00630 bool ret = true;
00631
00633 if (m_driver->transactionsSupported()) {
00634
00635 QValueList<Transaction>::ConstIterator it;
00636 d->dont_remove_transactions=true;
00637 for (it=d->transactions.constBegin(); it!= d->transactions.constEnd(); ++it) {
00638 if (!rollbackTransaction(*it)) {
00639 ret = false;
00640 }
00641 else {
00642 KexiDBDbg << "Connection::closeDatabase(): transaction rolled back!" << endl;
00643 KexiDBDbg << "Connection::closeDatabase(): trans.refcount==" <<
00644 ((*it).m_data ? QString::number((*it).m_data->refcount) : "(null)") << endl;
00645 }
00646 }
00647 d->dont_remove_transactions=false;
00648 d->transactions.clear();
00649 }
00650
00651
00652 m_cursors.clear();
00653
00654 d->tables.clear();
00655 d->kexiDBSystemTables.clear();
00656 d->queries.clear();
00657
00658 if (!drv_closeDatabase())
00659 return false;
00660
00661 d->usedDatabase = "";
00662
00663 return ret;
00664 }
00665
00666 QString Connection::currentDatabase() const
00667 {
00668 return d->usedDatabase;
00669 }
00670
00671 bool Connection::useTemporaryDatabaseIfNeeded(QString &tmpdbName)
00672 {
00673 if (!m_driver->isFileDriver() && m_driver->beh->USING_DATABASE_REQUIRED_TO_CONNECT
00674 && !isDatabaseUsed()) {
00675
00676 tmpdbName = anyAvailableDatabaseName();
00677 if (tmpdbName.isEmpty()) {
00678 setError(ERR_NO_DB_USED, i18n("Cannot find any database for temporary connection.") );
00679 return false;
00680 }
00681 const bool orig_skip_databaseExists_check_in_useDatabase = d->skip_databaseExists_check_in_useDatabase;
00682 d->skip_databaseExists_check_in_useDatabase = true;
00683 bool ret = useDatabase(tmpdbName, false);
00684 d->skip_databaseExists_check_in_useDatabase = orig_skip_databaseExists_check_in_useDatabase;
00685 if (!ret) {
00686 setError(errorNum(),
00687 i18n("Error during starting temporary connection using \"%1\" database name.")
00688 .arg(tmpdbName) );
00689 return false;
00690 }
00691 }
00692 return true;
00693 }
00694
00695 bool Connection::dropDatabase( const QString &dbName )
00696 {
00697 if (!checkConnected())
00698 return false;
00699
00700 QString dbToDrop;
00701 if (dbName.isEmpty() && d->usedDatabase.isEmpty()) {
00702 if (!m_driver->isFileDriver()
00703 || (m_driver->isFileDriver() && d->conn_data->fileName().isEmpty()) ) {
00704 setError(ERR_NO_NAME_SPECIFIED, i18n("Cannot drop database - name not specified.") );
00705 return false;
00706 }
00707
00708 dbToDrop = d->conn_data->fileName();
00709 }
00710 else {
00711 if (dbName.isEmpty()) {
00712 dbToDrop = d->usedDatabase;
00713 } else {
00714 if (m_driver->isFileDriver())
00715 dbToDrop = QFileInfo(dbName).absFilePath();
00716 else
00717 dbToDrop = dbName;
00718 }
00719 }
00720
00721 if (dbToDrop.isEmpty()) {
00722 setError(ERR_NO_NAME_SPECIFIED, i18n("Cannot delete database - name not specified.") );
00723 return false;
00724 }
00725
00726 if (m_driver->isSystemDatabaseName( dbToDrop )) {
00727 setError(ERR_SYSTEM_NAME_RESERVED, i18n("Cannot delete system database \"%1\".").arg(dbToDrop) );
00728 return false;
00729 }
00730
00731 if (isDatabaseUsed() && d->usedDatabase == dbToDrop) {
00732
00733 if (!closeDatabase())
00734 return false;
00735 }
00736
00737 QString tmpdbName;
00738
00739 if (!useTemporaryDatabaseIfNeeded(tmpdbName))
00740 return false;
00741
00742
00743 bool ret = drv_dropDatabase( dbToDrop );
00744
00745 if (!tmpdbName.isEmpty()) {
00746
00747 if (!closeDatabase())
00748 return false;
00749 }
00750 return ret;
00751 }
00752
00753 QStringList Connection::objectNames(int objType, bool* ok)
00754 {
00755 QStringList list;
00756
00757 if (!checkIsDatabaseUsed()) {
00758 if(ok)
00759 *ok = false;
00760 return list;
00761 }
00762
00763 QString sql;
00764 if (objType==KexiDB::AnyObjectType)
00765 sql = "SELECT o_name FROM kexi__objects";
00766 else
00767 sql = QString::fromLatin1("SELECT o_name FROM kexi__objects WHERE o_type=%1").arg(objType);
00768
00769 Cursor *c = executeQuery(sql);
00770 if (!c) {
00771 if(ok)
00772 *ok = false;
00773 return list;
00774 }
00775
00776 for (c->moveFirst(); !c->eof(); c->moveNext()) {
00777 QString name = c->value(0).toString();
00778 if (KexiUtils::isIdentifier( name )) {
00779 list.append(name);
00780 }
00781 }
00782
00783 if (!deleteCursor(c)) {
00784 if(ok)
00785 *ok = false;
00786 return list;
00787 }
00788
00789 if(ok)
00790 *ok = true;
00791 return list;
00792 }
00793
00794 QStringList Connection::tableNames(bool also_system_tables)
00795 {
00796 bool ok = true;
00797 QStringList list = objectNames(TableObjectType, &ok);
00798 if (also_system_tables && ok) {
00799 list += Connection::kexiDBSystemTableNames();
00800 }
00801 return list;
00802 }
00803
00805 const QStringList& Connection::kexiDBSystemTableNames()
00806 {
00807 if (KexiDB_kexiDBSystemTableNames.isEmpty()) {
00808 KexiDB_kexiDBSystemTableNames
00809 << "kexi__objects"
00810 << "kexi__objectdata"
00811 << "kexi__fields"
00812
00813
00814
00815 << "kexi__db"
00816 ;
00817 }
00818 return KexiDB_kexiDBSystemTableNames;
00819 }
00820
00821 KexiDB::ServerVersionInfo* Connection::serverVersion() const
00822 {
00823 return isConnected() ? &d->serverVersion : 0;
00824 }
00825
00826 KexiDB::DatabaseVersionInfo* Connection::databaseVersion() const
00827 {
00828 return isDatabaseUsed() ? &d->databaseVersion : 0;
00829 }
00830
00831 DatabaseProperties& Connection::databaseProperties()
00832 {
00833 return *d->dbProperties;
00834 }
00835
00836 QValueList<int> Connection::tableIds()
00837 {
00838 return objectIds(KexiDB::TableObjectType);
00839 }
00840
00841 QValueList<int> Connection::queryIds()
00842 {
00843 return objectIds(KexiDB::QueryObjectType);
00844 }
00845
00846 QValueList<int> Connection::objectIds(int objType)
00847 {
00848 QValueList<int> list;
00849
00850 if (!checkIsDatabaseUsed())
00851 return list;
00852
00853 Cursor *c = executeQuery(
00854 QString::fromLatin1("SELECT o_id, o_name FROM kexi__objects WHERE o_type=%1").arg(objType));
00855 if (!c)
00856 return list;
00857 for (c->moveFirst(); !c->eof(); c->moveNext())
00858 {
00859 QString tname = c->value(1).toString();
00860 if (KexiUtils::isIdentifier( tname )) {
00861 list.append(c->value(0).toInt());
00862 }
00863 }
00864
00865 deleteCursor(c);
00866
00867 return list;
00868 }
00869
00870 QString Connection::createTableStatement( const KexiDB::TableSchema& tableSchema ) const
00871 {
00872
00873 QString sql;
00874 sql.reserve(4096);
00875 sql = "CREATE TABLE " + escapeIdentifier(tableSchema.name()) + " (";
00876 bool first=true;
00877 Field::ListIterator it( tableSchema.m_fields );
00878 Field *field;
00879 for (;(field = it.current())!=0; ++it) {
00880 if (first)
00881 first = false;
00882 else
00883 sql += ", ";
00884 QString v = escapeIdentifier(field->name()) + " ";
00885 const bool autoinc = field->isAutoIncrement();
00886 const bool pk = field->isPrimaryKey() || (autoinc && m_driver->beh->AUTO_INCREMENT_REQUIRES_PK);
00887
00888 if (autoinc && m_driver->beh->SPECIAL_AUTO_INCREMENT_DEF) {
00889 if (pk)
00890 v += m_driver->beh->AUTO_INCREMENT_TYPE + " " + m_driver->beh->AUTO_INCREMENT_PK_FIELD_OPTION;
00891 else
00892 v += m_driver->beh->AUTO_INCREMENT_TYPE + " " + m_driver->beh->AUTO_INCREMENT_FIELD_OPTION;
00893 }
00894 else {
00895 if (autoinc && !m_driver->beh->AUTO_INCREMENT_TYPE.isEmpty())
00896 v += m_driver->beh->AUTO_INCREMENT_TYPE;
00897 else
00898 v += m_driver->sqlTypeName(field->type(), field->precision());
00899
00900 if (field->isUnsigned())
00901 v += (" " + m_driver->beh->UNSIGNED_TYPE_KEYWORD);
00902
00903 if (field->isFPNumericType() && field->precision()>0) {
00904 if (field->scale()>0)
00905 v += QString::fromLatin1("(%1,%2)").arg(field->precision()).arg(field->scale());
00906 else
00907 v += QString::fromLatin1("(%1)").arg(field->precision());
00908 }
00909 else if (field->type()==Field::Text && field->length()>0)
00910 v += QString::fromLatin1("(%1)").arg(field->length());
00911
00912 if (autoinc)
00913 v += (" " +
00914 (pk ? m_driver->beh->AUTO_INCREMENT_PK_FIELD_OPTION : m_driver->beh->AUTO_INCREMENT_FIELD_OPTION));
00915 else
00916
00917 if (pk)
00918 v += " PRIMARY KEY";
00919 if (!pk && field->isUniqueKey())
00920 v += " UNIQUE";
00922 if (!autoinc && !pk && field->isNotNull())
00923 v += " NOT NULL";
00924 if (field->defaultValue().isValid()) {
00925 QString valToSQL( m_driver->valueToSQL( field, field->defaultValue() ) );
00926 if (!valToSQL.isEmpty())
00927 v += QString::fromLatin1(" DEFAULT ") + valToSQL;
00928 }
00929 }
00930 sql += v;
00931 }
00932 sql += ")";
00933 return sql;
00934 }
00935
00936
00937 #define C_A(a) , const QVariant& c ## a
00938
00939 #define V_A0 m_driver->valueToSQL( tableSchema.field(0), c0 )
00940 #define V_A(a) +","+m_driver->valueToSQL( \
00941 tableSchema.field(a) ? tableSchema.field(a)->type() : Field::Text, c ## a )
00942
00943
00944
00945
00946
00947 #define C_INS_REC(args, vals) \
00948 bool Connection::insertRecord(KexiDB::TableSchema &tableSchema args) {\
00949 return executeSQL( \
00950 QString("INSERT INTO ") + escapeIdentifier(tableSchema.name()) + " VALUES (" + vals + ")" \
00951 ); \
00952 }
00953
00954 #define C_INS_REC_ALL \
00955 C_INS_REC( C_A(0), V_A0 ) \
00956 C_INS_REC( C_A(0) C_A(1), V_A0 V_A(1) ) \
00957 C_INS_REC( C_A(0) C_A(1) C_A(2), V_A0 V_A(1) V_A(2) ) \
00958 C_INS_REC( C_A(0) C_A(1) C_A(2) C_A(3), V_A0 V_A(1) V_A(2) V_A(3) ) \
00959 C_INS_REC( C_A(0) C_A(1) C_A(2) C_A(3) C_A(4), V_A0 V_A(1) V_A(2) V_A(3) V_A(4) ) \
00960 C_INS_REC( C_A(0) C_A(1) C_A(2) C_A(3) C_A(4) C_A(5), V_A0 V_A(1) V_A(2) V_A(3) V_A(4) V_A(5) ) \
00961 C_INS_REC( C_A(0) C_A(1) C_A(2) C_A(3) C_A(4) C_A(5) C_A(6), V_A0 V_A(1) V_A(2) V_A(3) V_A(4) V_A(5) V_A(6) ) \
00962 C_INS_REC( C_A(0) C_A(1) C_A(2) C_A(3) C_A(4) C_A(5) C_A(6) C_A(7), V_A0 V_A(1) V_A(2) V_A(3) V_A(4) V_A(5) V_A(6) V_A(7) )
00963
00964 C_INS_REC_ALL
00965
00966 #undef V_A0
00967 #undef V_A
00968 #undef C_INS_REC
00969
00970 #define V_A0 value += m_driver->valueToSQL( flist->first(), c0 );
00971 #define V_A( a ) value += ("," + m_driver->valueToSQL( flist->next(), c ## a ));
00972
00973
00974
00975 #define C_INS_REC(args, vals) \
00976 bool Connection::insertRecord(FieldList& fields args) \
00977 { \
00978 QString value; \
00979 Field::List *flist = fields.fields(); \
00980 vals \
00981 return executeSQL( \
00982 QString("INSERT INTO ") + \
00983 ((fields.fields()->first() && fields.fields()->first()->table()) ? \
00984 escapeIdentifier(fields.fields()->first()->table()->name()) : \
00985 "??") \
00986 + "(" + fields.sqlFieldsList(m_driver) + ") VALUES (" + value + ")" \
00987 ); \
00988 }
00989
00990 C_INS_REC_ALL
00991
00992 #undef C_A
00993 #undef V_A
00994 #undef V_ALAST
00995 #undef C_INS_REC
00996 #undef C_INS_REC_ALL
00997
00998 bool Connection::insertRecord(TableSchema &tableSchema, QValueList<QVariant>& values)
00999 {
01000
01001 Field::List *fields = tableSchema.fields();
01002 Field *f = fields->first();
01003
01004
01005 m_sql = QString::null;
01006 QValueList<QVariant>::ConstIterator it = values.constBegin();
01007
01008 while (f && (it!=values.end())) {
01009 if (m_sql.isEmpty())
01010 m_sql = QString("INSERT INTO ") +
01011 escapeIdentifier(tableSchema.name()) +
01012 " VALUES (";
01013 else
01014 m_sql += ",";
01015 m_sql += m_driver->valueToSQL( f, *it );
01016
01017 ++it;
01018 f=fields->next();
01019 }
01020 m_sql += ")";
01021
01022
01023 return executeSQL(m_sql);
01024 }
01025
01026 bool Connection::insertRecord(FieldList& fields, QValueList<QVariant>& values)
01027 {
01028
01029 Field::List *flist = fields.fields();
01030 Field *f = flist->first();
01031 if (!f)
01032 return false;
01033
01034
01035 m_sql = QString::null;
01036 QValueList<QVariant>::ConstIterator it = values.constBegin();
01037
01038 while (f && (it!=values.constEnd())) {
01039 if (m_sql.isEmpty())
01040 m_sql = QString("INSERT INTO ") +
01041 escapeIdentifier(flist->first()->table()->name()) + "(" +
01042 fields.sqlFieldsList(m_driver) + ") VALUES (";
01043 else
01044 m_sql += ",";
01045 m_sql += m_driver->valueToSQL( f, *it );
01046
01047 ++it;
01048 f=flist->next();
01049 }
01050 m_sql += ")";
01051
01052 return executeSQL(m_sql);
01053 }
01054
01055 bool Connection::executeSQL( const QString& statement )
01056 {
01057 m_sql = statement;
01058 if (!drv_executeSQL( m_sql )) {
01059 m_errMsg = QString::null;
01060 m_errorSql = statement;
01061 setError(this, ERR_SQL_EXECUTION_ERROR, i18n("Error while executing SQL statement."));
01062 return false;
01063 }
01064 return true;
01065 }
01066
01067 QString Connection::selectStatement( KexiDB::QuerySchema& querySchema,
01068 const QValueList<QVariant>& params,
01069 const SelectStatementOptions& options) const
01070 {
01071
01072
01073
01074
01075
01076 if (!querySchema.statement().isEmpty())
01077 return querySchema.statement();
01078
01081 Field *f;
01082 uint number = 0;
01083 bool singleTable = querySchema.tables()->count() <= 1;
01084 if (singleTable) {
01085
01086 for (Field::ListIterator it = querySchema.fieldsIterator(); (f = it.current()); ++it, number++) {
01087 if (querySchema.isColumnVisible(number) && f->table() && f->table()->lookupFieldSchema( *f )) {
01088
01089 singleTable = false;
01090 break;
01091 }
01092 }
01093 }
01094
01095 QString sql;
01096 sql.reserve(4096);
01097
01098 QString s_additional_joins;
01099 QString s_additional_fields;
01100 uint internalUniqueTableAliasNumber = 0;
01101 number = 0;
01102 for (Field::ListIterator it = querySchema.fieldsIterator(); (f = it.current()); ++it, number++) {
01103 if (querySchema.isColumnVisible(number)) {
01104 if (!sql.isEmpty())
01105 sql += QString::fromLatin1(", ");
01106
01107 if (f->isQueryAsterisk()) {
01108 if (!singleTable && static_cast<QueryAsterisk*>(f)->isSingleTableAsterisk())
01109 sql += escapeIdentifier(f->table()->name(), options.identifierEscaping) +
01110 QString::fromLatin1(".*");
01111 else
01112 sql += QString::fromLatin1("*");
01113 }
01114 else {
01115 if (f->isExpression()) {
01116 sql += f->expression()->toString();
01117 }
01118 else {
01119 if (!f->table())
01120 return QString::null;
01121
01122 QString tableName;
01123 int tablePosition = querySchema.tableBoundToColumn(number);
01124 if (tablePosition>=0)
01125 tableName = querySchema.tableAlias(tablePosition);
01126 if (tableName.isEmpty())
01127 tableName = f->table()->name();
01128
01129 if (!singleTable) {
01130 sql += (escapeIdentifier(tableName, options.identifierEscaping) + ".");
01131 }
01132 sql += escapeIdentifier(f->name(), options.identifierEscaping);
01133 }
01134 QString aliasString = QString(querySchema.columnAlias(number));
01135 if (!aliasString.isEmpty())
01136 sql += (QString::fromLatin1(" AS ") + aliasString);
01138 }
01139 LookupFieldSchema *lookupFieldSchema = f->table() ? f->table()->lookupFieldSchema( *f ) : 0;
01140 if (lookupFieldSchema) {
01141
01142
01143
01144
01145 LookupFieldSchema::RowSource& rowSource = lookupFieldSchema->rowSource();
01146 if (rowSource.type()==LookupFieldSchema::RowSource::Table) {
01147 TableSchema *lookupTable = querySchema.connection()->tableSchema( rowSource.name() );
01148 Field *visibleField = 0;
01149 Field *boundField = 0;
01150 if (lookupTable && lookupFieldSchema->boundColumn()>=0
01151 && (uint)lookupFieldSchema->boundColumn() < lookupTable->fieldCount()
01152 && (visibleField = lookupTable->field( lookupFieldSchema->visibleColumn()))
01153 && (boundField = lookupTable->field( lookupFieldSchema->boundColumn() )))
01154 {
01155
01156 if (!s_additional_joins.isEmpty())
01157 s_additional_joins += QString::fromLatin1(" ");
01158 QString internalUniqueTableAlias( QString("__kexidb_") + lookupTable->name() + "_"
01159 + QString::number(internalUniqueTableAliasNumber++) );
01160 s_additional_joins += QString("LEFT OUTER JOIN %1 AS %2 ON %3.%4=%5.%6")
01161 .arg(escapeIdentifier(lookupTable->name(), options.identifierEscaping))
01162 .arg(internalUniqueTableAlias)
01163 .arg(escapeIdentifier(f->table()->name(), options.identifierEscaping))
01164 .arg(escapeIdentifier(f->name(), options.identifierEscaping))
01165 .arg(internalUniqueTableAlias)
01166 .arg(escapeIdentifier(boundField->name(), options.identifierEscaping));
01167
01168
01169
01170 if (!querySchema.table( visibleField->table()->name() )) {
01171
01172
01173
01174
01175
01176
01177 }
01178 if (!s_additional_fields.isEmpty())
01179 s_additional_fields += QString::fromLatin1(", ");
01180 s_additional_fields += (internalUniqueTableAlias + "."
01181 + escapeIdentifier(visibleField->name(), options.identifierEscaping));
01182
01183 }
01184 }
01185 }
01186 }
01187 }
01188
01189
01190 if (!s_additional_fields.isEmpty())
01191 sql += (QString::fromLatin1(", ") + s_additional_fields);
01192
01193 if (options.alsoRetrieveROWID) {
01194 QString s;
01195 if (!sql.isEmpty())
01196 s = QString::fromLatin1(", ");
01197 if (querySchema.masterTable())
01198 s += (escapeIdentifier(querySchema.masterTable()->name())+".");
01199 s += m_driver->beh->ROW_ID_FIELD_NAME;
01200 sql += s;
01201 }
01202
01203 sql.prepend("SELECT ");
01204 TableSchema::List* tables = querySchema.tables();
01205 if (tables && !tables->isEmpty()) {
01206 sql += QString::fromLatin1(" FROM ");
01207 QString s_from;
01208 TableSchema *table;
01209 number = 0;
01210 for (TableSchema::ListIterator it(*tables); (table = it.current());
01211 ++it, number++)
01212 {
01213 if (!s_from.isEmpty())
01214 s_from += QString::fromLatin1(", ");
01215 s_from += escapeIdentifier(table->name(), options.identifierEscaping);
01216 QString aliasString = QString(querySchema.tableAlias(number));
01217 if (!aliasString.isEmpty())
01218 s_from += (QString::fromLatin1(" AS ") + aliasString);
01219 }
01220
01221
01222
01223
01224
01225 sql += s_from;
01226 }
01227 QString s_where;
01228 s_where.reserve(4096);
01229
01230
01231 if (!s_additional_joins.isEmpty()) {
01232 sql += QString::fromLatin1(" ") + s_additional_joins + QString::fromLatin1(" ");
01233 }
01234
01235
01236
01237
01238 Relationship *rel;
01239 bool wasWhere = false;
01240 for (Relationship::ListIterator it(*querySchema.relationships()); (rel = it.current()); ++it) {
01241 if (s_where.isEmpty()) {
01242 wasWhere = true;
01243 }
01244 else
01245 s_where += QString::fromLatin1(" AND ");
01246 Field::Pair *pair;
01247 QString s_where_sub;
01248 for (QPtrListIterator<Field::Pair> p_it(*rel->fieldPairs()); (pair = p_it.current()); ++p_it) {
01249 if (!s_where_sub.isEmpty())
01250 s_where_sub += QString::fromLatin1(" AND ");
01251 s_where_sub += (
01252 escapeIdentifier(pair->first->table()->name(), options.identifierEscaping) +
01253 QString::fromLatin1(".") +
01254 escapeIdentifier(pair->first->name(), options.identifierEscaping) +
01255 QString::fromLatin1(" = ") +
01256 escapeIdentifier(pair->second->table()->name(), options.identifierEscaping) +
01257 QString::fromLatin1(".") +
01258 escapeIdentifier(pair->second->name(), options.identifierEscaping));
01259 }
01260 if (rel->fieldPairs()->count()>1) {
01261 s_where_sub.prepend("(");
01262 s_where_sub += QString::fromLatin1(")");
01263 }
01264 s_where += s_where_sub;
01265 }
01266
01267 if (querySchema.whereExpression()) {
01268 QuerySchemaParameterValueListIterator paramValuesIt(*m_driver, params);
01269 QuerySchemaParameterValueListIterator *paramValuesItPtr = params.isEmpty() ? 0 : ¶mValuesIt;
01270 if (wasWhere) {
01271
01272 s_where = "(" + s_where + ") AND (" + querySchema.whereExpression()->toString(paramValuesItPtr) + ")";
01273 }
01274 else {
01275 s_where = querySchema.whereExpression()->toString(paramValuesItPtr);
01276 }
01277 }
01278 if (!s_where.isEmpty())
01279 sql += QString::fromLatin1(" WHERE ") + s_where;
01281
01282
01283
01284 QString orderByString( querySchema.orderByColumnList().toSQLString(!singleTable) );
01285 if (!orderByString.isEmpty())
01286 sql += (" ORDER BY " + orderByString);
01287
01288
01289 return sql;
01290 }
01291
01292 QString Connection::selectStatement( KexiDB::TableSchema& tableSchema,
01293 const SelectStatementOptions& options) const
01294 {
01295 return selectStatement( *tableSchema.query(), options );
01296 }
01297
01298 Field* Connection::findSystemFieldName(KexiDB::FieldList* fieldlist)
01299 {
01300 Field *f = fieldlist->fields()->first();
01301 while (f) {
01302 if (m_driver->isSystemFieldName( f->name() ))
01303 return f;
01304 f = fieldlist->fields()->next();
01305 }
01306 return 0;
01307 }
01308
01309 Q_ULLONG Connection::lastInsertedAutoIncValue(const QString& aiFieldName, const QString& tableName,
01310 Q_ULLONG* ROWID)
01311 {
01312 Q_ULLONG row_id = drv_lastInsertRowID();
01313 if (ROWID)
01314 *ROWID = row_id;
01315 if (m_driver->beh->ROW_ID_FIELD_RETURNS_LAST_AUTOINCREMENTED_VALUE) {
01316 return row_id;
01317 }
01318 RowData rdata;
01319 if (row_id<=0 || true!=querySingleRecord(
01320 QString::fromLatin1("SELECT ") + tableName + QString::fromLatin1(".") + aiFieldName + QString::fromLatin1(" FROM ") + tableName
01321 + QString::fromLatin1(" WHERE ") + m_driver->beh->ROW_ID_FIELD_NAME + QString::fromLatin1("=") + QString::number(row_id), rdata))
01322 {
01323
01324 return (Q_ULLONG)-1;
01325 }
01326 return rdata[0].toULongLong();
01327 }
01328
01329 Q_ULLONG Connection::lastInsertedAutoIncValue(const QString& aiFieldName,
01330 const KexiDB::TableSchema& table, Q_ULLONG* ROWID)
01331 {
01332 return lastInsertedAutoIncValue(aiFieldName,table.name(), ROWID);
01333 }
01334
01336 static FieldList* createFieldListForKexi__Fields(TableSchema *kexi__fieldsSchema)
01337 {
01338 if (!kexi__fieldsSchema)
01339 return 0;
01340 return kexi__fieldsSchema->subList(
01341 "t_id",
01342 "f_type",
01343 "f_name",
01344 "f_length",
01345 "f_precision",
01346 "f_constraints",
01347 "f_options",
01348 "f_default",
01349 "f_order",
01350 "f_caption",
01351 "f_help"
01352 );
01353 }
01354
01356 void buildValuesForKexi__Fields(QValueList<QVariant>& vals, Field* f)
01357 {
01358 vals.clear();
01359 vals
01360 << QVariant(f->table()->id())
01361 << QVariant(f->type())
01362 << QVariant(f->name())
01363 << QVariant(f->isFPNumericType() ? f->scale() : f->length())
01364 << QVariant(f->isFPNumericType() ? f->precision() : 0)
01365 << QVariant(f->constraints())
01366 << QVariant(f->options())
01367
01368
01369 << (f->defaultValue().isNull()
01370 ? QVariant() : QVariant(KexiDB::variantToString( f->defaultValue() )))
01371 << QVariant(f->order())
01372 << QVariant(f->caption())
01373 << QVariant(f->description());
01374 }
01375
01376 bool Connection::storeMainFieldSchema(Field *field)
01377 {
01378 if (!field || !field->table())
01379 return false;
01380 FieldList *fl = createFieldListForKexi__Fields(d->tables_byname["kexi__fields"]);
01381 if (!fl)
01382 return false;
01383
01384 QValueList<QVariant> vals;
01385 buildValuesForKexi__Fields(vals, field);
01386 QValueList<QVariant>::ConstIterator valsIt = vals.constBegin();
01387 Field *f;
01388 bool first = true;
01389 QString sql = "UPDATE kexi__fields SET ";
01390 for (Field::ListIterator it( fl->fieldsIterator() ); (f = it.current()); ++it, ++valsIt) {
01391 sql.append( (first ? QString::null : QString(", ")) +
01392 f->name() + "=" + m_driver->valueToSQL( f, *valsIt ) );
01393 if (first)
01394 first = false;
01395 }
01396 delete fl;
01397
01398 sql.append(QString(" WHERE t_id=") + QString::number( field->table()->id() )
01399 + " AND f_name=" + m_driver->valueToSQL( Field::Text, field->name() ) );
01400 return executeSQL( sql );
01401 }
01402
01403 #define createTable_ERR \
01404 { KexiDBDbg << "Connection::createTable(): ERROR!" <<endl; \
01405 setError(this, i18n("Creating table failed.")); \
01406 rollbackAutoCommitTransaction(tg.transaction()); \
01407 return false; }
01408
01409
01411
01418 bool Connection::createTable( KexiDB::TableSchema* tableSchema, bool replaceExisting )
01419 {
01420 if (!tableSchema || !checkIsDatabaseUsed())
01421 return false;
01422
01423
01424 if (tableSchema->fieldCount()<1) {
01425 clearError();
01426 setError(ERR_CANNOT_CREATE_EMPTY_OBJECT, i18n("Cannot create table without fields."));
01427 return false;
01428 }
01429 const bool internalTable = dynamic_cast<InternalTableSchema*>(tableSchema);
01430
01431 const QString &tableName = tableSchema->name().lower();
01432
01433 if (!internalTable) {
01434 if (m_driver->isSystemObjectName( tableName )) {
01435 clearError();
01436 setError(ERR_SYSTEM_NAME_RESERVED, i18n("System name \"%1\" cannot be used as table name.")
01437 .arg(tableSchema->name()));
01438 return false;
01439 }
01440
01441 Field *sys_field = findSystemFieldName(tableSchema);
01442 if (sys_field) {
01443 clearError();
01444 setError(ERR_SYSTEM_NAME_RESERVED,
01445 i18n("System name \"%1\" cannot be used as one of fields in \"%2\" table.")
01446 .arg(sys_field->name()).arg(tableName));
01447 return false;
01448 }
01449 }
01450
01451 bool previousSchemaStillKept = false;
01452
01453 KexiDB::TableSchema *existingTable = 0;
01454 if (replaceExisting) {
01455
01456 existingTable = d->tables_byname[tableName];
01457 if (existingTable) {
01458 if (existingTable == tableSchema) {
01459 clearError();
01460 setError(ERR_OBJECT_EXISTS,
01461 i18n("Could not create the same table \"%1\" twice.").arg(tableSchema->name()) );
01462 return false;
01463 }
01464
01465 if (existingTable->id()>0)
01466 tableSchema->m_id = existingTable->id();
01467 previousSchemaStillKept = true;
01468 if (!dropTable( existingTable, false ))
01469 return false