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