summaryrefslogtreecommitdiffstats
path: root/src/sql/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'src/sql/drivers')
-rw-r--r--src/sql/drivers/db2/qsql_db2.cpp105
-rw-r--r--src/sql/drivers/ibase/qsql_ibase.cpp62
-rw-r--r--src/sql/drivers/mysql/qsql_mysql.cpp21
-rw-r--r--src/sql/drivers/mysql/qsql_mysql.h3
-rw-r--r--src/sql/drivers/oci/qsql_oci.cpp60
-rw-r--r--src/sql/drivers/odbc/qsql_odbc.cpp148
-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
11 files changed, 404 insertions, 88 deletions
diff --git a/src/sql/drivers/db2/qsql_db2.cpp b/src/sql/drivers/db2/qsql_db2.cpp
index 69383f7..11d0041 100644
--- a/src/sql/drivers/db2/qsql_db2.cpp
+++ b/src/sql/drivers/db2/qsql_db2.cpp
@@ -49,6 +49,7 @@
#include <qstringlist.h>
#include <qvarlengtharray.h>
#include <qvector.h>
+#include <QDebug>
#ifndef UNICODE
#define UNICODE
@@ -87,8 +88,19 @@ public:
{}
~QDB2ResultPrivate()
{
- for (int i = 0; i < valueCache.count(); ++i)
+ emptyValueCache();
+ }
+ void clearValueCache()
+ {
+ for (int i = 0; i < valueCache.count(); ++i) {
delete valueCache[i];
+ valueCache[i] = NULL;
+ }
+ }
+ void emptyValueCache()
+ {
+ clearValueCache();
+ valueCache.clear();
}
const QDB2DriverPrivate* dp;
@@ -544,7 +556,7 @@ bool QDB2Result::reset (const QString& query)
SQLRETURN r;
d->recInf.clear();
- d->valueCache.clear();
+ d->emptyValueCache();
if (!qMakeStatement(d, isForwardOnly()))
return false;
@@ -568,6 +580,7 @@ bool QDB2Result::reset (const QString& query)
setSelect(false);
}
d->valueCache.resize(count);
+ d->valueCache.fill(NULL);
setActive(true);
return true;
}
@@ -579,7 +592,7 @@ bool QDB2Result::prepare(const QString& query)
SQLRETURN r;
d->recInf.clear();
- d->valueCache.clear();
+ d->emptyValueCache();
if (!qMakeStatement(d, isForwardOnly()))
return false;
@@ -607,7 +620,7 @@ bool QDB2Result::exec()
SQLRETURN r;
d->recInf.clear();
- d->valueCache.clear();
+ d->emptyValueCache();
if (!qMakeStatement(d, isForwardOnly(), false))
return false;
@@ -811,6 +824,7 @@ bool QDB2Result::exec()
}
setActive(true);
d->valueCache.resize(count);
+ d->valueCache.fill(NULL);
//get out parameters
if (!hasOutValues())
@@ -858,7 +872,7 @@ bool QDB2Result::fetch(int i)
return false;
if (i == at())
return true;
- d->valueCache.fill(0);
+ d->clearValueCache();
int actualIdx = i + 1;
if (actualIdx <= 0) {
setAt(QSql::BeforeFirstRow);
@@ -887,7 +901,7 @@ bool QDB2Result::fetch(int i)
bool QDB2Result::fetchNext()
{
SQLRETURN r;
- d->valueCache.fill(0);
+ d->clearValueCache();
r = SQLFetchScroll(d->hStmt,
SQL_FETCH_NEXT,
0);
@@ -907,7 +921,7 @@ bool QDB2Result::fetchFirst()
return false;
if (isForwardOnly())
return fetchNext();
- d->valueCache.fill(0);
+ d->clearValueCache();
SQLRETURN r;
r = SQLFetchScroll(d->hStmt,
SQL_FETCH_FIRST,
@@ -923,7 +937,7 @@ bool QDB2Result::fetchFirst()
bool QDB2Result::fetchLast()
{
- d->valueCache.fill(0);
+ d->clearValueCache();
int i = at();
if (i == QSql::AfterLastRow) {
@@ -1044,7 +1058,7 @@ QVariant QDB2Result::data(int field)
case QSql::HighPrecision:
default:
// length + 1 for the comma
- v = new QVariant(qGetStringData(d->hStmt, field, info.length() + 1, isNull));
+ v = new QVariant(value);
ok = true;
break;
}
@@ -1101,7 +1115,7 @@ bool QDB2Result::nextResult()
setActive(false);
setAt(QSql::BeforeFirstRow);
d->recInf.clear();
- d->valueCache.clear();
+ d->emptyValueCache();
setSelect(false);
SQLRETURN r = SQLMoreResults(d->hStmt);
@@ -1120,6 +1134,7 @@ bool QDB2Result::nextResult()
d->recInf.append(qMakeFieldInfo(d, i));
d->valueCache.resize(fieldCount);
+ d->valueCache.fill(NULL);
setActive(true);
return true;
@@ -1167,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())
@@ -1190,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) {
@@ -1220,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());
}
@@ -1229,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;
@@ -1250,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;
@@ -1295,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);
@@ -1312,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,
@@ -1392,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,
@@ -1423,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 64f13b5..6834d9a 100644
--- a/src/sql/drivers/ibase/qsql_ibase.cpp
+++ b/src/sql/drivers/ibase/qsql_ibase.cpp
@@ -871,7 +871,7 @@ QIBaseResult::~QIBaseResult()
bool QIBaseResult::prepare(const QString& query)
{
- //qDebug("prepare: %s\n", qPrintable(query));
+// qDebug("prepare: %s", qPrintable(query));
if (!driver() || !driver()->isOpen() || driver()->isOpenError())
return false;
d->cleanup();
@@ -1025,7 +1025,7 @@ bool QIBaseResult::exec()
}
if (ok) {
- if (colCount()) {
+ if (colCount() && d->queryType != isc_info_sql_stmt_exec_procedure) {
isc_dsql_free_statement(d->status, &d->stmt, DSQL_close);
if (d->isError(QT_TRANSLATE_NOOP("QIBaseResult", "Unable to close statement")))
return false;
@@ -1039,7 +1039,7 @@ bool QIBaseResult::exec()
return false;
// Not all stored procedures necessarily return values.
- if (d->queryType == isc_info_sql_stmt_exec_procedure && d->sqlda->sqld == 0)
+ if (d->queryType == isc_info_sql_stmt_exec_procedure && d->sqlda && d->sqlda->sqld == 0)
delDA(d->sqlda);
if (d->sqlda)
@@ -1270,27 +1270,27 @@ QSqlRecord QIBaseResult::record() const
v = d->sqlda->sqlvar[i];
QSqlField f(QString::fromLatin1(v.aliasname, v.aliasname_length).simplified(),
qIBaseTypeName2(v.sqltype, v.sqlscale < 0));
- QSqlQuery q(new QIBaseResult(d->db));
- q.setForwardOnly(true);
- q.exec(QLatin1String("select b.RDB$FIELD_PRECISION, b.RDB$FIELD_SCALE, b.RDB$FIELD_LENGTH, 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 = '") + QString::fromAscii(v.relname, v.relname_length).toUpper() + QLatin1String("' "
- "AND a.RDB$FIELD_NAME = '") + QString::fromAscii(v.sqlname, v.sqlname_length).toUpper() + QLatin1String("' "));
- if(q.first()) {
- if(v.sqlscale < 0) {
- f.setLength(q.value(0).toInt());
- f.setPrecision(qAbs(q.value(1).toInt()));
- } else {
- f.setLength(q.value(2).toInt());
- f.setPrecision(0);
+ f.setLength(v.sqllen);
+ f.setPrecision(qAbs(v.sqlscale));
+ f.setRequiredStatus((v.sqltype & 1) == 0 ? QSqlField::Required : QSqlField::Optional);
+ if(v.sqlscale < 0) {
+ QSqlQuery q(new QIBaseResult(d->db));
+ q.setForwardOnly(true);
+ q.exec(QLatin1String("select b.RDB$FIELD_PRECISION, b.RDB$FIELD_SCALE, b.RDB$FIELD_LENGTH, 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 = '") + QString::fromAscii(v.relname, v.relname_length).toUpper() + QLatin1String("' "
+ "AND a.RDB$FIELD_NAME = '") + QString::fromAscii(v.sqlname, v.sqlname_length).toUpper() + QLatin1String("' "));
+ if(q.first()) {
+ if(v.sqlscale < 0) {
+ f.setLength(q.value(0).toInt());
+ f.setPrecision(qAbs(q.value(1).toInt()));
+ } else {
+ f.setLength(q.value(2).toInt());
+ f.setPrecision(0);
+ }
+ f.setRequiredStatus(q.value(3).toBool() ? QSqlField::Required : QSqlField::Optional);
}
- f.setRequiredStatus(q.value(3).toBool() ? QSqlField::Required : QSqlField::Optional);
- }
- else {
- f.setLength(0);
- f.setPrecision(0);
- f.setRequiredStatus(QSqlField::Unknown);
}
f.setSqlType(v.sqltype);
rec.append(f);
@@ -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 9b57f3c..1f54db7 100644
--- a/src/sql/drivers/mysql/qsql_mysql.cpp
+++ b/src/sql/drivers/mysql/qsql_mysql.cpp
@@ -224,7 +224,7 @@ static QTextCodec* codec(MYSQL* mysql)
static QSqlError qMakeError(const QString& err, QSqlError::ErrorType type,
const QMYSQLDriverPrivate* p)
{
- const char *cerr = mysql_error(p->mysql);
+ const char *cerr = p->mysql ? mysql_error(p->mysql) : 0;
return QSqlError(QLatin1String("QMYSQL: ") + err,
p->tc ? toUnicode(p->tc, cerr) : QString::fromLatin1(cerr),
type, mysql_errno(p->mysql));
@@ -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 97aa346..31d9dcf 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 7017d6c..d63c482 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().toUpper() != user.toUpper())
tl.append(t.value(0).toString() + QLatin1String(".") + t.value(1).toString());
else
tl.append(t.value(1).toString());
@@ -2217,7 +2224,7 @@ QStringList QOCIDriver::tables(QSql::TableType type) const
"and owner != 'CTXSYS'"
"and owner != 'WMSYS'"));
while (t.next()) {
- if (t.value(0).toString() != d->user)
+ if (t.value(0).toString().toUpper() != d->user.toUpper())
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 f6710db..ee500a0 100644
--- a/src/sql/drivers/odbc/qsql_odbc.cpp
+++ b/src/sql/drivers/odbc/qsql_odbc.cpp
@@ -55,6 +55,7 @@
#include <qvarlengtharray.h>
#include <qvector.h>
#include <QDebug>
+#include <QSqlQuery>
QT_BEGIN_NAMESPACE
@@ -69,18 +70,15 @@ QT_BEGIN_NAMESPACE
#endif
// newer platform SDKs use SQLLEN instead of SQLINTEGER
-#if defined(SQLLEN) || defined(Q_OS_WIN64)
-# define QSQLLEN SQLLEN
-#else
+#if defined(WIN32) && (_MSC_VER < 1300)
# define QSQLLEN SQLINTEGER
-#endif
-
-#if defined(SQLULEN) || defined(Q_OS_WIN64)
-# define QSQLULEN SQLULEN
-#else
# define QSQLULEN SQLUINTEGER
+#else
+# define QSQLLEN SQLLEN
+# define QSQLULEN SQLULEN
#endif
+
static const int COLNAMESIZE = 256;
//Map Qt parameter types to ODBC types
static const SQLSMALLINT qParamType[4] = { SQL_PARAM_INPUT, SQL_PARAM_INPUT, SQL_PARAM_OUTPUT, SQL_PARAM_INPUT_OUTPUT };
@@ -88,6 +86,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 +118,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
@@ -350,7 +352,7 @@ static QString qGetStringData(SQLHANDLE hStmt, int column, int colSize, bool uni
} else {
fieldVal += QString::fromAscii(buf, rSize);
}
- if (fieldVal.size() + lengthIndicator >= colSize) {
+ if (lengthIndicator - fieldVal.size() <= 0) {
// workaround for Drivermanagers that don't return SQL_NO_DATA
break;
}
@@ -555,6 +557,28 @@ 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];
+ 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 +729,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)
@@ -1714,6 +1797,10 @@ bool QODBCDriver::open(const QString & db,
d->checkHasMultiResults();
setOpen(true);
setOpenError(false);
+ if(d->isMSSqlServer) {
+ QSqlQuery i(createResult());
+ i.exec(QLatin1String("SET QUOTED_IDENTIFIER ON"));
+ }
return true;
}
@@ -2084,6 +2171,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 +2289,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 +2428,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 4148007..51f53ea 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 afe45fc..16d19f1 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 605c4e8..f732077 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 ff73caa..d0c6e18 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 46e4a0b..515f0de 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*"));