diff options
-rw-r--r-- | src/sql/drivers/db2/qsql_db2.cpp | 70 | ||||
-rw-r--r-- | src/sql/drivers/ibase/qsql_ibase.cpp | 16 | ||||
-rw-r--r-- | src/sql/drivers/odbc/qsql_odbc.cpp | 4 | ||||
-rw-r--r-- | src/sql/drivers/psql/qsql_psql.cpp | 32 | ||||
-rw-r--r-- | src/sql/drivers/sqlite/qsql_sqlite.cpp | 16 | ||||
-rw-r--r-- | src/sql/drivers/tds/qsql_tds.cpp | 21 | ||||
-rw-r--r-- | src/sql/models/qsqltablemodel.cpp | 20 | ||||
-rw-r--r-- | tests/auto/qsqldatabase/tst_databases.h | 34 | ||||
-rw-r--r-- | tests/auto/qsqldriver/qsqldriver.pro | 16 | ||||
-rw-r--r-- | tests/auto/qsqldriver/tst_qsqldriver.cpp | 218 | ||||
-rw-r--r-- | tests/auto/qsqlrelationaltablemodel/tst_qsqlrelationaltablemodel.cpp | 455 | ||||
-rw-r--r-- | tests/auto/qsqltablemodel/tst_qsqltablemodel.cpp | 15 |
12 files changed, 824 insertions, 93 deletions
diff --git a/src/sql/drivers/db2/qsql_db2.cpp b/src/sql/drivers/db2/qsql_db2.cpp index da87460..1a82377 100644 --- a/src/sql/drivers/db2/qsql_db2.cpp +++ b/src/sql/drivers/db2/qsql_db2.cpp @@ -1177,7 +1177,7 @@ QDB2Driver::~QDB2Driver() delete d; } -bool QDB2Driver::open(const QString& db, const QString& user, const QString& password, const QString&, int, +bool QDB2Driver::open(const QString& db, const QString& user, const QString& password, const QString& host, int port, const QString& connOpts) { if (isOpen()) @@ -1200,6 +1200,8 @@ bool QDB2Driver::open(const QString& db, const QString& user, const QString& pas setOpenError(true); return false; } + + QString protocol; // Set connection attributes const QStringList opts(connOpts.split(QLatin1Char(';'), QString::SkipEmptyParts)); for (int i = 0; i < opts.count(); ++i) { @@ -1230,7 +1232,10 @@ bool QDB2Driver::open(const QString& db, const QString& user, const QString& pas } else if (opt == QLatin1String("SQL_ATTR_LOGIN_TIMEOUT")) { v = val.toUInt(); r = SQLSetConnectAttr(d->hDbc, SQL_ATTR_LOGIN_TIMEOUT, (SQLPOINTER) v, 0); - } else { + } else if (opt.compare(QLatin1String("PROTOCOL"), Qt::CaseInsensitive) == 0) { + protocol = tmp; + } + else { qWarning("QDB2Driver::open: Unknown connection attribute '%s'", tmp.toLocal8Bit().constData()); } @@ -1239,9 +1244,18 @@ bool QDB2Driver::open(const QString& db, const QString& user, const QString& pas "Unable to set connection attribute '%1'").arg(opt), d); } + if (protocol.isEmpty()) + protocol = QLatin1String("PROTOCOL=TCPIP"); + + if (port < 0 ) + port = 50000; + QString connQStr; - connQStr = QLatin1String("DSN=") + db + QLatin1String(";UID=") + user + QLatin1String(";PWD=") - + password; + connQStr = protocol + QLatin1String(";DATABASE=") + db + QLatin1String(";HOSTNAME=") + host + + QLatin1String(";PORT=") + QString::number(port) + QLatin1String(";UID=") + user + + QLatin1String(";PWD=") + password; + + SQLTCHAR connOut[SQL_MAX_OPTION_STRING_LENGTH]; SQLSMALLINT cb; @@ -1260,7 +1274,7 @@ bool QDB2Driver::open(const QString& db, const QString& user, const QString& pas return false; } - d->user = user.toUpper(); + d->user = user; setOpen(true); setOpenError(false); return true; @@ -1305,10 +1319,25 @@ QSqlRecord QDB2Driver::record(const QString& tableName) const SQLHANDLE hStmt; QString catalog, schema, table; - qSplitTableQualifier(tableName.toUpper(), &catalog, &schema, &table); + qSplitTableQualifier(tableName, &catalog, &schema, &table); if (schema.isEmpty()) schema = d->user; + if (isIdentifierEscaped(catalog, QSqlDriver::TableName)) + catalog = stripDelimiters(catalog, QSqlDriver::TableName); + else + catalog = catalog.toUpper(); + + if (isIdentifierEscaped(schema, QSqlDriver::TableName)) + schema = stripDelimiters(schema, QSqlDriver::TableName); + else + schema = schema.toUpper(); + + if (isIdentifierEscaped(table, QSqlDriver::TableName)) + table = stripDelimiters(table, QSqlDriver::TableName); + else + table = table.toUpper(); + SQLRETURN r = SQLAllocHandle(SQL_HANDLE_STMT, d->hDbc, &hStmt); @@ -1322,6 +1351,9 @@ QSqlRecord QDB2Driver::record(const QString& tableName) const (SQLPOINTER) SQL_CURSOR_FORWARD_ONLY, SQL_IS_UINTEGER); + + //Aside: szSchemaName and szTableName parameters of SQLColumns + //are case sensitive search patterns, so no escaping is used. r = SQLColumns(hStmt, NULL, 0, @@ -1402,7 +1434,13 @@ QStringList QDB2Driver::tables(QSql::TableType type) const bool isNull; QString fieldVal = qGetStringData(hStmt, 2, -1, isNull); QString userVal = qGetStringData(hStmt, 1, -1, isNull); - if (userVal != d->user) + QString user = d->user; + if ( isIdentifierEscaped(user, QSqlDriver::TableName)) + user = stripDelimiters(user, QSqlDriver::TableName); + else + user = user.toUpper(); + + if (userVal != user) fieldVal = userVal + QLatin1Char('.') + fieldVal; tl.append(fieldVal); r = SQLFetchScroll(hStmt, @@ -1433,7 +1471,23 @@ QSqlIndex QDB2Driver::primaryIndex(const QString& tablename) const return index; } QString catalog, schema, table; - qSplitTableQualifier(tablename.toUpper(), &catalog, &schema, &table); + qSplitTableQualifier(tablename, &catalog, &schema, &table); + + if (isIdentifierEscaped(catalog, QSqlDriver::TableName)) + catalog = stripDelimiters(catalog, QSqlDriver::TableName); + else + catalog = catalog.toUpper(); + + if (isIdentifierEscaped(schema, QSqlDriver::TableName)) + schema = stripDelimiters(schema, QSqlDriver::TableName); + else + schema = schema.toUpper(); + + if (isIdentifierEscaped(table, QSqlDriver::TableName)) + table = stripDelimiters(table, QSqlDriver::TableName); + else + table = table.toUpper(); + r = SQLSetStmtAttr(hStmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY, diff --git a/src/sql/drivers/ibase/qsql_ibase.cpp b/src/sql/drivers/ibase/qsql_ibase.cpp index 259a247..d714327 100644 --- a/src/sql/drivers/ibase/qsql_ibase.cpp +++ b/src/sql/drivers/ibase/qsql_ibase.cpp @@ -1592,12 +1592,16 @@ QSqlRecord QIBaseDriver::record(const QString& tablename) const QSqlQuery q(createResult()); q.setForwardOnly(true); - + QString table = tablename; + if (isIdentifierEscaped(table, QSqlDriver::TableName)) + table = stripDelimiters(table, QSqlDriver::TableName); + else + table = table.toUpper(); q.exec(QLatin1String("SELECT a.RDB$FIELD_NAME, b.RDB$FIELD_TYPE, b.RDB$FIELD_LENGTH, " "b.RDB$FIELD_SCALE, b.RDB$FIELD_PRECISION, a.RDB$NULL_FLAG " "FROM RDB$RELATION_FIELDS a, RDB$FIELDS b " "WHERE b.RDB$FIELD_NAME = a.RDB$FIELD_SOURCE " - "AND a.RDB$RELATION_NAME = '") + tablename.toUpper() + QLatin1String("' " + "AND a.RDB$RELATION_NAME = '") + table + QLatin1String("' " "ORDER BY a.RDB$FIELD_POSITION")); while (q.next()) { @@ -1625,12 +1629,18 @@ QSqlIndex QIBaseDriver::primaryIndex(const QString &table) const if (!isOpen()) return index; + QString tablename = table; + if (isIdentifierEscaped(tablename, QSqlDriver::TableName)) + tablename = stripDelimiters(tablename, QSqlDriver::TableName); + else + tablename = tablename.toUpper(); + QSqlQuery q(createResult()); q.setForwardOnly(true); q.exec(QLatin1String("SELECT a.RDB$INDEX_NAME, b.RDB$FIELD_NAME, d.RDB$FIELD_TYPE, d.RDB$FIELD_SCALE " "FROM RDB$RELATION_CONSTRAINTS a, RDB$INDEX_SEGMENTS b, RDB$RELATION_FIELDS c, RDB$FIELDS d " "WHERE a.RDB$CONSTRAINT_TYPE = 'PRIMARY KEY' " - "AND a.RDB$RELATION_NAME = '") + table.toUpper() + + "AND a.RDB$RELATION_NAME = '") + tablename + QLatin1String(" 'AND a.RDB$INDEX_NAME = b.RDB$INDEX_NAME " "AND c.RDB$RELATION_NAME = a.RDB$RELATION_NAME " "AND c.RDB$FIELD_NAME = b.RDB$FIELD_NAME " diff --git a/src/sql/drivers/odbc/qsql_odbc.cpp b/src/sql/drivers/odbc/qsql_odbc.cpp index 727c5ce..c47e7e5 100644 --- a/src/sql/drivers/odbc/qsql_odbc.cpp +++ b/src/sql/drivers/odbc/qsql_odbc.cpp @@ -598,6 +598,7 @@ QChar QODBCDriverPrivate::quoteChar() const return quote; } + bool QODBCDriverPrivate::setConnectionOptions(const QString& connOpts) { // Set any connection attributes @@ -2441,6 +2442,9 @@ bool QODBCDriver::isIdentifierEscapedImplementation(const QString &identifier, I return identifier.size() > 2 && identifier.startsWith(quote) //left delimited && identifier.endsWith(quote); //right delimited + return true; + else + return false; } QT_END_NAMESPACE diff --git a/src/sql/drivers/psql/qsql_psql.cpp b/src/sql/drivers/psql/qsql_psql.cpp index db09e93..1ab8214 100644 --- a/src/sql/drivers/psql/qsql_psql.cpp +++ b/src/sql/drivers/psql/qsql_psql.cpp @@ -891,6 +891,16 @@ QSqlIndex QPSQLDriver::primaryIndex(const QString& tablename) const QString schema; qSplitTableName(tbl, schema); + if (isIdentifierEscaped(tbl, QSqlDriver::TableName)) + tbl = stripDelimiters(tbl, QSqlDriver::TableName); + else + tbl = tbl.toLower(); + + if (isIdentifierEscaped(schema, QSqlDriver::TableName)) + schema = stripDelimiters(schema, QSqlDriver::TableName); + else + schema = schema.toLower(); + switch(d->pro) { case QPSQLDriver::Version6: stmt = QLatin1String("select pg_att1.attname, int(pg_att1.atttypid), pg_cl.relname " @@ -923,7 +933,7 @@ QSqlIndex QPSQLDriver::primaryIndex(const QString& tablename) const "FROM pg_attribute, pg_class " "WHERE %1 pg_class.oid IN " "(SELECT indexrelid FROM pg_index WHERE indisprimary = true AND indrelid IN " - " (SELECT oid FROM pg_class WHERE lower(relname) = '%2')) " + " (SELECT oid FROM pg_class WHERE relname = '%2')) " "AND pg_attribute.attrelid = pg_class.oid " "AND pg_attribute.attisdropped = false " "ORDER BY pg_attribute.attnum"); @@ -931,11 +941,11 @@ QSqlIndex QPSQLDriver::primaryIndex(const QString& tablename) const stmt = stmt.arg(QLatin1String("pg_table_is_visible(pg_class.oid) AND")); else stmt = stmt.arg(QString::fromLatin1("pg_class.relnamespace = (select oid from " - "pg_namespace where pg_namespace.nspname = '%1') AND ").arg(schema.toLower())); + "pg_namespace where pg_namespace.nspname = '%1') AND ").arg(schema)); break; } - i.exec(stmt.arg(tbl.toLower())); + i.exec(stmt.arg(tbl)); while (i.isActive() && i.next()) { QSqlField f(i.value(0).toString(), qDecodePSQLType(i.value(1).toInt())); idx.append(f); @@ -954,6 +964,16 @@ QSqlRecord QPSQLDriver::record(const QString& tablename) const QString schema; qSplitTableName(tbl, schema); + if (isIdentifierEscaped(tbl, QSqlDriver::TableName)) + tbl = stripDelimiters(tbl, QSqlDriver::TableName); + else + tbl = tbl.toLower(); + + if (isIdentifierEscaped(schema, QSqlDriver::TableName)) + schema = stripDelimiters(schema, QSqlDriver::TableName); + else + schema = schema.toLower(); + QString stmt; switch(d->pro) { case QPSQLDriver::Version6: @@ -998,7 +1018,7 @@ QSqlRecord QPSQLDriver::record(const QString& tablename) const "left join pg_attrdef on (pg_attrdef.adrelid = " "pg_attribute.attrelid and pg_attrdef.adnum = pg_attribute.attnum) " "where %1 " - "and lower(pg_class.relname) = '%2' " + "and pg_class.relname = '%2' " "and pg_attribute.attnum > 0 " "and pg_attribute.attrelid = pg_class.oid " "and pg_attribute.attisdropped = false " @@ -1007,12 +1027,12 @@ QSqlRecord QPSQLDriver::record(const QString& tablename) const stmt = stmt.arg(QLatin1String("pg_table_is_visible(pg_class.oid)")); else stmt = stmt.arg(QString::fromLatin1("pg_class.relnamespace = (select oid from " - "pg_namespace where pg_namespace.nspname = '%1')").arg(schema.toLower())); + "pg_namespace where pg_namespace.nspname = '%1')").arg(schema)); break; } QSqlQuery query(createResult()); - query.exec(stmt.arg(tbl.toLower())); + query.exec(stmt.arg(tbl)); if (d->pro >= QPSQLDriver::Version71) { while (query.next()) { int len = query.value(3).toInt(); diff --git a/src/sql/drivers/sqlite/qsql_sqlite.cpp b/src/sql/drivers/sqlite/qsql_sqlite.cpp index 05f5ab3..8e1091b 100644 --- a/src/sql/drivers/sqlite/qsql_sqlite.cpp +++ b/src/sql/drivers/sqlite/qsql_sqlite.cpp @@ -656,9 +656,13 @@ QSqlIndex QSQLiteDriver::primaryIndex(const QString &tblname) const if (!isOpen()) return QSqlIndex(); + QString table = tblname; + if (isIdentifierEscaped(table, QSqlDriver::TableName)) + table = stripDelimiters(table, QSqlDriver::TableName); + QSqlQuery q(createResult()); q.setForwardOnly(true); - return qGetTableInfo(q, tblname, true); + return qGetTableInfo(q, table, true); } QSqlRecord QSQLiteDriver::record(const QString &tbl) const @@ -666,9 +670,13 @@ QSqlRecord QSQLiteDriver::record(const QString &tbl) const if (!isOpen()) return QSqlRecord(); + QString table = tbl; + if (isIdentifierEscaped(table, QSqlDriver::TableName)) + table = stripDelimiters(table, QSqlDriver::TableName); + QSqlQuery q(createResult()); q.setForwardOnly(true); - return qGetTableInfo(q, tbl); + return qGetTableInfo(q, table); } QVariant QSQLiteDriver::handle() const @@ -676,10 +684,10 @@ QVariant QSQLiteDriver::handle() const return qVariantFromValue(d->access); } -QString QSQLiteDriver::escapeIdentifier(const QString &identifier, IdentifierType /*type*/) const +QString QSQLiteDriver::escapeIdentifier(const QString &identifier, IdentifierType type) const { QString res = identifier; - if(!identifier.isEmpty() && identifier.left(1) != QString(QLatin1Char('"')) && identifier.right(1) != QString(QLatin1Char('"')) ) { + if(!identifier.isEmpty() && !isIdentifierEscaped(identifier, type) ) { res.replace(QLatin1Char('"'), QLatin1String("\"\"")); res.prepend(QLatin1Char('"')).append(QLatin1Char('"')); res.replace(QLatin1Char('.'), QLatin1String("\".\"")); diff --git a/src/sql/drivers/tds/qsql_tds.cpp b/src/sql/drivers/tds/qsql_tds.cpp index 5ddc4e4..e100863 100644 --- a/src/sql/drivers/tds/qsql_tds.cpp +++ b/src/sql/drivers/tds/qsql_tds.cpp @@ -293,6 +293,8 @@ QTDSResult::QTDSResult(const QTDSDriver* db) // insert d in error handler dict errs()->insert(d->dbproc, d); + dbcmd(d->dbproc, "set quoted_identifier on"); + dbsqlexec(d->dbproc); } QTDSResult::~QTDSResult() @@ -367,7 +369,7 @@ bool QTDSResult::gotoNext(QSqlCachedResult::ValueCache &values, int index) if (qIsNull(d->buffer.at(i * 2 + 1))) values[idx] = QVariant(QVariant::String); else - values[idx] = QString::fromLocal8Bit((const char*)d->buffer.at(i * 2)); + values[idx] = QString::fromLocal8Bit((const char*)d->buffer.at(i * 2)).trimmed(); break; case QVariant::ByteArray: { if (qIsNull(d->buffer.at(i * 2 + 1))) @@ -698,9 +700,14 @@ QSqlRecord QTDSDriver::record(const QString& tablename) const return info; QSqlQuery t(createResult()); t.setForwardOnly(true); + + QString table = tablename; + if (isIdentifierEscaped(table, QSqlDriver::TableName)) + table = stripDelimiters(table, QSqlDriver::TableName); + QString stmt (QLatin1String("select name, type, length, prec from syscolumns " "where id = (select id from sysobjects where name = '%1')")); - t.exec(stmt.arg(tablename)); + t.exec(stmt.arg(table)); while (t.next()) { QSqlField f(t.value(0).toString().simplified(), qDecodeTDSType(t.value(1).toInt())); f.setLength(t.value(2).toInt()); @@ -770,13 +777,17 @@ QSqlIndex QTDSDriver::primaryIndex(const QString& tablename) const { QSqlRecord rec = record(tablename); - QSqlIndex idx(tablename); - if ((!isOpen()) || (tablename.isEmpty())) + QString table = tablename; + if (isIdentifierEscaped(table, QSqlDriver::TableName)) + table = stripDelimiters(table, QSqlDriver::TableName); + + QSqlIndex idx(table); + if ((!isOpen()) || (table.isEmpty())) return QSqlIndex(); QSqlQuery t(createResult()); t.setForwardOnly(true); - t.exec(QString::fromLatin1("sp_helpindex '%1'").arg(tablename)); + t.exec(QString::fromLatin1("sp_helpindex '%1'").arg(table)); if (t.next()) { QStringList fNames = t.value(2).toString().simplified().split(QLatin1Char(',')); QRegExp regx(QLatin1String("\\s*(\\S+)(?:\\s+(DESC|desc))?\\s*")); diff --git a/src/sql/models/qsqltablemodel.cpp b/src/sql/models/qsqltablemodel.cpp index 1acc846..156af26 100644 --- a/src/sql/models/qsqltablemodel.cpp +++ b/src/sql/models/qsqltablemodel.cpp @@ -98,7 +98,10 @@ bool QSqlTableModelPrivate::setRecord(int row, const QSqlRecord &record) int QSqlTableModelPrivate::nameToIndex(const QString &name) const { - return rec.indexOf(name); + QString fieldname = name; + if (db.driver()->isIdentifierEscaped(fieldname, QSqlDriver::FieldName)) + fieldname = db.driver()->stripDelimiters(fieldname, QSqlDriver::FieldName); + return rec.indexOf(fieldname); } void QSqlTableModelPrivate::initRecordAndPrimaryIndex() @@ -367,10 +370,7 @@ void QSqlTableModel::setTable(const QString &tableName) { Q_D(QSqlTableModel); clear(); - if(d->db.tables().contains(tableName.toUpper())) - d->tableName = tableName.toUpper(); - else - d->tableName = tableName; + d->tableName = tableName; d->initRecordAndPrimaryIndex(); d->initColOffsets(d->rec.count()); @@ -976,7 +976,9 @@ QString QSqlTableModel::orderByClause() const if (!f.isValid()) return s; - QString table = d->db.driver()->escapeIdentifier(d->tableName, QSqlDriver::TableName); + QString table = d->tableName; + //we can safely escape the field because it would have been obtained from the database + //and have the correct case QString field = d->db.driver()->escapeIdentifier(f.name(), QSqlDriver::FieldName); s.append(QLatin1String("ORDER BY ")).append(table).append(QLatin1Char('.')).append(field); s += d->sortOrder == Qt::AscendingOrder ? QLatin1String(" ASC") : QLatin1String(" DESC"); @@ -1317,8 +1319,12 @@ bool QSqlTableModel::setRecord(int row, const QSqlRecord &record) mrow.rec = d->rec; mrow.primaryValues = d->primaryValues(indexInQuery(createIndex(row, 0)).row()); } + QString fieldName; for (int i = 0; i < record.count(); ++i) { - int idx = mrow.rec.indexOf(record.fieldName(i)); + fieldName = record.fieldName(i); + if (d->db.driver()->isIdentifierEscaped(fieldName, QSqlDriver::FieldName)) + fieldName = d->db.driver()->stripDelimiters(fieldName, QSqlDriver::FieldName); + int idx = mrow.rec.indexOf(fieldName); if (idx == -1) isOk = false; else diff --git a/tests/auto/qsqldatabase/tst_databases.h b/tests/auto/qsqldatabase/tst_databases.h index b193303..a490a2f 100644 --- a/tests/auto/qsqldatabase/tst_databases.h +++ b/tests/auto/qsqldatabase/tst_databases.h @@ -105,11 +105,7 @@ inline static QString qTableName( const QString& prefix, QSqlDriver* driver = 0 inline static bool testWhiteSpaceNames( const QString &name ) { -/* return name.startsWith( "QPSQL" ) - || name.startsWith( "QODBC" ) - || name.startsWith( "QSQLITE" ) - || name.startsWith( "QMYSQL" );*/ - return name != QLatin1String("QSQLITE2"); + return name != QLatin1String("QTDS7"); } inline static QString toHex( const QString& binary ) @@ -211,7 +207,7 @@ public: // This requires a local ODBC data source to be configured( pointing to a MySql database ) // addDb( "QODBC", "mysqlodbc", "troll", "trond" ); // addDb( "QODBC", "SqlServer", "troll", "trond" ); -// addDb( "QTDS7", "testdb", "troll", "trondk", "horsehead.nokia.troll.no" ); +// addDb( "QTDS7", "testdb", "troll", "trondk", "horsehead" ); // addDb( "QODBC", "silencetestdb", "troll", "trond", "silence" ); // addDb( "QODBC", "horseheadtestdb", "troll", "trondk", "horsehead" ); @@ -221,7 +217,7 @@ public: // addDb( "QMYSQL3", "testdb", "troll", "trond", "horsehead.nokia.troll.no", 3309, "CLIENT_COMPRESS=1;CLIENT_SSL=1" ); // MySQL 5.0.18 Linux // addDb( "QMYSQL3", "testdb", "troll", "trond", "iceblink.nokia.troll.no" ); // MySQL 5.0.13 Windows // addDb( "QMYSQL3", "testdb", "testuser", "Ee4Gabf6_", "mysql4-nokia.trolltech.com.au" ); // MySQL 4.1.22-2.el4 linux -// addDb( "QMYSQL3", "testdb", "testuser", "Ee4Gabf6_", "mysql5-nokia.trolltech.com.au" ); // MySQL 5.0.45-7.el5 linux +// addDb( "QMYSQL3", "testdb", "testuser", "Ee4Gabf6_", "mysql5-nokia.trolltech.com.au" ); // MySQL 5.0.45-7.el5 linux // addDb( "QPSQL7", "testdb", "troll", "trond", "horsehead.nokia.troll.no" ); // V7.2 NOT SUPPORTED! // addDb( "QPSQL7", "testdb", "troll", "trond", "horsehead.nokia.troll.no", 5434 ); // V7.2 NOT SUPPORTED! Multi-byte @@ -242,8 +238,8 @@ public: // addDb( "QIBASE", "/opt/firebird/databases/testdb.fdb", "testuser", "Ee4Gabf6_", "firebird2-nokia.trolltech.com.au" ); // Firebird 2.1.1 // use in-memory database to prevent local files -// addDb("QSQLITE", ":memory:"); - addDb( "QSQLITE", QDir::toNativeSeparators(QDir::tempPath()+"/foo.db") ); + addDb("QSQLITE", ":memory:"); +// addDb( "QSQLITE", QDir::toNativeSeparators(QDir::tempPath()+"/foo.db") ); // addDb( "QSQLITE2", QDir::toNativeSeparators(QDir::tempPath()+"/foo2.db") ); // addDb( "QODBC3", "DRIVER={SQL SERVER};SERVER=iceblink.nokia.troll.no\\ICEBLINK", "troll", "trond", "" ); // addDb( "QODBC3", "DRIVER={SQL Native Client};SERVER=silence.nokia.troll.no\\SQLEXPRESS", "troll", "trond", "" ); @@ -320,16 +316,18 @@ public: QSqlQuery q( db ); QStringList dbtables=db.tables(); - foreach(const QString &tableName, tableNames) { + foreach(QString tableName, tableNames) + { wasDropped = true; - foreach(const QString dbtablesName, dbtables) { - if(dbtablesName.toUpper() == tableName.toUpper()) { - dbtables.removeAll(dbtablesName); - wasDropped = q.exec("drop table " + db.driver()->escapeIdentifier( dbtablesName, QSqlDriver::TableName )); - if(!wasDropped) - wasDropped = q.exec("drop table " + dbtablesName); - } - } + QString table=tableName; + if ( db.driver()->isIdentifierEscaped(table, QSqlDriver::TableName)) + table = db.driver()->stripDelimiters(table, QSqlDriver::TableName); + + if ( dbtables.contains( table, Qt::CaseSensitive ) ) + wasDropped = q.exec( "drop table " + tableName); + else if ( dbtables.contains( table, Qt::CaseInsensitive ) ) + wasDropped = q.exec( "drop table " + tableName); + if ( !wasDropped ) qWarning() << dbToString(db) << "unable to drop table" << tableName << ':' << q.lastError().text() << "tables:" << dbtables; } diff --git a/tests/auto/qsqldriver/qsqldriver.pro b/tests/auto/qsqldriver/qsqldriver.pro new file mode 100644 index 0000000..0024841 --- /dev/null +++ b/tests/auto/qsqldriver/qsqldriver.pro @@ -0,0 +1,16 @@ +load(qttest_p4) +SOURCES += tst_qsqldriver.cpp + +QT += sql + +wince*: { + plugFiles.sources = ../../../plugins/sqldrivers + plugFiles.path = . + DEPLOYMENT += plugFiles +} else { + win32-g++ { + LIBS += -lws2_32 + } else:win32 { + LIBS += ws2_32.lib + } +} diff --git a/tests/auto/qsqldriver/tst_qsqldriver.cpp b/tests/auto/qsqldriver/tst_qsqldriver.cpp new file mode 100644 index 0000000..bbd7483 --- /dev/null +++ b/tests/auto/qsqldriver/tst_qsqldriver.cpp @@ -0,0 +1,218 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QtTest/QtTest> +#include <QtSql/QtSql> + +#include "../qsqldatabase/tst_databases.h" + + + +//TESTED_CLASS= +//TESTED_FILES= + +class tst_QSqlDriver : public QObject +{ + Q_OBJECT + +public: + void recreateTestTables(QSqlDatabase); + + tst_Databases dbs; + +public slots: + void initTestCase_data(); + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + +private slots: + void record(); + void primaryIndex(); +}; + + +void tst_QSqlDriver::initTestCase_data() +{ + dbs.open(); + if (dbs.fillTestTable() == 0) { + qWarning("NO DATABASES"); + QSKIP("No database drivers are available in this Qt configuration", SkipAll); + } +} + +void tst_QSqlDriver::recreateTestTables(QSqlDatabase db) +{ + QSqlQuery q(db); + + QStringList tableNames; + tableNames << qTableName( "relTEST1" ); + tst_Databases::safeDropTables( db, tableNames ); + + QVERIFY_SQL( q, exec("create table " + qTableName("relTEST1") + + " (id int not null primary key, name varchar(20), title_key int, another_title_key int)")); + QVERIFY_SQL( q, exec("insert into " + qTableName("relTEST1") + " values(1, 'harry', 1, 2)")); + QVERIFY_SQL( q, exec("insert into " + qTableName("relTEST1") + " values(2, 'trond', 2, 1)")); + QVERIFY_SQL( q, exec("insert into " + qTableName("relTEST1") + " values(3, 'vohi', 1, 2)")); + QVERIFY_SQL( q, exec("insert into " + qTableName("relTEST1") + " values(4, 'boris', 2, 2)")); +} + +void tst_QSqlDriver::initTestCase() +{ + foreach (const QString &dbname, dbs.dbNames) + recreateTestTables(QSqlDatabase::database(dbname)); +} + +void tst_QSqlDriver::cleanupTestCase() +{ + QStringList tableNames; + tableNames << qTableName( "relTEST1" ); + foreach (const QString &dbName, dbs.dbNames) { + QSqlDatabase db = QSqlDatabase::database(dbName); + tst_Databases::safeDropTables( db, tableNames ); + } + dbs.close(); +} + +void tst_QSqlDriver::init() +{ +} + +void tst_QSqlDriver::cleanup() +{ +} + +void tst_QSqlDriver::record() +{ + QFETCH_GLOBAL(QString, dbName); + QSqlDatabase db = QSqlDatabase::database(dbName); + CHECK_DATABASE(db); + + QString tablename = qTableName("relTEST1"); + QStringList fields; + fields << "id" << "name" << "title_key" << "another_title_key"; + + //check we can get records using an unquoted mixed case table name + QSqlRecord rec = db.driver()->record(tablename); + QCOMPARE(rec.count(), 4); + + if (db.driverName().startsWith("QIBASE")|| db.driverName().startsWith("QOCI") || db.driverName().startsWith("QDB2")) + for(int i = 0; i < fields.count(); ++i) + fields[i] = fields[i].toUpper(); + + for (int i = 0; i < fields.count(); ++i) + QCOMPARE(rec.fieldName(i), fields[i]); + + if (db.driverName().startsWith("QIBASE") || db.driverName().startsWith("QOCI") || db.driverName().startsWith("QDB2")) + tablename = tablename.toUpper(); + else if (db.driverName().startsWith("QPSQL")) + tablename = tablename.toLower(); + + //check we can get records using a properly quoted table name + rec = db.driver()->record(db.driver()->escapeIdentifier(tablename,QSqlDriver::TableName)); + QCOMPARE(rec.count(), 4); + + for (int i = 0; i < fields.count(); ++i) + QCOMPARE(rec.fieldName(i), fields[i]); + + if( db.driverName().startsWith("QIBASE") || db.driverName().startsWith("QOCI") || db.driverName().startsWith("QDB2")) + tablename = tablename.toLower(); + else if (db.driverName().startsWith("QPSQL")) + tablename = tablename.toUpper(); + + //check that we can't get records using incorrect tablename casing that's been quoted + rec = db.driver()->record(db.driver()->escapeIdentifier(tablename,QSqlDriver::TableName)); + if (db.driverName().startsWith("QMYSQL") || db.driverName().startsWith("QSQLITE") || db.driverName().startsWith("QTDS")) + QCOMPARE(rec.count(), 4); //mysql, sqlite and tds will match + else + QCOMPARE(rec.count(), 0); + +} + +void tst_QSqlDriver::primaryIndex() +{ + QFETCH_GLOBAL(QString, dbName); + QSqlDatabase db = QSqlDatabase::database(dbName); + CHECK_DATABASE(db); + + QString tablename = qTableName("relTEST1"); + //check that we can get primary index using unquoted mixed case table name + QSqlIndex index = db.driver()->primaryIndex(tablename); + QCOMPARE(index.count(), 1); + + if( db.driverName().startsWith("QIBASE") || db.driverName().startsWith("QOCI") || db.driverName().startsWith("QDB2")) + QCOMPARE(index.fieldName(0), QString::fromLatin1("ID")); + else + QCOMPARE(index.fieldName(0), QString::fromLatin1("id")); + + + //check that we can get the primary index using a quoted tablename + if( db.driverName().startsWith("QIBASE") || db.driverName().startsWith("QOCI") || db.driverName().startsWith("QDB2")) + tablename = tablename.toUpper(); + else if (db.driverName().startsWith("QPSQL")) + tablename = tablename.toLower(); + + index = db.driver()->primaryIndex(db.driver()->escapeIdentifier(tablename, QSqlDriver::TableName)); + QCOMPARE(index.count(), 1); + if( db.driverName().startsWith("QIBASE") || db.driverName().startsWith("QOCI") || db.driverName().startsWith("QDB2")) + QCOMPARE(index.fieldName(0), QString::fromLatin1("ID")); + else + QCOMPARE(index.fieldName(0), QString::fromLatin1("id")); + + + + //check that we can not get the primary index using a quoted but incorrect table name casing + if( db.driverName().startsWith("QIBASE") || db.driverName().startsWith("QOCI") || db.driverName().startsWith("QDB2")) + tablename = tablename.toLower(); + else if (db.driverName().startsWith("QPSQL")) + tablename = tablename.toUpper(); + + index = db.driver()->primaryIndex(db.driver()->escapeIdentifier(tablename, QSqlDriver::TableName)); + if (db.driverName().startsWith("QMYSQL") || db.driverName().startsWith("QSQLITE") || db.driverName().startsWith("QTDS")) + QCOMPARE(index.count(), 1); //mysql will always find the table name regardless of casing + else + QCOMPARE(index.count(), 0); +} + +QTEST_MAIN(tst_QSqlDriver) +#include "tst_qsqldriver.moc" diff --git a/tests/auto/qsqlrelationaltablemodel/tst_qsqlrelationaltablemodel.cpp b/tests/auto/qsqlrelationaltablemodel/tst_qsqlrelationaltablemodel.cpp index 5725548..4588af8 100644 --- a/tests/auto/qsqlrelationaltablemodel/tst_qsqlrelationaltablemodel.cpp +++ b/tests/auto/qsqlrelationaltablemodel/tst_qsqlrelationaltablemodel.cpp @@ -82,6 +82,10 @@ private slots: void insertRecordDuplicateFieldNames(); void invalidData(); void relationModel(); + void casing(); + void escapedRelations(); + void escapedTableName(); + void whiteSpaceInIdentifiers(); }; @@ -103,7 +107,9 @@ void tst_QSqlRelationalTableModel::recreateTestTables(QSqlDatabase db) << qTableName( "reltest2" ) << qTableName( "reltest3" ) << qTableName( "reltest4" ) - << qTableName( "reltest5" ); + << qTableName( "reltest5" ) + << db.driver()->escapeIdentifier(qTableName( "rel test6" ), QSqlDriver::TableName) + << db.driver()->escapeIdentifier(qTableName( "rel test7" ), QSqlDriver::TableName); tst_Databases::safeDropTables( db, tableNames ); QVERIFY_SQL( q, exec("create table " + qTableName("reltest1") + @@ -128,6 +134,19 @@ void tst_QSqlRelationalTableModel::recreateTestTables(QSqlDatabase db) QVERIFY_SQL( q, exec("create table " + qTableName("reltest5") + " (title varchar(20) not null primary key, abbrev varchar(20))")); QVERIFY_SQL( q, exec("insert into " + qTableName("reltest5") + " values('herr', 'Hr')")); QVERIFY_SQL( q, exec("insert into " + qTableName("reltest5") + " values('mister', 'Mr')")); + + if (testWhiteSpaceNames(db.driverName())) { + QString reltest6 = db.driver()->escapeIdentifier(qTableName("rel test6"), QSqlDriver::TableName); + QVERIFY_SQL( q, exec("create table " + reltest6 + " (id int not null primary key, " + db.driver()->escapeIdentifier("city key", QSqlDriver::FieldName) + + " int, " + db.driver()->escapeIdentifier("extra field", QSqlDriver::FieldName) + " int)")); + QVERIFY_SQL( q, exec("insert into " + reltest6 + " values(1, 1,9)")); + QVERIFY_SQL( q, exec("insert into " + reltest6 + " values(2, 2,8)")); + + QString reltest7 = db.driver()->escapeIdentifier(qTableName("rel test7"), QSqlDriver::TableName); + QVERIFY_SQL( q, exec("create table " + reltest7 + " (" + db.driver()->escapeIdentifier("city id", QSqlDriver::TableName) + " int not null primary key, " + db.driver()->escapeIdentifier("city name", QSqlDriver::FieldName) + " varchar(20))")); + QVERIFY_SQL( q, exec("insert into " + reltest7 + " values(1, 'New York')")); + QVERIFY_SQL( q, exec("insert into " + reltest7 + " values(2, 'Washington')")); + } } void tst_QSqlRelationalTableModel::initTestCase() @@ -142,10 +161,14 @@ void tst_QSqlRelationalTableModel::cleanupTestCase() tableNames << qTableName( "reltest1" ) << qTableName( "reltest2" ) << qTableName( "reltest3" ) - << qTableName( "reltest4" ); + << qTableName( "reltest4" ) + << qTableName( "reltest5" ); foreach (const QString &dbName, dbs.dbNames) { QSqlDatabase db = QSqlDatabase::database(dbName); - tst_Databases::safeDropTables( db, tableNames ); + QStringList tables = tableNames; + tables << db.driver()->escapeIdentifier(qTableName( "rel test6" ), QSqlDriver::TableName) + << db.driver()->escapeIdentifier(qTableName( "rel test7" ), QSqlDriver::TableName); + tst_Databases::safeDropTables( db, tables ); } dbs.close(); } @@ -273,7 +296,12 @@ void tst_QSqlRelationalTableModel::setData() model.setTable(qTableName("reltest1")); model.setRelation(2, QSqlRelation(qTableName("reltest2"), "tid", "title")); - model.setRelation(3, QSqlRelation(qTableName("reltest2"), "tid", "title")); + + //sybase doesn't allow tables with the same alias used twice as col names + //so don't set up an identical relation when using the tds driver + if (!db.driverName().startsWith("QTDS")) + model.setRelation(3, QSqlRelation(qTableName("reltest2"), "tid", "title")); + model.setEditStrategy(QSqlTableModel::OnManualSubmit); model.setSort(0, Qt::AscendingOrder); QVERIFY_SQL(model, select()); @@ -284,7 +312,10 @@ void tst_QSqlRelationalTableModel::setData() QCOMPARE(model.data(model.index(2, 1)).toString(), QString("vohi2")); QCOMPARE(model.data(model.index(3, 2)).toString(), QString("herr")); - QCOMPARE(model.data(model.index(0, 3)).toString(), QString("herr")); + if (!db.driverName().startsWith("QTDS")) + QCOMPARE(model.data(model.index(0, 3)).toString(), QString("herr")); + else + QCOMPARE(model.data(model.index(0, 3)).toInt(), 1); QVERIFY_SQL(model, submitAll()); } @@ -299,10 +330,15 @@ void tst_QSqlRelationalTableModel::setData() QCOMPARE(model.data(model.index(0, 3)).toInt(), 1); model.setRelation(2, QSqlRelation(qTableName("reltest2"), "tid", "title")); - model.setRelation(3, QSqlRelation(qTableName("reltest2"), "tid", "title")); + if (!db.driverName().startsWith("QTDS")) + model.setRelation(3, QSqlRelation(qTableName("reltest2"), "tid", "title")); QVERIFY_SQL(model, select()); QCOMPARE(model.data(model.index(3, 2)).toString(), QString("herr")); - QCOMPARE(model.data(model.index(0, 3)).toString(), QString("herr")); + + if (!db.driverName().startsWith("QTDS")) + QCOMPARE(model.data(model.index(0, 3)).toString(), QString("herr")); + else + QCOMPARE(model.data(model.index(0, 3)).toInt(), 1); } //check setting of data when the relational key is a non-integer type @@ -336,7 +372,8 @@ void tst_QSqlRelationalTableModel::multipleRelation() model.setTable(qTableName("reltest1")); model.setRelation(2, QSqlRelation(qTableName("reltest2"), "tid", "title")); - model.setRelation(3, QSqlRelation(qTableName("reltest2"), "tid", "title")); + model.setRelation(3, QSqlRelation(qTableName("reltest4"), "id", "name")); + model.setSort(0, Qt::AscendingOrder); QVERIFY_SQL(model, select()); QCOMPARE(model.data(model.index(2, 0)).toInt(), 3); @@ -344,7 +381,7 @@ void tst_QSqlRelationalTableModel::multipleRelation() QCOMPARE(model.data(model.index(0, 0)).toInt(), 1); QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry")); QCOMPARE(model.data(model.index(0, 2)).toString(), QString("herr")); - QCOMPARE(model.data(model.index(0, 3)).toString(), QString("mister")); + QCOMPARE(model.data(model.index(0, 3)).toString(), QString("Trondheim")); } void tst_QSqlRelationalTableModel::insertRecord() @@ -357,6 +394,7 @@ void tst_QSqlRelationalTableModel::insertRecord() model.setTable(qTableName("reltest1")); model.setRelation(2, QSqlRelation(qTableName("reltest2"), "tid", "title")); + model.setSort(0, Qt::AscendingOrder); QVERIFY_SQL(model, select()); QSqlRecord rec; @@ -398,6 +436,7 @@ void tst_QSqlRelationalTableModel::setRecord() model.setTable(qTableName("reltest1")); model.setRelation(2, QSqlRelation(qTableName("reltest2"), "tid", "title")); + model.setSort(0, Qt::AscendingOrder); QVERIFY_SQL(model, select()); QSqlRecord rec; @@ -450,13 +489,18 @@ void tst_QSqlRelationalTableModel::insertWithStrategies() model.setTable(qTableName("reltest1")); model.setRelation(2, QSqlRelation(qTableName("reltest2"), "tid", "title")); - model.setRelation(3, QSqlRelation(qTableName("reltest2"), "tid", "title")); + + if (!db.driverName().startsWith("QTDS")) + model.setRelation(3, QSqlRelation(qTableName("reltest2"), "tid", "title")); QVERIFY_SQL(model, select()); QCOMPARE(model.data(model.index(0,0)).toInt(), 1); QCOMPARE(model.data(model.index(0,1)).toString(), QString("harry")); QCOMPARE(model.data(model.index(0,2)).toString(), QString("herr")); - QCOMPARE(model.data(model.index(0,3)).toString(), QString("mister")); + if (!db.driverName().startsWith("QTDS")) + QCOMPARE(model.data(model.index(0,3)).toString(), QString("mister")); + else + QCOMPARE(model.data(model.index(0,3)).toInt(), 2); model.insertRows(0, 1); model.setData(model.index(0, 0), 1011); @@ -467,12 +511,20 @@ void tst_QSqlRelationalTableModel::insertWithStrategies() QCOMPARE(model.data(model.index(0,0)).toInt(), 1011); QCOMPARE(model.data(model.index(0,1)).toString(), QString("test")); QCOMPARE(model.data(model.index(0,2)).toString(), QString("mister")); - QCOMPARE(model.data(model.index(0,3)).toString(), QString("herr")); + if (!db.driverName().startsWith("QTDS")) + QCOMPARE(model.data(model.index(0,3)).toString(), QString("herr")); + else + QCOMPARE(model.data(model.index(0,3)).toInt(), 1); QCOMPARE(model.data(model.index(1,0)).toInt(), 1); QCOMPARE(model.data(model.index(1,1)).toString(), QString("harry")); QCOMPARE(model.data(model.index(1,2)).toString(), QString("herr")); - QCOMPARE(model.data(model.index(1,3)).toString(), QString("mister")); + if (!db.driverName().startsWith("QTDS")) + QCOMPARE(model.data(model.index(1,3)).toString(), QString("mister")); + else + QCOMPARE(model.data(model.index(1,3)).toInt(), 2); + + QVERIFY_SQL(model, submitAll()); @@ -481,9 +533,16 @@ void tst_QSqlRelationalTableModel::insertWithStrategies() QCOMPARE(model.data(model.index(0,0)).toInt(), 1); QCOMPARE(model.data(model.index(0,1)).toString(), QString("harry")); QCOMPARE(model.data(model.index(0,2)).toString(), QString("herr")); - QCOMPARE(model.data(model.index(0,3)).toString(), QString("mister")); - model.setData(model.index(0,3),1); - QCOMPARE(model.data(model.index(0,3)).toString(), QString("herr")); + + if (!db.driverName().startsWith("QTDS")) { + QCOMPARE(model.data(model.index(0,3)).toString(), QString("mister")); + model.setData(model.index(0,3),1); + QCOMPARE(model.data(model.index(0,3)).toString(), QString("herr")); + } else { + QCOMPARE(model.data(model.index(0,3)).toInt(), 2); + model.setData(model.index(0,3),1); + QCOMPARE(model.data(model.index(0,3)).toInt(), 1); + } model.insertRows(0, 2); model.setData(model.index(0, 0), 1012); @@ -499,17 +558,27 @@ void tst_QSqlRelationalTableModel::insertWithStrategies() QCOMPARE(model.data(model.index(0,0)).toInt(),1012); QCOMPARE(model.data(model.index(0,1)).toString(), QString("george")); QCOMPARE(model.data(model.index(0,2)).toString(), QString("mister")); - QCOMPARE(model.data(model.index(0,3)).toString(), QString("mister")); + if (!db.driverName().startsWith("QTDS")) + QCOMPARE(model.data(model.index(0,3)).toString(), QString("mister")); + else + QCOMPARE(model.data(model.index(0,3)).toInt(), 2); + QCOMPARE(model.data(model.index(1,0)).toInt(),1013); QCOMPARE(model.data(model.index(1,1)).toString(), QString("kramer")); QCOMPARE(model.data(model.index(1,2)).toString(), QString("mister")); - QCOMPARE(model.data(model.index(1,3)).toString(), QString("herr")); + if (!db.driverName().startsWith("QTDS")) + QCOMPARE(model.data(model.index(1,3)).toString(), QString("herr")); + else + QCOMPARE(model.data(model.index(1,3)).toInt(), 1); QCOMPARE(model.data(model.index(2,0)).toInt(), 1); QCOMPARE(model.data(model.index(2,1)).toString(), QString("harry")); QCOMPARE(model.data(model.index(2,2)).toString(), QString("herr")); - QCOMPARE(model.data(model.index(2,3)).toString(), QString("herr")); + if (!db.driverName().startsWith("QTDS")) + QCOMPARE(model.data(model.index(2,3)).toString(), QString("herr")); + else + QCOMPARE(model.data(model.index(2,3)).toInt(), 1); QVERIFY_SQL(model, submitAll()); } @@ -574,7 +643,8 @@ void tst_QSqlRelationalTableModel::sort() model.setTable(qTableName("reltest1")); model.setRelation(2, QSqlRelation(qTableName("reltest2"), "tid", "title")); - model.setRelation(3, QSqlRelation(qTableName("reltest2"), "tid", "title")); + if (!db.driverName().startsWith("QTDS")) + model.setRelation(3, QSqlRelation(qTableName("reltest2"), "tid", "title")); model.setSort(2, Qt::DescendingOrder); QVERIFY_SQL(model, select()); @@ -589,11 +659,19 @@ void tst_QSqlRelationalTableModel::sort() model.setSort(3, Qt::AscendingOrder); QVERIFY_SQL(model, select()); - QCOMPARE(model.rowCount(), 4); - QCOMPARE(model.data(model.index(0, 3)).toString(), QString("herr")); - QCOMPARE(model.data(model.index(1, 3)).toString(), QString("mister")); - QCOMPARE(model.data(model.index(2, 3)).toString(), QString("mister")); - QCOMPARE(model.data(model.index(3, 3)).toString(), QString("mister")); + if (!db.driverName().startsWith("QTDS")) { + QCOMPARE(model.rowCount(), 4); + QCOMPARE(model.data(model.index(0, 3)).toString(), QString("herr")); + QCOMPARE(model.data(model.index(1, 3)).toString(), QString("mister")); + QCOMPARE(model.data(model.index(2, 3)).toString(), QString("mister")); + QCOMPARE(model.data(model.index(3, 3)).toString(), QString("mister")); + } else { + QCOMPARE(model.data(model.index(0, 3)).toInt(), 1); + QCOMPARE(model.data(model.index(1, 3)).toInt(), 2); + QCOMPARE(model.data(model.index(2, 3)).toInt(), 2); + QCOMPARE(model.data(model.index(3, 3)).toInt(), 2); + } + } static void testRevert(QSqlRelationalTableModel &model) @@ -663,7 +741,7 @@ void tst_QSqlRelationalTableModel::revert() model.setTable(qTableName("reltest1")); model.setRelation(2, QSqlRelation(qTableName("reltest2"), "tid", "title")); - model.setRelation(3, QSqlRelation(qTableName("reltest2"), "tid", "title")); + model.setRelation(3, QSqlRelation(qTableName("reltest4"), "id", "name")); model.setSort(0, Qt::AscendingOrder); @@ -689,7 +767,9 @@ void tst_QSqlRelationalTableModel::clearDisplayValuesCache() model.setTable(qTableName("reltest1")); model.setRelation(2, QSqlRelation(qTableName("reltest2"), "tid", "title")); - model.setRelation(3, QSqlRelation(qTableName("reltest2"), "tid", "title")); + + if (!db.driverName().startsWith("QTDS")) + model.setRelation(3, QSqlRelation(qTableName("reltest2"), "tid", "title")); model.setSort(1, Qt::AscendingOrder); model.setEditStrategy(QSqlTableModel::OnManualSubmit); @@ -698,7 +778,10 @@ void tst_QSqlRelationalTableModel::clearDisplayValuesCache() QCOMPARE(model.data(model.index(3, 0)).toInt(), 3); QCOMPARE(model.data(model.index(3, 1)).toString(), QString("vohi")); QCOMPARE(model.data(model.index(3, 2)).toString(), QString("herr")); - QCOMPARE(model.data(model.index(3, 3)).toString(), QString("mister")); + if (!db.driverName().startsWith("QTDS")) + QCOMPARE(model.data(model.index(3, 3)).toString(), QString("mister")); + else + QCOMPARE(model.data(model.index(3, 3)).toInt(), 2 ); model.insertRow(model.rowCount()); QVERIFY(model.setData(model.index(4, 0), 5, Qt::EditRole)); @@ -710,11 +793,18 @@ void tst_QSqlRelationalTableModel::clearDisplayValuesCache() QCOMPARE(model.data(model.index(0, 0)).toInt(), 5); QCOMPARE(model.data(model.index(0, 1)).toString(), QString("anders")); QCOMPARE(model.data(model.index(0, 2)).toString(), QString("herr")); - QCOMPARE(model.data(model.index(0, 3)).toString(), QString("herr")); + if (!db.driverName().startsWith("QTDS")) + QCOMPARE(model.data(model.index(0, 3)).toString(), QString("herr")); + else + QCOMPARE(model.data(model.index(0, 3)).toInt(), 1); + QCOMPARE(model.data(model.index(4, 0)).toInt(), 3); QCOMPARE(model.data(model.index(4, 1)).toString(), QString("vohi")); QCOMPARE(model.data(model.index(4, 2)).toString(), QString("herr")); - QCOMPARE(model.data(model.index(4, 3)).toString(), QString("mister")); + if (!db.driverName().startsWith("QTDS")) + QCOMPARE(model.data(model.index(4, 3)).toString(), QString("mister")); + else + QCOMPARE(model.data(model.index(4, 3)).toInt(), 2); } // For task 140782 and 176374: If the main table and the the related tables uses the same @@ -729,27 +819,38 @@ void tst_QSqlRelationalTableModel::insertRecordDuplicateFieldNames() QSqlRelationalTableModel model(0, db); model.setTable(qTableName("reltest3")); model.setEditStrategy(QSqlTableModel::OnManualSubmit); + model.setSort(0, Qt::AscendingOrder); // Duplication of "name", used in both reltest3 and reltest4. model.setRelation(2, QSqlRelation(qTableName("reltest4"), "id", "name")); QVERIFY_SQL(model, select()); - QCOMPARE(model.record(1).value(qTableName("reltest4").append(QLatin1String("_name"))).toString(), + if (db.driverName().startsWith("QIBASE") || db.driverName().startsWith("QOCI") || db.driverName().startsWith("QDB2")) { + QCOMPARE(model.record(1).value(qTableName("reltest4").append(QLatin1String("_name")).toUpper()).toString(), + QString("Trondheim")); + } else { + QCOMPARE(model.record(1).value(qTableName("reltest4").append(QLatin1String("_name"))).toString(), QString("Trondheim")); + } QSqlRecord rec = model.record(); rec.setValue(0, 3); rec.setValue(1, "Berge"); rec.setValue(2, 1); // Must insert the key value - QCOMPARE(rec.fieldName(0), QLatin1String("id")); - QCOMPARE(rec.fieldName(1), QLatin1String("name")); // This comes from main table + if (db.driverName().startsWith("QIBASE") || db.driverName().startsWith("QOCI") || db.driverName().startsWith("QDB2")) { + QCOMPARE(rec.fieldName(0), QLatin1String("ID")); + QCOMPARE(rec.fieldName(1), QLatin1String("NAME")); // This comes from main table + } else { + QCOMPARE(rec.fieldName(0), QLatin1String("id")); + QCOMPARE(rec.fieldName(1), QLatin1String("name")); + } // The duplicate field names is aliased because it's comes from the relation's display column. - if(!db.driverName().startsWith("QIBASE")) - QCOMPARE(rec.fieldName(2), qTableName("reltest4").append(QLatin1String("_name"))); - else + if(db.driverName().startsWith("QIBASE") || db.driverName().startsWith("QOCI") || db.driverName().startsWith("QDB2")) QCOMPARE(rec.fieldName(2), (qTableName("reltest4").append(QLatin1String("_name"))).toUpper()); + else + QCOMPARE(rec.fieldName(2), qTableName("reltest4").append(QLatin1String("_name"))); QVERIFY(model.insertRecord(-1, rec)); QCOMPARE(model.data(model.index(2, 2)).toString(), QString("Oslo")); @@ -793,7 +894,7 @@ void tst_QSqlRelationalTableModel::relationModel() QVERIFY(model.relationModel(3) == NULL); QVERIFY(model.relationModel(4) == NULL); - model.setRelation(3, QSqlRelation(qTableName("reltest2"), "tid", "title")); + model.setRelation(3, QSqlRelation(qTableName("reltest4"), "id", "name")); QVERIFY_SQL(model, select()); QVERIFY(model.relationModel(0) == NULL); @@ -806,5 +907,285 @@ void tst_QSqlRelationalTableModel::relationModel() QCOMPARE(rel_model->data(rel_model->index(0,1)).toString(), QString("herr")); } +void tst_QSqlRelationalTableModel::casing() +{ + QFETCH_GLOBAL(QString, dbName); + QSqlDatabase db = QSqlDatabase::database(dbName); + CHECK_DATABASE(db); + + if (db.driverName().startsWith("QSQLITE")) + QSKIP("The casing test for SQLITE is irrelevant since SQLITE is case insensitive", SkipAll); + + QStringList tableNames; + tableNames << qTableName("CASETEST1", db.driver()).toUpper(); + tableNames << qTableName("casetest1", db.driver()); + tst_Databases::safeDropTables(db, tableNames); + + QSqlQuery q(db); + QVERIFY_SQL( q, exec("create table " + qTableName("CASETEST1", db.driver()).toUpper() + + " (id int not null primary key, name varchar(20), title_key int, another_title_key int)")); + QVERIFY_SQL( q, exec("insert into " + qTableName("CASETEST1", db.driver()).toUpper() + " values(1, 'harry', 1, 2)")); + QVERIFY_SQL( q, exec("insert into " + qTableName("CASETEST1", db.driver()).toUpper() + " values(2, 'trond', 2, 1)")); + QVERIFY_SQL( q, exec("insert into " + qTableName("CASETEST1", db.driver()).toUpper() + " values(3, 'vohi', 1, 2)")); + QVERIFY_SQL( q, exec("insert into " + qTableName("CASETEST1", db.driver()).toUpper() + " values(4, 'boris', 2, 2)")); + + QVERIFY_SQL( q, exec("create table " + qTableName("casetest1", db.driver()) + + " (ident int not null primary key, name varchar(20), title_key int)")); + QVERIFY_SQL( q, exec("insert into " + qTableName("casetest1", db.driver()) + " values(1, 'jerry', 1)")); + QVERIFY_SQL( q, exec("insert into " + qTableName("casetest1", db.driver()) + " values(2, 'george', 2)")); + QVERIFY_SQL( q, exec("insert into " + qTableName("casetest1", db.driver()) + " values(4, 'kramer', 2)")); + + if (db.driverName().startsWith("QOCI")) { + //try an owner that doesn't exist + QSqlRecord rec = db.driver()->record("doug." + qTableName("CASETEST1", db.driver()).toUpper()); + QCOMPARE( rec.count(), 0); + + //try an owner that does exist + rec = db.driver()->record(db.userName() + "." + qTableName("CASETEST1", db.driver()).toUpper()); + QCOMPARE( rec.count(), 4); + } + QSqlRecord rec = db.driver()->record(qTableName("CASETEST1", db.driver()).toUpper()); + QCOMPARE( rec.count(), 4); + + rec = db.driver()->record(qTableName("casetest1", db.driver())); + QCOMPARE( rec.count(), 3); + + QSqlTableModel upperCaseModel(0, db); + upperCaseModel.setTable(qTableName("CASETEST1", db.driver()).toUpper()); + + QCOMPARE(upperCaseModel.tableName(),qTableName("CASETEST1",db.driver()).toUpper()); + + QVERIFY_SQL(upperCaseModel, select()); + + QCOMPARE(upperCaseModel.rowCount(), 4); + + QSqlTableModel lowerCaseModel(0, db); + lowerCaseModel.setTable(qTableName("casetest1", db.driver())); + QCOMPARE(lowerCaseModel.tableName(), qTableName("casetest1",db.driver())); + QVERIFY_SQL(lowerCaseModel, select()); + + QCOMPARE(lowerCaseModel.rowCount(), 3); + + QSqlRelationalTableModel model(0, db); + model.setTable(qTableName("CASETEST1", db.driver()).toUpper()); + model.setRelation(2, QSqlRelation(qTableName("reltest2"), "tid", "title")); + QVERIFY_SQL(model, select()); + + QCOMPARE(model.data(model.index(0, 0)).toInt(), 1); + QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry")); + QCOMPARE(model.data(model.index(0, 2)).toString(), QString("herr")); + + tst_Databases::safeDropTables(db, tableNames); +} + +void tst_QSqlRelationalTableModel::escapedRelations() +{ + QFETCH_GLOBAL(QString, dbName); + QSqlDatabase db = QSqlDatabase::database(dbName); + CHECK_DATABASE(db); + recreateTestTables(db); + + QSqlRelationalTableModel model(0, db); + model.setTable(qTableName("reltest1")); + + //try with relation table name quoted + if (db.driverName().startsWith("QIBASE") || db.driverName().startsWith("QOCI") || db.driverName().startsWith("QDB2")) { + model.setRelation(2, QSqlRelation(db.driver()->escapeIdentifier(qTableName("reltest2").toUpper(),QSqlDriver::TableName), + "tid", + "title")); + } else { + model.setRelation(2, QSqlRelation(db.driver()->escapeIdentifier(qTableName("reltest2"),QSqlDriver::TableName), + "tid", + "title")); + + } + QVERIFY_SQL(model, select()); + + QCOMPARE(model.data(model.index(0, 0)).toInt(), 1); + QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry")); + QCOMPARE(model.data(model.index(0, 2)).toString(), QString("herr")); + + //try with index column quoted + if (db.driverName().startsWith("QIBASE") || db.driverName().startsWith("QOCI") || db.driverName().startsWith("QDB2")) { + model.setRelation(2, QSqlRelation(qTableName("reltest2"), + db.driver()->escapeIdentifier("tid", QSqlDriver::FieldName).toUpper(), + "title")); + } else { + model.setRelation(2, QSqlRelation(qTableName("reltest2"), + db.driver()->escapeIdentifier("tid", QSqlDriver::FieldName), + "title")); + } + QVERIFY_SQL(model, select()); + + QCOMPARE(model.data(model.index(0, 0)).toInt(), 1); + QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry")); + QCOMPARE(model.data(model.index(0, 2)).toString(), QString("herr")); + + //try with display column quoted + + if (db.driverName().startsWith("QIBASE") || db.driverName().startsWith("QOCI") || db.driverName().startsWith("QDB2")) { + + model.setRelation(2, QSqlRelation(qTableName("reltest2"), + "tid", + db.driver()->escapeIdentifier("title", QSqlDriver::FieldName).toUpper())); + } else { + model.setRelation(2, QSqlRelation(qTableName("reltest2"), + "tid", + db.driver()->escapeIdentifier("title", QSqlDriver::FieldName))); + } + + QVERIFY_SQL(model, select()); + + QCOMPARE(model.data(model.index(0, 0)).toInt(), 1); + QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry")); + QCOMPARE(model.data(model.index(0, 2)).toString(), QString("herr")); + + //try with tablename and index and display columns quoted in the relation + + if (db.driverName().startsWith("QIBASE") || db.driverName().startsWith("QOCI") || db.driverName().startsWith("QDB2")) { + model.setRelation(2, QSqlRelation(qTableName("reltest2"), + "tid", + db.driver()->escapeIdentifier("title", QSqlDriver::FieldName).toUpper())); + } else { + model.setRelation(2, QSqlRelation(qTableName("reltest2"), + "tid", + db.driver()->escapeIdentifier("title", QSqlDriver::FieldName))); + } + QVERIFY_SQL(model, select()); + + QCOMPARE(model.data(model.index(0, 0)).toInt(), 1); + QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry")); + QCOMPARE(model.data(model.index(0, 2)).toString(), QString("herr")); +} + +void tst_QSqlRelationalTableModel::escapedTableName() +{ + QFETCH_GLOBAL(QString, dbName); + QSqlDatabase db = QSqlDatabase::database(dbName); + CHECK_DATABASE(db); + + // set the values using OnRowChange Strategy with an escaped tablename + { + QSqlRelationalTableModel model(0, db); + + if (db.driverName().startsWith("QIBASE") || db.driverName().startsWith("QOCI") || db.driverName().startsWith("QDB2")) { + model.setTable(db.driver()->escapeIdentifier(qTableName("reltest1").toUpper(), QSqlDriver::TableName)); + } else { + model.setTable(db.driver()->escapeIdentifier(qTableName("reltest1"), QSqlDriver::TableName)); + } + model.setSort(0, Qt::AscendingOrder); + model.setRelation(2, QSqlRelation(qTableName("reltest2"), "tid", "title")); + QVERIFY_SQL(model, select()); + + QVERIFY(model.setData(model.index(0, 1), QString("harry2"))); + QVERIFY(model.setData(model.index(0, 2), 2)); + + QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry2")); + QCOMPARE(model.data(model.index(0, 2)).toString(), QString("mister")); + + model.submit(); + + QVERIFY(model.setData(model.index(3,1), QString("boris2"))); + QVERIFY(model.setData(model.index(3, 2), 1)); + + QCOMPARE(model.data(model.index(3,1)).toString(), QString("boris2")); + QCOMPARE(model.data(model.index(3, 2)).toString(), QString("herr")); + + model.submit(); + } + { //verify values + QSqlRelationalTableModel model(0, db); + model.setTable(qTableName("reltest1")); + model.setSort(0, Qt::AscendingOrder); + QVERIFY_SQL(model, select()); + + QCOMPARE(model.data(model.index(0, 1)).toString(), QString("harry2")); + QCOMPARE(model.data(model.index(0, 2)).toInt(), 2); + QCOMPARE(model.data(model.index(3, 1)).toString(), QString("boris2")); + QCOMPARE(model.data(model.index(3, 2)).toInt(), 1); + + model.setRelation(2, QSqlRelation(qTableName("reltest2"), "tid", "title")); + QVERIFY_SQL(model, select()); + QCOMPARE(model.data(model.index(0, 2)).toString(), QString("mister")); + QCOMPARE(model.data(model.index(3,2)).toString(), QString("herr")); + + } +} + +void tst_QSqlRelationalTableModel::whiteSpaceInIdentifiers() { + + QFETCH_GLOBAL(QString, dbName); + QSqlDatabase db = QSqlDatabase::database(dbName); + CHECK_DATABASE(db); + + if (!testWhiteSpaceNames(db.driverName())) + QSKIP("White space test irrelevant for driver", SkipAll); + QSqlRelationalTableModel model(0, db); + model.setTable(db.driver()->escapeIdentifier(qTableName("rel test6"), QSqlDriver::TableName)); + model.setSort(0, Qt::DescendingOrder); + model.setRelation(1, QSqlRelation(db.driver()->escapeIdentifier(qTableName("rel test7"), QSqlDriver::TableName), + db.driver()->escapeIdentifier("city id", QSqlDriver::FieldName), + db.driver()->escapeIdentifier("city name", QSqlDriver::FieldName))); + QVERIFY_SQL(model, select()); + + QCOMPARE(model.data(model.index(0,1)).toString(), QString("Washington")); + QCOMPARE(model.data(model.index(1,1)).toString(), QString("New York")); + + QSqlRecord rec; + QSqlField f1("id", QVariant::Int); + QSqlField f2(db.driver()->escapeIdentifier("city key", QSqlDriver::FieldName), QVariant::Int); + QSqlField f3(db.driver()->escapeIdentifier("extra field", QSqlDriver::FieldName), QVariant::Int); + + f1.setValue(3); + f2.setValue(2); + f3.setValue(7); + + f1.setGenerated(true); + f2.setGenerated(true); + f3.setGenerated(true); + + rec.append(f1); + rec.append(f2); + rec.append(f3); + + QVERIFY_SQL(model, insertRecord(-1, rec)); + model.submitAll(); + + QCOMPARE(model.data(model.index(0, 0)).toInt(), 3); + QCOMPARE(model.data(model.index(0, 1)).toString(), QString("Washington")); + QCOMPARE(model.data(model.index(0, 2)).toInt(), 7); + + //TODO: For some reson setting a record using manual submit fails + //model.setEditStrategy(QSqlTableModel::OnManualSubmit); + + QSqlRecord recNew; + QSqlField f1New("id", QVariant::Int); + QSqlField f2New(db.driver()->escapeIdentifier("city key", QSqlDriver::FieldName), QVariant::Int); + QSqlField f3New(db.driver()->escapeIdentifier("extra field", QSqlDriver::FieldName), QVariant::Int); + + f1New.setValue(4); + f2New.setValue(1); + f3New.setValue(6); + + f1New.setGenerated(true); + f2New.setGenerated(true); + f3New.setGenerated(true); + + recNew.append(f1New); + recNew.append(f2New); + recNew.append(f3New); + + QVERIFY_SQL(model, setRecord(0, recNew)); + + QCOMPARE(model.data(model.index(0, 0)).toInt(), 4); + QCOMPARE(model.data(model.index(0, 1)).toString(), QString("New York")); + QCOMPARE(model.data(model.index(0, 2)).toInt(), 6); + + QVERIFY_SQL(model, submitAll()); + QCOMPARE(model.data(model.index(0, 0)).toInt(), 4); + QCOMPARE(model.data(model.index(0, 1)).toString(), QString("New York")); + QCOMPARE(model.data(model.index(0, 2)).toInt(), 6); +} + QTEST_MAIN(tst_QSqlRelationalTableModel) #include "tst_qsqlrelationaltablemodel.moc" diff --git a/tests/auto/qsqltablemodel/tst_qsqltablemodel.cpp b/tests/auto/qsqltablemodel/tst_qsqltablemodel.cpp index 5d1f9d4..aa882be 100644 --- a/tests/auto/qsqltablemodel/tst_qsqltablemodel.cpp +++ b/tests/auto/qsqltablemodel/tst_qsqltablemodel.cpp @@ -145,7 +145,7 @@ void tst_QSqlTableModel::dropTestTables() << qTableName("bigtable") << qTableName("foo"); if (testWhiteSpaceNames(db.driverName())) - tableNames << qTableName("qtestw hitespace"); + tableNames << qTableName("qtestw hitespace", db.driver()); tst_Databases::safeDropTables(db, tableNames); @@ -277,6 +277,7 @@ void tst_QSqlTableModel::setRecord() QList<QSqlTableModel::EditStrategy> policies = QList<QSqlTableModel::EditStrategy>() << QSqlTableModel::OnFieldChange << QSqlTableModel::OnRowChange << QSqlTableModel::OnManualSubmit; + QString Xsuffix; foreach( QSqlTableModel::EditStrategy submitpolicy, policies) { QSqlTableModel model(0, db); @@ -295,6 +296,8 @@ void tst_QSqlTableModel::setRecord() if ((QSqlTableModel::EditStrategy)submitpolicy == QSqlTableModel::OnManualSubmit) QVERIFY(model.submitAll()); + else if ((QSqlTableModel::EditStrategy)submitpolicy == QSqlTableModel::OnRowChange && i == model.rowCount() -1) + model.submit(); else { // dataChanged() is not emitted when submitAll() is called QCOMPARE(spy.count(), 2); @@ -304,10 +307,12 @@ void tst_QSqlTableModel::setRecord() } } - QCOMPARE(model.data(model.index(0, 1)).toString(), QString("fooX")); - QCOMPARE(model.data(model.index(0, 2)).toString(), QString("barX")); - QCOMPARE(model.data(model.index(1, 1)).toString(), QString("bazX")); - QCOMPARE(model.data(model.index(1, 2)).toString(), QString("joeX")); + Xsuffix.append('X'); + + QCOMPARE(model.data(model.index(0, 1)).toString(), QString("foo").append(Xsuffix)); + QCOMPARE(model.data(model.index(0, 2)).toString(), QString("bar").append(Xsuffix)); + QCOMPARE(model.data(model.index(1, 1)).toString(), QString("baz").append(Xsuffix)); + QCOMPARE(model.data(model.index(1, 2)).toString(), QString("joe").append(Xsuffix)); } } |