summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/sql/drivers/db2/qsql_db2.cpp70
-rw-r--r--src/sql/drivers/ibase/qsql_ibase.cpp16
-rw-r--r--src/sql/drivers/mysql/qsql_mysql.cpp19
-rw-r--r--src/sql/drivers/mysql/qsql_mysql.h3
-rw-r--r--src/sql/drivers/oci/qsql_oci.cpp58
-rw-r--r--src/sql/drivers/odbc/qsql_odbc.cpp129
-rw-r--r--src/sql/drivers/odbc/qsql_odbc.h4
-rw-r--r--src/sql/drivers/psql/qsql_psql.cpp32
-rw-r--r--src/sql/drivers/sqlite/qsql_sqlite.cpp16
-rw-r--r--src/sql/drivers/sqlite2/qsql_sqlite2.cpp20
-rw-r--r--src/sql/drivers/tds/qsql_tds.cpp21
-rw-r--r--src/sql/kernel/qsqldriver.cpp131
-rw-r--r--src/sql/kernel/qsqldriver.h6
-rw-r--r--src/sql/models/qsqlrelationaltablemodel.cpp73
-rw-r--r--src/sql/models/qsqltablemodel.cpp20
-rw-r--r--tests/auto/qsqldatabase/tst_databases.h37
-rw-r--r--tests/auto/qsqldriver/qsqldriver.pro16
-rw-r--r--tests/auto/qsqldriver/tst_qsqldriver.cpp218
-rw-r--r--tests/auto/qsqlrelationaltablemodel/tst_qsqlrelationaltablemodel.cpp455
-rw-r--r--tests/auto/qsqltablemodel/tst_qsqltablemodel.cpp15
20 files changed, 1218 insertions, 141 deletions
diff --git a/src/sql/drivers/db2/qsql_db2.cpp b/src/sql/drivers/db2/qsql_db2.cpp
index 2786dbb107..11d0041972 100644
--- a/src/sql/drivers/db2/qsql_db2.cpp
+++ b/src/sql/drivers/db2/qsql_db2.cpp
@@ -1182,7 +1182,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())
@@ -1205,6 +1205,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) {
@@ -1235,7 +1237,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());
}
@@ -1244,9 +1249,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;
@@ -1265,7 +1279,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;
@@ -1310,10 +1324,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);
@@ -1327,6 +1356,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,
@@ -1407,7 +1439,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,
@@ -1438,7 +1476,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 64f13b5def..0705722b8a 100644
--- a/src/sql/drivers/ibase/qsql_ibase.cpp
+++ b/src/sql/drivers/ibase/qsql_ibase.cpp
@@ -1552,12 +1552,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()) {
@@ -1585,12 +1589,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/mysql/qsql_mysql.cpp b/src/sql/drivers/mysql/qsql_mysql.cpp
index 9b57f3c6a7..a84e840efe 100644
--- a/src/sql/drivers/mysql/qsql_mysql.cpp
+++ b/src/sql/drivers/mysql/qsql_mysql.cpp
@@ -1314,7 +1314,7 @@ QSqlIndex QMYSQLDriver::primaryIndex(const QString& tablename) const
QSqlQuery i(createResult());
QString stmt(QLatin1String("show index from %1;"));
QSqlRecord fil = record(tablename);
- i.exec(stmt.arg(escapeIdentifier(tablename, QSqlDriver::TableName)));
+ i.exec(stmt.arg(tablename));
while (i.isActive() && i.next()) {
if (i.value(2).toString() == QLatin1String("PRIMARY")) {
idx.append(fil.field(i.value(4).toString()));
@@ -1329,10 +1329,14 @@ QSqlIndex QMYSQLDriver::primaryIndex(const QString& tablename) const
QSqlRecord QMYSQLDriver::record(const QString& tablename) const
{
+ QString table=tablename;
+ if(isIdentifierEscaped(table, QSqlDriver::TableName))
+ table = stripDelimiters(table, QSqlDriver::TableName);
+
QSqlRecord info;
if (!isOpen())
return info;
- MYSQL_RES* r = mysql_list_fields(d->mysql, tablename.toLocal8Bit().constData(), 0);
+ MYSQL_RES* r = mysql_list_fields(d->mysql, table.toLocal8Bit().constData(), 0);
if (!r) {
return info;
}
@@ -1443,4 +1447,15 @@ QString QMYSQLDriver::escapeIdentifier(const QString &identifier, IdentifierType
return res;
}
+bool QMYSQLDriver::isIdentifierEscapedImplementation(const QString &identifier, IdentifierType type) const
+{
+ Q_UNUSED(type);
+ bool isLeftDelimited = (identifier.left(1) == QString(QLatin1Char('`')));
+ bool isRightDelimited = (identifier.right(1) == QString(QLatin1Char('`')));
+ if( identifier.size() > 2 && isLeftDelimited && isRightDelimited )
+ return true;
+ else
+ return false;
+}
+
QT_END_NAMESPACE
diff --git a/src/sql/drivers/mysql/qsql_mysql.h b/src/sql/drivers/mysql/qsql_mysql.h
index 97aa346025..31d9dcf731 100644
--- a/src/sql/drivers/mysql/qsql_mysql.h
+++ b/src/sql/drivers/mysql/qsql_mysql.h
@@ -123,6 +123,9 @@ public:
QVariant handle() const;
QString escapeIdentifier(const QString &identifier, IdentifierType type) const;
+protected Q_SLOTS:
+ bool isIdentifierEscapedImplementation(const QString &identifier, IdentifierType type) const;
+
protected:
bool beginTransaction();
bool commitTransaction();
diff --git a/src/sql/drivers/oci/qsql_oci.cpp b/src/sql/drivers/oci/qsql_oci.cpp
index 7017d6ca47..fa9b5f0e65 100644
--- a/src/sql/drivers/oci/qsql_oci.cpp
+++ b/src/sql/drivers/oci/qsql_oci.cpp
@@ -2098,7 +2098,7 @@ bool QOCIDriver::open(const QString & db,
setOpen(true);
setOpenError(false);
- d->user = user.toUpper();
+ d->user = user;
return true;
}
@@ -2200,8 +2200,15 @@ QStringList QOCIDriver::tables(QSql::TableType type) const
"and owner != 'WKSYS'"
"and owner != 'CTXSYS'"
"and owner != 'WMSYS'"));
+
+ QString user = d->user;
+ if ( isIdentifierEscaped(user, QSqlDriver::TableName))
+ user = stripDelimiters(user, QSqlDriver::TableName);
+ else
+ user = user.toUpper();
+
while (t.next()) {
- if (t.value(0).toString() != d->user)
+ if (t.value(0).toString() != user)
tl.append(t.value(0).toString() + QLatin1String(".") + t.value(1).toString());
else
tl.append(t.value(1).toString());
@@ -2237,10 +2244,10 @@ void qSplitTableAndOwner(const QString & tname, QString * tbl,
{
int i = tname.indexOf(QLatin1Char('.')); // prefixed with owner?
if (i != -1) {
- *tbl = tname.right(tname.length() - i - 1).toUpper();
- *owner = tname.left(i).toUpper();
+ *tbl = tname.right(tname.length() - i - 1);
+ *owner = tname.left(i);
} else {
- *tbl = tname.toUpper();
+ *tbl = tname;
}
}
@@ -2256,7 +2263,7 @@ QSqlRecord QOCIDriver::record(const QString& tablename) const
QString stmt(QLatin1String("select column_name, data_type, data_length, "
"data_precision, data_scale, nullable, data_default%1"
"from all_tab_columns "
- "where upper(table_name)=%2"));
+ "where table_name=%2"));
if (d->serverVersion >= 9)
stmt = stmt.arg(QLatin1String(", char_length "));
else
@@ -2264,11 +2271,23 @@ QSqlRecord QOCIDriver::record(const QString& tablename) const
bool buildRecordInfo = false;
QString table, owner, tmpStmt;
qSplitTableAndOwner(tablename, &table, &owner);
+
+ if (isIdentifierEscaped(table, QSqlDriver::TableName))
+ table = stripDelimiters(table, QSqlDriver::TableName);
+ else
+ table = table.toUpper();
+
tmpStmt = stmt.arg(QLatin1Char('\'') + table + QLatin1Char('\''));
if (owner.isEmpty()) {
owner = d->user;
}
- tmpStmt += QLatin1String(" and upper(owner)='") + owner + QLatin1String("'");
+
+ if (isIdentifierEscaped(owner, QSqlDriver::TableName))
+ owner = stripDelimiters(owner, QSqlDriver::TableName);
+ else
+ owner = owner.toUpper();
+
+ tmpStmt += QLatin1String(" and owner='") + owner + QLatin1String("'");
t.setForwardOnly(true);
t.exec(tmpStmt);
if (!t.next()) { // try and see if the tablename is a synonym
@@ -2317,11 +2336,23 @@ QSqlIndex QOCIDriver::primaryIndex(const QString& tablename) const
bool buildIndex = false;
QString table, owner, tmpStmt;
qSplitTableAndOwner(tablename, &table, &owner);
- tmpStmt = stmt + QLatin1String(" and upper(a.table_name)='") + table + QLatin1String("'");
+
+ if (isIdentifierEscaped(table, QSqlDriver::TableName))
+ table = stripDelimiters(table, QSqlDriver::TableName);
+ else
+ table = table.toUpper();
+
+ tmpStmt = stmt + QLatin1String(" and a.table_name='") + table + QLatin1String("'");
if (owner.isEmpty()) {
owner = d->user;
}
- tmpStmt += QLatin1String(" and upper(a.owner)='") + owner + QLatin1String("'");
+
+ if (isIdentifierEscaped(owner, QSqlDriver::TableName))
+ owner = stripDelimiters(owner, QSqlDriver::TableName);
+ else
+ owner = owner.toUpper();
+
+ tmpStmt += QLatin1String(" and a.owner='") + owner + QLatin1String("'");
t.setForwardOnly(true);
t.exec(tmpStmt);
@@ -2415,13 +2446,14 @@ QVariant QOCIDriver::handle() const
return qVariantFromValue(d->env);
}
-QString QOCIDriver::escapeIdentifier(const QString &identifier, IdentifierType /* type */) const
+QString QOCIDriver::escapeIdentifier(const QString &identifier, IdentifierType type) const
{
QString res = identifier;
- res.replace(QLatin1Char('"'), QLatin1String("\"\""));
- if (identifier.indexOf(QLatin1Char(' ')) != -1)
+ if(!identifier.isEmpty() && !isIdentifierEscaped(identifier, type)) {
+ res.replace(QLatin1Char('"'), QLatin1String("\"\""));
res.prepend(QLatin1Char('"')).append(QLatin1Char('"'));
-// res.replace(QLatin1Char('.'), QLatin1String("\".\""));
+ res.replace(QLatin1Char('.'), QLatin1String("\".\""));
+ }
return res;
}
diff --git a/src/sql/drivers/odbc/qsql_odbc.cpp b/src/sql/drivers/odbc/qsql_odbc.cpp
index f6710db564..71b1b2a213 100644
--- a/src/sql/drivers/odbc/qsql_odbc.cpp
+++ b/src/sql/drivers/odbc/qsql_odbc.cpp
@@ -88,6 +88,7 @@ static const SQLSMALLINT qParamType[4] = { SQL_PARAM_INPUT, SQL_PARAM_INPUT, SQL
class QODBCDriverPrivate
{
public:
+ enum DefaultCase{Lower, Mixed, Upper, Sensitive};
QODBCDriverPrivate()
: hEnv(0), hDbc(0), useSchema(false), disconnectCount(0), isMySqlServer(false),
isMSSqlServer(false), hasSQLFetchScroll(true), hasMultiResultSets(false)
@@ -119,6 +120,9 @@ public:
bool setConnectionOptions(const QString& connOpts);
void splitTableQualifier(const QString &qualifier, QString &catalog,
QString &schema, QString &table);
+ DefaultCase defaultCase() const;
+ QString adjustCase(const QString&) const;
+ QChar quoteChar() const;
};
class QODBCPrivate
@@ -555,6 +559,29 @@ static int qGetODBCVersion(const QString &connOpts)
return SQL_OV_ODBC2;
}
+QChar QODBCDriverPrivate::quoteChar() const
+{
+ static bool isQuoteInitialized = false;
+ static QChar quote = QChar::fromLatin1('"');
+ if (!isQuoteInitialized) {
+ char driverResponse[4];
+ SQLUSMALLINT casing;
+ SQLSMALLINT length;
+ int r = SQLGetInfo(hDbc,
+ SQL_IDENTIFIER_QUOTE_CHAR,
+ &driverResponse,
+ sizeof(driverResponse),
+ &length);
+ if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
+ quote = QChar::fromLatin1(driverResponse[0]);
+ } else {
+ quote = QChar::fromLatin1('"');
+ }
+ isQuoteInitialized = true;
+ }
+ return quote;
+}
+
bool QODBCDriverPrivate::setConnectionOptions(const QString& connOpts)
{
// Set any connection attributes
@@ -705,6 +732,65 @@ void QODBCDriverPrivate::splitTableQualifier(const QString & qualifier, QString
}
}
+QODBCDriverPrivate::DefaultCase QODBCDriverPrivate::defaultCase() const
+{
+ static bool isInitialized = false;
+ static DefaultCase ret;
+
+ if (!isInitialized) {
+ SQLUSMALLINT casing;
+ int r = SQLGetInfo(hDbc,
+ SQL_IDENTIFIER_CASE,
+ &casing,
+ sizeof(casing),
+ NULL);
+ if ( r != SQL_SUCCESS)
+ ret = Lower;//arbitrary case if driver cannot be queried
+ else {
+ switch (casing) {
+ case (SQL_IC_UPPER):
+ ret = Upper;
+ break;
+ case (SQL_IC_LOWER):
+ ret = Lower;
+ break;
+ case (SQL_IC_SENSITIVE):
+ ret = Sensitive;
+ break;
+ case (SQL_IC_MIXED):
+ ret = Mixed;
+ break;
+ default:
+ ret = Upper;
+ }
+ }
+ isInitialized = true;
+ }
+ return ret;
+}
+
+/*
+ Adjust the casing of an identifier to match what the
+ database engine would have done to it.
+*/
+QString QODBCDriverPrivate::adjustCase(const QString &identifier) const
+{
+ QString ret = identifier;
+ switch(defaultCase()) {
+ case (Lower):
+ ret = identifier.toLower();
+ break;
+ case (Upper):
+ ret = identifier.toUpper();
+ break;
+ case(Mixed):
+ case(Sensitive):
+ default:
+ ret = identifier;
+ }
+ return ret;
+}
+
////////////////////////////////////////////////////////////////////////////
QODBCResult::QODBCResult(const QODBCDriver * db, QODBCDriverPrivate* p)
@@ -2084,6 +2170,22 @@ QSqlIndex QODBCDriver::primaryIndex(const QString& tablename) const
}
QString catalog, schema, table;
d->splitTableQualifier(tablename, catalog, schema, table);
+
+ if (isIdentifierEscaped(catalog, QSqlDriver::TableName))
+ catalog = stripDelimiters(catalog, QSqlDriver::TableName);
+ else
+ catalog = d->adjustCase(catalog);
+
+ if (isIdentifierEscaped(schema, QSqlDriver::TableName))
+ schema = stripDelimiters(schema, QSqlDriver::TableName);
+ else
+ schema = d->adjustCase(schema);
+
+ if (isIdentifierEscaped(table, QSqlDriver::TableName))
+ table = stripDelimiters(table, QSqlDriver::TableName);
+ else
+ table = d->adjustCase(table);
+
r = SQLSetStmtAttr(hStmt,
SQL_ATTR_CURSOR_TYPE,
(SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
@@ -2186,6 +2288,22 @@ QSqlRecord QODBCDriver::record(const QString& tablename) const
SQLHANDLE hStmt;
QString catalog, schema, table;
d->splitTableQualifier(tablename, catalog, schema, table);
+
+ if (isIdentifierEscaped(catalog, QSqlDriver::TableName))
+ catalog = stripDelimiters(catalog, QSqlDriver::TableName);
+ else
+ catalog = d->adjustCase(catalog);
+
+ if (isIdentifierEscaped(schema, QSqlDriver::TableName))
+ schema = stripDelimiters(schema, QSqlDriver::TableName);
+ else
+ schema = d->adjustCase(schema);
+
+ if (isIdentifierEscaped(table, QSqlDriver::TableName))
+ table = stripDelimiters(table, QSqlDriver::TableName);
+ else
+ table = d->adjustCase(table);
+
SQLRETURN r = SQLAllocHandle(SQL_HANDLE_STMT,
d->hDbc,
&hStmt);
@@ -2309,4 +2427,15 @@ QString QODBCDriver::escapeIdentifier(const QString &identifier, IdentifierType)
return res;
}
+bool QODBCDriver::isIdentifierEscapedImplementation(const QString &identifier, IdentifierType) const
+{
+ QString quote = d->quoteChar();
+ bool isLeftDelimited = identifier.left(1) == quote;
+ bool isRightDelimited = identifier.right(1) == quote;
+ if( identifier.size() > 2 && isLeftDelimited && isRightDelimited )
+ return true;
+ else
+ return false;
+}
+
QT_END_NAMESPACE
diff --git a/src/sql/drivers/odbc/qsql_odbc.h b/src/sql/drivers/odbc/qsql_odbc.h
index 4148007694..51f53eaff0 100644
--- a/src/sql/drivers/odbc/qsql_odbc.h
+++ b/src/sql/drivers/odbc/qsql_odbc.h
@@ -145,10 +145,14 @@ public:
QString escapeIdentifier(const QString &identifier, IdentifierType type) const;
+protected Q_SLOTS:
+ bool isIdentifierEscapedImplementation(const QString &identifier, IdentifierType type) const;
+
protected:
bool beginTransaction();
bool commitTransaction();
bool rollbackTransaction();
+
private:
void init();
bool endTrans();
diff --git a/src/sql/drivers/psql/qsql_psql.cpp b/src/sql/drivers/psql/qsql_psql.cpp
index afe45fc660..16d19f1867 100644
--- a/src/sql/drivers/psql/qsql_psql.cpp
+++ b/src/sql/drivers/psql/qsql_psql.cpp
@@ -894,6 +894,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 "
@@ -926,7 +936,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");
@@ -934,11 +944,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);
@@ -957,6 +967,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:
@@ -1001,7 +1021,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 "
@@ -1010,12 +1030,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 605c4e8cd3..f732077a93 100644
--- a/src/sql/drivers/sqlite/qsql_sqlite.cpp
+++ b/src/sql/drivers/sqlite/qsql_sqlite.cpp
@@ -661,9 +661,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
@@ -671,9 +675,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
@@ -681,10 +689,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/sqlite2/qsql_sqlite2.cpp b/src/sql/drivers/sqlite2/qsql_sqlite2.cpp
index ff73caaf66..d0c6e18a54 100644
--- a/src/sql/drivers/sqlite2/qsql_sqlite2.cpp
+++ b/src/sql/drivers/sqlite2/qsql_sqlite2.cpp
@@ -167,7 +167,15 @@ void QSQLite2ResultPrivate::init(const char **cnames, int numCols)
for (int i = 0; i < numCols; ++i) {
const char* lastDot = strrchr(cnames[i], '.');
const char* fieldName = lastDot ? lastDot + 1 : cnames[i];
- rInf.append(QSqlField(QString::fromAscii(fieldName),
+
+ //remove quotations around the field name if any
+ QString fieldStr = QString::fromAscii(fieldName);
+ QString quote = QString::fromLatin1("\"");
+ if ( fieldStr.length() > 2 && fieldStr.left(1) == quote && fieldStr.right(1) == quote) {
+ fieldStr = fieldStr.mid(1);
+ fieldStr.chop(1);
+ }
+ rInf.append(QSqlField(fieldStr,
nameToType(QString::fromAscii(cnames[i+numCols]))));
}
}
@@ -503,8 +511,11 @@ QSqlIndex QSQLite2Driver::primaryIndex(const QString &tblname) const
QSqlQuery q(createResult());
q.setForwardOnly(true);
+ QString table = tblname;
+ if (isIdentifierEscaped(table, QSqlDriver::TableName))
+ table = stripDelimiters(table, QSqlDriver::TableName);
// finrst find a UNIQUE INDEX
- q.exec(QLatin1String("PRAGMA index_list('") + tblname + QLatin1String("');"));
+ q.exec(QLatin1String("PRAGMA index_list('") + table + QLatin1String("');"));
QString indexname;
while(q.next()) {
if (q.value(2).toInt()==1) {
@@ -517,7 +528,7 @@ QSqlIndex QSQLite2Driver::primaryIndex(const QString &tblname) const
q.exec(QLatin1String("PRAGMA index_info('") + indexname + QLatin1String("');"));
- QSqlIndex index(tblname, indexname);
+ QSqlIndex index(table, indexname);
while(q.next()) {
QString name = q.value(2).toString();
QVariant::Type type = QVariant::Invalid;
@@ -532,6 +543,9 @@ QSqlRecord QSQLite2Driver::record(const QString &tbl) const
{
if (!isOpen())
return QSqlRecord();
+ QString table = tbl;
+ if (isIdentifierEscaped(tbl, QSqlDriver::TableName))
+ table = stripDelimiters(table, QSqlDriver::TableName);
QSqlQuery q(createResult());
q.setForwardOnly(true);
diff --git a/src/sql/drivers/tds/qsql_tds.cpp b/src/sql/drivers/tds/qsql_tds.cpp
index 46e4a0be45..515f0de5d1 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/kernel/qsqldriver.cpp b/src/sql/kernel/qsqldriver.cpp
index a99500566b..40bc0dfcf9 100644
--- a/src/sql/kernel/qsqldriver.cpp
+++ b/src/sql/kernel/qsqldriver.cpp
@@ -49,6 +49,17 @@
QT_BEGIN_NAMESPACE
+static QString prepareIdentifier(const QString &identifier,
+ QSqlDriver::IdentifierType type, const QSqlDriver *driver)
+{
+ Q_ASSERT( driver != NULL );
+ QString ret = identifier;
+ if (!driver->isIdentifierEscaped(identifier, type)) {
+ ret = driver->escapeIdentifier(identifier, type);
+ }
+ return ret;
+}
+
class QSqlDriverPrivate : public QObjectPrivate
{
public:
@@ -372,6 +383,7 @@ QSqlRecord QSqlDriver::record(const QString & /* tableName */) const
on \a type.
The default implementation does nothing.
+ \sa isIdentifierEscaped()
*/
QString QSqlDriver::escapeIdentifier(const QString &identifier, IdentifierType) const
{
@@ -379,6 +391,55 @@ QString QSqlDriver::escapeIdentifier(const QString &identifier, IdentifierType)
}
/*!
+ Returns whether \a identifier is escaped according to the database rules.
+ \a identifier can either be a table name or field name, dependent
+ on \a type.
+
+ \warning Because of binary compatability constraints, this function is not virtual.
+ If you want to provide your own implementation in your QSqlDriver subclass,
+ reimplement the isIdentifierEscapedImplementation() slot in your subclass instead.
+ The isIdentifierEscapedFunction() will dynamically detect the slot and call it.
+
+ \sa stripDelimiters(), escapeIdentifier()
+ */
+bool QSqlDriver::isIdentifierEscaped(const QString &identifier, IdentifierType type) const
+{
+ bool result;
+ QMetaObject::invokeMethod(const_cast<QSqlDriver*>(this),
+ "isIdentifierEscapedImplementation", Qt::DirectConnection,
+ Q_RETURN_ARG(bool, result),
+ Q_ARG(QString, identifier),
+ Q_ARG(IdentifierType, type));
+ return result;
+}
+
+/*!
+ Returns the \a identifier with the leading and trailing delimiters removed,
+ \a identifier can either be a table name or field name,
+ dependent on \a type. If \a identifier does not have leading
+ and trailing delimiter characters, \a identifier is returned without
+ modification.
+
+ \warning Because of binary compatability constraints, this function is not virtual,
+ If you want to provide your own implementation in your QSqlDriver subclass,
+ reimplement the stripDelimitersImplementation() slot in your subclass instead.
+ The stripDelimiters() function will dynamically detect the slot and call it.
+
+ \since 4.5
+ \sa isIdentifierEscaped()
+ */
+QString QSqlDriver::stripDelimiters(const QString &identifier, IdentifierType type) const
+{
+ QString result;
+ QMetaObject::invokeMethod(const_cast<QSqlDriver*>(this),
+ "stripDelimitersImplementation", Qt::DirectConnection,
+ Q_RETURN_ARG(QString, result),
+ Q_ARG(QString, identifier),
+ Q_ARG(IdentifierType, type));
+ return result;
+}
+
+/*!
Returns a SQL statement of type \a type for the table \a tableName
with the values from \a rec. If \a preparedStatement is true, the
string will contain placeholders instead of values.
@@ -397,17 +458,17 @@ QString QSqlDriver::sqlStatement(StatementType type, const QString &tableName,
case SelectStatement:
for (i = 0; i < rec.count(); ++i) {
if (rec.isGenerated(i))
- s.append(escapeIdentifier(rec.fieldName(i), FieldName)).append(QLatin1String(", "));
+ s.append(prepareIdentifier(rec.fieldName(i), QSqlDriver::FieldName, this)).append(QLatin1String(", "));
}
if (s.isEmpty())
return s;
s.chop(2);
- s.prepend(QLatin1String("SELECT ")).append(QLatin1String(" FROM ")).append(escapeIdentifier(tableName, TableName));
+ s.prepend(QLatin1String("SELECT ")).append(QLatin1String(" FROM ")).append(tableName);
break;
case WhereStatement:
if (preparedStatement) {
for (int i = 0; i < rec.count(); ++i) {
- s.append(escapeIdentifier(rec.fieldName(i), FieldName));
+ s.append(prepareIdentifier(rec.fieldName(i), FieldName,this));
if (rec.isNull(i))
s.append(QLatin1String(" IS NULL"));
else
@@ -416,7 +477,7 @@ QString QSqlDriver::sqlStatement(StatementType type, const QString &tableName,
}
} else {
for (i = 0; i < rec.count(); ++i) {
- s.append(escapeIdentifier(rec.fieldName(i), FieldName));
+ s.append(prepareIdentifier(rec.fieldName(i), QSqlDriver::FieldName, this));
QString val = formatValue(rec.field(i));
if (val == QLatin1String("NULL"))
s.append(QLatin1String(" IS NULL"));
@@ -431,12 +492,12 @@ QString QSqlDriver::sqlStatement(StatementType type, const QString &tableName,
}
break;
case UpdateStatement:
- s.append(QLatin1String("UPDATE ")).append(escapeIdentifier(tableName, TableName)).append(
+ s.append(QLatin1String("UPDATE ")).append(tableName).append(
QLatin1String(" SET "));
for (i = 0; i < rec.count(); ++i) {
if (!rec.isGenerated(i) || !rec.value(i).isValid())
continue;
- s.append(escapeIdentifier(rec.fieldName(i), FieldName)).append(QLatin1Char('='));
+ s.append(prepareIdentifier(rec.fieldName(i), QSqlDriver::FieldName, this)).append(QLatin1Char('='));
if (preparedStatement)
s.append(QLatin1Char('?'));
else
@@ -449,15 +510,15 @@ QString QSqlDriver::sqlStatement(StatementType type, const QString &tableName,
s.clear();
break;
case DeleteStatement:
- s.append(QLatin1String("DELETE FROM ")).append(escapeIdentifier(tableName, TableName));
+ s.append(QLatin1String("DELETE FROM ")).append(tableName);
break;
case InsertStatement: {
- s.append(QLatin1String("INSERT INTO ")).append(escapeIdentifier(tableName, TableName)).append(QLatin1String(" ("));
+ s.append(QLatin1String("INSERT INTO ")).append(tableName).append(QLatin1String(" ("));
QString vals;
for (i = 0; i < rec.count(); ++i) {
if (!rec.isGenerated(i) || !rec.value(i).isValid())
continue;
- s.append(escapeIdentifier(rec.fieldName(i), FieldName)).append(QLatin1String(", "));
+ s.append(prepareIdentifier(rec.fieldName(i), QSqlDriver::FieldName, this)).append(QLatin1String(", "));
if (preparedStatement)
vals.append(QLatin1String("?"));
else
@@ -805,4 +866,56 @@ QStringList QSqlDriver::subscribedToNotificationsImplementation() const
return QStringList();
}
+/*!
+ This slot returns whether \a identifier is escaped according to the database rules.
+ \a identifier can either be a table name or field name, dependent
+ on \a type.
+
+ Because of binary compatability constraints, isIdentifierEscaped() function
+ (introduced in Qt 4.5) is not virtual. Instead, isIdentifierEscaped() will
+ dynamically detect and call \e this slot. The default implementation
+ assumes the escape/delimiter character is a double quote. Reimplement this
+ slot in your own QSqlDriver if your database engine uses a different
+ delimiter character.
+
+ \since 4.5
+ \sa isIdentifierEscaped()
+ */
+bool QSqlDriver::isIdentifierEscapedImplementation(const QString &identifier, IdentifierType type) const
+{
+ Q_UNUSED(type);
+ bool isLeftDelimited = identifier.left(1) == QString(QLatin1Char('"'));
+ bool isRightDelimited = identifier.right(1) == QString(QLatin1Char('"'));
+ if( identifier.size() > 2 && isLeftDelimited && isRightDelimited )
+ return true;
+ else
+ return false;
+}
+
+/*!
+ This slot returns \a identifier with the leading and trailing delimiters removed,
+ \a identifier can either be a tablename or field name, dependent on \a type.
+ If \a identifier does not have leading and trailing delimiter characters, \a
+ identifier is returned without modification.
+
+ Because of binary compatability constraints, the stripDelimiters() function
+ (introduced in Qt 4.5) is not virtual. Instead, stripDelimiters() will
+ dynamically detect and call \e this slot. It generally unnecessary
+ to reimplement this slot.
+
+ \since 4.5
+ \sa stripDelimiters()
+ */
+QString QSqlDriver::stripDelimitersImplementation(const QString &identifier, IdentifierType type) const
+{
+ QString ret;
+ if (this->isIdentifierEscaped(identifier, type)) {
+ ret = identifier.mid(1);
+ ret.chop(1);
+ } else {
+ ret = identifier;
+ }
+ return ret;
+}
+
QT_END_NAMESPACE
diff --git a/src/sql/kernel/qsqldriver.h b/src/sql/kernel/qsqldriver.h
index e763719ef4..8ac1471db1 100644
--- a/src/sql/kernel/qsqldriver.h
+++ b/src/sql/kernel/qsqldriver.h
@@ -127,6 +127,9 @@ public:
bool unsubscribeFromNotification(const QString &name); // ### Qt 5: make virtual
QStringList subscribedToNotifications() const; // ### Qt 5: make virtual
+ bool isIdentifierEscaped(const QString &identifier, IdentifierType type) const; // ### Qt 5: make virtual
+ QString stripDelimiters(const QString &identifier, IdentifierType type) const; // ### Qt 5: make virtual
+
Q_SIGNALS:
void notification(const QString &name);
@@ -140,6 +143,9 @@ protected Q_SLOTS:
bool unsubscribeFromNotificationImplementation(const QString &name); // ### Qt 5: eliminate, see unsubscribeFromNotification()
QStringList subscribedToNotificationsImplementation() const; // ### Qt 5: eliminate, see subscribedNotifications()
+ bool isIdentifierEscapedImplementation(const QString &identifier, IdentifierType type) const; // ### Qt 5: eliminate, see isIdentifierEscaped()
+ QString stripDelimitersImplementation(const QString &identifier, IdentifierType type) const; // ### Qt 5: eliminate, see stripDelimiters()
+
private:
Q_DISABLE_COPY(QSqlDriver)
};
diff --git a/src/sql/models/qsqlrelationaltablemodel.cpp b/src/sql/models/qsqlrelationaltablemodel.cpp
index 935466bd4e..12eae84f24 100644
--- a/src/sql/models/qsqlrelationaltablemodel.cpp
+++ b/src/sql/models/qsqlrelationaltablemodel.cpp
@@ -182,10 +182,21 @@ void QRelation::populateDictionary()
populateModel();
QSqlRecord record;
+ QString indexColumn;
+ QString displayColumn;
for (int i=0; i < model->rowCount(); ++i) {
record = model->record(i);
- dictionary[record.field(rel.indexColumn()).value().toString()] =
- record.field(rel.displayColumn()).value();
+
+ indexColumn = rel.indexColumn();
+ if (m_parent->database().driver()->isIdentifierEscaped(indexColumn, QSqlDriver::FieldName))
+ indexColumn = m_parent->database().driver()->stripDelimiters(indexColumn, QSqlDriver::FieldName);
+
+ displayColumn = rel.displayColumn();
+ if (m_parent->database().driver()->isIdentifierEscaped(displayColumn, QSqlDriver::FieldName))
+ displayColumn = m_parent->database().driver()->stripDelimiters(displayColumn, QSqlDriver::FieldName);
+
+ dictionary[record.field(indexColumn).value().toString()] =
+ record.field(displayColumn).value();
}
m_dictInitialized = true;
}
@@ -215,7 +226,7 @@ public:
QSqlRelationalTableModelPrivate()
: QSqlTableModelPrivate()
{}
- QString escapedRelationField(const QString &tableName, const QString &fieldName) const;
+ QString relationField(const QString &tableName, const QString &fieldName) const;
int nameToIndex(const QString &name) const;
mutable QVector<QRelation> relations;
@@ -255,7 +266,10 @@ void QSqlRelationalTableModelPrivate::revertCachedRow(int row)
int QSqlRelationalTableModelPrivate::nameToIndex(const QString &name) const
{
- return baseRec.indexOf(name);
+ QString fieldname = name;
+ if (db.driver()->isIdentifierEscaped(fieldname, QSqlDriver::FieldName))
+ fieldname = db.driver()->stripDelimiters(fieldname, QSqlDriver::FieldName);
+ return baseRec.indexOf(fieldname);
}
void QSqlRelationalTableModelPrivate::clearEditBuffer()
@@ -481,14 +495,14 @@ QSqlRelation QSqlRelationalTableModel::relation(int column) const
return d->relations.value(column).rel;
}
-QString QSqlRelationalTableModelPrivate::escapedRelationField(const QString &tableName,
+QString QSqlRelationalTableModelPrivate::relationField(const QString &tableName,
const QString &fieldName) const
{
- QString esc;
- esc.reserve(tableName.size() + fieldName.size() + 1);
- esc.append(tableName).append(QLatin1Char('.')).append(fieldName);
+ QString ret;
+ ret.reserve(tableName.size() + fieldName.size() + 1);
+ ret.append(tableName).append(QLatin1Char('.')).append(fieldName);
- return db.driver()->escapeIdentifier(esc, QSqlDriver::FieldName);
+ return ret;
}
/*!
@@ -514,15 +528,29 @@ QString QSqlRelationalTableModel::selectStatement() const
// Count how many times each field name occurs in the record
QHash<QString, int> fieldNames;
+ QStringList fieldList;
for (int i = 0; i < rec.count(); ++i) {
QSqlRelation relation = d->relations.value(i, nullRelation).rel;
QString name;
if (relation.isValid())
+ {
// Count the display column name, not the original foreign key
name = relation.displayColumn();
+ if (d->db.driver()->isIdentifierEscaped(name, QSqlDriver::FieldName))
+ name = d->db.driver()->stripDelimiters(name, QSqlDriver::FieldName);
+
+ QSqlRecord rec = database().record(relation.tableName());
+ for (int i = 0; i < rec.count(); ++i) {
+ if (name.compare(rec.fieldName(i), Qt::CaseInsensitive) == 0) {
+ name = rec.fieldName(i);
+ break;
+ }
+ }
+ }
else
name = rec.fieldName(i);
fieldNames.insert(name, fieldNames.value(name, 0) + 1);
+ fieldList.append(name);
}
for (int i = 0; i < rec.count(); ++i) {
@@ -531,27 +559,30 @@ QString QSqlRelationalTableModel::selectStatement() const
QString relTableAlias = QString::fromLatin1("relTblAl_%1").arg(i);
if (!fList.isEmpty())
fList.append(QLatin1String(", "));
- fList.append(d->escapedRelationField(relTableAlias, relation.displayColumn()));
+ fList.append(d->relationField(relTableAlias,relation.displayColumn()));
// If there are duplicate field names they must be aliased
- if (fieldNames.value(relation.displayColumn()) > 1) {
- fList.append(QString::fromLatin1(" AS %1_%2").arg(relation.tableName()).arg(relation.displayColumn()));
+ if (fieldNames.value(fieldList[i]) > 1) {
+ QString relTableName = relation.tableName();
+ if (d->db.driver()->isIdentifierEscaped(relTableName, QSqlDriver::TableName))
+ relTableName = d->db.driver()->stripDelimiters(relTableName, QSqlDriver::TableName);
+ QString displayColumn = relation.displayColumn();
+ if (d->db.driver()->isIdentifierEscaped(displayColumn, QSqlDriver::FieldName))
+ displayColumn = d->db.driver()->stripDelimiters(displayColumn, QSqlDriver::FieldName);
+ fList.append(QString::fromLatin1(" AS %1_%2").arg(relTableName).arg(displayColumn));
}
// this needs fixing!! the below if is borken.
- if (!tables.contains(relation.tableName()))
- tables.append(d->db.driver()->escapeIdentifier(relation.tableName(),QSqlDriver::TableName)
- .append(QLatin1String(" "))
- .append(d->db.driver()->escapeIdentifier(relTableAlias, QSqlDriver::TableName)));
+ tables.append(relation.tableName().append(QLatin1String(" ")).append(relTableAlias));
if(!where.isEmpty())
where.append(QLatin1String(" AND "));
- where.append(d->escapedRelationField(tableName(), rec.fieldName(i)));
+ where.append(d->relationField(tableName(), d->db.driver()->escapeIdentifier(rec.fieldName(i), QSqlDriver::FieldName)));
where.append(QLatin1String(" = "));
- where.append(d->escapedRelationField(relTableAlias, relation.indexColumn()));
+ where.append(d->relationField(relTableAlias, relation.indexColumn()));
} else {
if (!fList.isEmpty())
fList.append(QLatin1String(", "));
- fList.append(d->escapedRelationField(tableName(), rec.fieldName(i)));
+ fList.append(d->relationField(tableName(), d->db.driver()->escapeIdentifier(rec.fieldName(i), QSqlDriver::FieldName)));
}
}
if (!tables.isEmpty())
@@ -560,7 +591,7 @@ QString QSqlRelationalTableModel::selectStatement() const
return query;
if(!tList.isEmpty())
tList.prepend(QLatin1String(", "));
- tList.prepend(d->db.driver()->escapeIdentifier(tableName(),QSqlDriver::TableName));
+ tList.prepend(tableName());
query.append(QLatin1String("SELECT "));
query.append(fList).append(QLatin1String(" FROM ")).append(tList);
qAppendWhereClause(query, where, filter());
@@ -690,7 +721,7 @@ QString QSqlRelationalTableModel::orderByClause() const
return QSqlTableModel::orderByClause();
QString s = QLatin1String("ORDER BY ");
- s.append(d->escapedRelationField(QLatin1String("relTblAl_") + QString::number(d->sortColumn),
+ s.append(d->relationField(QLatin1String("relTblAl_") + QString::number(d->sortColumn),
rel.displayColumn()));
s += d->sortOrder == Qt::AscendingOrder ? QLatin1String(" ASC") : QLatin1String(" DESC");
return s;
diff --git a/src/sql/models/qsqltablemodel.cpp b/src/sql/models/qsqltablemodel.cpp
index 2fb9b0fc42..c2442c57cf 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 9c19048a9d..611077f4ed 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,12 +238,15 @@ 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", "" );
+// addDb( "QODBC", "DRIVER={MySQL ODBC 3.51 Driver};SERVER=mysql5-nokia.trolltech.com.au;DATABASE=testdb", "testuser", "Ee4Gabf6_", "" );
+// addDb( "QODBC", "DRIVER={FreeTDS};SERVER=horsehead.nokia.troll.no;DATABASE=testdb;PORT=4101;UID=troll;PWD=trondk", "troll", "trondk", "" );
+
}
void open()
@@ -313,16 +312,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 0000000000..0024841e12
--- /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 0000000000..bbd7483212
--- /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 76785c339a..bb2cdddd52 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 d4affe40d9..0e7355e71d 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));
}
}