20#include <kexidb/connection.h>
23#include "connection_p.h"
24#include "connectiondata.h"
27#include "schemadata.h"
28#include "tableschema.h"
29#include "relationship.h"
30#include "transaction.h"
33#include "roweditbuffer.h"
35#include "dbproperties.h"
36#include "lookupfieldschema.h"
37#include "parser/parser.h"
39#include <kexiutils/utils.h>
40#include <kexiutils/identifier.h>
43#include <tqfileinfo.h>
44#include <tqguardedptr.h>
50#define KEXIDB_EXTENDED_TABLE_SCHEMA_VERSION 1
56Connection::SelectStatementOptions::SelectStatementOptions()
57 : identifierEscaping( Driver::EscapeDriver| Driver::EscapeAsNecessary)
58 , alsoRetrieveROWID(false)
59 , addVisibleLookupColumns(true)
63Connection::SelectStatementOptions::~SelectStatementOptions()
69ConnectionInternal::ConnectionInternal( Connection *conn)
74ConnectionInternal::~ConnectionInternal()
80class ConnectionPrivate
85 , conn_data(&conn_data)
86 , tableSchemaChangeListeners(1009)
88 , tables_byname(1009, false)
89 , queries_byname(1009, false)
90 , kexiDBSystemTables(101)
91 , dont_remove_transactions(false)
92 , skip_databaseExists_check_in_useDatabase(false)
93 , default_trans_started_inside(false)
97 tableSchemaChangeListeners.setAutoDelete( true);
98 obsoleteQueries.setAutoDelete( true);
100 tables.setAutoDelete( true);
101 tables_byname.setAutoDelete( false);
102 kexiDBSystemTables.setAutoDelete( true);
103 queries.setAutoDelete( true);
104 queries_byname.setAutoDelete( false);
108 queries.resize(1009);
115 void errorInvalidDBContents( const TQString& details) {
116 conn-> setError( ERR_INVALID_DATABASE_CONTENTS, i18n( "Invalid database contents. ")+details);
119 TQString strItIsASystemObject() const {
120 return i18n( "It is a system object.");
123 inline Parser *parser() { return m_parser ? m_parser : (m_parser = new Parser(conn)); }
126 TQGuardedPtr<ConnectionData> conn_data;
133 TQValueList<Transaction> transactions;
135 TQPtrDict< TQPtrList<Connection::TableSchemaChangeListenerInterface> > tableSchemaChangeListeners;
139 TQPtrList<QuerySchema> obsoleteQueries;
151 TQIntDict<TableSchema> tables;
152 TQDict<TableSchema> tables_byname;
153 TQIntDict<QuerySchema> queries;
154 TQDict<QuerySchema> queries_byname;
157 TQPtrDict<TableSchema> kexiDBSystemTables;
162 TQString availableDatabaseName;
163 TQString usedDatabase;
167 bool dont_remove_transactions : 1;
171 bool skip_databaseExists_check_in_useDatabase : 1;
181 bool default_trans_started_inside : 1;
183 bool isConnected : 1;
197TQStringList KexiDB_kexiDBSystemTableNames;
202 ,d(new ConnectionPrivate(this, conn_data))
204 ,m_destructor_started(false)
212 m_sql.reserve(0x4000);
219 m_driver->d->connections.take( this );
224 m_destructor_started = true;
226 delete d->dbProperties;
249 if (d->isConnected) {
250 setError(ERR_ALREADY_CONNECTED, i18n( "Connection already established.") );
254 d->serverVersion.clear();
255 if (!(d->isConnected = drv_connect(d->serverVersion))) {
257 i18n( "Could not open \"%1\" project file.").arg(TQDir::convertSeparators(d->conn_data->fileName()))
258 : i18n( "Could not connect to \"%1\" database server.").arg(d->conn_data->serverInfoString()) );
260 return d->isConnected;
285 d->isConnected = false;
291 return d->isConnected;
296 if (d->isConnected) {
300 setError(ERR_NO_CONNECTION, i18n( "Not connected to the database server.") );
310 setError(ERR_NO_DB_USED, i18n( "Currently no database is used.") );
316 KexiDBDbg << "Connection::databaseNames("<<also_system_db<< ")"<< endl;
318 return TQStringList();
323 return TQStringList();
325 TQStringList list, non_system_list;
329 if (!tmpdbName.isEmpty()) {
332 return TQStringList();
336 return TQStringList();
341 for (TQStringList::ConstIterator it = list.constBegin(); it!=list.constEnd(); ++it) {
342 KexiDBDbg << "Connection::databaseNames(): " << *it << endl;
344 KexiDBDbg << "add " << *it << endl;
345 non_system_list << (*it);
348 return non_system_list;
364 if (list.find( dbName )==list.end()) {
366 setError(ERR_OBJECT_NOT_FOUND, i18n( "The database \"%1\" does not exist.").arg(dbName));
383 TQFileInfo file(d->conn_data->fileName());
384 if (!file.exists() || ( !file.isFile() && !file.isSymLink()) ) {
386 setError(ERR_OBJECT_NOT_FOUND, i18n( "Database file \"%1\" does not exist.")
387 .arg(TQDir::convertSeparators(d->conn_data->fileName())) );
390 if (!file.isReadable()) {
392 setError(ERR_ACCESS_RIGHTS, i18n( "Database file \"%1\" is not readable.")
393 .arg(TQDir::convertSeparators(d->conn_data->fileName())) );
396 if (!file.isWritable()) {
398 setError(ERR_ACCESS_RIGHTS, i18n( "Database file \"%1\" is not writable.")
399 .arg(TQDir::convertSeparators(d->conn_data->fileName())) );
407 const bool orig_skip_databaseExists_check_in_useDatabase = d->skip_databaseExists_check_in_useDatabase;
408 d->skip_databaseExists_check_in_useDatabase = true;
410 d->skip_databaseExists_check_in_useDatabase = orig_skip_databaseExists_check_in_useDatabase;
416 if (!tmpdbName.isEmpty()) {
425#define createDatabase_CLOSE \
426 { if (!closeDatabase()) { \
427 setError(i18n("Database \"%1\" created but could not be closed after creation.").arg(dbName) ); \
431#define createDatabase_ERROR \
432 { createDatabase_CLOSE; return false; }
441 setError(ERR_OBJECT_EXISTS, i18n( "Database \"%1\" already exists.").arg(dbName) );
446 i18n( "Cannot create database \"%1\". This name is reserved for system database.").arg(dbName) );
451 d->conn_data->setFileName( dbName );
461 setError(i18n( "Error creating database \"%1\" on the server.").arg(dbName) );
466 if (!tmpdbName.isEmpty()) {
472 if (!tmpdbName.isEmpty() || !m_driver->d->isDBOpenedAfterCreate) {
475 setError(i18n( "Database \"%1\" created but could not be opened.").arg(dbName) );
481 d->usedDatabase = dbName;
499 for (TQPtrDictIterator<TableSchema> it(d->kexiDBSystemTables); it.current(); ++it) {
501 createDatabase_ERROR;
522 createDatabase_ERROR;
525 createDatabase_ERROR;
528 createDatabase_ERROR;
530 createDatabase_CLOSE;
534#undef createDatabase_CLOSE
535#undef createDatabase_ERROR
541 KexiDBDbg << "Connection::useDatabase(" << dbName << "," << kexiCompatible << ")" << endl;
545 if (dbName.isEmpty())
547 TQString my_dbName = dbName;
553 if (d->usedDatabase == my_dbName)
556 if (!d->skip_databaseExists_check_in_useDatabase) {
564 d->usedDatabase = "";
567 if (cancelled && *cancelled)
569 TQString msg(i18n( "Opening database \"%1\" failed.").arg( my_dbName ));
586 num = d->dbProperties->value( "kexidb_major_ver").toInt(&ok);
589 d->databaseVersion.major = num;
595 num = d->dbProperties->value( "kexidb_minor_ver").toInt(&ok);
598 d->databaseVersion.minor = num;
607 if (m_driver->versionMajor()!=KexiDB::versionMajor()) {
608 setError(ERR_INCOMPAT_DATABASE_VERSION,
609 i18n( "Database version (%1) does not match Kexi application's version (%2)")
610 .arg( TQString( "%1.%2").arg(versionMajor()).arg(versionMinor()) )
611 .arg( TQString( "%1.%2").arg(KexiDB::versionMajor()).arg(KexiDB::versionMinor()) ) );
614 if (m_driver->versionMinor()!=KexiDB::versionMinor()) {
620 d->usedDatabase = my_dbName;
626 if (d->usedDatabase.isEmpty())
636 TQValueList<Transaction>::ConstIterator it;
637 d->dont_remove_transactions= true;
638 for (it=d->transactions.constBegin(); it!= d->transactions.constEnd(); ++it) {
643 KexiDBDbg << "Connection::closeDatabase(): transaction rolled back!" << endl;
644 KexiDBDbg << "Connection::closeDatabase(): trans.refcount==" <<
645 ((*it).m_data ? TQString::number((*it).m_data->refcount) : "(null)") << endl;
648 d->dont_remove_transactions= false;
649 d->transactions.clear();
656 d->kexiDBSystemTables.clear();
662 d->usedDatabase = "";
669 return d->usedDatabase;
674 if (!m_driver-> isFileDriver() && m_driver->beh->USING_DATABASE_REQUIRED_TO_CONNECT
678 if (tmpdbName.isEmpty()) {
679 setError(ERR_NO_DB_USED, i18n( "Cannot find any database for temporary connection.") );
682 const bool orig_skip_databaseExists_check_in_useDatabase = d->skip_databaseExists_check_in_useDatabase;
683 d->skip_databaseExists_check_in_useDatabase = true;
685 d->skip_databaseExists_check_in_useDatabase = orig_skip_databaseExists_check_in_useDatabase;
688 i18n( "Error during starting temporary connection using \"%1\" database name.")
702 if (dbName.isEmpty() && d->usedDatabase.isEmpty()) {
704 || (m_driver-> isFileDriver() && d->conn_data->fileName().isEmpty()) ) {
705 setError(ERR_NO_NAME_SPECIFIED, i18n( "Cannot drop database - name not specified.") );
709 dbToDrop = d->conn_data->fileName();
712 if (dbName.isEmpty()) {
713 dbToDrop = d->usedDatabase;
716 dbToDrop = TQFileInfo(dbName).absFilePath();
722 if (dbToDrop.isEmpty()) {
723 setError(ERR_NO_NAME_SPECIFIED, i18n( "Cannot delete database - name not specified.") );
728 setError(ERR_SYSTEM_NAME_RESERVED, i18n( "Cannot delete system database \"%1\".").arg(dbToDrop) );
746 if (!tmpdbName.isEmpty()) {
766 sql = "SELECT o_name FROM kexi__objects";
768 sql = TQString::fromLatin1( "SELECT o_name FROM kexi__objects WHERE o_type=%1").arg(objType);
778 TQString name = c-> value(0).toString();
798 TQStringList list = objectNames(TableObjectType, &ok);
799 if (also_system_tables && ok) {
808 if (KexiDB_kexiDBSystemTableNames.isEmpty()) {
809 KexiDB_kexiDBSystemTableNames
811 << "kexi__objectdata"
819 return KexiDB_kexiDBSystemTableNames;
834 return *d->dbProperties;
839 return objectIds(KexiDB::TableObjectType);
844 return objectIds(KexiDB::QueryObjectType);
849 TQValueList<int> list;
855 TQString::fromLatin1( "SELECT o_id, o_name FROM kexi__objects WHERE o_type=%1").arg(objType));
860 TQString tname = c-> value(1).toString();
862 list.append(c-> value(0).toInt());
880 for (;(field = it.current())!=0; ++it) {
887 const bool pk = field-> isPrimaryKey() || (autoinc && m_driver->beh->AUTO_INCREMENT_REQUIRES_PK);
889 if (autoinc && m_driver->beh->SPECIAL_AUTO_INCREMENT_DEF) {
891 v += m_driver->beh->AUTO_INCREMENT_TYPE + " " + m_driver->beh->AUTO_INCREMENT_PK_FIELD_OPTION;
893 v += m_driver->beh->AUTO_INCREMENT_TYPE + " " + m_driver->beh->AUTO_INCREMENT_FIELD_OPTION;
896 if (autoinc && !m_driver->beh->AUTO_INCREMENT_TYPE.isEmpty())
897 v += m_driver->beh->AUTO_INCREMENT_TYPE;
902 v += ( " " + m_driver->beh->UNSIGNED_TYPE_KEYWORD);
905 if (field-> scale()>0)
906 v += TQString::fromLatin1( "(%1,%2)").arg(field-> precision()).arg(field-> scale());
908 v += TQString::fromLatin1( "(%1)").arg(field-> precision());
911 v += TQString::fromLatin1( "(%1)").arg(field-> length());
915 (pk ? m_driver->beh->AUTO_INCREMENT_PK_FIELD_OPTION : m_driver->beh->AUTO_INCREMENT_FIELD_OPTION));
923 if (!autoinc && !pk && field-> isNotNull())
927 if (!valToSQL.isEmpty())
928 v += TQString::fromLatin1( " DEFAULT ") + valToSQL;
938#define C_A(a) , const TQVariant& c ## a
940#define V_A0 m_driver->valueToSQL( tableSchema.field(0), c0 )
941#define V_A(a) +","+m_driver->valueToSQL( \
942 tableSchema.field(a) ? tableSchema.field(a)->type() : Field::Text, c ## a )
948#define C_INS_REC(args, vals) \
949 bool Connection::insertRecord(KexiDB::TableSchema &tableSchema args) {\
951 TQString("INSERT INTO ") + escapeIdentifier(tableSchema.name()) + " VALUES (" + vals + ")" \
955#define C_INS_REC_ALL \
956C_INS_REC( C_A(0), V_A0 ) \
957C_INS_REC( C_A(0) C_A(1), V_A0 V_A(1) ) \
958C_INS_REC( C_A(0) C_A(1) C_A(2), V_A0 V_A(1) V_A(2) ) \
959C_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) ) \
960C_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) ) \
961C_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) ) \
962C_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) ) \
963C_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) )
971#define V_A0 value += m_driver->valueToSQL( flist->first(), c0 );
972#define V_A( a ) value += ("," + m_driver->valueToSQL( flist->next(), c ## a ));
976#define C_INS_REC(args, vals) \
977 bool Connection::insertRecord(FieldList& fields args) \
980 Field::List *flist = fields.fields(); \
983 TQString("INSERT INTO ") + \
984 ((fields.fields()->first() && fields.fields()->first()->table()) ? \
985 escapeIdentifier(fields.fields()->first()->table()->name()) : \
987 + "(" + fields.sqlFieldsList(m_driver) + ") VALUES (" + value + ")" \
999bool Connection::insertRecord( TableSchema &tableSchema, TQValueList<TQVariant>& values)
1003 Field *f = fields->first();
1007 TQValueList<TQVariant>::ConstIterator it = values.constBegin();
1009 while (f && (it!=values.end())) {
1010 if ( m_sql.isEmpty())
1011 m_sql = TQString( "INSERT INTO ") +
1027bool Connection::insertRecord( FieldList& fields, TQValueList<TQVariant>& values)
1031 Field *f = flist->first();
1037 TQValueList<TQVariant>::ConstIterator it = values.constBegin();
1039 while (f && (it!=values.constEnd())) {
1040 if ( m_sql.isEmpty())
1041 m_sql = TQString( "INSERT INTO ") +
1060 m_errMsg = TQString();
1061 m_errorSql = statement;
1062 setError( this, ERR_SQL_EXECUTION_ERROR, i18n( "Error while executing SQL statement."));
1069 const TQValueList<TQVariant>& params,
1090 singleTable = false;
1099 TQString s_additional_joins;
1100 TQString s_additional_fields;
1101 uint internalUniqueTableAliasNumber = 0;
1102 uint internalUniqueQueryAliasNumber = 0;
1104 TQPtrList<QuerySchema> subqueries_for_lookup_data;
1105 TQString kexidb_subquery_prefix( "__kexidb_subquery_");
1109 sql += TQString::fromLatin1( ", ");
1114 TQString::fromLatin1( ".*");
1116 sql += TQString::fromLatin1( "*");
1128 if (tablePosition>=0)
1130 if (tableName.isEmpty())
1131 tableName = f-> table()->name();
1139 if (!aliasString.isEmpty())
1140 sql += (TQString::fromLatin1( " AS ") + aliasString);
1145 if (lookupFieldSchema && lookupFieldSchema-> boundColumn()>=0) {
1154 Field *boundField = 0;
1161 if (!s_additional_joins.isEmpty())
1162 s_additional_joins += TQString::fromLatin1( " ");
1163 TQString internalUniqueTableAlias( TQString( "__kexidb_") + lookupTable->name() + "_"
1164 + TQString::number(internalUniqueTableAliasNumber++) );
1165 s_additional_joins += TQString( "LEFT OUTER JOIN %1 AS %2 ON %3.%4=%5.%6")
1167 .arg(internalUniqueTableAlias)
1170 .arg(internalUniqueTableAlias)
1185 if (!s_additional_fields.isEmpty())
1186 s_additional_fields += TQString::fromLatin1( ", ");
1194 delete visibleColumns;
1199 KexiDBWarn << "Connection::selectStatement(): !lookupQuery" << endl;
1202 const QueryColumnInfo::Vector fieldsExpanded( lookupQuery-> fieldsExpanded() );
1203 if ((uint)lookupFieldSchema-> boundColumn() >= fieldsExpanded.count()) {
1204 KexiDBWarn << "Connection::selectStatement(): (uint)lookupFieldSchema->boundColumn() >= fieldsExpanded.count()" << endl;
1208 if (!boundColumnInfo) {
1209 KexiDBWarn << "Connection::selectStatement(): !boundColumnInfo" << endl;
1212 Field *boundField = boundColumnInfo->field;
1214 KexiDBWarn << "Connection::selectStatement(): !boundField" << endl;
1218 if (!s_additional_joins.isEmpty())
1219 s_additional_joins += TQString::fromLatin1( " ");
1220 TQString internalUniqueQueryAlias(
1221 kexidb_subquery_prefix + lookupQuery->name() + "_"
1222 + TQString::number(internalUniqueQueryAliasNumber++) );
1223 s_additional_joins += TQString( "LEFT OUTER JOIN (%1) AS %2 ON %3.%4=%5.%6")
1225 .arg(internalUniqueQueryAlias)
1228 .arg(internalUniqueQueryAlias)
1231 if (!s_additional_fields.isEmpty())
1232 s_additional_fields += TQString::fromLatin1( ", ");
1233 const TQValueList<uint> visibleColumns( lookupFieldSchema-> visibleColumns() );
1234 TQString expression;
1235 foreach (TQValueList<uint>::ConstIterator, visibleColumnsIt, visibleColumns) {
1238 if (fieldsExpanded.count() <= (*visibleColumnsIt)) {
1239 KexiDBWarn << "Connection::selectStatement(): fieldsExpanded.count() <= (*visibleColumnsIt) : "
1240 << fieldsExpanded.count() << " <= " << *visibleColumnsIt << endl;
1243 if (!expression.isEmpty())
1244 expression += " || ' ' || ";
1245 expression += (internalUniqueQueryAlias + "." +
1249 s_additional_fields += expression;
1253 KexiDBWarn << "Connection::selectStatement(): unsupported row source type "
1262 if (!s_additional_fields.isEmpty())
1263 sql += (TQString::fromLatin1( ", ") + s_additional_fields);
1268 s = TQString::fromLatin1( ", ");
1271 s += m_driver->beh->ROW_ID_FIELD_NAME;
1275 sql.prepend( "SELECT ");
1277 if ((tables && !tables->isEmpty()) || !subqueries_for_lookup_data.isEmpty()) {
1278 sql += TQString::fromLatin1( " FROM ");
1286 if (!s_from.isEmpty())
1287 s_from += TQString::fromLatin1( ", ");
1290 if (!aliasString.isEmpty())
1291 s_from += (TQString::fromLatin1( " AS ") + aliasString);
1300 uint subqueries_for_lookup_data_counter = 0;
1301 for (TQPtrListIterator<QuerySchema> it(subqueries_for_lookup_data);
1302 subqueries_for_lookup_data.current(); ++it, subqueries_for_lookup_data_counter++)
1304 if (!s_from.isEmpty())
1305 s_from += TQString::fromLatin1( ", ");
1306 s_from += TQString::fromLatin1( "(");
1308 s_from += TQString::fromLatin1( ") AS %1%2")
1309 .arg(kexidb_subquery_prefix).arg(subqueries_for_lookup_data_counter);
1314 s_where.reserve(4096);
1317 if (!s_additional_joins.isEmpty()) {
1318 sql += TQString::fromLatin1( " ") + s_additional_joins + TQString::fromLatin1( " ");
1325 bool wasWhere = false;
1327 if (s_where.isEmpty()) {
1331 s_where += TQString::fromLatin1( " AND ");
1333 TQString s_where_sub;
1334 for (TQPtrListIterator<Field::Pair> p_it(*rel->fieldPairs()); (pair = p_it.current()); ++p_it) {
1335 if (!s_where_sub.isEmpty())
1336 s_where_sub += TQString::fromLatin1( " AND ");
1339 TQString::fromLatin1( ".") +
1341 TQString::fromLatin1( " = ") +
1343 TQString::fromLatin1( ".") +
1346 if (rel->fieldPairs()->count()>1) {
1347 s_where_sub.prepend( "(");
1348 s_where_sub += TQString::fromLatin1( ")");
1350 s_where += s_where_sub;
1364 if (!s_where.isEmpty())
1365 sql += TQString::fromLatin1( " WHERE ") + s_where;
1370 TQString orderByString(
1374 if (orderByString.isEmpty() && !pkeyFieldsOrder.isEmpty()) {
1378 foreach (TQValueVector<int>::ConstIterator, it, pkeyFieldsOrder) {
1381 if ((*it) >= ( int)fieldsExpanded.count()) {
1382 KexiDBWarn << "Connection::selectStatement(): ORDER BY: (*it) >= fieldsExpanded.count() - "
1383 << (*it) << " >= " << fieldsExpanded.count() << endl;
1389 orderByString = automaticPKOrderBy. toSQLString(!singleTable,
1392 if (!orderByString.isEmpty())
1393 sql += ( " ORDER BY " + orderByString);
1407 Field *f = fieldlist->fields()->first();
1411 f = fieldlist->fields()->next();
1422 if (m_driver->beh->ROW_ID_FIELD_RETURNS_LAST_AUTOINCREMENTED_VALUE) {
1427 TQString::fromLatin1( "SELECT ") + tableName + TQString::fromLatin1( ".") + aiFieldName + TQString::fromLatin1( " FROM ") + tableName
1428 + TQString::fromLatin1( " WHERE ") + m_driver->beh->ROW_ID_FIELD_NAME + TQString::fromLatin1( "=") + TQString::number(row_id), rdata))
1431 return (TQ_ULLONG)-1;
1433 return rdata[0].toULongLong();
1445 if (!kexi__fieldsSchema)
1447 return kexi__fieldsSchema-> subList(
1463void buildValuesForKexi__Fields(TQValueList<TQVariant>& vals, Field* f)
1467 << TQVariant(f-> table()->id())
1468 << TQVariant(f-> type())
1469 << TQVariant(f->name())
1471 << TQVariant(f->isFPNumericType() ? f->precision() : 0)
1472 << TQVariant(f->constraints())
1473 << TQVariant(f->options())
1476 << (f->defaultValue().isNull()
1478 << TQVariant(f->order())
1479 << TQVariant(f->caption())
1480 << TQVariant(f->description());
1483bool Connection::storeMainFieldSchema( Field *field)
1485 if (!field || !field-> table())
1487 FieldList *fl = createFieldListForKexi__Fields(d->tables_byname[ "kexi__fields"]);
1491 TQValueList<TQVariant> vals;
1492 buildValuesForKexi__Fields(vals, field);
1493 TQValueList<TQVariant>::ConstIterator valsIt = vals.constBegin();
1496 TQString sql = "UPDATE kexi__fields SET ";
1497 for ( Field::ListIterator it( fl->fieldsIterator() ); (f = it.current()); ++it, ++valsIt) {
1498 sql.append( (first ? TQString() : TQString( ", ")) +
1499 f->name() + "=" + m_driver-> valueToSQL( f, *valsIt ) );
1505 sql.append(TQString( " WHERE t_id=") + TQString::number( field-> table()->id() )
1510#define createTable_ERR \
1511 { KexiDBDbg << "Connection::createTable(): ERROR!" <<endl; \
1512 setError(this, i18n("Creating table failed.")); \
1513 rollbackAutoCommitTransaction(tg.transaction()); \
1533 setError(ERR_CANNOT_CREATE_EMPTY_OBJECT, i18n( "Cannot create table without fields."));
1538 const TQString &tableName = tableSchema->name().lower();
1540 if (!internalTable) {
1543 setError(ERR_SYSTEM_NAME_RESERVED, i18n( "System name \"%1\" cannot be used as table name.")
1552 i18n( "System name \"%1\" cannot be used as one of fields in \"%2\" table.")
1553 .arg(sys_field->name()).arg(tableName));
1558 bool previousSchemaStillKept = false;
1561 if (replaceExisting) {
1563 existingTable = d->tables_byname[tableName];
1564 if (existingTable) {
1568 i18n( "Could not create the same table \"%1\" twice.").arg( tableSchema->name()) );
1572 if (existingTable->id()>0)
1574 previousSchemaStillKept = true;
1580 if (this-> tableSchema( tableSchema->name() ) != 0) {
1582 setError(ERR_OBJECT_EXISTS, i18n( "Table \"%1\" already exists.").arg( tableSchema->name()) );
1601 if (!internalTable) {
1606 TableSchema *ts = d->tables_byname[ "kexi__fields"];
1613 FieldList *fl = createFieldListForKexi__Fields(d->tables_byname[ "kexi__fields"]);
1620 TQValueList<TQVariant> vals;
1621 buildValuesForKexi__Fields(vals, f);
1622 if (!insertRecord(*fl, vals ))
1642 if (internalTable) {
1647 if (previousSchemaStillKept) {
1661void Connection::removeTableSchemaInternal( TableSchema *tableSchema)
1672 || ! KexiDB::deleteRow(* this, d->tables_byname[ "kexi__objectdata"], "o_id", objId)) {
1673 setError(ERR_DELETE_SERVER_ERROR, i18n( "Could not remove object's data."));
1704 TQString errmsg(i18n( "Table \"%1\" cannot be removed.\n"));
1711 +i18n( "Unexpected name or identifier."));
1721 setError(ERR_SYSTEM_NAME_RESERVED, errmsg.arg( tableSchema->name()) + d->strItIsASystemObject());
1735 TableSchema *ts = d->tables_byname[ "kexi__fields"];
1744 if (alsoRemoveSchema) {
1759 setError(ERR_OBJECT_NOT_FOUND, i18n( "Table \"%1\" does not exist.")
1774 setError(ERR_OBJECT_THE_SAME, i18n( "Could not alter table \"%1\" using the same table.")
1800 setError(ERR_INVALID_IDENTIFIER, i18n( "Invalid table name \"%1\"").arg(newName));
1804 const TQString newTableName = newName.lower().stripWhiteSpace();
1805 if (oldTableName.lower().stripWhiteSpace() == newTableName) {
1806 setError(ERR_OBJECT_THE_SAME, i18n( "Could rename table \"%1\" using the same name.")
1807 .arg(newTableName));
1814 const bool destTableExists = tableToReplace != 0;
1815 const int origID = destTableExists ? tableToReplace->id() : -1;
1816 if (!replace && destTableExists) {
1818 i18n( "Could not rename table \"%1\" to \"%2\". Table \"%3\" already exists.")
1819 .arg( tableSchema.name()).arg(newName).arg(newName));
1824#define alterTableName_ERR \
1825 tableSchema.setName(oldTableName)
1832 if (destTableExists) {
1841 if (! executeSQL(TQString::fromLatin1( "UPDATE kexi__objects SET o_id=%1 WHERE o_id=%2 AND o_type=%3")
1842 .arg(origID).arg( tableSchema.id()).arg(( int)TableObjectType)))
1846 if (! executeSQL(TQString::fromLatin1( "UPDATE kexi__fields SET t_id=%1 WHERE t_id=%2")
1864 if (! executeSQL(TQString::fromLatin1( "UPDATE kexi__objects SET o_name=%1 WHERE o_id=%2")
1892 if (! executeSQL(TQString::fromLatin1( "ALTER TABLE %1 RENAME TO %2")
1940 setError(ERR_OBJECT_NOT_FOUND, i18n( "Query \"%1\" does not exist.")
1950 KexiDBDbg<< "******** "<< m_sql<<endl;
1956 TableSchema *ts = d->tables_byname[tableSchemaName];
1974 if (d->default_trans_started_inside)
1980 d->default_trans_started_inside = d->default_trans.isNull();
1981 if (!d->default_trans_started_inside) {
2002 if (!d->default_trans_started_inside)
2015#define SET_ERR_TRANS_NOT_SUPP \
2016 { setError(ERR_UNSUPPORTED_DRV_FEATURE, \
2017 i18n("Transactions are not supported for \"%1\" driver.").arg(m_driver->name() )); }
2019#define SET_BEGIN_TR_ERROR \
2021 setError(ERR_ROLLBACK_OR_COMMIT_TRANSACTION, i18n("Begin transaction failed")); }
2032 d->transactions.append(trans);
2036 if (d->default_trans.active()) {
2037 setError(ERR_TRANSACTION_ACTIVE, i18n( "Transaction already started.") );
2044 d->default_trans = trans;
2045 d->transactions.append(trans);
2046 return d->default_trans;
2053 d->transactions.append(trans);
2057 SET_ERR_TRANS_NOT_SUPP;
2070 SET_ERR_TRANS_NOT_SUPP;
2075 if (!d->default_trans.active()) {
2076 if (ignore_inactive)
2079 setError(ERR_NO_TRANSACTION_ACTIVE, i18n( "Transaction not started.") );
2082 t = d->default_trans;
2089 t.m_data->m_active = false;
2090 if (!d->dont_remove_transactions)
2091 d->transactions.remove(t);
2092 if (!ret && ! error())
2093 setError(ERR_ROLLBACK_OR_COMMIT_TRANSACTION, i18n( "Error on commit transaction"));
2106 SET_ERR_TRANS_NOT_SUPP;
2111 if (!d->default_trans.active()) {
2112 if (ignore_inactive)
2115 setError(ERR_NO_TRANSACTION_ACTIVE, i18n( "Transaction not started.") );
2118 t = d->default_trans;
2125 t.m_data->m_active = false;
2126 if (!d->dont_remove_transactions)
2127 d->transactions.remove(t);
2128 if (!ret && ! error())
2129 setError(ERR_ROLLBACK_OR_COMMIT_TRANSACTION, i18n( "Error on rollback transaction"));
2133#undef SET_ERR_TRANS_NOT_SUPP
2134#undef SET_BEGIN_TR_ERROR
2143 return d->default_trans;
2157 d->default_trans = trans;
2162 return d->transactions;
2167 return d->autoCommit;
2182 TQString old_sql = m_sql;
2205 if (statement.isEmpty())
2219 uint cursor_options )
2234 return executeQuery(query, TQValueList<TQVariant>(), cursor_options);
2248 uint cursor_options )
2261 KexiDBWarn << "Connection::deleteCursor(): Cannot delete the cursor not owned by the same connection!" << endl;
2264 const bool ret = cursor-> close();
2284 sdata.m_id = data[0].toInt(&ok);
2288 sdata.m_name = data[2].toString();
2290 setError(ERR_INVALID_IDENTIFIER, i18n( "Invalid object name \"%1\"").arg(sdata.m_name));
2293 sdata.m_caption = data[3].toString();
2294 sdata.m_desc = data[4].toString();
2304 "SELECT o_id, o_type, o_name, o_caption, o_desc FROM kexi__objects WHERE o_id=%1")
2305 .arg(objectID), data))
2313 if ( true!= querySingleRecord(TQString::fromLatin1( "SELECT o_id, o_type, o_name, o_caption, o_desc "
2314 "FROM kexi__objects WHERE o_type=%1 AND lower(o_name)=%2")
2322 TableSchema *ts = d->tables_byname[ "kexi__objects"];
2328 "SELECT o_id FROM kexi__objects WHERE o_type=%1 AND lower(o_name)=%2")
2333 sdata.m_id = existingID;
2340 if (sdata.id()<=0) {
2341 fl = ts-> subList( "o_type", "o_name", "o_caption", "o_desc");
2343 if (ok && !insertRecord(*fl, TQVariant(sdata.type()), TQVariant(sdata.name()),
2344 TQVariant(sdata.caption()), TQVariant(sdata.description()) ))
2352 KexiDBDbg << "######## NEW obj_id == " << obj_id << endl;
2355 sdata.m_id = obj_id;
2358 fl = ts-> subList( "o_id", "o_type", "o_name", "o_caption", "o_desc");
2360 if (ok && !insertRecord(*fl, TQVariant(sdata.id()), TQVariant(sdata.type()), TQVariant(sdata.name()),
2361 TQVariant(sdata.caption()), TQVariant(sdata.description()) ))
2368 return executeSQL(TQString( "UPDATE kexi__objects SET o_type=%2, o_caption=%3, o_desc=%4 WHERE o_id=%1")
2369 .arg(sdata.id()).arg(sdata.type())
2377 Q_ASSERT(sql || query);
2380 m_sql = addLimitTo1 ? (*sql + " LIMIT 1") : *sql;
2383 KexiDBWarn << "Connection::querySingleRecord(): !executeQuery() " << m_sql << endl;
2387 const tristate result = cursor-> error() ? false : cancelled;
2388 KexiDBWarn << "Connection::querySingleRecord(): !cursor->moveFirst() || cursor->eof() m_sql=" << m_sql << endl;
2407bool Connection::checkIfColumnExists( Cursor *cursor, uint column)
2410 setError(ERR_CURSOR_RECORD_FETCHING, i18n( "Column %1 does not exist for the query.").arg(column));
2419 m_sql = addLimitTo1 ? (sql + " LIMIT 1") : sql;
2421 KexiDBWarn << "Connection::querySingleRecord(): !executeQuery() " << m_sql << endl;
2425 const tristate result = cursor-> error() ? false : cancelled;
2426 KexiDBWarn << "Connection::querySingleRecord(): !cursor->moveFirst() || cursor->eof() " << m_sql << endl;
2430 if (!checkIfColumnExists(cursor, column)) {
2434 value = cursor-> value(column).toString();
2440 static TQString str;
2445 number = str.toInt(&ok);
2455 KexiDBWarn << "Connection::queryStringList(): !executeQuery() " << m_sql << endl;
2459 if (cursor-> error()) {
2464 if (!cursor-> eof() && !checkIfColumnExists(cursor, column)) {
2469 while (!cursor-> eof()) {
2470 list.append( cursor-> value(column).toString() );
2484 if (m_driver->beh->SELECT_1_SUBQUERY_SUPPORTED) {
2486 if (addLimitTo1 && sql.left(6).upper() == "SELECT")
2487 m_sql = TQString( "SELECT 1 FROM (") + sql + ") LIMIT 1";
2492 if (addLimitTo1 && sql.left(6).upper() == "SELECT")
2493 m_sql = sql + " LIMIT 1";
2498 KexiDBWarn << "Connection::querySingleRecord(): !executeQuery() " << m_sql << endl;
2503 success = !cursor-> error();
2504 KexiDBWarn << "Connection::querySingleRecord(): !cursor->moveFirst() || cursor->eof() " << m_sql << endl;
2519static void createExtendedTableSchemaMainElementIfNeeded(
2520 TQDomDocument& doc, TQDomElement& extendedTableSchemaMainEl,
2521 bool& extendedTableSchemaStringIsEmpty)
2523 if (!extendedTableSchemaStringIsEmpty)
2526 extendedTableSchemaMainEl = doc.createElement( "EXTENDED_TABLE_SCHEMA");
2527 doc.appendChild( extendedTableSchemaMainEl );
2528 extendedTableSchemaMainEl.setAttribute( "version", TQString::number(KEXIDB_EXTENDED_TABLE_SCHEMA_VERSION));
2529 extendedTableSchemaStringIsEmpty = false;
2533static void createExtendedTableSchemaFieldElementIfNeeded(TQDomDocument& doc,
2534 TQDomElement& extendedTableSchemaMainEl, const TQString& fieldName, TQDomElement& extendedTableSchemaFieldEl,
2537 if (!extendedTableSchemaFieldEl.isNull())
2539 extendedTableSchemaFieldEl = doc.createElement( "field");
2541 extendedTableSchemaMainEl.appendChild( extendedTableSchemaFieldEl );
2542 extendedTableSchemaFieldEl.setAttribute( "name", fieldName);
2551static void addFieldPropertyToExtendedTableSchemaData(
2552 Field *f, const char* propertyName, const TQVariant& propertyValue,
2553 TQDomDocument& doc, TQDomElement& extendedTableSchemaMainEl,
2554 TQDomElement& extendedTableSchemaFieldEl,
2555 bool& extendedTableSchemaStringIsEmpty,
2556 bool custom = false )
2558 createExtendedTableSchemaMainElementIfNeeded(doc,
2559 extendedTableSchemaMainEl, extendedTableSchemaStringIsEmpty);
2560 createExtendedTableSchemaFieldElementIfNeeded(
2561 doc, extendedTableSchemaMainEl, f->name(), extendedTableSchemaFieldEl);
2564 TQDomElement extendedTableSchemaFieldPropertyEl = doc.createElement( "property");
2565 extendedTableSchemaFieldEl.appendChild( extendedTableSchemaFieldPropertyEl );
2567 extendedTableSchemaFieldPropertyEl.setAttribute( "custom", "true");
2568 extendedTableSchemaFieldPropertyEl.setAttribute( "name", propertyName);
2569 TQDomElement extendedTableSchemaFieldPropertyValueEl;
2570 switch (propertyValue.type()) {
2571 case TQVariant::String:
2572 extendedTableSchemaFieldPropertyValueEl = doc.createElement( "string");
2574 case TQVariant::CString:
2575 extendedTableSchemaFieldPropertyValueEl = doc.createElement( "cstring");
2577 case TQVariant::Int:
2578 case TQVariant::Double:
2579 case TQVariant::UInt:
2580 case TQVariant::LongLong:
2581 case TQVariant::ULongLong:
2582 extendedTableSchemaFieldPropertyValueEl = doc.createElement( "number");
2584 case TQVariant::Bool:
2585 extendedTableSchemaFieldPropertyValueEl = doc.createElement( "bool");
2589 KexiDBFatal << "addFieldPropertyToExtendedTableSchemaData(): impl. error" << endl;
2591 extendedTableSchemaFieldPropertyEl.appendChild( extendedTableSchemaFieldPropertyValueEl );
2592 extendedTableSchemaFieldPropertyValueEl.appendChild(
2593 doc.createTextNode( propertyValue.toString() ) );
2599 TQDomDocument doc( "EXTENDED_TABLE_SCHEMA");
2600 TQDomElement extendedTableSchemaMainEl;
2601 bool extendedTableSchemaStringIsEmpty = true;
2606 TQDomElement extendedTableSchemaFieldEl;
2608 addFieldPropertyToExtendedTableSchemaData(
2610 extendedTableSchemaMainEl, extendedTableSchemaFieldEl,
2611 extendedTableSchemaStringIsEmpty );
2617 foreach( Field::CustomPropertiesMap::ConstIterator, itCustom, customProperties ) {
2618 addFieldPropertyToExtendedTableSchemaData(
2619 f, itCustom.key(), itCustom.data(), doc,
2620 extendedTableSchemaMainEl, extendedTableSchemaFieldEl, extendedTableSchemaStringIsEmpty,
2625 if (lookupFieldSchema) {
2626 createExtendedTableSchemaFieldElementIfNeeded(
2627 doc, extendedTableSchemaMainEl, f->name(), extendedTableSchemaFieldEl, false);
2630 if (extendedTableSchemaFieldEl.hasChildNodes()) {
2632 createExtendedTableSchemaMainElementIfNeeded(doc, extendedTableSchemaMainEl,
2633 extendedTableSchemaStringIsEmpty);
2634 extendedTableSchemaMainEl.appendChild( extendedTableSchemaFieldEl );
2640 if (extendedTableSchemaStringIsEmpty) {
2641#ifdef KEXI_DEBUG_GUI
2648#ifdef KEXI_DEBUG_GUI
2659#define loadExtendedTableSchemaData_ERR \
2660 { setError(i18n("Error while loading extended table schema information.")); \
2662#define loadExtendedTableSchemaData_ERR2(details) \
2663 { setError(i18n("Error while loading extended table schema information."), details); \
2665#define loadExtendedTableSchemaData_ERR3(data) \
2666 { setError(i18n("Error while loading extended table schema information."), \
2667 i18n("Invalid XML data: ") + data.left(1024) ); \
2671 TQString extendedTableSchemaString;
2674 loadExtendedTableSchemaData_ERR;
2677#ifdef KEXIDB_LOOKUP_FIELD_TEST
2684 lookupFieldSchema->setVisibleColumn(3);
2690 if (extendedTableSchemaString.isEmpty())
2695 int errorLine, errorColumn;
2696 if (!doc.setContent( extendedTableSchemaString, & errorMsg, &errorLine, &errorColumn ))
2697 loadExtendedTableSchemaData_ERR2( i18n( "Error in XML data: \"%1\" in line %2, column %3.\nXML data: ")
2698 .arg( errorMsg).arg(errorLine).arg(errorColumn) + extendedTableSchemaString.left(1024));
2702 if (doc.doctype().name()!= "EXTENDED_TABLE_SCHEMA")
2703 loadExtendedTableSchemaData_ERR3( extendedTableSchemaString );
2705 TQDomElement docEl = doc.documentElement();
2706 if (docEl.tagName()!= "EXTENDED_TABLE_SCHEMA")
2707 loadExtendedTableSchemaData_ERR3( extendedTableSchemaString );
2709 for (TQDomNode n = docEl.firstChild(); !n.isNull(); n = n.nextSibling()) {
2710 TQDomElement fieldEl = n.toElement();
2711 if (fieldEl.tagName()== "field") {
2716 for (TQDomNode propNode = fieldEl.firstChild();
2717 !propNode.isNull(); propNode = propNode.nextSibling())
2719 TQDomElement propEl = propNode.toElement();
2722 if (propEl.tagName()== "property") {
2723 TQCString propertyName = propEl.attribute( "name").latin1();
2724 if (propEl.attribute( "custom")== "true") {
2729 else if (propertyName == "visibleDecimalPlaces"
2738 else if (propEl.tagName()== "lookup-column") {
2740 if (lookupFieldSchema)
2741 lookupFieldSchema-> debug();
2747 KexiDBWarn << "Connection::loadExtendedTableSchemaData(): no such field \""
2748 << fieldEl.attribute( "name") << "\" in table \"" << tableSchema.name() << "\"" << endl;
2759 int f_int_type = data.at(1).toInt(&ok);
2765 int f_len = TQMAX( 0, data.at(3).toInt(&ok) );
2768 int f_prec = data.at(4).toInt(&ok);
2771 int f_constr = data.at(5).toInt(&ok);
2774 int f_opts = data.at(6).toInt(&ok);
2779 setError(ERR_INVALID_IDENTIFIER, i18n( "Invalid object name \"%1\"")
2780 .arg( data.at(2).toString() ));
2786 data.at(2).toString(), f_type, f_constr, f_opts, f_len, f_prec );
2790 KexiDBWarn << "Connection::setupTableSchema() problem with KexiDB::stringToVariant("
2791 << data.at(7).toString() << ")" << endl;
2795 f->m_caption = data.at(9).toString();
2796 f->m_desc = data.at(10).toString();
2810 TQString::fromLatin1( "SELECT t_id, f_type, f_name, f_length, f_precision, f_constraints, "
2811 "f_options, f_default, f_order, f_caption, f_help"
2812 " FROM kexi__fields WHERE t_id=%1 ORDER BY f_order").arg(t->m_id) )))
2818 if (!cursor-> error() && cursor-> eof()) {
2819 setError(i18n( "Table has no fields defined."));
2829 while (!cursor-> eof()) {
2857 d->tables.insert(t->m_id, t);
2858 d->tables_byname.insert(t->m_name.lower(), t);
2864 TQString m_tableName = tableName.lower();
2871 "SELECT o_id, o_type, o_name, o_caption, o_desc FROM kexi__objects WHERE lower(o_name)='%1' AND o_type=%2")
2872 .arg(m_tableName).arg(KexiDB::TableObjectType), data))
2886 "SELECT o_id, o_type, o_name, o_caption, o_desc FROM kexi__objects WHERE o_id=%1")
2887 .arg(tableId), data))
2898 TQString( "SELECT o_data FROM kexi__objectdata WHERE o_id=") + TQString::number(objectID)
2907 TQString sql(TQString::fromLatin1( "SELECT kexi__objectdata.o_id FROM kexi__objectdata WHERE o_id=%1").arg(objectID));
2915 return executeSQL( "UPDATE kexi__objectdata SET o_data="
2917 + " WHERE o_id=" + TQString::number(objectID) + " AND " + sql_sub );
2920 TQString::fromLatin1( "INSERT INTO kexi__objectdata (o_id, o_data, o_sub_id) VALUES (")
2929 if (dataID.isEmpty())
2930 return KexiDB::deleteRow(* this, "kexi__objectdata", "o_id", TQString::number(objectID));
2939 const int objID = data[0].toInt(&ok);
2945 i18n( "Could not find definition for query \"%1\". Removing this query is recommended.")
2946 .arg( data[2].toString()));
2949 d->parser()->parse( sqlText );
2954 i18n( "<p>Could not load definition for query \"%1\". "
2955 "SQL statement for this query is invalid:<br><tt>%2</tt></p>\n"
2956 "<p>You can open this query in Text View and correct it.</p>").arg( data[2].toString())
2957 .arg(d->parser()->statement()));
2964 d->queries.insert(query->m_id, query);
2965 d->queries_byname.insert(query->m_name, query);
2971 TQString m_queryName = queryName.lower();
2978 "SELECT o_id, o_type, o_name, o_caption, o_desc FROM kexi__objects WHERE lower(o_name)='%1' AND o_type=%2")
2979 .arg(m_queryName).arg(KexiDB::QueryObjectType), data))
2994 "SELECT o_id, o_type, o_name, o_caption, o_desc FROM kexi__objects WHERE o_id=%1").arg(queryId), data))
3005 d->obsoleteQueries.append(oldQuery);
3006 d->queries_byname.take(queryName);
3007 d->queries.take(oldQuery->id());
3014 insertInternalTableSchema( ts );
3018bool Connection::isInternalTableSchema( const TQString& tableName)
3020 return (d->kexiDBSystemTables[ d->tables_byname[tableName] ])
3023 || tableName== "kexi__final" || tableName== "kexi__useractions";
3026void Connection::insertInternalTableSchema( TableSchema *tableSchema)
3036 if (!d->kexiDBSystemTables.isEmpty())
3116 if (ts && !m_destructor_started) {
3117 d->tables.take(ts->id());
3118 d->tables_byname.take(ts->name());
3124 if (!d->availableDatabaseName.isEmpty()) {
3125 return d->availableDatabaseName;
3127 return m_driver->beh->ALWAYS_AVAILABLE_DATABASE_NAME;
3132 d->availableDatabaseName = dbName;
3136inline void updateRowDataWithNewValues( QuerySchema &query, RowData& data, KexiDB::RowEditBuffer::DBMap& b,
3137 TQMap<QueryColumnInfo*,int>& columnsOrderExpanded)
3140 TQMap<QueryColumnInfo*,int>::ConstIterator columnsOrderExpandedIt;
3141 for (KexiDB::RowEditBuffer::DBMap::ConstIterator it=b.constBegin();it!=b.constEnd();++it) {
3142 columnsOrderExpandedIt = columnsOrderExpanded.find( it.key() );
3143 if (columnsOrderExpandedIt == columnsOrderExpanded.constEnd()) {
3144 KexiDBWarn << "(Connection) updateRowDataWithNewValues(): \"now also assign new value in memory\" step "
3145 "- could not find item '" << it.key()->aliasOrName() << "'" << endl;
3148 data[ columnsOrderExpandedIt.data() ] = it.data();
3157 KexiDBDbg << "Connection::updateRow.." << endl;
3160 if (buf.dbBuffer().isEmpty()) {
3161 KexiDBDbg << " -- NO CHANGES DATA!" << endl;
3166 KexiDBWarn << " -- NO MASTER TABLE!" << endl;
3167 setError(ERR_UPDATE_NO_MASTER_TABLE,
3168 i18n( "Could not update row because there is no master table defined."));
3172 if (!useROWID && !pkey) {
3173 KexiDBWarn << " -- NO MASTER TABLE's PKEY!" << endl;
3174 setError(ERR_UPDATE_NO_MASTER_TABLES_PKEY,
3175 i18n( "Could not update row because master table has no primary key defined."));
3181 TQString sqlset, sqlwhere;
3182 sqlset.reserve(1024);
3183 sqlwhere.reserve(1024);
3184 KexiDB::RowEditBuffer::DBMap b = buf.dbBuffer();
3185 for (KexiDB::RowEditBuffer::DBMap::ConstIterator it=b.constBegin();it!=b.constEnd();++it) {
3186 if (it.key()->field->table()!=mt)
3188 if (!sqlset.isEmpty())
3191 m_driver-> valueToSQL(it.key()->field,it.data()));
3197 KexiDBWarn << " -- NO ENTIRE MASTER TABLE's PKEY SPECIFIED!" << endl;
3198 setError(ERR_UPDATE_NO_ENTIRE_MASTER_TABLES_PKEY,
3199 i18n( "Could not update row because it does not contain entire master table's primary key."));
3202 if (!pkey->fields()->isEmpty()) {
3205 if (!sqlwhere.isEmpty())
3207 TQVariant val = data[ pkeyFieldsOrder[i] ];
3208 if (val.isNull() || !val.isValid()) {
3209 setError(ERR_UPDATE_NULL_PKEY_FIELD,
3210 i18n( "Primary key's field \"%1\" cannot be empty.").arg(it.current()->name()));
3223 m_sql += (sqlset + " WHERE " + sqlwhere);
3224 KexiDBDbg << " -- SQL == " << (( m_sql.length() > 400) ? ( m_sql.left(400)+ "[.....]") : m_sql) << endl;
3227 setError(ERR_UPDATE_SERVER_ERROR, i18n( "Row updating on the server failed."));
3231 if (m_driver->beh->ROW_ID_FIELD_NAME == "xmin")
3235 TQMap<QueryColumnInfo*,int> columnsOrderExpanded;
3236 updateRowDataWithNewValues(query, data, b, columnsOrderExpanded);
3243 KexiDBDbg << "Connection::updateRow.." << endl;
3252 KexiDBWarn << " -- NO MASTER TABLE!" << endl;
3253 setError(ERR_INSERT_NO_MASTER_TABLE,
3254 i18n( "Could not insert row because there is no master table defined."));
3258 if (!getROWID && !pkey)
3259 KexiDBWarn << " -- WARNING: NO MASTER TABLE's PKEY" << endl;
3261 TQString sqlcols, sqlvals;
3262 sqlcols.reserve(1024);
3263 sqlvals.reserve(1024);
3267 KexiDB::RowEditBuffer::DBMap b = buf.dbBuffer();
3271 for (uint i=0; i<fieldsExpanded.count(); i++) {
3275 && !b.contains( ci ))
3277 KexiDBDbg << "Connection::insertRow(): adding default value '" << ci->field-> defaultValue().toString()
3278 << "' for column '" << ci->field->name() << "'" << endl;
3285 if (!getROWID && !pkey) {
3286 KexiDBWarn << "MASTER TABLE's PKEY REQUIRED FOR INSERTING EMPTY ROWS: INSERT CANCELLED" << endl;
3287 setError(ERR_INSERT_NO_MASTER_TABLES_PKEY,
3288 i18n( "Could not insert row because master table has no primary key defined."));
3295 KexiDBWarn << "NO ENTIRE MASTER TABLE's PKEY SPECIFIED!" << endl;
3296 setError(ERR_INSERT_NO_ENTIRE_MASTER_TABLES_PKEY,
3297 i18n( "Could not insert row because it does not contain entire master table's primary key.")
3298 .arg(query.name()));
3306 KexiDBWarn << "WARNING: NO FIELD AVAILABLE TO SET IT TO NULL" << endl;
3311 anyField = pkey->fields()->first();
3315 sqlvals += m_driver-> valueToSQL(anyField,TQVariant());
3319 for (KexiDB::RowEditBuffer::DBMap::ConstIterator it=b.constBegin();it!=b.constEnd();++it) {
3320 if (it.key()->field->table()!=mt)
3322 if (!sqlcols.isEmpty()) {
3327 sqlvals += m_driver-> valueToSQL(it.key()->field,it.data());
3330 m_sql += (sqlcols + ") VALUES (" + sqlvals + ")");
3336 setError(ERR_INSERT_SERVER_ERROR, i18n( "Row inserting on the server failed."));
3340 TQMap<QueryColumnInfo*,int> columnsOrderExpanded;
3341 updateRowDataWithNewValues(query, data, b, columnsOrderExpanded);
3345 TQ_ULLONG ROWID = 0;
3346 if (pkey && !aif_list->isEmpty()) {
3351 id_columnInfo->field->name(), id_columnInfo->field-> table()->name(), &ROWID);
3352 if (last_id==(TQ_ULLONG)-1 || last_id<=0) {
3358 TQString getAutoIncForInsertedValue = TQString::fromLatin1( "SELECT ")
3360 + TQString::fromLatin1( " FROM ")
3362 + TQString::fromLatin1( " WHERE ")
3364 + TQString::number(last_id);
3369 QueryColumnInfo::ListIterator ci_it(*aif_list);
3371 for (uint i=0; (ci = ci_it.current()); ++ci_it, i++) {
3374 ( data[ columnsOrderExpanded[ ci ] ] = aif_data[i] ).cast( ci->field-> variantType() );
3380 if (m_driver->beh->ROW_ID_FIELD_RETURNS_LAST_AUTOINCREMENTED_VALUE) {
3381 KexiDBWarn << "Connection::insertRow(): m_driver->beh->ROW_ID_FIELD_RETURNS_LAST_AUTOINCREMENTED_VALUE" << endl;
3385 if (getROWID && data.size() > fieldsExpanded.size()) {
3395 KexiDBWarn << "Connection::deleteRow.." << endl;
3399 KexiDBWarn << " -- NO MASTER TABLE!" << endl;
3400 setError(ERR_DELETE_NO_MASTER_TABLE,
3401 i18n( "Could not delete row because there is no master table defined.")
3402 .arg(query.name()));
3408 if (!useROWID && !pkey) {
3409 KexiDBWarn << " -- WARNING: NO MASTER TABLE's PKEY" << endl;
3410 setError(ERR_DELETE_NO_MASTER_TABLES_PKEY,
3411 i18n( "Could not delete row because there is no primary key for master table defined."));
3418 sqlwhere.reserve(1024);
3424 KexiDBWarn << " -- NO ENTIRE MASTER TABLE's PKEY SPECIFIED!" << endl;
3425 setError(ERR_DELETE_NO_ENTIRE_MASTER_TABLES_PKEY,
3426 i18n( "Could not delete row because it does not contain entire master table's primary key."));
3431 if (!sqlwhere.isEmpty())
3433 TQVariant val = data[ pkeyFieldsOrder[i] ];
3434 if (val.isNull() || !val.isValid()) {
3435 setError(ERR_DELETE_NULL_PKEY_FIELD, i18n( "Primary key's field \"%1\" cannot be empty.")
3436 .arg(it.current()->name()));
3449 KexiDBDbg << " -- SQL == " << m_sql << endl;
3452 setError(ERR_DELETE_SERVER_ERROR, i18n( "Row deletion on the server failed."));
3463 KexiDBWarn << " -- NO MASTER TABLE!" << endl;
3467 if (!pkey || pkey->fields()->isEmpty())
3468 KexiDBWarn << "Connection::deleteAllRows -- WARNING: NO MASTER TABLE's PKEY" << endl;
3472 KexiDBDbg << " -- SQL == " << m_sql << endl;
3475 setError(ERR_DELETE_SERVER_ERROR, i18n( "Row deletion on the server failed."));
3484 TQPtrList<TableSchemaChangeListenerInterface>* listeners = d->tableSchemaChangeListeners[&schema];
3486 listeners = new TQPtrList<TableSchemaChangeListenerInterface>();
3487 d->tableSchemaChangeListeners.insert(&schema, listeners);
3490 if (listeners->findRef( &listener )==-1)
3491 listeners->append( &listener );
3494void Connection::unregisterForTableSchemaChanges(TableSchemaChangeListenerInterface& listener,
3497 TQPtrList<TableSchemaChangeListenerInterface>* listeners = d->tableSchemaChangeListeners[&schema];
3501 listeners->remove( &listener );
3504void Connection::unregisterForTablesSchemaChanges(TableSchemaChangeListenerInterface& listener)
3506 for (TQPtrDictIterator< TQPtrList<TableSchemaChangeListenerInterface> > it(d->tableSchemaChangeListeners);
3509 if (-1!=it.current()->find(&listener))
3510 it.current()->take();
3514TQPtrList<Connection::TableSchemaChangeListenerInterface>*
3515Connection::tableSchemaChangeListeners( TableSchema& tableSchema) const
3517 KexiDBDbg << d->tableSchemaChangeListeners.count() << endl;
3518 return d->tableSchemaChangeListeners[& tableSchema];
3523 TQPtrList<Connection::TableSchemaChangeListenerInterface> *listeners = d->tableSchemaChangeListeners[& tableSchema];
3526 TQPtrListIterator<KexiDB::Connection::TableSchemaChangeListenerInterface> tmpListeners(*listeners);
3529 for (TQPtrListIterator<KexiDB::Connection::TableSchemaChangeListenerInterface> it(tmpListeners);
3530 it.current() && res== true; ++it)
3532 res = it.current()->closeListener();
3544void Connection::setReadOnly( bool set)
3556#include "connection.moc"
virtual TQString toString(QuerySchemaParameterValueListIterator *params=0)=0
Database specific connection data, e.g. host, port.
options used in selectStatement()
int identifierEscaping A mode for escaping identifier, Driver::EscapeDriver|Driver::EscapeAsNecessary by default.
bool addVisibleLookupColumns
bool alsoRetrieveROWID True if ROWID should be also retrieved. False by default.
Provides database connection, allowing queries and data modification.
TQValueList< int > queryIds()
TQStringList objectNames(int objType=KexiDB::AnyObjectType, bool *ok=0)
virtual bool drv_executeSQL(const TQString &statement)=0
TQString escapeIdentifier(const TQString &id, int escaping=Driver::EscapeDriver|Driver::EscapeAsNecessary) const Identifier escaping function in the associated Driver.
TQ_ULLONG lastInsertedAutoIncValue(const TQString &aiFieldName, const TQString &tableName, TQ_ULLONG *ROWID=0)
bool commitTransaction(Transaction trans=Transaction::null, bool ignore_inactive=false)
bool beginAutoCommitTransaction(TransactionGuard &tg)
DatabaseProperties & databaseProperties()
TQString createTableStatement(const TableSchema &tableSchema) const
bool deleteAllRows(QuerySchema &query)
TableSchema * tableSchema(int tableId)
bool deleteCursor(Cursor *cursor)
bool rollbackTransaction(Transaction trans=Transaction::null, bool ignore_inactive=false)
bool removeObject(uint objId)
KexiDB::DatabaseVersionInfo * databaseVersion() const
bool rollbackAutoCommitTransaction(const Transaction &trans)
bool executeSQL(const TQString &statement)
const TQValueList< Transaction > & transactions()
virtual bool drv_createTable(const TableSchema &tableSchema)
tristate querySingleRecordInternal(RowData &data, const TQString *sql, QuerySchema *query, bool addLimitTo1=true)
friend class KexiDB::DatabaseProperties for setError()
bool createTable(TableSchema *tableSchema, bool replaceExisting=false) Creates a table according to the given schema.
bool isDatabaseUsed() const
TableSchema * setupTableSchema(const RowData &data)
TQValueList< int > tableIds()
tristate loadDataBlock(int objectID, TQString &dataString, const TQString &dataID)
TQValueList< int > objectIds(int objType)
bool useDatabase(const TQString &dbName, bool kexiCompatible=true, bool *cancelled=0, MessageHandler *msgHandler=0) Opens an existing database specified by dbName.
bool closeDatabase() Closes currently used database for this connection.
TQPtrDict< KexiDB::Cursor > m_cursors cursors created for this connection
static const TQStringList & kexiDBSystemTableNames()
bool createDatabase(const TQString &dbName) Creates new database with name dbName, using this connection.
bool loadExtendedTableSchemaData(TableSchema &tableSchema)
void setAvailableDatabaseName(const TQString &dbName)
bool queryStringList(const TQString &sql, TQStringList &list, uint column=0)
virtual TQ_ULLONG drv_lastInsertRowID()=0
virtual bool drv_isDatabaseUsed() const
virtual Cursor * prepareQuery(const TQString &statement, uint cursor_options=0)=0
KexiDB::ServerVersionInfo * serverVersion() const
virtual bool drv_createDatabase(const TQString &dbName=TQString())=0
TableSchema * newKexiDBSystemTableSchema(const TQString &tsname)
virtual bool drv_getDatabasesList(TQStringList &list)
bool checkIsDatabaseUsed()
bool storeExtendedTableSchemaData(TableSchema &tableSchema)
bool insertRow(QuerySchema &query, RowData &data, RowEditBuffer &buf, bool getROWID=false)
bool isEmpty(TableSchema &table, bool &success)
void registerForTableSchemaChanges(TableSchemaChangeListenerInterface &listener, TableSchema &schema) Register listener for receiving (listening) information about changes in TableSchema object.
Field * findSystemFieldName(FieldList *fieldlist)
virtual bool drv_connect(KexiDB::ServerVersionInfo &version)=0
virtual bool drv_commitTransaction(TransactionData *trans)
bool setQuerySchemaObsolete(const TQString &queryName)
virtual TQString anyAvailableDatabaseName()
virtual bool drv_disconnect()=0
bool storeObjectSchemaData(SchemaData &sdata, bool newObject)
TQString selectStatement(QuerySchema &querySchema, const TQValueList< TQVariant > ¶ms, const SelectStatementOptions &options=SelectStatementOptions()) const
tristate querySingleString(const TQString &sql, TQString &value, uint column=0, bool addLimitTo1=true)
QuerySchema * querySchema(int queryId)
void removeMe(TableSchema *ts)
tristate loadObjectSchemaData(int objectID, SchemaData &sdata)
TQString currentDatabase() const Get the name of the current database.
virtual bool isReadOnly() const
bool updateRow(QuerySchema &query, RowData &data, RowEditBuffer &buf, bool useROWID=false)
virtual bool drv_dropDatabase(const TQString &dbName=TQString())=0
bool dropDatabase(const TQString &dbName=TQString()) Drops database with name dbName.
Cursor * executeQuery(const TQString &statement, uint cursor_options=0)
void setDefaultTransaction(const Transaction &trans)
virtual bool drv_setAutoCommit(bool on)
virtual bool drv_closeDatabase()=0
bool removeDataBlock(int objectID, const TQString &dataID=TQString())
bool alterTableName(TableSchema &tableSchema, const TQString &newName, bool replace=false)
bool disconnect() Disconnects from driver with given parameters.
bool deleteRow(QuerySchema &query, RowData &data, bool useROWID=false)
bool databaseExists(const TQString &dbName, bool ignoreErrors=true)
virtual bool drv_containsTable(const TQString &tableName)=0
bool commitAutoCommitTransaction(const Transaction &trans)
bool setupObjectSchemaData(const RowData &data, SchemaData &sdata)
virtual void clearError()
virtual TransactionData * drv_beginTransaction()
Transaction & defaultTransaction() const
tristate querySingleNumber(const TQString &sql, int &number, uint column=0, bool addLimitTo1=true)
bool resultExists(const TQString &sql, bool &success, bool addLimitTo1=true)
TQStringList tableNames(bool also_system_tables=false)
bool setAutoCommit(bool on)
virtual bool drv_rollbackTransaction(TransactionData *trans)
bool useTemporaryDatabaseIfNeeded(TQString &tmpdbName)
bool dropQuery(QuerySchema *querySchema)
bool setupKexiDBSystemSchema() Creates kexi__* tables.
tristate querySingleRecord(const TQString &sql, RowData &data, bool addLimitTo1=true)
Transaction beginTransaction() Creates new transaction handle and starts a new transaction.
KexiDB::Field * setupField(const RowData &data)
TQStringList databaseNames(bool also_system_db=false)
virtual bool drv_useDatabase(const TQString &dbName=TQString(), bool *cancelled=0, MessageHandler *msgHandler=0)=0
tristate dropTable(TableSchema *tableSchema) Drops a table corresponding to the name in the given schema.
virtual bool drv_alterTableName(TableSchema &tableSchema, const TQString &newName)
virtual bool drv_databaseExists(const TQString &dbName, bool ignoreErrors=true)
QuerySchema * setupQuerySchema(const RowData &data)
friend class KexiDB::TableSchema for removeMe()
Connection(Driver *driver, ConnectionData &conn_data)
ConnectionData * data() const
virtual bool drv_dropTable(const TQString &name)
bool storeDataBlock(int objectID, const TQString &dataString, const TQString &dataID=TQString())
bool connect() Connects to driver with given parameters.
tristate alterTable(TableSchema &tableSchema, TableSchema &newTableSchema)
Provides database cursor functionality.
void setQueryParameters(const TQValueList< TQVariant > ¶ms) Sets query parameters params for this cursor.
virtual TQVariant value(uint i)=0
virtual void storeCurrentRow(RowData &data) const =0
Connection * connection() const
A set of storable database properties.
Contains database version information about a Kexi-compatible database. The version is stored as inte...
Generic database abstraction.
bool transactionsSupported() const
virtual TQString valueToSQL(uint ftype, const TQVariant &v) const
@ SingleTransactions single trasactions are only supported
@ MultipleTransactions multiple concurrent trasactions are supported (this implies !SingleTransactions)
virtual TQString escapeString(const TQString &str) const =0
bool isFileDriver() const
bool isSystemFieldName(const TQString &n) const
virtual bool isSystemObjectName(const TQString &n) const
virtual bool isSystemDatabaseName(const TQString &n) const =0
virtual TQString sqlTypeName(int id_t, int p=0) const
FieldList * subList(const TQString &n1, const TQString &n2=TQString(), const TQString &n3=TQString(), const TQString &n4=TQString(), const TQString &n5=TQString(), const TQString &n6=TQString(), const TQString &n7=TQString(), const TQString &n8=TQString(), const TQString &n9=TQString(), const TQString &n10=TQString(), const TQString &n11=TQString(), const TQString &n12=TQString(), const TQString &n13=TQString(), const TQString &n14=TQString(), const TQString &n15=TQString(), const TQString &n16=TQString(), const TQString &n17=TQString(), const TQString &n18=TQString())
FieldList & addField(Field *field)
TQString sqlFieldsList(Driver *driver, const TQString &separator=TQString::fromLatin1(","), const TQString &tableAlias=TQString(), int drvEscaping=Driver::EscapeDriver|Driver::EscapeAsNecessary)
bool isPrimaryKey() const
KexiDB::BaseExpr * expression()
TQPair< Field *, Field * > Pair fields pair
void setVisibleDecimalPlaces(int p)
TQVariant::Type variantType() const Converts field's type to TQVariant equivalent as accurate as possible.
const CustomPropertiesMap customProperties() const
static TQVariant::Type variantType(uint type) Converts type type to TQVariant equivalent as accurate as possible.
void setDefaultValue(const TQVariant &def)
TQPtrList< Field > List list of fields
bool isFPNumericType() const
bool isAutoIncrement() const
TQPtrListIterator< Field > ListIterator iterator for list of fields
void setCustomProperty(const TQCString &propertyName, const TQVariant &value) Sets value value for custom property propertyName.
virtual bool isQueryAsterisk() const
bool isExpression() const
int visibleDecimalPlaces() const
TQMap< TQCString, TQVariant > CustomPropertiesMap A data type used for handling custom properties of a field.
virtual TableSchema * table() const
TQVariant defaultValue() const
bool isUnsigned() const if the type has the unsigned attribute
Provides information about database index that can be created for a database table.
Row source information that can be specified for the lookup field schema.
TQString typeName() const
@ Table table as lookup row source
@ Query named query as lookup row source
void setName(const TQString &name)
Provides information about lookup field's setup.
static LookupFieldSchema * loadFromDom(const TQDomElement &lookupEl)
void setBoundColumn(int column)
static void saveToDom(LookupFieldSchema &lookupSchema, TQDomDocument &doc, TQDomElement &parentEl)
TQValueList< uint > visibleColumns() const
TQString m_sql used to store of actually executed SQL statement
virtual void clearError()
virtual void setError(int code=ERR_OTHER, const TQString &msg=TQString())
const TQString & errorMsg() const
KexiDB::OrderByColumnList provides list of sorted columns for a query schema.
void appendColumn(QueryColumnInfo &columnInfo, bool ascending=true)
TQString toSQLString(bool includeTableNames=true, Driver *drv=0, int identifierEscaping=Driver::EscapeDriver|Driver::EscapeAsNecessary) const
Parser for SQL statements.
KexiDB::QueryAsterisk class encapsulates information about single asterisk in query definition.
bool isSingleTableAsterisk() const
Helper class that assigns additional information for the column in a query.
TQCString aliasOrName() const
An iteratof for a list of values of query schema parameters providing Allows to iterate over paramete...
KexiDB::QuerySchema provides information about database query.
TableSchema * masterTable() const
TQCString columnAlias(uint position) const
Relationship::List * relationships() const
Connection * connection() const
TQString autoIncrementSQLFieldsList(Driver *driver)
OrderByColumnList & orderByColumnList() const
TableSchema * table(const TQString &tableName) const
@ Unique Unique list of fields is returned.
TQMap< QueryColumnInfo *, int > columnsOrder(ColumnsOrderOptions options=ExpandedList)
QueryColumnInfo::Vector fieldsExpanded(FieldsExpandedOptions options=Default)
TQValueVector< int > pkeyFieldsOrder()
bool isColumnVisible(uint position) const
@ ExpandedList A map for expanded list is created.
QueryColumnInfo::List * autoIncrementFields()
int tableBoundToColumn(uint columnPosition) const
TableSchema::List * tables() const
TQCString tableAlias(uint position) const
TQString statement() const
BaseExpr * whereExpression() const
provides data for single edited database row KexiDB::RowEditBuffer provides data for single edited ro...
Contains version information about a database backend.
IndexSchema * primaryKey() const
TQPtrListIterator< TableSchema > ListIterator Iterator for tables list.
TQPtrList< TableSchema > List Type of tables list.
void setKexiDBSystem(bool set)
LookupFieldSchema * lookupFieldSchema(const Field &field) const
bool setLookupFieldSchema(const TQString &fieldName, LookupFieldSchema *lookupFieldSchema)
Helper class for using inside methods for given connection.
const Transaction transaction() const
void setTransaction(const Transaction &trans)
This class encapsulates transaction handle.
static const Transaction null
3-state logical type with three values: true, false and cancelled and convenient operators.
High-level database connectivity library with database backend drivers.
KEXI_DB_EXPORT bool isDefaultValueAllowed(Field *field)
KEXI_DB_EXPORT TQVariant stringToVariant(const TQString &s, TQVariant::Type type, bool &ok)
KEXI_DB_EXPORT bool supportsVisibleDecimalPlacesProperty(Field::Type type)
KEXI_DB_EXPORT TQVariant loadPropertyValueFromDom(const TQDomNode &node)
KEXI_DB_EXPORT DatabaseVersionInfo version()
TQValueVector< TQVariant > RowData structure for storing single record with type information
KEXI_DB_EXPORT TQString sqlWhere(Driver *drv, Field::Type t, const TQString fieldName, const TQVariant value)
KEXI_DB_EXPORT bool deleteRow(Connection &conn, TableSchema *table, const TQString &keyname, const TQString &keyval) for convenience
KEXI_DB_EXPORT int loadIntPropertyValueFromDom(const TQDomNode &node, bool *ok)
KEXI_DB_EXPORT TQString variantToString(const TQVariant &v)
type * findParent(TQObject *o, const char *className)
KEXIUTILS_EXPORT bool isIdentifier(const TQString &s)
|