| 1 | /**************************************************************************** | 
| 2 | ** | 
| 3 | ** Copyright (C) 2016 The Qt Company Ltd. | 
| 4 | ** Contact: https://www.qt.io/licensing/ | 
| 5 | ** | 
| 6 | ** This file is part of the test suite of the Qt Toolkit. | 
| 7 | ** | 
| 8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ | 
| 9 | ** Commercial License Usage | 
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in | 
| 11 | ** accordance with the commercial license agreement provided with the | 
| 12 | ** Software or, alternatively, in accordance with the terms contained in | 
| 13 | ** a written agreement between you and The Qt Company. For licensing terms | 
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further | 
| 15 | ** information use the contact form at https://www.qt.io/contact-us. | 
| 16 | ** | 
| 17 | ** GNU General Public License Usage | 
| 18 | ** Alternatively, this file may be used under the terms of the GNU | 
| 19 | ** General Public License version 3 as published by the Free Software | 
| 20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT | 
| 21 | ** included in the packaging of this file. Please review the following | 
| 22 | ** information to ensure the GNU General Public License requirements will | 
| 23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. | 
| 24 | ** | 
| 25 | ** $QT_END_LICENSE$ | 
| 26 | ** | 
| 27 | ****************************************************************************/ | 
| 28 |  | 
| 29 |  | 
| 30 | #include <QtTest/QtTest> | 
| 31 | #include <qsqldatabase.h> | 
| 32 | #include <qsqlquery.h> | 
| 33 | #include <qsqldriver.h> | 
| 34 | #include <qsqlrecord.h> | 
| 35 | #include <qsqlfield.h> | 
| 36 | #include <qsqlindex.h> | 
| 37 | #include <qregularexpression.h> | 
| 38 | #include <qvariant.h> | 
| 39 | #include <qdatetime.h> | 
| 40 | #include <qdebug.h> | 
| 41 |  | 
| 42 | #include "tst_databases.h" | 
| 43 |  | 
| 44 | Q_DECLARE_METATYPE(QSqlDriver::NotificationSource) | 
| 45 |  | 
| 46 | QT_FORWARD_DECLARE_CLASS(QSqlDatabase) | 
| 47 | struct FieldDef; | 
| 48 |  | 
| 49 | class tst_QSqlDatabase : public QObject | 
| 50 | { | 
| 51 |     Q_OBJECT | 
| 52 |  | 
| 53 | public: | 
| 54 |     tst_QSqlDatabase(); | 
| 55 |     virtual ~tst_QSqlDatabase(); | 
| 56 |  | 
| 57 | public slots: | 
| 58 |     void initTestCase(); | 
| 59 |     void cleanupTestCase(); | 
| 60 |     void init(); | 
| 61 |     void cleanup(); | 
| 62 | private slots: | 
| 63 |     void record_data() { generic_data(); } | 
| 64 |     //void record(); | 
| 65 |     void open_data() { generic_data(); } | 
| 66 |     void open(); | 
| 67 |     void tables_data() { generic_data(); } | 
| 68 |     void tables(); | 
| 69 |     void oci_tables_data() { generic_data(engine: "QOCI" ); } | 
| 70 |     void oci_tables(); | 
| 71 |     void transaction_data() { generic_data(); } | 
| 72 |     void transaction(); | 
| 73 |     void eventNotification_data() { generic_data(); } | 
| 74 |     void eventNotification(); | 
| 75 |     void addDatabase(); | 
| 76 |     void errorReporting_data(); | 
| 77 |     void errorReporting(); | 
| 78 |     void cloneDatabase_data() { generic_data(); } | 
| 79 |     void cloneDatabase(); | 
| 80 |  | 
| 81 |     //database specific tests | 
| 82 |     void recordMySQL_data() { generic_data(engine: "QMYSQL" ); } | 
| 83 |     void recordMySQL(); | 
| 84 |     void recordPSQL_data() { generic_data(engine: "QPSQL" ); } | 
| 85 |     void recordPSQL(); | 
| 86 |     void recordOCI_data() { generic_data(engine: "QOCI" ); } | 
| 87 |     void recordOCI(); | 
| 88 |     void recordTDS_data() { generic_data(engine: "QTDS" ); } | 
| 89 |     void recordTDS(); | 
| 90 |     void recordDB2_data() { generic_data(engine: "QDB2" ); } | 
| 91 |     void recordDB2(); | 
| 92 |     void recordSQLite_data() { generic_data(engine: "QSQLITE" ); } | 
| 93 |     void recordSQLite(); | 
| 94 |     void recordAccess_data() { generic_data(engine: "QODBC" ); } | 
| 95 |     void recordAccess(); | 
| 96 |     void recordSQLServer_data() { generic_data(engine: "QODBC" ); } | 
| 97 |     void recordSQLServer(); | 
| 98 |     void recordIBase_data() {generic_data(engine: "QIBASE" ); } | 
| 99 |     void recordIBase(); | 
| 100 |  | 
| 101 |     void eventNotificationIBase_data() { generic_data(engine: "QIBASE" ); } | 
| 102 |     void eventNotificationIBase(); | 
| 103 |     void eventNotificationPSQL_data() { generic_data(engine: "QPSQL" ); } | 
| 104 |     void eventNotificationPSQL(); | 
| 105 |     void eventNotificationSQLite_data() { generic_data(engine: "QSQLITE" ); } | 
| 106 |     void eventNotificationSQLite(); | 
| 107 |  | 
| 108 |     //database specific 64 bit integer test | 
| 109 |     void bigIntField_data() { generic_data(); } | 
| 110 |     void bigIntField(); | 
| 111 |  | 
| 112 |     // general tests | 
| 113 |     void getConnectionName_data() { generic_data(); } | 
| 114 |     void getConnectionName(); // For task 129992 | 
| 115 |  | 
| 116 |     //problem specific tests | 
| 117 |     void alterTable_data() { generic_data(); } | 
| 118 |     void alterTable(); | 
| 119 |     void caseSensivity_data() { generic_data(); } | 
| 120 |     void caseSensivity(); | 
| 121 |     void noEscapedFieldNamesInRecord_data() { generic_data(); } | 
| 122 |     void noEscapedFieldNamesInRecord(); | 
| 123 |     void whitespaceInIdentifiers_data() { generic_data(); } | 
| 124 |     void whitespaceInIdentifiers(); | 
| 125 |     void formatValueTrimStrings_data() { generic_data(); } | 
| 126 |     void formatValueTrimStrings(); | 
| 127 |     void precisionPolicy_data() { generic_data(); } | 
| 128 |     void precisionPolicy(); | 
| 129 |     void infinityAndNan_data() { generic_data(); } | 
| 130 |     void infinityAndNan(); | 
| 131 |     void multipleThreads_data() { generic_data(); } | 
| 132 |     void multipleThreads(); | 
| 133 |  | 
| 134 |     void db2_valueCacheUpdate_data() { generic_data(engine: "QDB2" ); } | 
| 135 |     void db2_valueCacheUpdate(); | 
| 136 |  | 
| 137 |     void psql_schemas_data() { generic_data(engine: "QPSQL" ); } | 
| 138 |     void psql_schemas(); | 
| 139 |     void psql_escapedIdentifiers_data() { generic_data(engine: "QPSQL" ); } | 
| 140 |     void psql_escapedIdentifiers(); | 
| 141 |     void psql_escapeBytea_data() { generic_data(engine: "QPSQL" ); } | 
| 142 |     void psql_escapeBytea(); | 
| 143 |     void psql_bug249059_data() { generic_data(engine: "QPSQL" ); } | 
| 144 |     void psql_bug249059(); | 
| 145 |  | 
| 146 |     void mysqlOdbc_unsignedIntegers_data() { generic_data(); } | 
| 147 |     void mysqlOdbc_unsignedIntegers(); | 
| 148 |     void mysql_multiselect_data() { generic_data(engine: "QMYSQL" ); } | 
| 149 |     void mysql_multiselect();  // For task 144331 | 
| 150 |     void mysql_savepointtest_data() { generic_data(engine: "QMYSQL" ); } | 
| 151 |     void mysql_savepointtest(); | 
| 152 |     void mysql_connectWithInvalidAddress(); | 
| 153 |  | 
| 154 |     void accessOdbc_strings_data() { generic_data(); } | 
| 155 |     void accessOdbc_strings(); | 
| 156 |  | 
| 157 |     void ibase_numericFields_data() { generic_data(engine: "QIBASE" ); } | 
| 158 |     void ibase_numericFields(); // For task 125053 | 
| 159 |     void ibase_fetchBlobs_data() { generic_data(engine: "QIBASE" ); } | 
| 160 |     void ibase_fetchBlobs(); // For task 143471 | 
| 161 |     void ibase_useCustomCharset_data() { generic_data(engine: "QIBASE" ); } | 
| 162 |     void ibase_useCustomCharset(); // For task 134608 | 
| 163 |     void ibase_procWithoutReturnValues_data() { generic_data(engine: "QIBASE" ); } // For task 165423 | 
| 164 |     void ibase_procWithoutReturnValues(); | 
| 165 |     void ibase_procWithReturnValues_data() { generic_data(engine: "QIBASE" ); } // For task 177530 | 
| 166 |     void ibase_procWithReturnValues(); | 
| 167 |  | 
| 168 |     void odbc_reopenDatabase_data() { generic_data(engine: "QODBC" ); } | 
| 169 |     void odbc_reopenDatabase(); | 
| 170 |     void odbc_uniqueidentifier_data() { generic_data(engine: "QODBC" ); } | 
| 171 |     void odbc_uniqueidentifier(); // For task 141822 | 
| 172 |     void odbc_uintfield_data() { generic_data(engine: "QODBC" ); } | 
| 173 |     void odbc_uintfield(); | 
| 174 |     void odbc_bindBoolean_data() { generic_data(engine: "QODBC" ); } | 
| 175 |     void odbc_bindBoolean(); | 
| 176 |     void odbc_testqGetString_data() { generic_data(engine: "QODBC" ); } | 
| 177 |     void odbc_testqGetString(); | 
| 178 |  | 
| 179 |     void oci_serverDetach_data() { generic_data(engine: "QOCI" ); } | 
| 180 |     void oci_serverDetach(); // For task 154518 | 
| 181 |     void oci_xmltypeSupport_data() { generic_data(engine: "QOCI" ); } | 
| 182 |     void oci_xmltypeSupport(); | 
| 183 |     void oci_fieldLength_data() { generic_data(engine: "QOCI" ); } | 
| 184 |     void oci_fieldLength(); | 
| 185 |     void oci_synonymstest_data() { generic_data(engine: "QOCI" ); } | 
| 186 |     void oci_synonymstest(); | 
| 187 |  | 
| 188 |     void sqlite_bindAndFetchUInt_data() { generic_data(engine: "QSQLITE" ); } | 
| 189 |     void sqlite_bindAndFetchUInt(); | 
| 190 |  | 
| 191 |     void sqlStatementUseIsNull_189093_data() { generic_data(); } | 
| 192 |     void sqlStatementUseIsNull_189093(); | 
| 193 |  | 
| 194 |     void sqlite_enable_cache_mode_data() { generic_data(engine: "QSQLITE" ); } | 
| 195 |     void sqlite_enable_cache_mode(); | 
| 196 |  | 
| 197 |     void sqlite_enableRegexp_data() { generic_data(engine: "QSQLITE" ); } | 
| 198 |     void sqlite_enableRegexp(); | 
| 199 |  | 
| 200 |     void sqlite_openError(); | 
| 201 |  | 
| 202 |     void sqlite_check_json1_data() { generic_data(engine: "QSQLITE" ); } | 
| 203 |     void sqlite_check_json1(); | 
| 204 |  | 
| 205 | private: | 
| 206 |     void createTestTables(QSqlDatabase db); | 
| 207 |     void dropTestTables(QSqlDatabase db); | 
| 208 |     void populateTestTables(QSqlDatabase db); | 
| 209 |     void generic_data(const QString &engine=QString()); | 
| 210 |  | 
| 211 |     void testRecord(const FieldDef fieldDefs[], const QSqlRecord& inf, QSqlDatabase db); | 
| 212 |     void commonFieldTest(const FieldDef fieldDefs[], QSqlDatabase, const int); | 
| 213 |  | 
| 214 |     tst_Databases dbs; | 
| 215 | }; | 
| 216 |  | 
| 217 | // number of records to be inserted per testfunction | 
| 218 | static const int ITERATION_COUNT = 2; | 
| 219 |  | 
| 220 | //helper class for database specific tests | 
| 221 | struct FieldDef { | 
| 222 |     FieldDef(QString tn = QString(), | 
| 223 |           QVariant::Type t = QVariant::Invalid, | 
| 224 |           QVariant v = QVariant(), | 
| 225 |           bool nl = true): | 
| 226 |         typeName(tn), type(t), val(v), nullable(nl) {} | 
| 227 |  | 
| 228 |     QString fieldName() const | 
| 229 |     { | 
| 230 |         QString rt = typeName; | 
| 231 |         rt.replace(re: QRegularExpression("\\s" ), after: QString("_" )); | 
| 232 |         int i = rt.indexOf(c: QLatin1Char('(')); | 
| 233 |         if (i == -1) | 
| 234 |             i = rt.length(); | 
| 235 |         if (i > 20) | 
| 236 |             i = 20; | 
| 237 |         return "t_"  + rt.left(n: i); | 
| 238 |     } | 
| 239 |     QString typeName; | 
| 240 |     QVariant::Type type; | 
| 241 |     QVariant val; | 
| 242 |     bool nullable; | 
| 243 | }; | 
| 244 |  | 
| 245 | // creates a table out of the FieldDefs and returns the number of fields | 
| 246 | // excluding the primary key field | 
| 247 | static int createFieldTable(const FieldDef fieldDefs[], QSqlDatabase db) | 
| 248 | { | 
| 249 |     QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db); | 
| 250 |     const QString tableName = qTableName(prefix: "qtestfields" , __FILE__, db); | 
| 251 |     tst_Databases::safeDropTable(db, tableName); | 
| 252 |     QSqlQuery q(db); | 
| 253 |     // construct a create table statement consisting of all fieldtypes | 
| 254 |     QString qs = "create table "  + tableName; | 
| 255 |     QString autoName = tst_Databases::autoFieldName(db); | 
| 256 |     if (tst_Databases::isMSAccess(db)) | 
| 257 |         qs.append(s: " (id int not null" ); | 
| 258 |     else if (dbType == QSqlDriver::PostgreSQL) | 
| 259 |         qs.append(s: " (id serial not null" ); | 
| 260 |     else | 
| 261 |         qs.append(s: QString("(id integer not null %1 primary key" ).arg(a: autoName)); | 
| 262 |  | 
| 263 |     int i = 0; | 
| 264 |     for (i = 0; !fieldDefs[ i ].typeName.isNull(); ++i) { | 
| 265 |         qs += QString(",\n %1 %2" ).arg(a: fieldDefs[ i ].fieldName()).arg(a: fieldDefs[ i ].typeName); | 
| 266 |         if ((dbType == QSqlDriver::Sybase || dbType == QSqlDriver::MSSqlServer) && fieldDefs[i].nullable) | 
| 267 |             qs += " null" ; | 
| 268 |     } | 
| 269 |  | 
| 270 |     if (tst_Databases::isMSAccess(db)) | 
| 271 |         qs.append(s: ",\n primary key (id)" ); | 
| 272 |  | 
| 273 |     qs += ')'; | 
| 274 |     if (!q.exec(query: qs)) { | 
| 275 |         qDebug() << "Creation of Table failed:"  << tst_Databases::printError(err: q.lastError(), db); | 
| 276 |         qDebug() << "Query: "  << qs; | 
| 277 |         return -1; | 
| 278 |     } | 
| 279 |     return i; | 
| 280 | } | 
| 281 |  | 
| 282 | tst_QSqlDatabase::tst_QSqlDatabase() | 
| 283 | { | 
| 284 | } | 
| 285 |  | 
| 286 | tst_QSqlDatabase::~tst_QSqlDatabase() | 
| 287 | { | 
| 288 | } | 
| 289 |  | 
| 290 | void tst_QSqlDatabase::createTestTables(QSqlDatabase db) | 
| 291 | { | 
| 292 |     if (!db.isValid()) | 
| 293 |     return; | 
| 294 |     const QString tableName = qTableName(prefix: "qtest" , __FILE__, db); | 
| 295 |     QSqlQuery q(db); | 
| 296 |     QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db); | 
| 297 |     if (dbType == QSqlDriver::MySqlServer) { | 
| 298 |         // ### stupid workaround until we find a way to hardcode this | 
| 299 |         // in the MySQL server startup script | 
| 300 |         q.exec(query: "set table_type=innodb" ); | 
| 301 |     } else if (dbType == QSqlDriver::MSSqlServer) { | 
| 302 |         QVERIFY_SQL(q, exec("SET ANSI_DEFAULTS ON" )); | 
| 303 |         QVERIFY_SQL(q, exec("SET IMPLICIT_TRANSACTIONS OFF" )); | 
| 304 |     } else if (dbType == QSqlDriver::PostgreSQL) { | 
| 305 |         QVERIFY_SQL( q, exec("set client_min_messages='warning'" )); | 
| 306 |     } | 
| 307 |     // please never ever change this table; otherwise fix all tests ;) | 
| 308 |     if (tst_Databases::isMSAccess(db)) { | 
| 309 |         QVERIFY_SQL(q, exec("create table "  + tableName + | 
| 310 |                    " (id int not null, t_varchar varchar(40) not null, t_char char(40), "  | 
| 311 |                    "t_numeric number, primary key (id, t_varchar))" )); | 
| 312 |     } else { | 
| 313 |         QVERIFY_SQL(q, exec("create table "  + tableName + | 
| 314 |                " (id integer not null, t_varchar varchar(40) not null, "  | 
| 315 |                "t_char char(40), t_numeric numeric(6, 3), primary key (id, t_varchar))" )); | 
| 316 |     } | 
| 317 |     if (testWhiteSpaceNames(name: db.driverName())) { | 
| 318 |         QString qry = "create table "  + qTableName(prefix: "qtest test" , __FILE__, db) | 
| 319 |             + '(' | 
| 320 |             + db.driver()->escapeIdentifier(identifier: QLatin1String("test test" ), type: QSqlDriver::FieldName) | 
| 321 |             + " int not null primary key)" ; | 
| 322 |         QVERIFY_SQL(q, exec(qry)); | 
| 323 |     } | 
| 324 | } | 
| 325 |  | 
| 326 | void tst_QSqlDatabase::dropTestTables(QSqlDatabase db) | 
| 327 | { | 
| 328 |     if (!db.isValid()) | 
| 329 |         return; | 
| 330 |  | 
| 331 |     QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db); | 
| 332 |     if (dbType == QSqlDriver::PostgreSQL) { | 
| 333 |         QSqlQuery q(db); | 
| 334 |         QVERIFY_SQL( q, exec("set client_min_messages='warning'" )); | 
| 335 |     } | 
| 336 |  | 
| 337 |     // drop the view first, otherwise we'll get dependency problems | 
| 338 |     tst_Databases::safeDropViews(db, viewNames: QStringList() << qTableName(prefix: "qtest_view" , __FILE__, db) << qTableName(prefix: "qtest_view2" , __FILE__, db)); | 
| 339 |     const QString qtestTable = qTableName(prefix: "qtest" , __FILE__, db); | 
| 340 |     QStringList tableNames; | 
| 341 |     tableNames << qtestTable | 
| 342 |             << qTableName(prefix: "qtest test" , __FILE__, db) | 
| 343 |             << qTableName(prefix: "qtestfields" , __FILE__, db) | 
| 344 |             << qTableName(prefix: "qtestalter" , __FILE__, db) | 
| 345 |             << qTableName(prefix: "qtest_temp" , __FILE__, db) | 
| 346 |             << qTableName(prefix: "qtest_bigint" , __FILE__, db) | 
| 347 |             << qTableName(prefix: "qtest_xmltype" , __FILE__, db) | 
| 348 |             << qTableName(prefix: "latin1table" , __FILE__, db) | 
| 349 |             << qTableName(prefix: "qtest_sqlguid" , __FILE__, db) | 
| 350 |             << qTableName(prefix: "batable" , __FILE__, db) | 
| 351 |             << qTableName(prefix: "qtest_prec" , __FILE__, db) | 
| 352 |             << qTableName(prefix: "uint" , __FILE__, db) | 
| 353 |             << qTableName(prefix: "strings" , __FILE__, db) | 
| 354 |             << qTableName(prefix: "numericfields" , __FILE__, db) | 
| 355 |             << qTableName(prefix: "qtest_ibaseblobs" , __FILE__, db) | 
| 356 |             << qTableName(prefix: "qtestBindBool" , __FILE__, db) | 
| 357 |             << qTableName(prefix: "testqGetString" , __FILE__, db) | 
| 358 |             << qTableName(prefix: "qtest_sqlguid" , __FILE__, db) | 
| 359 |             << qTableName(prefix: "uint_table" , __FILE__, db) | 
| 360 |             << qTableName(prefix: "uint_test" , __FILE__, db) | 
| 361 |             << qTableName(prefix: "bug_249059" , __FILE__, db) | 
| 362 |             << qTableName(prefix: "regexp_test" , __FILE__, db); | 
| 363 |  | 
| 364 |     QSqlQuery q(0, db); | 
| 365 |     if (dbType == QSqlDriver::PostgreSQL) { | 
| 366 |         q.exec(query: "drop schema "  + qTableName(prefix: "qtestschema" , __FILE__, db) + " cascade" ); | 
| 367 |         q.exec(query: "drop schema "  + qTableName(prefix: "qtestScHeMa" , __FILE__, db) + " cascade" ); | 
| 368 |     } | 
| 369 |  | 
| 370 |     if (testWhiteSpaceNames(name: db.driverName())) { | 
| 371 |         tableNames <<  db.driver()->escapeIdentifier(identifier: qTableName(prefix: "qtest test" , __FILE__, db), | 
| 372 |                                                      type: QSqlDriver::TableName); | 
| 373 |     } | 
| 374 |  | 
| 375 |     tst_Databases::safeDropTables(db, tableNames); | 
| 376 |  | 
| 377 |     if (dbType == QSqlDriver::Oracle) { | 
| 378 |         q.exec(query: "drop user " +qTableName(prefix: "CREATOR" , __FILE__, db)+ " cascade" ); | 
| 379 |         q.exec(query: "drop user " +qTableName(prefix: "APPUSER" , __FILE__, db) + " cascade" ); | 
| 380 |         q.exec(query: "DROP TABLE sys." +qTableName(prefix: "mypassword" , __FILE__, db)); | 
| 381 |  | 
| 382 |     } | 
| 383 | } | 
| 384 |  | 
| 385 | void tst_QSqlDatabase::populateTestTables(QSqlDatabase db) | 
| 386 | { | 
| 387 |     if (!db.isValid()) | 
| 388 |         return; | 
| 389 |     QSqlQuery q(db); | 
| 390 |     const QString qtest(qTableName(prefix: "qtest" , __FILE__, db)); | 
| 391 |  | 
| 392 |     q.exec(query: "delete from "  + qtest); //non-fatal | 
| 393 |     QVERIFY_SQL(q, exec("insert into "  + qtest + " (id, t_varchar, t_char, t_numeric) values (0, 'VarChar0', 'Char0', 1.1)" )); | 
| 394 |     QVERIFY_SQL(q, exec("insert into "  + qtest + " (id, t_varchar, t_char, t_numeric) values (1, 'VarChar1', 'Char1', 2.2)" )); | 
| 395 |     QVERIFY_SQL(q, exec("insert into "  + qtest + " (id, t_varchar, t_char, t_numeric) values (2, 'VarChar2', 'Char2', 3.3)" )); | 
| 396 |     QVERIFY_SQL(q, exec("insert into "  + qtest + " (id, t_varchar, t_char, t_numeric) values (3, 'VarChar3', 'Char3', 4.4)" )); | 
| 397 |     QVERIFY_SQL(q, exec("insert into "  + qtest + " (id, t_varchar, t_char, t_numeric) values (4, 'VarChar4', NULL, NULL)" )); | 
| 398 | } | 
| 399 |  | 
| 400 | void tst_QSqlDatabase::initTestCase() | 
| 401 | { | 
| 402 |     qRegisterMetaType<QSqlDriver::NotificationSource>(typeName: "QSqlDriver::NotificationSource" ); | 
| 403 |     QVERIFY(dbs.open()); | 
| 404 |  | 
| 405 |     for (QStringList::ConstIterator it = dbs.dbNames.begin(); it != dbs.dbNames.end(); ++it) { | 
| 406 |         QSqlDatabase db = QSqlDatabase::database(connectionName: (*it)); | 
| 407 |         CHECK_DATABASE(db); | 
| 408 |         dropTestTables(db); //in case of leftovers | 
| 409 |         createTestTables(db); | 
| 410 |         populateTestTables(db); | 
| 411 |     } | 
| 412 | } | 
| 413 |  | 
| 414 | void tst_QSqlDatabase::cleanupTestCase() | 
| 415 | { | 
| 416 |     for (QStringList::ConstIterator it = dbs.dbNames.begin(); it != dbs.dbNames.end(); ++it) { | 
| 417 |         QSqlDatabase db = QSqlDatabase::database(connectionName: (*it)); | 
| 418 |         CHECK_DATABASE(db); | 
| 419 |         dropTestTables(db); | 
| 420 |     } | 
| 421 |  | 
| 422 |     dbs.close(); | 
| 423 | } | 
| 424 |  | 
| 425 | void tst_QSqlDatabase::init() | 
| 426 | { | 
| 427 | } | 
| 428 |  | 
| 429 | void tst_QSqlDatabase::cleanup() | 
| 430 | { | 
| 431 | } | 
| 432 |  | 
| 433 | void tst_QSqlDatabase::generic_data(const QString& engine) | 
| 434 | { | 
| 435 |     if ( dbs.fillTestTable(driverPrefix: engine) == 0 ) { | 
| 436 |         if(engine.isEmpty()) | 
| 437 |            QSKIP( "No database drivers are available in this Qt configuration" ); | 
| 438 |         else | 
| 439 |            QSKIP( (QString("No database drivers of type %1 are available in this Qt configuration" ).arg(engine)).toLocal8Bit()); | 
| 440 |     } | 
| 441 | } | 
| 442 |  | 
| 443 | void tst_QSqlDatabase::addDatabase() | 
| 444 | { | 
| 445 |     QTest::ignoreMessage(type: QtWarningMsg, message: "QSqlDatabase: BLAH_FOO_NONEXISTENT_DRIVER driver not loaded" ); | 
| 446 |     QTest::ignoreMessage(type: QtWarningMsg, qPrintable("QSqlDatabase: available drivers: "  + QSqlDatabase::drivers().join(QLatin1Char(' ')))); | 
| 447 |     { | 
| 448 |         QSqlDatabase db = QSqlDatabase::addDatabase(type: "BLAH_FOO_NONEXISTENT_DRIVER" , | 
| 449 |                                                     connectionName: "INVALID_CONNECTION" ); | 
| 450 |         QVERIFY(!db.isValid()); | 
| 451 |     } | 
| 452 |     QVERIFY(QSqlDatabase::contains("INVALID_CONNECTION" )); | 
| 453 |     QSqlDatabase::removeDatabase(connectionName: "INVALID_CONNECTION" ); | 
| 454 |     QVERIFY(!QSqlDatabase::contains("INVALID_CONNECTION" )); | 
| 455 | } | 
| 456 |  | 
| 457 | void tst_QSqlDatabase::errorReporting_data() | 
| 458 | { | 
| 459 |     QTest::addColumn<QString>(name: "driver" ); | 
| 460 |  | 
| 461 |     QTest::newRow(dataTag: "QTDS" ) << QString::fromLatin1(str: "QTDS" ); | 
| 462 |     QTest::newRow(dataTag: "QTDS7" ) << QString::fromLatin1(str: "QTDS7" ); | 
| 463 | } | 
| 464 |  | 
| 465 | void tst_QSqlDatabase::errorReporting() | 
| 466 | { | 
| 467 |     QFETCH(QString, driver); | 
| 468 |  | 
| 469 |     if (!QSqlDatabase::drivers().contains(str: driver)) | 
| 470 |         QSKIP(QString::fromLatin1("Database driver %1 not available" ).arg(driver).toLocal8Bit().constData()); | 
| 471 |  | 
| 472 |     const QString dbName = QLatin1String("errorReportingDb-" ) + driver; | 
| 473 |     QSqlDatabase db = QSqlDatabase::addDatabase(type: driver, connectionName: dbName); | 
| 474 |  | 
| 475 |     db.setHostName(QLatin1String("127.0.0.1" )); | 
| 476 |     db.setDatabaseName(QLatin1String("NonExistantDatabase" )); | 
| 477 |     db.setUserName(QLatin1String("InvalidUser" )); | 
| 478 |     db.setPassword(QLatin1String("IncorrectPassword" )); | 
| 479 |  | 
| 480 |     QVERIFY(!db.open()); | 
| 481 |  | 
| 482 |     db = QSqlDatabase(); | 
| 483 |  | 
| 484 |     QSqlDatabase::removeDatabase(connectionName: dbName); | 
| 485 | } | 
| 486 |  | 
| 487 | void tst_QSqlDatabase::open() | 
| 488 | { | 
| 489 |     QFETCH(QString, dbName); | 
| 490 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 491 |     CHECK_DATABASE(db); | 
| 492 |  | 
| 493 |     int i; | 
| 494 |     for (i = 0; i < 10; ++i) { | 
| 495 |         db.close(); | 
| 496 |         QVERIFY(!db.isOpen()); | 
| 497 |         QVERIFY_SQL(db, open()); | 
| 498 |         QVERIFY(db.isOpen()); | 
| 499 |         QVERIFY(!db.isOpenError()); | 
| 500 |     } | 
| 501 |  | 
| 502 |     QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db); | 
| 503 |     if (dbType == QSqlDriver::SQLite && db.databaseName() == ":memory:" ) { | 
| 504 |         // tables in in-memory databases don't survive an open/close | 
| 505 |         createTestTables(db); | 
| 506 |         populateTestTables(db); | 
| 507 |     } | 
| 508 | } | 
| 509 |  | 
| 510 | void tst_QSqlDatabase::tables() | 
| 511 | { | 
| 512 |     QFETCH(QString, dbName); | 
| 513 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 514 |     CHECK_DATABASE(db); | 
| 515 |     QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db); | 
| 516 |  | 
| 517 |     const auto qtest(qTableName(prefix: "qtest" , __FILE__, db, escape: false)), | 
| 518 |                qtest_view(qTableName(prefix: "qtest_view" , __FILE__, db, escape: false)), | 
| 519 |                temp_tab(qTableName(prefix: "test_tab" , __FILE__, db, escape: false)), | 
| 520 |                qtestspace(qTableName(prefix: "qtest test" , __FILE__, db, escape: false)); | 
| 521 |  | 
| 522 |     bool views = true; | 
| 523 |     bool tempTables = false; | 
| 524 |  | 
| 525 |     QSqlQuery q(db); | 
| 526 |     if (!q.exec(query: "CREATE VIEW "  + qtest_view + " as select * from "  + qtest)) { | 
| 527 |         qDebug(msg: "DBMS '%s' cannot handle VIEWs: %s" , | 
| 528 |                qPrintable(tst_Databases::dbToString(db)), | 
| 529 |                qPrintable(tst_Databases::printError(q.lastError()))); | 
| 530 |         views = false; | 
| 531 |     } | 
| 532 |  | 
| 533 |     if (db.driverName().startsWith(s: "QSQLITE3" )) { | 
| 534 |         QVERIFY_SQL(q, exec("CREATE TEMPORARY TABLE "  + temp_tab + " (id int)" )); | 
| 535 |         tempTables = true; | 
| 536 |     } | 
| 537 |  | 
| 538 |     QStringList tables = db.tables(type: QSql::Tables); | 
| 539 |     QVERIFY(tables.contains(qtest, Qt::CaseInsensitive)); | 
| 540 |     QVERIFY(!tables.contains("sql_features" , Qt::CaseInsensitive)); //check for postgres 7.4 internal tables | 
| 541 |     if (views) { | 
| 542 |         QVERIFY(!tables.contains(qtest_view, Qt::CaseInsensitive)); | 
| 543 |     } | 
| 544 |     if (tempTables) | 
| 545 |         QVERIFY(tables.contains(temp_tab, Qt::CaseInsensitive)); | 
| 546 |  | 
| 547 |     tables = db.tables(type: QSql::Views); | 
| 548 |     if (views) { | 
| 549 |         if(!tables.contains(str: qtest_view, cs: Qt::CaseInsensitive)) | 
| 550 |             qDebug() << "failed to find"  << qtest_view << "in"  << tables; | 
| 551 |         QVERIFY(tables.contains(qtest_view, Qt::CaseInsensitive)); | 
| 552 |     } | 
| 553 |     if (tempTables) | 
| 554 |         QVERIFY(!tables.contains(temp_tab, Qt::CaseInsensitive)); | 
| 555 |     QVERIFY(!tables.contains(qtest, Qt::CaseInsensitive)); | 
| 556 |  | 
| 557 |     tables = db.tables(type: QSql::SystemTables); | 
| 558 |     QVERIFY(!tables.contains(qtest, Qt::CaseInsensitive)); | 
| 559 |     QVERIFY(!tables.contains(qtest_view, Qt::CaseInsensitive)); | 
| 560 |     QVERIFY(!tables.contains(temp_tab, Qt::CaseInsensitive)); | 
| 561 |  | 
| 562 |     tables = db.tables(type: QSql::AllTables); | 
| 563 |     if (views) | 
| 564 |         QVERIFY(tables.contains(qtest_view, Qt::CaseInsensitive)); | 
| 565 |     if (tempTables) | 
| 566 |         QVERIFY(tables.contains(temp_tab, Qt::CaseInsensitive)); | 
| 567 |     QVERIFY(tables.contains(qtest, Qt::CaseInsensitive)); | 
| 568 |  | 
| 569 |     if (dbType == QSqlDriver::PostgreSQL) | 
| 570 |         QVERIFY(tables.contains(qtestspace)); | 
| 571 | } | 
| 572 |  | 
| 573 | void tst_QSqlDatabase::whitespaceInIdentifiers() | 
| 574 | { | 
| 575 |     QFETCH(QString, dbName); | 
| 576 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 577 |     CHECK_DATABASE(db); | 
| 578 |     const QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db); | 
| 579 |  | 
| 580 |     if (testWhiteSpaceNames(name: db.driverName())) { | 
| 581 |         const auto tableName(qTableName(prefix: "qtest test" , __FILE__, db, escape: false)); | 
| 582 |         QVERIFY(db.tables().contains(tableName, Qt::CaseInsensitive)); | 
| 583 |  | 
| 584 |         QSqlRecord rec = db.record(tablename: tableName); | 
| 585 |         QCOMPARE(rec.count(), 1); | 
| 586 |         QCOMPARE(rec.fieldName(0), QString("test test" )); | 
| 587 |         if (dbType == QSqlDriver::Oracle) | 
| 588 |             QCOMPARE(rec.field(0).type(), QVariant::Double); | 
| 589 |         else | 
| 590 |             QCOMPARE(rec.field(0).type(), QVariant::Int); | 
| 591 |  | 
| 592 |         QSqlIndex idx = db.primaryIndex(tablename: tableName); | 
| 593 |         QCOMPARE(idx.count(), 1); | 
| 594 |         QCOMPARE(idx.fieldName(0), QString("test test" )); | 
| 595 |         if (dbType == QSqlDriver::Oracle) | 
| 596 |             QCOMPARE(idx.field(0).type(), QVariant::Double); | 
| 597 |         else | 
| 598 |             QCOMPARE(idx.field(0).type(), QVariant::Int); | 
| 599 |     } else { | 
| 600 |         QSKIP("DBMS does not support whitespaces in identifiers" ); | 
| 601 |     } | 
| 602 | } | 
| 603 |  | 
| 604 | void tst_QSqlDatabase::alterTable() | 
| 605 | { | 
| 606 |     QFETCH(QString, dbName); | 
| 607 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 608 |     CHECK_DATABASE(db); | 
| 609 |     const QString qtestalter(qTableName(prefix: "qtestalter" , __FILE__, db)); | 
| 610 |     const auto noEscapeAlterTable = qTableName(prefix: "qtestalter" , __FILE__, db, escape: false); | 
| 611 |  | 
| 612 |     QSqlQuery q(db); | 
| 613 |  | 
| 614 |     QVERIFY_SQL(q, exec("create table "  + qtestalter + " (F1 char(20), F2 char(20), F3 char(20))" )); | 
| 615 |     QSqlRecord rec = db.record(tablename: noEscapeAlterTable); | 
| 616 |     QCOMPARE((int)rec.count(), 3); | 
| 617 |  | 
| 618 |     int i; | 
| 619 |     for (i = 0; i < 3; ++i) { | 
| 620 |         QCOMPARE(rec.field(i).name().toUpper(), QString("F%1" ).arg(i + 1)); | 
| 621 |     } | 
| 622 |  | 
| 623 |     if (!q.exec(query: "alter table "  + qtestalter + " drop column F2" )) { | 
| 624 |         QSKIP("DBMS doesn't support dropping columns in ALTER TABLE statement" ); | 
| 625 |     } | 
| 626 |  | 
| 627 |     rec = db.record(tablename: noEscapeAlterTable); | 
| 628 |  | 
| 629 |     QCOMPARE((int)rec.count(), 2); | 
| 630 |  | 
| 631 |     QCOMPARE(rec.field(0).name().toUpper(), QString("F1" )); | 
| 632 |     QCOMPARE(rec.field(1).name().toUpper(), QString("F3" )); | 
| 633 |  | 
| 634 |     q.exec(query: "select * from "  + qtestalter); | 
| 635 | } | 
| 636 |  | 
| 637 | #if 0 | 
| 638 | // this is the general test that should work on all databases. | 
| 639 | // unfortunately no DBMS supports SQL 92/ 99 so the general | 
| 640 | // test is more or less a joke. Please write a test for each | 
| 641 | // database plugin (see recordOCI and so on). Use this test | 
| 642 | // as a template. | 
| 643 | void tst_QSqlDatabase::record() | 
| 644 | { | 
| 645 |     QFETCH(QString, dbName); | 
| 646 |     QSqlDatabase db = QSqlDatabase::database(dbName); | 
| 647 |     CHECK_DATABASE(db); | 
| 648 |  | 
| 649 |     static const FieldDef fieldDefs[] = { | 
| 650 |         FieldDef("char(20)" , QVariant::String,         QString("blah1" ), false), | 
| 651 |         FieldDef("varchar(20)" , QVariant::String,      QString("blah2" ), false), | 
| 652 |         FieldDef() | 
| 653 |     }; | 
| 654 |  | 
| 655 |     const int fieldCount = createFieldTable(fieldDefs, db); | 
| 656 |     QVERIFY(fieldCount > 0); | 
| 657 |  | 
| 658 |     commonFieldTest(fieldDefs, db, fieldCount); | 
| 659 | } | 
| 660 | #endif | 
| 661 |  | 
| 662 | void tst_QSqlDatabase::testRecord(const FieldDef fieldDefs[], const QSqlRecord& inf, QSqlDatabase db) | 
| 663 | { | 
| 664 |     int i = 0; | 
| 665 |     if (!tst_Databases::autoFieldName(db).isEmpty()) // Currently only MySQL is tested | 
| 666 |         QVERIFY2(inf.field(i).isAutoValue(), qPrintable(inf.field(i).name() + " should be reporting as an autovalue" )); | 
| 667 |     for (i = 0; !fieldDefs[ i ].typeName.isNull(); ++i) { | 
| 668 |         QCOMPARE(inf.field(i+1).name().toUpper(), fieldDefs[ i ].fieldName().toUpper()); | 
| 669 |         if (inf.field(i: i+1).type() != fieldDefs[ i ].type) { | 
| 670 |             QFAIL(qPrintable(QString(" Expected: '%1' Received: '%2' for field %3 in testRecord" ).arg( | 
| 671 |               QVariant::typeToName(fieldDefs[ i ].type)).arg( | 
| 672 |             QVariant::typeToName(inf.field(i+1).type())).arg( | 
| 673 |               fieldDefs[ i ].fieldName()))); | 
| 674 |         } | 
| 675 |         QVERIFY(!inf.field(i+1).isAutoValue()); | 
| 676 |  | 
| 677 | //      qDebug(QString(" field: %1 type: %2 variant type: %3").arg(fieldDefs[ i ].fieldName()).arg(QVariant::typeToName(inf.field(i+1)->type())).arg(QVariant::typeToName(inf.field(i+1)->value().type()))); | 
| 678 |     } | 
| 679 | } | 
| 680 |  | 
| 681 | // non-dbms specific tests | 
| 682 | void tst_QSqlDatabase::commonFieldTest(const FieldDef fieldDefs[], QSqlDatabase db, const int fieldCount) | 
| 683 | { | 
| 684 |     CHECK_DATABASE(db); | 
| 685 |     const QStringList tableNames = { qTableName(prefix: "qtestfields" , __FILE__, db), | 
| 686 |                                      qTableName(prefix: "qtestfields" , __FILE__, db, escape: false) }; | 
| 687 |     for (const QString table : tableNames) { | 
| 688 |         QSqlRecord rec = db.record(tablename: table); | 
| 689 |         QCOMPARE(rec.count(), fieldCount + 1); | 
| 690 |         testRecord(fieldDefs, inf: rec, db); | 
| 691 |     } | 
| 692 |     QSqlQuery q(db); | 
| 693 |     // Only check the escaped entry | 
| 694 |     QVERIFY_SQL(q, exec("select * from "  + tableNames.at(0))); | 
| 695 | } | 
| 696 |  | 
| 697 | void tst_QSqlDatabase::recordTDS() | 
| 698 | { | 
| 699 |     QFETCH(QString, dbName); | 
| 700 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 701 |     CHECK_DATABASE(db); | 
| 702 |  | 
| 703 |     static const FieldDef fieldDefs[] = { | 
| 704 |         FieldDef("tinyint" , QVariant::Int,              255), | 
| 705 |         FieldDef("smallint" , QVariant::Int,             32767), | 
| 706 |         FieldDef("int" , QVariant::Int,                  2147483647), | 
| 707 |         FieldDef("numeric(10,9)" , QVariant::Double,     1.23456789), | 
| 708 |         FieldDef("decimal(10,9)" , QVariant::Double,     1.23456789), | 
| 709 |         FieldDef("float(4)" , QVariant::Double,          1.23456789), | 
| 710 |         FieldDef("double precision" , QVariant::Double,  1.23456789), | 
| 711 |         FieldDef("real" , QVariant::Double,              1.23456789), | 
| 712 |         FieldDef("smallmoney" , QVariant::Double,        100.42), | 
| 713 |         FieldDef("money" , QVariant::Double,             200.42), | 
| 714 |         // accuracy is that of a minute | 
| 715 |         FieldDef("smalldatetime" , QVariant::DateTime,   QDateTime(QDate::currentDate(), QTime(1, 2, 0, 0))), | 
| 716 |         // accuracy is that of a second | 
| 717 |         FieldDef("datetime" , QVariant::DateTime,        QDateTime(QDate::currentDate(), QTime(1, 2, 3, 0))), | 
| 718 |         FieldDef("char(20)" , QVariant::String,          "blah1" ), | 
| 719 |         FieldDef("varchar(20)" , QVariant::String,       "blah2" ), | 
| 720 |         FieldDef("nchar(20)" , QVariant::String,         "blah3" ), | 
| 721 |         FieldDef("nvarchar(20)" , QVariant::String,      "blah4" ), | 
| 722 |         FieldDef("text" , QVariant::String,              "blah5" ), | 
| 723 |         FieldDef("bit" , QVariant::Int,                  1, false), | 
| 724 |  | 
| 725 |         FieldDef() | 
| 726 |     }; | 
| 727 |  | 
| 728 |     const int fieldCount = createFieldTable(fieldDefs, db); | 
| 729 |     QVERIFY(fieldCount > 0); | 
| 730 |  | 
| 731 |     commonFieldTest(fieldDefs, db, fieldCount); | 
| 732 | } | 
| 733 |  | 
| 734 | void tst_QSqlDatabase::recordOCI() | 
| 735 | { | 
| 736 |     bool hasTimeStamp = false; | 
| 737 |  | 
| 738 |     QFETCH(QString, dbName); | 
| 739 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 740 |     CHECK_DATABASE(db); | 
| 741 |  | 
| 742 |     // runtime check for Oracle version since V8 doesn't support TIMESTAMPs | 
| 743 |     if (tst_Databases::getOraVersion(db) >= 9) | 
| 744 |         hasTimeStamp = true; | 
| 745 |  | 
| 746 |     FieldDef tsdef; | 
| 747 |     FieldDef tstzdef; | 
| 748 |     FieldDef tsltzdef; | 
| 749 |     FieldDef intytm; | 
| 750 |     FieldDef intdts; | 
| 751 |  | 
| 752 |     static const QDateTime dt(QDate::currentDate(), QTime(1, 2, 3, 0)); | 
| 753 |  | 
| 754 |     if (hasTimeStamp) { | 
| 755 |         tsdef = FieldDef("timestamp" , QVariant::DateTime,  dt); | 
| 756 |         tstzdef = FieldDef("timestamp with time zone" , QVariant::DateTime, dt); | 
| 757 |         tsltzdef = FieldDef("timestamp with local time zone" , QVariant::DateTime, dt); | 
| 758 |         intytm = FieldDef("interval year to month" , QVariant::String, QString("+01-01" )); | 
| 759 |         intdts = FieldDef("interval day to second" , QVariant::String, QString("+01 00:00:01.000000" )); | 
| 760 |     } | 
| 761 |  | 
| 762 |     const FieldDef fieldDefs[] = { | 
| 763 |         FieldDef("char(20)" , QVariant::String,          QString("blah1" )), | 
| 764 |         FieldDef("varchar(20)" , QVariant::String,       QString("blah2" )), | 
| 765 |         FieldDef("nchar(20)" , QVariant::String,         QString("blah3" )), | 
| 766 |         FieldDef("nvarchar2(20)" , QVariant::String,     QString("blah4" )), | 
| 767 |         FieldDef("number(10,5)" , QVariant::Double,      1.1234567), | 
| 768 |         FieldDef("date" , QVariant::DateTime,            dt), | 
| 769 |         FieldDef("long raw" , QVariant::ByteArray,       QByteArray("blah5" )), | 
| 770 |         FieldDef("raw(2000)" , QVariant::ByteArray,      QByteArray("blah6" ), false), | 
| 771 |         FieldDef("blob" , QVariant::ByteArray,           QByteArray("blah7" )), | 
| 772 |         FieldDef("clob" , QVariant::ByteArray, QByteArray("blah8" )), | 
| 773 |         FieldDef("nclob" , QVariant::ByteArray, QByteArray("blah9" )), | 
| 774 | //        FieldDef("bfile", QVariant::ByteArray,         QByteArray("blah10")), | 
| 775 |  | 
| 776 |         intytm, | 
| 777 |         intdts, | 
| 778 |         tsdef, | 
| 779 |         tstzdef, | 
| 780 |         tsltzdef, | 
| 781 |         FieldDef() | 
| 782 |     }; | 
| 783 |  | 
| 784 |     const int fieldCount = createFieldTable(fieldDefs, db); | 
| 785 |     QVERIFY(fieldCount > 0); | 
| 786 |  | 
| 787 |     commonFieldTest(fieldDefs, db, fieldCount); | 
| 788 |  | 
| 789 |     // some additional tests | 
| 790 |     const QString tableName = qTableName(prefix: "qtestfields" , __FILE__, db); | 
| 791 |     QSqlRecord rec = db.record(tablename: tableName); | 
| 792 |     QCOMPARE(rec.field("T_NUMBER" ).length(), 10); | 
| 793 |     QCOMPARE(rec.field("T_NUMBER" ).precision(), 5); | 
| 794 |  | 
| 795 |     QSqlQuery q(db); | 
| 796 |     QVERIFY_SQL(q, exec("SELECT * FROM "  + tableName)); | 
| 797 |     rec = q.record(); | 
| 798 |     QCOMPARE(rec.field("T_NUMBER" ).length(), 10); | 
| 799 |     QCOMPARE(rec.field("T_NUMBER" ).precision(), 5); | 
| 800 | } | 
| 801 |  | 
| 802 | void tst_QSqlDatabase::recordPSQL() | 
| 803 | { | 
| 804 |     QFETCH(QString, dbName); | 
| 805 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 806 |     CHECK_DATABASE(db); | 
| 807 |  | 
| 808 |     FieldDef byteadef; | 
| 809 |     if (db.driver()->hasFeature(f: QSqlDriver::BLOB)) | 
| 810 |         byteadef = FieldDef("bytea" , QVariant::ByteArray, QByteArray("bl\\ah" )); | 
| 811 |     static FieldDef fieldDefs[] = { | 
| 812 |         FieldDef("bigint" , QVariant::LongLong,       Q_INT64_C(9223372036854775807)), | 
| 813 |         FieldDef("bigserial" , QVariant::LongLong,    100, false), | 
| 814 |         FieldDef("bit" , QVariant::String,            "1" ), // a bit in postgres is a bit-string | 
| 815 |         FieldDef("box" , QVariant::String,            "(5,6),(1,2)" ), | 
| 816 |         FieldDef("char(20)" , QVariant::String,       "blah5678901234567890" ), | 
| 817 |         FieldDef("varchar(20)" , QVariant::String,    "blah5678901234567890" ), | 
| 818 |         FieldDef("cidr" , QVariant::String,           "12.123.0.0/24" ), | 
| 819 |         FieldDef("circle" , QVariant::String,         "<(1,2),3>" ), | 
| 820 |         FieldDef("date" , QVariant::Date,             QDate::currentDate()), | 
| 821 |         FieldDef("float8" , QVariant::Double,         1.12345678912), | 
| 822 |         FieldDef("inet" , QVariant::String,           "12.123.12.23" ), | 
| 823 |         FieldDef("integer" , QVariant::Int,           2147483647), | 
| 824 |         FieldDef("interval" , QVariant::String,       "1 day 12:59:10" ), | 
| 825 | //      LOL... you can create a "line" datatype in PostgreSQL <= 7.2.x but | 
| 826 | //      as soon as you want to insert data you get a "not implemented yet" error | 
| 827 | //      FieldDef("line", QVariant::Polygon, QPolygon(QRect(1, 2, 3, 4))), | 
| 828 |         FieldDef("lseg" , QVariant::String,           "[(1,1),(2,2)]" ), | 
| 829 |         FieldDef("macaddr" , QVariant::String,        "08:00:2b:01:02:03" ), | 
| 830 |         FieldDef("money" , QVariant::String,          "$12.23" ), | 
| 831 |         FieldDef("numeric" , QVariant::Double,        1.2345678912), | 
| 832 |         FieldDef("path" , QVariant::String,           "((1,2),(3,2),(3,5),(1,5))" ), | 
| 833 |         FieldDef("point" , QVariant::String,          "(1,2)" ), | 
| 834 |         FieldDef("polygon" , QVariant::String,        "((1,2),(3,2),(3,5),(1,5))" ), | 
| 835 |         FieldDef("real" , QVariant::Double,           1.1234), | 
| 836 |         FieldDef("smallint" , QVariant::Int,          32767), | 
| 837 |         FieldDef("serial" , QVariant::Int,            100, false), | 
| 838 |         FieldDef("text" , QVariant::String,           "blah" ), | 
| 839 |         FieldDef("time(6)" , QVariant::Time,          QTime(1, 2, 3)), | 
| 840 |         FieldDef("timetz" , QVariant::Time,           QTime(1, 2, 3)), | 
| 841 |         FieldDef("timestamp(6)" , QVariant::DateTime, QDateTime::currentDateTime()), | 
| 842 |         FieldDef("timestamptz" , QVariant::DateTime,  QDateTime::currentDateTime()), | 
| 843 |         byteadef, | 
| 844 |  | 
| 845 |         FieldDef() | 
| 846 |     }; | 
| 847 |  | 
| 848 |     QSqlQuery q(db); | 
| 849 |  | 
| 850 |     QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db); | 
| 851 |     if (dbType == QSqlDriver::PostgreSQL) | 
| 852 |         QVERIFY_SQL( q, exec("set client_min_messages='warning'" )); | 
| 853 |     q.exec(query: "drop sequence "  + qTableName(prefix: "qtestfields_t_bigserial_seq" , __FILE__, db)); | 
| 854 |     q.exec(query: "drop sequence "  + qTableName(prefix: "qtestfields_t_serial_seq" , __FILE__, db)); | 
| 855 |  | 
| 856 |     const int fieldCount = createFieldTable(fieldDefs, db); | 
| 857 |     QVERIFY(fieldCount > 0); | 
| 858 |  | 
| 859 |     commonFieldTest(fieldDefs, db, fieldCount); | 
| 860 |     for (int i = 0; i < ITERATION_COUNT; ++i) { | 
| 861 |         // increase serial values | 
| 862 |         for (int i2 = 0; !fieldDefs[ i2 ].typeName.isNull(); ++i2) { | 
| 863 |             if (fieldDefs[ i2 ].typeName == "serial"  || | 
| 864 |                 fieldDefs[ i2 ].typeName == "bigserial" ) { | 
| 865 |  | 
| 866 |                 FieldDef def = fieldDefs[ i2 ]; | 
| 867 |                 def.val = def.val.toInt() + 1; | 
| 868 |                 fieldDefs[ i2 ] = def; | 
| 869 |             } | 
| 870 |         } | 
| 871 |     } | 
| 872 | } | 
| 873 |  | 
| 874 | void tst_QSqlDatabase::recordMySQL() | 
| 875 | { | 
| 876 |     QFETCH(QString, dbName); | 
| 877 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 878 |     CHECK_DATABASE(db); | 
| 879 |  | 
| 880 |     FieldDef bin10, varbin10; | 
| 881 |     int major = tst_Databases::getMySqlVersion( db ).section( asep: QChar('.'), astart: 0, aend: 0 ).toInt(); | 
| 882 |     int minor = tst_Databases::getMySqlVersion( db ).section( asep: QChar('.'), astart: 1, aend: 1 ).toInt(); | 
| 883 |     int revision = tst_Databases::getMySqlVersion( db ).section( asep: QChar('.'), astart: 2, aend: 2 ).toInt(); | 
| 884 |     int vernum = (major << 16) + (minor << 8) + revision; | 
| 885 |  | 
| 886 |     /* The below is broken in mysql below 5.0.15 | 
| 887 |         see http://dev.mysql.com/doc/refman/5.0/en/binary-varbinary.html | 
| 888 |         specifically: Before MySQL 5.0.15, the pad value is space. Values are right-padded | 
| 889 |         with space on insert, and trailing spaces are removed on select. | 
| 890 |     */ | 
| 891 |     if( vernum >= ((5 << 16) + 15) ) { | 
| 892 |         bin10 = FieldDef("binary(10)" , QVariant::ByteArray, QString("123abc    " )); | 
| 893 |         varbin10 = FieldDef("varbinary(10)" , QVariant::ByteArray, QString("123abcv   " )); | 
| 894 |     } | 
| 895 |  | 
| 896 |     static QDateTime dt(QDate::currentDate(), QTime(1, 2, 3, 0)); | 
| 897 |     static const FieldDef fieldDefs[] = { | 
| 898 |         FieldDef("tinyint" , static_cast<QVariant::Type>(QMetaType::Char), 127), | 
| 899 |         FieldDef("tinyint unsigned" , static_cast<QVariant::Type>(QMetaType::UChar), 255), | 
| 900 |         FieldDef("smallint" , static_cast<QVariant::Type>(QMetaType::Short), 32767), | 
| 901 |         FieldDef("smallint unsigned" , static_cast<QVariant::Type>(QMetaType::UShort), 65535), | 
| 902 |         FieldDef("mediumint" , QVariant::Int,             8388607), | 
| 903 |         FieldDef("mediumint unsigned" , QVariant::UInt,   16777215), | 
| 904 |         FieldDef("integer" , QVariant::Int,               2147483647), | 
| 905 |         FieldDef("integer unsigned" , QVariant::UInt,     4294967295u), | 
| 906 |         FieldDef("bigint" , QVariant::LongLong,           Q_INT64_C(9223372036854775807)), | 
| 907 |         FieldDef("bigint unsigned" , QVariant::ULongLong, Q_UINT64_C(18446744073709551615)), | 
| 908 |         FieldDef("float" , QVariant::Double,              1.12345), | 
| 909 |         FieldDef("double" , QVariant::Double,             1.123456789), | 
| 910 |         FieldDef("decimal(10, 9)" , QVariant::Double,     1.123456789), | 
| 911 |         FieldDef("numeric(5, 2)" , QVariant::Double,      123.67), | 
| 912 |         FieldDef("date" , QVariant::Date,                 QDate::currentDate()), | 
| 913 |         FieldDef("datetime" , QVariant::DateTime,         dt), | 
| 914 |         FieldDef("timestamp" , QVariant::DateTime,        dt, false), | 
| 915 |         FieldDef("time" , QVariant::String,               dt.time()), | 
| 916 |         FieldDef("year" , QVariant::Int,                  2003), | 
| 917 |         FieldDef("char(20)" , QVariant::String,           "Blah" ), | 
| 918 |         FieldDef("varchar(20)" , QVariant::String,        "BlahBlah" ), | 
| 919 |         FieldDef("tinytext" , QVariant::String,           QString("blah5" )), | 
| 920 |         FieldDef("text" , QVariant::String,               QString("blah6" )), | 
| 921 |         FieldDef("mediumtext" , QVariant::String,         QString("blah7" )), | 
| 922 |         FieldDef("longtext" , QVariant::String,           QString("blah8" )), | 
| 923 |         // SET OF? | 
| 924 |  | 
| 925 |         FieldDef() | 
| 926 |     }; | 
| 927 |  | 
| 928 |     const int fieldCount = createFieldTable(fieldDefs, db); | 
| 929 |     QVERIFY(fieldCount > 0); | 
| 930 |  | 
| 931 |     commonFieldTest(fieldDefs, db, fieldCount); | 
| 932 |  | 
| 933 |     QSqlQuery q(db); | 
| 934 |     QVERIFY_SQL(q, exec("SELECT DATE_SUB(CURDATE(), INTERVAL 2 DAY)" )); | 
| 935 |     QVERIFY(q.next()); | 
| 936 |     QCOMPARE(q.value(0).toDateTime().date(), QDate::currentDate().addDays(-2)); | 
| 937 | } | 
| 938 |  | 
| 939 | void tst_QSqlDatabase::recordDB2() | 
| 940 | { | 
| 941 |     QFETCH(QString, dbName); | 
| 942 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 943 |     CHECK_DATABASE(db); | 
| 944 |  | 
| 945 |     static const FieldDef fieldDefs[] = { | 
| 946 |         FieldDef("char(20)" , QVariant::String,         QString("Blah1" )), | 
| 947 |         FieldDef("varchar(20)" , QVariant::String,      QString("Blah2" )), | 
| 948 |         FieldDef("long varchar" , QVariant::String,     QString("Blah3" )), | 
| 949 |         // using BOOLEAN results in "SQL0486N  The BOOLEAN data type is currently only supported internally." | 
| 950 | //X     FieldDef("boolean" , QVariant::Bool,           QVariant(true, 1)), | 
| 951 |         FieldDef("smallint" , QVariant::Int,            32767), | 
| 952 |         FieldDef("integer" , QVariant::Int,             2147483647), | 
| 953 |         FieldDef("bigint" , QVariant::LongLong,         Q_INT64_C(9223372036854775807)), | 
| 954 |         FieldDef("real" , QVariant::Double,             1.12345), | 
| 955 |         FieldDef("double" , QVariant::Double,           1.23456789), | 
| 956 |         FieldDef("float" , QVariant::Double,            1.23456789), | 
| 957 |         FieldDef("decimal(10,9)" , QVariant::Double,    1.234567891), | 
| 958 |         FieldDef("numeric(10,9)" , QVariant::Double,    1.234567891), | 
| 959 |         FieldDef("date" , QVariant::Date,               QDate::currentDate()), | 
| 960 |         FieldDef("time" , QVariant::Time,               QTime(1, 2, 3)), | 
| 961 |         FieldDef("timestamp" , QVariant::DateTime,      QDateTime::currentDateTime()), | 
| 962 | //         FieldDef("graphic(20)", QVariant::String,       QString("Blah4")), | 
| 963 | //         FieldDef("vargraphic(20)", QVariant::String,    QString("Blah5")), | 
| 964 | //         FieldDef("long vargraphic", QVariant::String,   QString("Blah6")), | 
| 965 |         //X FieldDef("datalink", QVariant::String,          QString("DLVALUE('Blah10')")), | 
| 966 |         FieldDef() | 
| 967 |     }; | 
| 968 |  | 
| 969 |     const int fieldCount = createFieldTable(fieldDefs, db); | 
| 970 |     QVERIFY(fieldCount > 0); | 
| 971 |  | 
| 972 |     commonFieldTest(fieldDefs, db, fieldCount); | 
| 973 | } | 
| 974 |  | 
| 975 | void tst_QSqlDatabase::recordIBase() | 
| 976 | { | 
| 977 |     QFETCH(QString, dbName); | 
| 978 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 979 |     CHECK_DATABASE(db); | 
| 980 |  | 
| 981 |     static const FieldDef fieldDefs[] = { | 
| 982 |         FieldDef("char(20)" , QVariant::String, QString("Blah1" ), false), | 
| 983 |         FieldDef("varchar(20)" , QVariant::String, QString("Blah2" )), | 
| 984 |         FieldDef("smallint" , QVariant::Int, 32767), | 
| 985 |         FieldDef("float" , QVariant::Double, 1.2345), | 
| 986 |         FieldDef("double precision" , QVariant::Double, 1.2345678), | 
| 987 |         FieldDef("timestamp" , QVariant::DateTime, QDateTime::currentDateTime()), | 
| 988 |         FieldDef("time" , QVariant::Time, QTime::currentTime()), | 
| 989 |         FieldDef("decimal(18)" , QVariant::LongLong, Q_INT64_C(9223372036854775807)), | 
| 990 |         FieldDef("numeric(5,2)" , QVariant::Double, 123.45), | 
| 991 |  | 
| 992 |         FieldDef() | 
| 993 |     }; | 
| 994 |  | 
| 995 |     const int fieldCount = createFieldTable(fieldDefs, db); | 
| 996 |     QVERIFY(fieldCount > 0); | 
| 997 |  | 
| 998 |     commonFieldTest(fieldDefs, db, fieldCount); | 
| 999 | } | 
| 1000 |  | 
| 1001 | void tst_QSqlDatabase::recordSQLite() | 
| 1002 | { | 
| 1003 |     QFETCH(QString, dbName); | 
| 1004 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 1005 |     CHECK_DATABASE(db); | 
| 1006 |  | 
| 1007 |     static const FieldDef fieldDefs[] = { | 
| 1008 |         // The affinity of these fields are TEXT so SQLite should give us strings, not ints or doubles. | 
| 1009 |         FieldDef("char(20)" , QVariant::String,          QString("123" )), | 
| 1010 |         FieldDef("varchar(20)" , QVariant::String,       QString("123.4" )), | 
| 1011 |         FieldDef("clob" , QVariant::String,              QString("123.45" )), | 
| 1012 |         FieldDef("text" , QVariant::String,              QString("123.456" )), | 
| 1013 |  | 
| 1014 |         FieldDef("integer" , QVariant::Int,              QVariant(13)), | 
| 1015 |         FieldDef("int" , QVariant::Int,                  QVariant(12)), | 
| 1016 |         FieldDef("real" , QVariant::Double,              QVariant(1.234567890123456)), | 
| 1017 |  | 
| 1018 |         FieldDef() | 
| 1019 |     }; | 
| 1020 |  | 
| 1021 |     const int fieldCount = createFieldTable(fieldDefs, db); | 
| 1022 |     QVERIFY(fieldCount > 0); | 
| 1023 |  | 
| 1024 |     commonFieldTest(fieldDefs, db, fieldCount); | 
| 1025 | } | 
| 1026 |  | 
| 1027 | void tst_QSqlDatabase::recordSQLServer() | 
| 1028 | { | 
| 1029 |     QFETCH(QString, dbName); | 
| 1030 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 1031 |     CHECK_DATABASE(db); | 
| 1032 |  | 
| 1033 |     QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db); | 
| 1034 |     if (dbType != QSqlDriver::MSSqlServer) | 
| 1035 |         QSKIP("SQL server specific test" ); | 
| 1036 |  | 
| 1037 |     // ### TODO: Add the rest of the fields | 
| 1038 |     static const FieldDef fieldDefs[] = { | 
| 1039 |         FieldDef("varchar(20)" , QVariant::String, QString("Blah1" )), | 
| 1040 |         FieldDef("bigint" , QVariant::LongLong, 12345), | 
| 1041 |         FieldDef("int" , QVariant::Int, 123456), | 
| 1042 |         FieldDef("tinyint" , QVariant::UInt, 255), | 
| 1043 |         FieldDef("float" , QVariant::Double, 1.12345), | 
| 1044 |         FieldDef("numeric(5,2)" , QVariant::Double, 123.45), | 
| 1045 |         FieldDef("uniqueidentifier" , QVariant::String, | 
| 1046 |             QString("AA7DF450-F119-11CD-8465-00AA00425D90" )), | 
| 1047 |  | 
| 1048 |         FieldDef() | 
| 1049 |     }; | 
| 1050 |  | 
| 1051 |     const int fieldCount = createFieldTable(fieldDefs, db); | 
| 1052 |     QVERIFY(fieldCount > 0); | 
| 1053 |  | 
| 1054 |     commonFieldTest(fieldDefs, db, fieldCount); | 
| 1055 | } | 
| 1056 |  | 
| 1057 | void tst_QSqlDatabase::recordAccess() | 
| 1058 | { | 
| 1059 |     QFETCH(QString, dbName); | 
| 1060 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 1061 |     CHECK_DATABASE(db); | 
| 1062 |  | 
| 1063 |     if (!tst_Databases::isMSAccess(db)) | 
| 1064 |         QSKIP("MS Access specific test" ); | 
| 1065 |  | 
| 1066 |     QString memo; | 
| 1067 |     for (int i = 0; i < 32; i++) | 
| 1068 |         memo.append(s: "ABCDEFGH12345678abcdefgh12345678" ); | 
| 1069 |  | 
| 1070 |     // ### TODO: Add the rest of the fields | 
| 1071 |     static const FieldDef fieldDefs[] = { | 
| 1072 |     FieldDef("varchar(20)" , QVariant::String, QString("Blah1" )), | 
| 1073 |     FieldDef("single" , QVariant::Double, 1.12345), | 
| 1074 |     FieldDef("double" , QVariant::Double, 1.123456), | 
| 1075 |     FieldDef("byte" , QVariant::UInt, 255), | 
| 1076 |     FieldDef("long" , QVariant::Int, 2147483647), | 
| 1077 |         FieldDef("memo" , QVariant::String, memo), | 
| 1078 |     FieldDef() | 
| 1079 |     }; | 
| 1080 |  | 
| 1081 |     const int fieldCount = createFieldTable(fieldDefs, db); | 
| 1082 |     QVERIFY(fieldCount > 0); | 
| 1083 |  | 
| 1084 |     commonFieldTest(fieldDefs, db, fieldCount); | 
| 1085 | } | 
| 1086 |  | 
| 1087 | void tst_QSqlDatabase::transaction() | 
| 1088 | { | 
| 1089 |     QFETCH(QString, dbName); | 
| 1090 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 1091 |     CHECK_DATABASE(db); | 
| 1092 |     const QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db); | 
| 1093 |     const QString qtest(qTableName(prefix: "qtest" , __FILE__, db)); | 
| 1094 |  | 
| 1095 |     if (!db.driver()->hasFeature(f: QSqlDriver::Transactions)) | 
| 1096 |         QSKIP("DBMS not transaction capable" ); | 
| 1097 |  | 
| 1098 |     QVERIFY(db.transaction()); | 
| 1099 |  | 
| 1100 |     QSqlQuery q(db); | 
| 1101 |     QVERIFY_SQL(q, exec("insert into "  + qtest + " values (40, 'VarChar40', 'Char40', 40.40)" )); | 
| 1102 |     QVERIFY_SQL(q, exec("select * from "  + qtest + " where id = 40" )); | 
| 1103 |     QVERIFY(q.next()); | 
| 1104 |     QCOMPARE(q.value(0).toInt(), 40); | 
| 1105 |     q.clear(); | 
| 1106 |  | 
| 1107 |     QVERIFY(db.commit()); | 
| 1108 |  | 
| 1109 |     QVERIFY(db.transaction()); | 
| 1110 |     QVERIFY_SQL(q, exec("select * from "  + qtest + " where id = 40" )); | 
| 1111 |     QVERIFY(q.next()); | 
| 1112 |     QCOMPARE(q.value(0).toInt(), 40); | 
| 1113 |     q.clear(); | 
| 1114 |     QVERIFY(db.commit()); | 
| 1115 |  | 
| 1116 |     QVERIFY(db.transaction()); | 
| 1117 |     QVERIFY_SQL(q, exec("insert into "  + qtest + " values (41, 'VarChar41', 'Char41', 41.41)" )); | 
| 1118 |     QVERIFY_SQL(q, exec("select * from "  + qtest + " where id = 41" )); | 
| 1119 |     QVERIFY(q.next()); | 
| 1120 |     QCOMPARE(q.value(0).toInt(), 41); | 
| 1121 |     q.clear(); // for SQLite which does not allow any references on rows that shall be rolled back | 
| 1122 |     if (!db.rollback()) { | 
| 1123 |         if (dbType == QSqlDriver::MySqlServer) | 
| 1124 |             QSKIP("MySQL transaction failed: "  + tst_Databases::printError(db.lastError())); | 
| 1125 |         else | 
| 1126 |             QFAIL("Could not rollback transaction: "  + tst_Databases::printError(db.lastError())); | 
| 1127 |     } | 
| 1128 |  | 
| 1129 |     QVERIFY_SQL(q, exec("select * from "  + qtest + " where id = 41" )); | 
| 1130 |     QVERIFY(!q.next()); | 
| 1131 |  | 
| 1132 |     populateTestTables(db); | 
| 1133 | } | 
| 1134 |  | 
| 1135 | void tst_QSqlDatabase::bigIntField() | 
| 1136 | { | 
| 1137 |     QFETCH(QString, dbName); | 
| 1138 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 1139 |     CHECK_DATABASE(db); | 
| 1140 |     const QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db); | 
| 1141 |     const QString qtest_bigint(qTableName(prefix: "qtest_bigint" , __FILE__, db)); | 
| 1142 |  | 
| 1143 |     QSqlQuery q(db); | 
| 1144 |     q.setForwardOnly(true); | 
| 1145 |  | 
| 1146 |     if (dbType == QSqlDriver::Oracle) | 
| 1147 |         q.setNumericalPrecisionPolicy(QSql::LowPrecisionInt64); | 
| 1148 |  | 
| 1149 |     if (dbType == QSqlDriver::MySqlServer) { | 
| 1150 |         QVERIFY_SQL(q, exec("create table "  + qtest_bigint + " (id int, t_s64bit bigint, t_u64bit bigint unsigned)" )); | 
| 1151 |     } else if (dbType == QSqlDriver::PostgreSQL | 
| 1152 |                 || dbType == QSqlDriver::DB2 | 
| 1153 |                 || dbType == QSqlDriver::MSSqlServer) { | 
| 1154 |         QVERIFY_SQL(q, exec("create table "  + qtest_bigint + "(id int, t_s64bit bigint, t_u64bit bigint)" )); | 
| 1155 |     } else if (dbType == QSqlDriver::Oracle) { | 
| 1156 |         QVERIFY_SQL(q, exec("create table "  + qtest_bigint + " (id int, t_s64bit int, t_u64bit int)" )); | 
| 1157 |     //} else if (dbType == QSqlDriver::Interbase) { | 
| 1158 |     //    QVERIFY_SQL(q, exec("create table " + qtest_bigint + " (id int, t_s64bit int64, t_u64bit int64)")); | 
| 1159 |     } else { | 
| 1160 |         QSKIP("no 64 bit integer support" ); | 
| 1161 |     } | 
| 1162 |     QVERIFY(q.prepare("insert into "  + qtest_bigint + " values (?, ?, ?)" )); | 
| 1163 |     qlonglong ll = Q_INT64_C(9223372036854775807); | 
| 1164 |     qulonglong ull = Q_UINT64_C(18446744073709551615); | 
| 1165 |  | 
| 1166 |     if (dbType == QSqlDriver::MySqlServer || dbType == QSqlDriver::Oracle) { | 
| 1167 |         q.bindValue(pos: 0, val: 0); | 
| 1168 |         q.bindValue(pos: 1, val: ll); | 
| 1169 |         q.bindValue(pos: 2, val: ull); | 
| 1170 |         QVERIFY_SQL(q, exec()); | 
| 1171 |         q.bindValue(pos: 0, val: 1); | 
| 1172 |         q.bindValue(pos: 1, val: -ll); | 
| 1173 |         q.bindValue(pos: 2, val: ull); | 
| 1174 |         QVERIFY_SQL(q, exec()); | 
| 1175 |     } else { | 
| 1176 |         // usinged bigint fields not supported - a cast is necessary | 
| 1177 |         q.bindValue(pos: 0, val: 0); | 
| 1178 |         q.bindValue(pos: 1, val: ll); | 
| 1179 |         q.bindValue(pos: 2, val: (qlonglong) ull); | 
| 1180 |         QVERIFY_SQL(q, exec()); | 
| 1181 |         q.bindValue(pos: 0, val: 1); | 
| 1182 |         q.bindValue(pos: 1, val: -ll); | 
| 1183 |         q.bindValue(pos: 2,  val: (qlonglong) ull); | 
| 1184 |         QVERIFY_SQL(q, exec()); | 
| 1185 |     } | 
| 1186 |     QVERIFY(q.exec("select * from "  + qtest_bigint + " order by id" )); | 
| 1187 |     QVERIFY(q.next()); | 
| 1188 |     QCOMPARE(q.value(1).toDouble(), (double)ll); | 
| 1189 |     QCOMPARE(q.value(1).toLongLong(), ll); | 
| 1190 |     if (dbType == QSqlDriver::Oracle) | 
| 1191 |         QEXPECT_FAIL("" , "Oracle driver lacks support for unsigned int64 types" , Continue); | 
| 1192 |     QCOMPARE(q.value(2).toULongLong(), ull); | 
| 1193 |     QVERIFY(q.next()); | 
| 1194 |     QCOMPARE(q.value(1).toLongLong(), -ll); | 
| 1195 |     if (dbType == QSqlDriver::Oracle) | 
| 1196 |         QEXPECT_FAIL("" , "Oracle driver lacks support for unsigned int64 types" , Continue); | 
| 1197 |     QCOMPARE(q.value(2).toULongLong(), ull); | 
| 1198 | } | 
| 1199 |  | 
| 1200 | void tst_QSqlDatabase::caseSensivity() | 
| 1201 | { | 
| 1202 |     QFETCH(QString, dbName); | 
| 1203 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 1204 |     CHECK_DATABASE(db); | 
| 1205 |     const QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db); | 
| 1206 |  | 
| 1207 |     bool cs = false; | 
| 1208 |     if (dbType == QSqlDriver::MySqlServer || dbType == QSqlDriver::SQLite | 
| 1209 |         || dbType == QSqlDriver::Sybase || dbType == QSqlDriver::PostgreSQL | 
| 1210 |         || dbType == QSqlDriver::MSSqlServer || db.driverName().startsWith(s: "QODBC" )) | 
| 1211 |     cs = true; | 
| 1212 |  | 
| 1213 |     QSqlRecord rec = db.record(tablename: qTableName(prefix: "qtest" , __FILE__, db, escape: false)); | 
| 1214 |     QVERIFY((int)rec.count() > 0); | 
| 1215 |     if (!cs) { | 
| 1216 |     rec = db.record(tablename: qTableName(prefix: "QTEST" , __FILE__, db, escape: false).toUpper()); | 
| 1217 |     QVERIFY((int)rec.count() > 0); | 
| 1218 |     rec = db.record(tablename: qTableName(prefix: "qTesT" , __FILE__, db, escape: false)); | 
| 1219 |     QVERIFY((int)rec.count() > 0); | 
| 1220 |     } | 
| 1221 |  | 
| 1222 |     rec = db.primaryIndex(tablename: qTableName(prefix: "qtest" , __FILE__, db, escape: false)); | 
| 1223 |     QVERIFY((int)rec.count() > 0); | 
| 1224 |     if (!cs) { | 
| 1225 |     rec = db.primaryIndex(tablename: qTableName(prefix: "QTEST" , __FILE__, db, escape: false).toUpper()); | 
| 1226 |     QVERIFY((int)rec.count() > 0); | 
| 1227 |     rec = db.primaryIndex(tablename: qTableName(prefix: "qTesT" , __FILE__, db, escape: false)); | 
| 1228 |     QVERIFY((int)rec.count() > 0); | 
| 1229 |     } | 
| 1230 |  | 
| 1231 |     // Explicit test for case sensitive table creation without quoting | 
| 1232 |     QSqlQuery qry(db); | 
| 1233 |     const auto noQuotesTable = qTableName(prefix: "NoQuotes" , __FILE__, db, escape: false); | 
| 1234 |     tst_Databases::safeDropTable(db, tableName: noQuotesTable); | 
| 1235 |     QVERIFY_SQL(qry, exec("CREATE TABLE "  + noQuotesTable + " (id INTEGER)" )); | 
| 1236 |     QVERIFY_SQL(qry, exec("INSERT INTO "  + noQuotesTable + " VALUES(1)" )); | 
| 1237 |     QVERIFY_SQL(qry, exec("SELECT * FROM "  + noQuotesTable)); | 
| 1238 |     QVERIFY_SQL(qry, next()); | 
| 1239 |     QCOMPARE(qry.value(0).toInt(), 1); | 
| 1240 |     rec = db.record(tablename: cs ? noQuotesTable.toLower() : noQuotesTable); | 
| 1241 |     QVERIFY(rec.count() > 0); | 
| 1242 | } | 
| 1243 |  | 
| 1244 | void tst_QSqlDatabase::noEscapedFieldNamesInRecord() | 
| 1245 | { | 
| 1246 |     QFETCH(QString, dbName); | 
| 1247 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 1248 |     CHECK_DATABASE(db); | 
| 1249 |  | 
| 1250 |     QString fieldname("t_varchar" ); | 
| 1251 |     QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db); | 
| 1252 |     if (dbType == QSqlDriver::Oracle || dbType == QSqlDriver::Interbase || dbType == QSqlDriver::DB2) | 
| 1253 |         fieldname = fieldname.toUpper(); | 
| 1254 |  | 
| 1255 |     QSqlQuery q(db); | 
| 1256 |     QString query = "SELECT "  + db.driver()->escapeIdentifier(identifier: fieldname, type: QSqlDriver::FieldName) + " FROM "  + qTableName(prefix: "qtest" , __FILE__, db); | 
| 1257 |     QVERIFY_SQL(q, exec(query)); | 
| 1258 |     QCOMPARE(q.record().fieldName(0), fieldname); | 
| 1259 | } | 
| 1260 |  | 
| 1261 | void tst_QSqlDatabase::psql_schemas() | 
| 1262 | { | 
| 1263 |     QFETCH(QString, dbName); | 
| 1264 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 1265 |     CHECK_DATABASE(db); | 
| 1266 |  | 
| 1267 |     if (!db.tables(type: QSql::SystemTables).contains(str: "pg_namespace" )) | 
| 1268 |         QSKIP("server does not support schemas" ); | 
| 1269 |  | 
| 1270 |     QSqlQuery q(db); | 
| 1271 |     QVERIFY_SQL( q, exec("set client_min_messages='warning'" )); | 
| 1272 |  | 
| 1273 |     const QString schemaName = qTableName(prefix: "qtestschema" , __FILE__, db); | 
| 1274 |     QVERIFY_SQL(q, exec("CREATE SCHEMA "  + schemaName)); | 
| 1275 |  | 
| 1276 |     const auto table = schemaName + '.' + qTableName(prefix: "qtesttable" , __FILE__, db); | 
| 1277 |     const auto noescapeTable = qTableName(prefix: "qtestschema" , __FILE__, db, escape: false) + '.' + | 
| 1278 |                                qTableName(prefix: "qtesttable" , __FILE__, db, escape: false); | 
| 1279 |     QVERIFY_SQL(q, exec("CREATE TABLE "  + table + " (id int primary key, name varchar(20))" )); | 
| 1280 |  | 
| 1281 |     QVERIFY(db.tables().contains(noescapeTable, Qt::CaseInsensitive)); | 
| 1282 |  | 
| 1283 |     QSqlRecord rec = db.record(tablename: noescapeTable); | 
| 1284 |     QCOMPARE(rec.count(), 2); | 
| 1285 |     QCOMPARE(rec.fieldName(0), QString("id" )); | 
| 1286 |     QCOMPARE(rec.fieldName(1), QString("name" )); | 
| 1287 |  | 
| 1288 |     QSqlIndex idx = db.primaryIndex(tablename: noescapeTable); | 
| 1289 |     QCOMPARE(idx.count(), 1); | 
| 1290 |     QCOMPARE(idx.fieldName(0), QString("id" )); | 
| 1291 | } | 
| 1292 |  | 
| 1293 | void tst_QSqlDatabase::psql_escapedIdentifiers() | 
| 1294 | { | 
| 1295 |     QFETCH(QString, dbName); | 
| 1296 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 1297 |     QSqlDriver* drv = db.driver(); | 
| 1298 |     CHECK_DATABASE(db); | 
| 1299 |  | 
| 1300 |     if (!db.tables(type: QSql::SystemTables).contains(str: "pg_namespace" )) | 
| 1301 |         QSKIP("server does not support schemas" ); | 
| 1302 |  | 
| 1303 |     QSqlQuery q(db); | 
| 1304 |     QVERIFY_SQL( q, exec("set client_min_messages='warning'" )); | 
| 1305 |  | 
| 1306 |     const char bumpyCase[] = "qtestScHeMa" ; | 
| 1307 |     const QString schemaName(qTableName(prefix: bumpyCase, __FILE__, db)), | 
| 1308 |                   tableName(qTableName(prefix: "qtest" , __FILE__, db)), | 
| 1309 |                   field1Name(QLatin1String("fIeLdNaMe" )), | 
| 1310 |                   field2Name(QLatin1String("ZuLu" )); | 
| 1311 |  | 
| 1312 |     q.exec(query: QString("DROP SCHEMA %1 CASCADE" ).arg(a: schemaName)); | 
| 1313 |     const auto createSchema = QString("CREATE SCHEMA %1" ).arg(a: schemaName); | 
| 1314 |     QVERIFY_SQL(q, exec(createSchema)); | 
| 1315 |     const auto createTable = QString("CREATE TABLE %1.%2 (\"%3\" int PRIMARY KEY, \"%4\" varchar(20))" ) | 
| 1316 |                                 .arg(a1: schemaName, a2: tableName, a3: field1Name, a4: field2Name); | 
| 1317 |     QVERIFY_SQL(q, exec(createTable)); | 
| 1318 |  | 
| 1319 |     QVERIFY(db.tables().contains(qTableName(bumpyCase, __FILE__, db, false) + '.' + | 
| 1320 |                                  qTableName("qtest" , __FILE__, db, false), Qt::CaseSensitive)); | 
| 1321 |  | 
| 1322 |     QSqlField fld1(field1Name, QVariant::Int); | 
| 1323 |     QSqlField fld2(field2Name, QVariant::String); | 
| 1324 |     QSqlRecord rec; | 
| 1325 |     rec.append(field: fld1); | 
| 1326 |     rec.append(field: fld2); | 
| 1327 |  | 
| 1328 |     QVERIFY_SQL(q, exec(drv->sqlStatement(QSqlDriver::SelectStatement, | 
| 1329 |                                           schemaName + '.' + tableName, | 
| 1330 |                                           rec, false))); | 
| 1331 |  | 
| 1332 |     rec = q.record(); | 
| 1333 |     QCOMPARE(rec.count(), 2); | 
| 1334 |     QCOMPARE(rec.fieldName(0), field1Name); | 
| 1335 |     QCOMPARE(rec.fieldName(1), field2Name); | 
| 1336 |     QCOMPARE(rec.field(0).type(), QVariant::Int); | 
| 1337 |  | 
| 1338 |     q.exec(query: QString("DROP SCHEMA %1 CASCADE" ).arg(a: schemaName)); | 
| 1339 | } | 
| 1340 |  | 
| 1341 | void tst_QSqlDatabase::psql_escapeBytea() | 
| 1342 | { | 
| 1343 |     QFETCH(QString, dbName); | 
| 1344 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 1345 |     CHECK_DATABASE(db); | 
| 1346 |  | 
| 1347 |     const char dta[4] = {'\x71', '\x14', '\x32', '\x81'}; | 
| 1348 |     QByteArray ba(dta, 4); | 
| 1349 |  | 
| 1350 |     QSqlQuery q(db); | 
| 1351 |     const QString tableName(qTableName(prefix: "batable" , __FILE__, db)); | 
| 1352 |     QVERIFY_SQL(q, exec(QString("CREATE TABLE %1 (ba bytea)" ).arg(tableName))); | 
| 1353 |  | 
| 1354 |     QSqlQuery iq(db); | 
| 1355 |     QVERIFY_SQL(iq, prepare(QString("INSERT INTO %1 VALUES (?)" ).arg(tableName))); | 
| 1356 |     iq.bindValue(pos: 0, val: QVariant(ba)); | 
| 1357 |     QVERIFY_SQL(iq, exec()); | 
| 1358 |  | 
| 1359 |     QVERIFY_SQL(q, exec(QString("SELECT ba FROM %1" ).arg(tableName))); | 
| 1360 |     QVERIFY_SQL(q, next()); | 
| 1361 |  | 
| 1362 |     QByteArray res = q.value(i: 0).toByteArray(); | 
| 1363 |     int i = 0; | 
| 1364 |     for (; i < ba.size(); ++i){ | 
| 1365 |         if (ba[i] != res[i]) | 
| 1366 |             break; | 
| 1367 |     } | 
| 1368 |  | 
| 1369 |     QCOMPARE(i, 4); | 
| 1370 | } | 
| 1371 |  | 
| 1372 | void tst_QSqlDatabase::psql_bug249059() | 
| 1373 | { | 
| 1374 |     QFETCH(QString, dbName); | 
| 1375 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 1376 |     CHECK_DATABASE(db); | 
| 1377 |  | 
| 1378 |     QSqlQuery q(db); | 
| 1379 |     const QString tableName(qTableName(prefix: "bug_249059" , __FILE__, db)); | 
| 1380 |     QVERIFY_SQL(q, exec(QString("CREATE TABLE %1 (dt timestamp, t time)" ).arg(tableName))); | 
| 1381 |  | 
| 1382 |     QSqlQuery iq(db); | 
| 1383 |     QVERIFY_SQL(iq, prepare(QString("INSERT INTO %1 VALUES (?, ?)" ).arg(tableName))); | 
| 1384 |     iq.bindValue(pos: 0, val: QVariant(QString("2001-09-09 04:05:06.789 -5:00" ))); | 
| 1385 |     iq.bindValue(pos: 1, val: QVariant(QString("04:05:06.789 -5:00" ))); | 
| 1386 |     QVERIFY_SQL(iq, exec()); | 
| 1387 |     iq.bindValue(pos: 0, val: QVariant(QString("2001-09-09 04:05:06.789 +5:00" ))); | 
| 1388 |     iq.bindValue(pos: 1, val: QVariant(QString("04:05:06.789 +5:00" ))); | 
| 1389 |     QVERIFY_SQL(iq, exec()); | 
| 1390 |  | 
| 1391 |     QVERIFY_SQL(q, exec(QString("SELECT dt, t FROM %1" ).arg(tableName))); | 
| 1392 |     QVERIFY_SQL(q, next()); | 
| 1393 |     QDateTime dt1=q.value(i: 0).toDateTime(); | 
| 1394 |     QTime t1=q.value(i: 1).toTime(); | 
| 1395 |     QVERIFY_SQL(q, next()); | 
| 1396 |     QDateTime dt2=q.value(i: 0).toDateTime(); | 
| 1397 |     QTime t2=q.value(i: 1).toTime(); | 
| 1398 |  | 
| 1399 |     // These will fail when timezone support is added, when that's the case, set the second record to 14:05:06.789 and it should work correctly | 
| 1400 |     QCOMPARE(dt1, dt2); | 
| 1401 |     QCOMPARE(t1, t2); | 
| 1402 | } | 
| 1403 |  | 
| 1404 | // This test should be rewritten to work with Oracle as well - or the Oracle driver | 
| 1405 | // should be fixed to make this test pass (handle overflows) | 
| 1406 | void tst_QSqlDatabase::precisionPolicy() | 
| 1407 | { | 
| 1408 |     QFETCH(QString, dbName); | 
| 1409 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 1410 |     CHECK_DATABASE(db); | 
| 1411 | //     DBMS_SPECIFIC(db, "QPSQL"); | 
| 1412 |  | 
| 1413 |     QSqlQuery q(db); | 
| 1414 |     const QString tableName(qTableName(prefix: "qtest_prec" , __FILE__, db)); | 
| 1415 |     if(!db.driver()->hasFeature(f: QSqlDriver::LowPrecisionNumbers)) | 
| 1416 |         QSKIP("Driver or database doesn't support setting precision policy" ); | 
| 1417 |  | 
| 1418 |     // Create a test table with some data | 
| 1419 |     if(tst_Databases::isMSAccess(db)) | 
| 1420 |         QVERIFY_SQL(q, exec(QString("CREATE TABLE %1 (id smallint, num number)" ).arg(tableName))); | 
| 1421 |     else | 
| 1422 |         QVERIFY_SQL(q, exec(QString("CREATE TABLE %1 (id smallint, num numeric(18,5))" ).arg(tableName))); | 
| 1423 |     QVERIFY_SQL(q, prepare(QString("INSERT INTO %1 VALUES (?, ?)" ).arg(tableName))); | 
| 1424 |     q.bindValue(pos: 0, val: 1); | 
| 1425 |     q.bindValue(pos: 1, val: 123); | 
| 1426 |     QVERIFY_SQL(q, exec()); | 
| 1427 |     q.bindValue(pos: 0, val: 2); | 
| 1428 |     q.bindValue(pos: 1, val: 1850000000000.0001); | 
| 1429 |     QVERIFY_SQL(q, exec()); | 
| 1430 |  | 
| 1431 |     // These are expected to pass | 
| 1432 |     q.setNumericalPrecisionPolicy(QSql::HighPrecision); | 
| 1433 |     QString query = QString("SELECT num FROM %1 WHERE id = 1" ).arg(a: tableName); | 
| 1434 |     QVERIFY_SQL(q, exec(query)); | 
| 1435 |     QVERIFY_SQL(q, next()); | 
| 1436 |     QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db); | 
| 1437 |     if (dbType == QSqlDriver::SQLite) | 
| 1438 |         QEXPECT_FAIL("" , "SQLite returns this value as determined by contents of the field, not the declaration" , Continue); | 
| 1439 |     QCOMPARE(q.value(0).type(), QVariant::String); | 
| 1440 |  | 
| 1441 |     q.setNumericalPrecisionPolicy(QSql::LowPrecisionInt64); | 
| 1442 |     QVERIFY_SQL(q, exec(query)); | 
| 1443 |     QVERIFY_SQL(q, next()); | 
| 1444 |     if(q.value(i: 0).type() != QVariant::LongLong) | 
| 1445 |         QEXPECT_FAIL("" , "SQLite returns this value as determined by contents of the field, not the declaration" , Continue); | 
| 1446 |     QCOMPARE(q.value(0).type(), QVariant::LongLong); | 
| 1447 |     QCOMPARE(q.value(0).toLongLong(), (qlonglong)123); | 
| 1448 |  | 
| 1449 |     q.setNumericalPrecisionPolicy(QSql::LowPrecisionInt32); | 
| 1450 |     QVERIFY_SQL(q, exec(query)); | 
| 1451 |     QVERIFY_SQL(q, next()); | 
| 1452 |     if (dbType == QSqlDriver::SQLite) | 
| 1453 |         QEXPECT_FAIL("" , "SQLite returns this value as determined by contents of the field, not the declaration" , Continue); | 
| 1454 |     QCOMPARE(q.value(0).type(), QVariant::Int); | 
| 1455 |     QCOMPARE(q.value(0).toInt(), 123); | 
| 1456 |  | 
| 1457 |     q.setNumericalPrecisionPolicy(QSql::LowPrecisionDouble); | 
| 1458 |     QVERIFY_SQL(q, exec(query)); | 
| 1459 |     QVERIFY_SQL(q, next()); | 
| 1460 |     if (dbType == QSqlDriver::SQLite) | 
| 1461 |         QEXPECT_FAIL("" , "SQLite returns this value as determined by contents of the field, not the declaration" , Continue); | 
| 1462 |     QCOMPARE(q.value(0).type(), QVariant::Double); | 
| 1463 |     QCOMPARE(q.value(0).toDouble(), (double)123); | 
| 1464 |  | 
| 1465 |     query = QString("SELECT num FROM %1 WHERE id = 2" ).arg(a: tableName); | 
| 1466 |     QVERIFY_SQL(q, exec(query)); | 
| 1467 |     QVERIFY_SQL(q, next()); | 
| 1468 |     if (dbType == QSqlDriver::SQLite) | 
| 1469 |         QEXPECT_FAIL("" , "SQLite returns this value as determined by contents of the field, not the declaration" , Continue); | 
| 1470 |     QCOMPARE(q.value(0).type(), QVariant::Double); | 
| 1471 |     QCOMPARE(q.value(0).toDouble(), QString("1850000000000.0001" ).toDouble()); | 
| 1472 |  | 
| 1473 |     // Postgres returns invalid QVariants on overflow | 
| 1474 |     q.setNumericalPrecisionPolicy(QSql::HighPrecision); | 
| 1475 |     QVERIFY_SQL(q, exec(query)); | 
| 1476 |     QVERIFY_SQL(q, next()); | 
| 1477 |     if (dbType == QSqlDriver::SQLite) | 
| 1478 |         QEXPECT_FAIL("" , "SQLite returns this value as determined by contents of the field, not the declaration" , Continue); | 
| 1479 |     QCOMPARE(q.value(0).type(), QVariant::String); | 
| 1480 |  | 
| 1481 |     q.setNumericalPrecisionPolicy(QSql::LowPrecisionInt64); | 
| 1482 |     QEXPECT_FAIL("QOCI" , "Oracle fails here, to retrieve next" , Continue); | 
| 1483 |     QVERIFY_SQL(q, exec(query)); | 
| 1484 |     QVERIFY_SQL(q, next()); | 
| 1485 |     QCOMPARE(q.value(0).type(), QVariant::LongLong); | 
| 1486 |  | 
| 1487 |     QSql::NumericalPrecisionPolicy oldPrecision= db.numericalPrecisionPolicy(); | 
| 1488 |     db.setNumericalPrecisionPolicy(QSql::LowPrecisionInt64); | 
| 1489 |     QSqlQuery q2(db); | 
| 1490 |     q2.exec(query: QString("SELECT num FROM %1 WHERE id = 2" ).arg(a: tableName)); | 
| 1491 |     QVERIFY_SQL(q2, exec(query)); | 
| 1492 |     QVERIFY_SQL(q2, next()); | 
| 1493 |     QCOMPARE(q2.value(0).type(), QVariant::LongLong); | 
| 1494 |     db.setNumericalPrecisionPolicy(oldPrecision); | 
| 1495 | } | 
| 1496 |  | 
| 1497 | void tst_QSqlDatabase::infinityAndNan() | 
| 1498 | { | 
| 1499 |     QFETCH(QString, dbName); | 
| 1500 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 1501 |     CHECK_DATABASE(db); | 
| 1502 |  | 
| 1503 |     if (tst_Databases::getDatabaseType(db) != QSqlDriver::PostgreSQL) | 
| 1504 |        QSKIP("checking for infinity/nan currently only works for PostgreSQL" ); | 
| 1505 |  | 
| 1506 |     QSqlQuery q(db); | 
| 1507 |     const QString tableName(qTableName(prefix: "infititytest" , __FILE__, db)); | 
| 1508 |     tst_Databases::safeDropTables(db, tableNames: {tableName}); | 
| 1509 |     QVERIFY_SQL(q, exec(QString("CREATE TABLE %1 (id smallint, val double precision)" ).arg(tableName))); | 
| 1510 |  | 
| 1511 |     QVERIFY_SQL(q, prepare(QString("INSERT INTO %1 VALUES (?, ?)" ).arg(tableName))); | 
| 1512 |  | 
| 1513 |     q.bindValue(pos: 0, val: 1); | 
| 1514 |     q.bindValue(pos: 1, val: qQNaN()); | 
| 1515 |     QVERIFY_SQL(q, exec()); | 
| 1516 |     q.bindValue(pos: 0, val: 2); | 
| 1517 |     q.bindValue(pos: 1, val: qInf()); | 
| 1518 |     QVERIFY_SQL(q, exec()); | 
| 1519 |     q.bindValue(pos: 0, val: 3); | 
| 1520 |     q.bindValue(pos: 1, val: -qInf()); | 
| 1521 |     QVERIFY_SQL(q, exec()); | 
| 1522 |  | 
| 1523 |     QVERIFY_SQL(q, exec(QString("SELECT val FROM %1 ORDER BY id" ).arg(tableName))); | 
| 1524 |  | 
| 1525 |     QVERIFY_SQL(q, next()); | 
| 1526 |     QVERIFY(qIsNaN(q.value(0).toDouble())); | 
| 1527 |  | 
| 1528 |     QVERIFY_SQL(q, next()); | 
| 1529 |     QVERIFY(qIsInf(q.value(0).toDouble())); | 
| 1530 |     QVERIFY(q.value(0).toDouble() > 0); | 
| 1531 |  | 
| 1532 |     QVERIFY_SQL(q, next()); | 
| 1533 |     QVERIFY(qIsInf(q.value(0).toDouble())); | 
| 1534 |     QVERIFY(q.value(0).toDouble() < 0); | 
| 1535 | } | 
| 1536 |  | 
| 1537 | // This test needs a ODBC data source containing MYSQL in it's name | 
| 1538 | void tst_QSqlDatabase::mysqlOdbc_unsignedIntegers() | 
| 1539 | { | 
| 1540 |     QFETCH(QString, dbName); | 
| 1541 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 1542 |     CHECK_DATABASE(db); | 
| 1543 |  | 
| 1544 |     if (tst_Databases::getDatabaseType(db) != QSqlDriver::MySqlServer || !db.driverName().startsWith(s: "QODBC" )) | 
| 1545 |        QSKIP("MySQL through ODBC-driver specific test" ); | 
| 1546 |  | 
| 1547 |     QSqlQuery q(db); | 
| 1548 |     const QString tableName(qTableName(prefix: "uint" , __FILE__, db)); | 
| 1549 |     QVERIFY_SQL(q, exec(QString("CREATE TABLE %1 (foo integer(10) unsigned, bar integer(10))" ).arg(tableName))); | 
| 1550 |     QVERIFY_SQL(q, exec(QString("INSERT INTO %1 VALUES (-4000000000, -4000000000)" ).arg(tableName))); | 
| 1551 |     QVERIFY_SQL(q, exec(QString("INSERT INTO %1 VALUES (4000000000, 4000000000)" ).arg(tableName))); | 
| 1552 |  | 
| 1553 |     QVERIFY_SQL(q, exec(QString("SELECT foo, bar FROM %1" ).arg(tableName))); | 
| 1554 |     QVERIFY(q.next()); | 
| 1555 |     QCOMPARE(q.value(0).toString(), QString("0" )); | 
| 1556 |     QCOMPARE(q.value(1).toString(), QString("-2147483648" )); | 
| 1557 |     QVERIFY(q.next()); | 
| 1558 |     QCOMPARE(q.value(0).toString(), QString("4000000000" )); | 
| 1559 |     QCOMPARE(q.value(1).toString(), QString("2147483647" )); | 
| 1560 | } | 
| 1561 |  | 
| 1562 | void tst_QSqlDatabase::accessOdbc_strings() | 
| 1563 | { | 
| 1564 |     QFETCH(QString, dbName); | 
| 1565 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 1566 |     CHECK_DATABASE(db); | 
| 1567 |  | 
| 1568 |     if (!tst_Databases::isMSAccess(db)) | 
| 1569 |         QSKIP("MS Access specific test" ); | 
| 1570 |  | 
| 1571 |     QSqlQuery q(db); | 
| 1572 |     const QString tableName(qTableName(prefix: "strings" , __FILE__, db)); | 
| 1573 |     QVERIFY_SQL(q, exec(QString("CREATE TABLE %1 (aStr memo, bStr memo, cStr memo, dStr memo"  | 
| 1574 |             ", eStr memo, fStr memo, gStr memo, hStr memo)" ).arg(tableName))); | 
| 1575 |  | 
| 1576 |     QVERIFY_SQL(q, prepare(QString("INSERT INTO %1 VALUES (?, ?, ?, ?, ?, ?, ?, ?)" ).arg(tableName))); | 
| 1577 |     QString aStr, bStr, cStr, dStr, eStr, fStr, gStr, hStr; | 
| 1578 |  | 
| 1579 |     q.bindValue(pos: 0, val: aStr.fill(c: 'A', size: 32)); | 
| 1580 |     q.bindValue(pos: 1, val: bStr.fill(c: 'B', size: 127)); | 
| 1581 |     q.bindValue(pos: 2, val: cStr.fill(c: 'C', size: 128)); | 
| 1582 |     q.bindValue(pos: 3, val: dStr.fill(c: 'D', size: 129)); | 
| 1583 |     q.bindValue(pos: 4, val: eStr.fill(c: 'E', size: 254)); | 
| 1584 |     q.bindValue(pos: 5, val: fStr.fill(c: 'F', size: 255)); | 
| 1585 |     q.bindValue(pos: 6, val: gStr.fill(c: 'G', size: 256)); | 
| 1586 |     q.bindValue(pos: 7, val: hStr.fill(c: 'H', size: 512)); | 
| 1587 |  | 
| 1588 |     QVERIFY_SQL(q, exec()); | 
| 1589 |  | 
| 1590 |     QVERIFY_SQL(q, exec(QString("SELECT aStr, bStr, cStr, dStr, eStr, fStr, gStr, hStr FROM %1" ).arg(tableName))); | 
| 1591 |     q.next(); | 
| 1592 |     QCOMPARE(q.value(0).toString(), aStr); | 
| 1593 |     QCOMPARE(q.value(1).toString(), bStr); | 
| 1594 |     QCOMPARE(q.value(2).toString(), cStr); | 
| 1595 |     QCOMPARE(q.value(3).toString(), dStr); | 
| 1596 |     QCOMPARE(q.value(4).toString(), eStr); | 
| 1597 |     QCOMPARE(q.value(5).toString(), fStr); | 
| 1598 |     QCOMPARE(q.value(6).toString(), gStr); | 
| 1599 |     QCOMPARE(q.value(7).toString(), hStr); | 
| 1600 | } | 
| 1601 |  | 
| 1602 | // For task 125053 | 
| 1603 | void tst_QSqlDatabase::ibase_numericFields() | 
| 1604 | { | 
| 1605 |     QFETCH(QString, dbName); | 
| 1606 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 1607 |     CHECK_DATABASE(db); | 
| 1608 |  | 
| 1609 |     QSqlQuery q(db); | 
| 1610 |     const QString tableName(qTableName(prefix: "numericfields" , __FILE__, db)); | 
| 1611 |     QVERIFY_SQL(q, exec(QString("CREATE TABLE %1 (id int not null, num1 NUMERIC(2,1), "  | 
| 1612 |         "num2 NUMERIC(5,2), num3 NUMERIC(10,3), "  | 
| 1613 |         "num4 NUMERIC(18,4))" ).arg(tableName))); | 
| 1614 |  | 
| 1615 |     QVERIFY_SQL(q, exec(QString("INSERT INTO %1 VALUES (1, 1.1, 123.45, 1234567.123, 10203040506070.8090)" ).arg(tableName))); | 
| 1616 |  | 
| 1617 |     QVERIFY_SQL(q, prepare(QString("INSERT INTO %1 VALUES (?, ?, ?, ?, ?)" ).arg(tableName))); | 
| 1618 |  | 
| 1619 |     double num1 = 1.1; | 
| 1620 |     double num2 = 123.45; | 
| 1621 |     double num3 = 1234567.123; | 
| 1622 |     double num4 = 10203040506070.8090; | 
| 1623 |  | 
| 1624 |     q.bindValue(pos: 0, val: 2); | 
| 1625 |     q.bindValue(pos: 1, val: QVariant(num1)); | 
| 1626 |     q.bindValue(pos: 2, val: QVariant(num2)); | 
| 1627 |     q.bindValue(pos: 3, val: QVariant(num3)); | 
| 1628 |     q.bindValue(pos: 4, val: QVariant(num4)); | 
| 1629 |     QVERIFY_SQL(q, exec()); | 
| 1630 |  | 
| 1631 |     QVERIFY_SQL(q, exec(QString("SELECT id, num1, num2, num3, num4 FROM %1" ).arg(tableName))); | 
| 1632 |  | 
| 1633 |     int id = 0; | 
| 1634 |     while (q.next()) { | 
| 1635 |         QCOMPARE(q.value(0).toInt(), ++id); | 
| 1636 |         QCOMPARE(q.value(1).toString(), QString("%1" ).arg(num1)); | 
| 1637 |         QCOMPARE(q.value(2).toString(), QString("%1" ).arg(num2)); | 
| 1638 |         QCOMPARE(QString("%1" ).arg(q.value(3).toDouble()), QString("%1" ).arg(num3)); | 
| 1639 |         QCOMPARE(QString("%1" ).arg(q.value(4).toDouble()), QString("%1" ).arg(num4)); | 
| 1640 |         QCOMPARE(q.value(0).type(), QVariant::Int); | 
| 1641 |         QCOMPARE(q.value(1).type(), QVariant::Double); | 
| 1642 |         QCOMPARE(q.value(2).type(), QVariant::Double); | 
| 1643 |         QCOMPARE(q.value(3).type(), QVariant::Double); | 
| 1644 |         QCOMPARE(q.value(4).type(), QVariant::Double); | 
| 1645 |  | 
| 1646 |         QCOMPARE(q.record().field(1).length(), 2); | 
| 1647 |         QCOMPARE(q.record().field(1).precision(), 1); | 
| 1648 |         QCOMPARE(q.record().field(2).length(), 5); | 
| 1649 |         QCOMPARE(q.record().field(2).precision(), 2); | 
| 1650 |         QCOMPARE(q.record().field(3).length(), 10); | 
| 1651 |         QCOMPARE(q.record().field(3).precision(), 3); | 
| 1652 |         QCOMPARE(q.record().field(4).length(), 18); | 
| 1653 |         QCOMPARE(q.record().field(4).precision(), 4); | 
| 1654 |         QCOMPARE(q.record().field(0).requiredStatus(), QSqlField::Required); | 
| 1655 |         QCOMPARE(q.record().field(1).requiredStatus(), QSqlField::Optional); | 
| 1656 |     } | 
| 1657 |  | 
| 1658 |     QSqlRecord r = db.record(tablename: tableName); | 
| 1659 |     QCOMPARE(r.field(0).type(), QVariant::Int); | 
| 1660 |     QCOMPARE(r.field(1).type(), QVariant::Double); | 
| 1661 |     QCOMPARE(r.field(2).type(), QVariant::Double); | 
| 1662 |     QCOMPARE(r.field(3).type(), QVariant::Double); | 
| 1663 |     QCOMPARE(r.field(4).type(), QVariant::Double); | 
| 1664 |     QCOMPARE(r.field(1).length(), 2); | 
| 1665 |     QCOMPARE(r.field(1).precision(), 1); | 
| 1666 |     QCOMPARE(r.field(2).length(), 5); | 
| 1667 |     QCOMPARE(r.field(2).precision(), 2); | 
| 1668 |     QCOMPARE(r.field(3).length(), 10); | 
| 1669 |     QCOMPARE(r.field(3).precision(), 3); | 
| 1670 |     QCOMPARE(r.field(4).length(), 18); | 
| 1671 |     QCOMPARE(r.field(4).precision(), 4); | 
| 1672 |     QCOMPARE(r.field(0).requiredStatus(), QSqlField::Required); | 
| 1673 |     QCOMPARE(r.field(1).requiredStatus(), QSqlField::Optional); | 
| 1674 | } | 
| 1675 |  | 
| 1676 | void tst_QSqlDatabase::ibase_fetchBlobs() | 
| 1677 | { | 
| 1678 |     QFETCH(QString, dbName); | 
| 1679 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 1680 |     CHECK_DATABASE(db); | 
| 1681 |  | 
| 1682 |     const QString tableName(qTableName(prefix: "qtest_ibaseblobs" , __FILE__, db)); | 
| 1683 |     QSqlQuery q(db); | 
| 1684 |     QVERIFY_SQL(q, exec(QString("CREATE TABLE %1 (blob1 BLOB segment size 256)" ).arg(tableName))); | 
| 1685 |  | 
| 1686 |     QVERIFY_SQL(q, prepare(QString("INSERT INTO %1 VALUES (?)" ).arg(tableName))); | 
| 1687 |     q.bindValue(pos: 0, val: QByteArray().fill(c: 'x', size: 1024)); | 
| 1688 |     QVERIFY_SQL(q, exec()); | 
| 1689 |  | 
| 1690 |     QVERIFY_SQL(q, prepare(QString("INSERT INTO %1 VALUES (?)" ).arg(tableName))); | 
| 1691 |     q.bindValue(pos: 0, val: QByteArray().fill(c: 'x', size: 16383)); | 
| 1692 |     QVERIFY_SQL(q, exec()); | 
| 1693 |  | 
| 1694 |     QVERIFY_SQL(q, prepare(QString("INSERT INTO %1 VALUES (?)" ).arg(tableName))); | 
| 1695 |     q.bindValue(pos: 0, val: QByteArray().fill(c: 'x', size: 17408)); | 
| 1696 |     QVERIFY_SQL(q, exec()); | 
| 1697 |  | 
| 1698 |     QVERIFY_SQL(q, exec(QString("SELECT * FROM %1" ).arg(tableName))); | 
| 1699 |  | 
| 1700 |     QVERIFY_SQL(q, next()); | 
| 1701 |     QCOMPARE(q.value(0).toByteArray().size(), 1024); | 
| 1702 |     QVERIFY_SQL(q, next()); | 
| 1703 |     QCOMPARE(q.value(0).toByteArray().size(), 16383); | 
| 1704 |     QVERIFY_SQL(q, next()); | 
| 1705 |     QCOMPARE(q.value(0).toByteArray().size(), 17408); | 
| 1706 | } | 
| 1707 |  | 
| 1708 | void tst_QSqlDatabase::ibase_procWithoutReturnValues() | 
| 1709 | { | 
| 1710 |     QFETCH(QString, dbName); | 
| 1711 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 1712 |     CHECK_DATABASE(db); | 
| 1713 |  | 
| 1714 |     QSqlQuery q(db); | 
| 1715 |     const QString procName(qTableName(prefix: "qtest_proc1" , __FILE__, db)); | 
| 1716 |     q.exec(query: QString("drop procedure %1" ).arg(a: procName)); | 
| 1717 |     QVERIFY_SQL(q, exec("CREATE PROCEDURE "  + procName + " (str VARCHAR(10))\nAS BEGIN\nstr='test';\nEND;" )); | 
| 1718 |     QVERIFY_SQL(q, exec(QString("execute procedure %1('qtest')" ).arg(procName))); | 
| 1719 |     q.exec(query: QString("drop procedure %1" ).arg(a: procName)); | 
| 1720 | } | 
| 1721 |  | 
| 1722 | void tst_QSqlDatabase::ibase_procWithReturnValues() | 
| 1723 | { | 
| 1724 |     QFETCH(QString, dbName); | 
| 1725 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 1726 |     CHECK_DATABASE(db); | 
| 1727 |  | 
| 1728 |     const QString procName(qTableName(prefix: "qtest_proc2" , __FILE__, db)); | 
| 1729 |  | 
| 1730 |     QSqlQuery q(db); | 
| 1731 |     q.exec(query: QString("drop procedure %1" ).arg(a: procName)); | 
| 1732 |     QVERIFY_SQL(q, exec("CREATE PROCEDURE "  + procName + " ("  | 
| 1733 |                         "\nABC INTEGER)"  | 
| 1734 |                         "\nRETURNS ("  | 
| 1735 |                         "\nRESULT INTEGER)"  | 
| 1736 |                         "\nAS"  | 
| 1737 |                         "\nbegin"  | 
| 1738 |                         "\nRESULT = 10 * ABC;"  | 
| 1739 |                         "\nsuspend;"  | 
| 1740 |                         "\nend" )); | 
| 1741 |  | 
| 1742 |     // Interbase procedures can be executed in two ways: EXECUTE PROCEDURE or SELECT | 
| 1743 |     QVERIFY_SQL(q, exec(QString("execute procedure %1(123)" ).arg(procName))); | 
| 1744 |     QVERIFY_SQL(q, next()); | 
| 1745 |     QCOMPARE(q.value(0).toInt(), 1230); | 
| 1746 |     QVERIFY_SQL(q, exec(QString("select result from %1(456)" ).arg(procName))); | 
| 1747 |     QVERIFY_SQL(q, next()); | 
| 1748 |     QCOMPARE(q.value(0).toInt(), 4560); | 
| 1749 |     QVERIFY_SQL(q, prepare(QLatin1String("execute procedure " )+procName+QLatin1String("(?)" ))); | 
| 1750 |     q.bindValue(pos: 0, val: 123); | 
| 1751 |     QVERIFY_SQL(q, exec()); | 
| 1752 |     QVERIFY_SQL(q, next()); | 
| 1753 |     QCOMPARE(q.value(0).toInt(), 1230); | 
| 1754 |     q.bindValue(pos: 0, val: 456); | 
| 1755 |     QVERIFY_SQL(q, exec()); | 
| 1756 |     QVERIFY_SQL(q, next()); | 
| 1757 |     QCOMPARE(q.value(0).toInt(), 4560); | 
| 1758 |  | 
| 1759 |     q.exec(query: QString("drop procedure %1" ).arg(a: procName)); | 
| 1760 | } | 
| 1761 |  | 
| 1762 | void tst_QSqlDatabase::formatValueTrimStrings() | 
| 1763 | { | 
| 1764 |     QFETCH(QString, dbName); | 
| 1765 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 1766 |     CHECK_DATABASE(db); | 
| 1767 |  | 
| 1768 |     QSqlQuery q(db); | 
| 1769 |     const QString tableName = qTableName(prefix: "qtest" , __FILE__, db); | 
| 1770 |     QVERIFY_SQL(q, exec(QString("INSERT INTO %1 (id, t_varchar, t_char) values (50, 'Trim Test ', 'Trim Test 2   ')" ).arg(tableName))); | 
| 1771 |     QVERIFY_SQL(q, exec(QString("INSERT INTO %1 (id, t_varchar, t_char) values (51, 'TrimTest', 'Trim Test 2')" ).arg(tableName))); | 
| 1772 |     QVERIFY_SQL(q, exec(QString("INSERT INTO %1 (id, t_varchar, t_char) values (52, ' ', '    ')" ).arg(tableName))); | 
| 1773 |  | 
| 1774 |     QVERIFY_SQL(q, exec(QString("SELECT t_varchar, t_char FROM %1 WHERE id >= 50 AND id <= 52 ORDER BY id" ).arg(tableName))); | 
| 1775 |  | 
| 1776 |     QVERIFY_SQL(q, next()); | 
| 1777 |  | 
| 1778 |     QCOMPARE(db.driver()->formatValue(q.record().field(0), true), QString("'Trim Test'" )); | 
| 1779 |     QCOMPARE(db.driver()->formatValue(q.record().field(1), true), QString("'Trim Test 2'" )); | 
| 1780 |  | 
| 1781 |     QVERIFY_SQL(q, next()); | 
| 1782 |     QCOMPARE(db.driver()->formatValue(q.record().field(0), true), QString("'TrimTest'" )); | 
| 1783 |     QCOMPARE(db.driver()->formatValue(q.record().field(1), true), QString("'Trim Test 2'" )); | 
| 1784 |  | 
| 1785 |     QVERIFY_SQL(q, next()); | 
| 1786 |     QCOMPARE(db.driver()->formatValue(q.record().field(0), true), QString("''" )); | 
| 1787 |     QCOMPARE(db.driver()->formatValue(q.record().field(1), true), QString("''" )); | 
| 1788 |  | 
| 1789 | } | 
| 1790 |  | 
| 1791 | void tst_QSqlDatabase::odbc_reopenDatabase() | 
| 1792 | { | 
| 1793 |     QFETCH(QString, dbName); | 
| 1794 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 1795 |     const QString tableName = qTableName(prefix: "qtest" , __FILE__, db); | 
| 1796 |     CHECK_DATABASE(db); | 
| 1797 |  | 
| 1798 |     QSqlQuery q(db); | 
| 1799 |     QVERIFY_SQL(q, exec("SELECT * from "  + tableName)); | 
| 1800 |     QVERIFY_SQL(q, next()); | 
| 1801 |     db.open(); | 
| 1802 |     QVERIFY_SQL(q, exec("SELECT * from "  + tableName)); | 
| 1803 |     QVERIFY_SQL(q, next()); | 
| 1804 |     db.open(); | 
| 1805 | } | 
| 1806 |  | 
| 1807 | void tst_QSqlDatabase::odbc_bindBoolean() | 
| 1808 | { | 
| 1809 |     QFETCH(QString, dbName); | 
| 1810 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 1811 |     CHECK_DATABASE(db); | 
| 1812 |  | 
| 1813 |     QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db); | 
| 1814 |     if (dbType == QSqlDriver::MySqlServer) | 
| 1815 |         QSKIP("MySql has inconsistent behaviour of bit field type across versions." ); | 
| 1816 |  | 
| 1817 |     QSqlQuery q(db); | 
| 1818 |     const QString tableName = qTableName(prefix: "qtestBindBool" , __FILE__, db); | 
| 1819 |     QVERIFY_SQL(q, exec("CREATE TABLE "  + tableName + "(id int, boolvalue bit)" )); | 
| 1820 |  | 
| 1821 |     // Bind and insert | 
| 1822 |     QVERIFY_SQL(q, prepare("INSERT INTO "  + tableName + " VALUES(?, ?)" )); | 
| 1823 |     q.bindValue(pos: 0, val: 1); | 
| 1824 |     q.bindValue(pos: 1, val: true); | 
| 1825 |     QVERIFY_SQL(q, exec()); | 
| 1826 |     q.bindValue(pos: 0, val: 2); | 
| 1827 |     q.bindValue(pos: 1, val: false); | 
| 1828 |     QVERIFY_SQL(q, exec()); | 
| 1829 |  | 
| 1830 |     // Retrive | 
| 1831 |     QVERIFY_SQL(q, exec("SELECT id, boolvalue FROM "  + tableName + " ORDER BY id" )); | 
| 1832 |     QVERIFY_SQL(q, next()); | 
| 1833 |     QCOMPARE(q.value(0).toInt(), 1); | 
| 1834 |     QCOMPARE(q.value(1).toBool(), true); | 
| 1835 |     QVERIFY_SQL(q, next()); | 
| 1836 |     QCOMPARE(q.value(0).toInt(), 2); | 
| 1837 |     QCOMPARE(q.value(1).toBool(), false); | 
| 1838 | } | 
| 1839 |  | 
| 1840 | void tst_QSqlDatabase::odbc_testqGetString() | 
| 1841 | { | 
| 1842 |     QFETCH(QString, dbName); | 
| 1843 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 1844 |     CHECK_DATABASE(db); | 
| 1845 |     const QString testqGetString(qTableName(prefix: "testqGetString" , __FILE__, db)); | 
| 1846 |  | 
| 1847 |     QSqlQuery q(db); | 
| 1848 |     QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db); | 
| 1849 |     if (dbType == QSqlDriver::MSSqlServer) | 
| 1850 |         QVERIFY_SQL(q, exec("CREATE TABLE "  + testqGetString + "(id int, vcvalue varchar(MAX))" )); | 
| 1851 |     else if(tst_Databases::isMSAccess(db)) | 
| 1852 |         QVERIFY_SQL(q, exec("CREATE TABLE "  + testqGetString + "(id int, vcvalue memo)" )); | 
| 1853 |     else | 
| 1854 |         QVERIFY_SQL(q, exec("CREATE TABLE "  + testqGetString + "(id int, vcvalue varchar(65538))" )); | 
| 1855 |  | 
| 1856 |     QString largeString; | 
| 1857 |     largeString.fill(c: 'A', size: 65536); | 
| 1858 |  | 
| 1859 |     // Bind and insert | 
| 1860 |     QVERIFY_SQL(q, prepare("INSERT INTO "  + testqGetString + " VALUES(?, ?)" )); | 
| 1861 |     q.bindValue(pos: 0, val: 1); | 
| 1862 |     q.bindValue(pos: 1, val: largeString); | 
| 1863 |     QVERIFY_SQL(q, exec()); | 
| 1864 |     q.bindValue(pos: 0, val: 2); | 
| 1865 |     q.bindValue(pos: 1, val: largeString+QLatin1Char('B')); | 
| 1866 |     QVERIFY_SQL(q, exec()); | 
| 1867 |     q.bindValue(pos: 0, val: 3); | 
| 1868 |     q.bindValue(pos: 1, val: largeString+QLatin1Char('B')+QLatin1Char('C')); | 
| 1869 |     QVERIFY_SQL(q, exec()); | 
| 1870 |  | 
| 1871 |     // Retrive | 
| 1872 |     QVERIFY_SQL(q, exec("SELECT id, vcvalue FROM "  + testqGetString + " ORDER BY id" )); | 
| 1873 |     QVERIFY_SQL(q, next()); | 
| 1874 |     QCOMPARE(q.value(0).toInt(), 1); | 
| 1875 |     QCOMPARE(q.value(1).toString().length(), 65536); | 
| 1876 |     QVERIFY_SQL(q, next()); | 
| 1877 |     QCOMPARE(q.value(0).toInt(), 2); | 
| 1878 |     QCOMPARE(q.value(1).toString().length(), 65537); | 
| 1879 |     QVERIFY_SQL(q, next()); | 
| 1880 |     QCOMPARE(q.value(0).toInt(), 3); | 
| 1881 |     QCOMPARE(q.value(1).toString().length(), 65538); | 
| 1882 | } | 
| 1883 |  | 
| 1884 |  | 
| 1885 | void tst_QSqlDatabase::mysql_multiselect() | 
| 1886 | { | 
| 1887 |     QFETCH(QString, dbName); | 
| 1888 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 1889 |     CHECK_DATABASE(db); | 
| 1890 |     const QString qtest(qTableName(prefix: "qtest" , __FILE__, db)); | 
| 1891 |  | 
| 1892 |     QSqlQuery q(db); | 
| 1893 |     QVERIFY_SQL(q, exec("SELECT * FROM "  + qtest + "; SELECT * FROM "  + qtest)); | 
| 1894 |     QVERIFY_SQL(q, next()); | 
| 1895 |     QVERIFY_SQL(q, exec("SELECT * FROM "  + qtest + "; SELECT * FROM "  + qtest)); | 
| 1896 |     QVERIFY_SQL(q, next()); | 
| 1897 |     QVERIFY_SQL(q, exec("SELECT * FROM "  + qtest)); | 
| 1898 | } | 
| 1899 |  | 
| 1900 | void tst_QSqlDatabase::ibase_useCustomCharset() | 
| 1901 | { | 
| 1902 |     QFETCH(QString, dbName); | 
| 1903 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 1904 |     CHECK_DATABASE(db); | 
| 1905 |     QString nonlatin1string("��" ); | 
| 1906 |  | 
| 1907 |     db.close(); | 
| 1908 |     db.setConnectOptions("ISC_DPB_LC_CTYPE=Latin1" ); | 
| 1909 |     db.open(); | 
| 1910 |  | 
| 1911 |     const QString tableName(qTableName(prefix: "latin1table" , __FILE__, db)); | 
| 1912 |  | 
| 1913 |     QSqlQuery q(db); | 
| 1914 |     QVERIFY_SQL(q, exec(QString("CREATE TABLE %1(text VARCHAR(6) CHARACTER SET Latin1)" ).arg(tableName))); | 
| 1915 |     QVERIFY_SQL(q, prepare(QString("INSERT INTO %1 VALUES(?)" ).arg(tableName))); | 
| 1916 |     q.addBindValue(val: nonlatin1string); | 
| 1917 |     QVERIFY_SQL(q, exec()); | 
| 1918 |     QVERIFY_SQL(q, exec(QString("SELECT text FROM %1" ).arg(tableName))); | 
| 1919 |     QVERIFY_SQL(q, next()); | 
| 1920 |     QCOMPARE(toHex(q.value(0).toString()), toHex(nonlatin1string)); | 
| 1921 | } | 
| 1922 |  | 
| 1923 | void tst_QSqlDatabase::oci_serverDetach() | 
| 1924 | { | 
| 1925 |     QFETCH(QString, dbName); | 
| 1926 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 1927 |     CHECK_DATABASE(db); | 
| 1928 |  | 
| 1929 |     for (int i = 0; i < 2; i++) { | 
| 1930 |         db.close(); | 
| 1931 |         if (db.open()) { | 
| 1932 |             QSqlQuery query(db); | 
| 1933 |             query.exec(query: "SELECT 1 FROM DUAL" ); | 
| 1934 |             db.close(); | 
| 1935 |         } else { | 
| 1936 |             QFAIL(tst_Databases::printError(db.lastError(), db)); | 
| 1937 |         } | 
| 1938 |     } | 
| 1939 |     if(!db.open()) | 
| 1940 |         qFatal(msg: "%s" , qPrintable(tst_Databases::printError(db.lastError(), db))); | 
| 1941 | } | 
| 1942 |  | 
| 1943 | void tst_QSqlDatabase::oci_xmltypeSupport() | 
| 1944 | { | 
| 1945 |     QFETCH(QString, dbName); | 
| 1946 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 1947 |     CHECK_DATABASE(db); | 
| 1948 |  | 
| 1949 |     const QString tableName(qTableName(prefix: "qtest_xmltype" , __FILE__, db)); | 
| 1950 |     QString xml("<?xml version=\"1.0\"?>\n<TABLE_NAME>MY_TABLE</TABLE_NAME>\n" ); | 
| 1951 |     QSqlQuery q(db); | 
| 1952 |  | 
| 1953 |     // Embedding the XML in the statement | 
| 1954 |     if(!q.exec(query: QString("CREATE TABLE %1(xmldata xmltype)" ).arg(a: tableName))) | 
| 1955 |         QSKIP("This test requries xml type support" ); | 
| 1956 |     QVERIFY_SQL(q, exec(QString("INSERT INTO %1 values('%2')" ).arg(tableName).arg(xml))); | 
| 1957 |     QVERIFY_SQL(q, exec(QString("SELECT a.xmldata.getStringVal() FROM %1 a" ).arg(tableName))); | 
| 1958 |     QVERIFY_SQL(q, last()); | 
| 1959 |     QCOMPARE(q.value(0).toString(), xml); | 
| 1960 |  | 
| 1961 |     // Binding the XML with a prepared statement | 
| 1962 |     QVERIFY_SQL(q, prepare(QString("INSERT INTO %1 values(?)" ).arg(tableName))); | 
| 1963 |     q.addBindValue(val: xml); | 
| 1964 |     QVERIFY_SQL(q, exec()); | 
| 1965 |     QVERIFY_SQL(q, exec(QString("SELECT a.xmldata.getStringVal() FROM %1 a" ).arg(tableName))); | 
| 1966 |     QVERIFY_SQL(q, last()); | 
| 1967 |     QCOMPARE(q.value(0).toString(), xml); | 
| 1968 | } | 
| 1969 |  | 
| 1970 |  | 
| 1971 | void tst_QSqlDatabase::oci_fieldLength() | 
| 1972 | { | 
| 1973 |     QFETCH(QString, dbName); | 
| 1974 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 1975 |     CHECK_DATABASE(db); | 
| 1976 |  | 
| 1977 |     const QString tableName(qTableName(prefix: "qtest" , __FILE__, db)); | 
| 1978 |     QSqlQuery q(db); | 
| 1979 |  | 
| 1980 |     QVERIFY_SQL(q, exec(QString("SELECT t_varchar, t_char FROM %1" ).arg(tableName))); | 
| 1981 |     QVERIFY_SQL(q, next()); | 
| 1982 |     QCOMPARE(q.record().field(0).length(), 40); | 
| 1983 |     QCOMPARE(q.record().field(1).length(), 40); | 
| 1984 | } | 
| 1985 |  | 
| 1986 | void tst_QSqlDatabase::oci_synonymstest() | 
| 1987 | { | 
| 1988 |     QFETCH(QString, dbName); | 
| 1989 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 1990 |     CHECK_DATABASE(db); | 
| 1991 |  | 
| 1992 |     QSqlQuery q(db); | 
| 1993 |     const QString creator(qTableName(prefix: "CREATOR" , __FILE__, db)), appuser(qTableName(prefix: "APPUSER" , __FILE__, db)), table1(qTableName(prefix: "TABLE1" , __FILE__, db)); | 
| 1994 | //     QVERIFY_SQL(q, exec("drop public synonym "+table1)); | 
| 1995 |     QVERIFY_SQL(q, exec(QString("create user %1 identified by %2 default tablespace users temporary tablespace temp" ).arg(creator).arg(creator))); | 
| 1996 |     QVERIFY_SQL(q, exec(QString("grant CONNECT to %1" ).arg(creator))); | 
| 1997 |     QVERIFY_SQL(q, exec(QString("grant RESOURCE to %1" ).arg(creator))); | 
| 1998 |     QSqlDatabase db2=db.cloneDatabase(other: db, connectionName: QLatin1String("oci_synonymstest" )); | 
| 1999 |     db2.close(); | 
| 2000 |     QVERIFY_SQL(db2, open(creator,creator)); | 
| 2001 |     QSqlQuery q2(db2); | 
| 2002 |     QVERIFY_SQL(q2, exec(QString("create table %1(id int primary key)" ).arg(table1))); | 
| 2003 |     QVERIFY_SQL(q, exec(QString("create user %1 identified by %2 default tablespace users temporary tablespace temp" ).arg(appuser).arg(appuser))); | 
| 2004 |     QVERIFY_SQL(q, exec(QString("grant CREATE ANY SYNONYM to %1" ).arg(appuser))); | 
| 2005 |     QVERIFY_SQL(q, exec(QString("grant CONNECT to %1" ).arg(appuser))); | 
| 2006 |     QVERIFY_SQL(q2, exec(QString("grant select, insert, update, delete on %1 to %2" ).arg(table1).arg(appuser))); | 
| 2007 |     QSqlDatabase db3=db.cloneDatabase(other: db, connectionName: QLatin1String("oci_synonymstest2" )); | 
| 2008 |     db3.close(); | 
| 2009 |     QVERIFY_SQL(db3, open(appuser,appuser)); | 
| 2010 |     QSqlQuery q3(db3); | 
| 2011 |     QVERIFY_SQL(q3, exec("create synonym "  + appuser + '.' + qTableName("synonyms" , __FILE__, db) + " for "  + creator + '.' + table1)); | 
| 2012 |     QVERIFY_SQL(db3, tables().filter(qTableName("synonyms" , __FILE__, db), Qt::CaseInsensitive).count() >= 1); | 
| 2013 | } | 
| 2014 |  | 
| 2015 |  | 
| 2016 | // This test isn't really necessary as SQL_GUID / uniqueidentifier is | 
| 2017 | // already tested in recordSQLServer(). | 
| 2018 | void tst_QSqlDatabase::odbc_uniqueidentifier() | 
| 2019 | { | 
| 2020 |     QFETCH(QString, dbName); | 
| 2021 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 2022 |     CHECK_DATABASE(db); | 
| 2023 |     QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db); | 
| 2024 |     if (dbType != QSqlDriver::MSSqlServer) | 
| 2025 |         QSKIP("SQL Server (ODBC) specific test" ); | 
| 2026 |  | 
| 2027 |     const QString tableName(qTableName(prefix: "qtest_sqlguid" , __FILE__, db)); | 
| 2028 |     QString guid = QString("AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE" ); | 
| 2029 |     QString invalidGuid = QString("GAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE" ); | 
| 2030 |  | 
| 2031 |     QSqlQuery q(db); | 
| 2032 |     QVERIFY_SQL(q, exec(QString("CREATE TABLE %1(id uniqueidentifier)" ).arg(tableName))); | 
| 2033 |  | 
| 2034 |     q.prepare(query: QString("INSERT INTO %1 VALUES(?)" ).arg(a: tableName));; | 
| 2035 |     q.addBindValue(val: guid); | 
| 2036 |     QVERIFY_SQL(q, exec()); | 
| 2037 |  | 
| 2038 |     q.addBindValue(val: invalidGuid); | 
| 2039 |     QEXPECT_FAIL("" , "The GUID string is required to be correctly formated!" , | 
| 2040 |         Continue); | 
| 2041 |     QVERIFY_SQL(q, exec()); | 
| 2042 |  | 
| 2043 |     QVERIFY_SQL(q, exec(QString("SELECT id FROM %1" ).arg(tableName))); | 
| 2044 |     QVERIFY_SQL(q, next()); | 
| 2045 |     QCOMPARE(q.value(0).toString(), guid); | 
| 2046 | } | 
| 2047 |  | 
| 2048 | void tst_QSqlDatabase::getConnectionName() | 
| 2049 | { | 
| 2050 |     QFETCH(QString, dbName); | 
| 2051 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 2052 |     CHECK_DATABASE(db); | 
| 2053 |  | 
| 2054 |     QCOMPARE(db.connectionName(), dbName); | 
| 2055 |     QSqlDatabase clone = QSqlDatabase::cloneDatabase(other: db, connectionName: "clonedDatabase" ); | 
| 2056 |     QCOMPARE(clone.connectionName(), QString("clonedDatabase" )); | 
| 2057 |     QTest::ignoreMessage(type: QtWarningMsg, message: "QSqlDatabasePrivate::removeDatabase: "  | 
| 2058 |         "connection 'clonedDatabase' is still in use, all queries will cease to work." ); | 
| 2059 |     QSqlDatabase::removeDatabase(connectionName: "clonedDatabase" ); | 
| 2060 |     QCOMPARE(clone.connectionName(), QString()); | 
| 2061 |     QCOMPARE(db.connectionName(), dbName); | 
| 2062 | } | 
| 2063 |  | 
| 2064 | void tst_QSqlDatabase::odbc_uintfield() | 
| 2065 | { | 
| 2066 |     QFETCH(QString, dbName); | 
| 2067 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 2068 |     CHECK_DATABASE(db); | 
| 2069 |  | 
| 2070 |     const QString tableName(qTableName(prefix: "uint_table" , __FILE__, db)); | 
| 2071 |     unsigned int val = 4294967295U; | 
| 2072 |  | 
| 2073 |     QSqlQuery q(db); | 
| 2074 |     if ( tst_Databases::isMSAccess( db ) ) | 
| 2075 |         QVERIFY_SQL(q, exec(QString("CREATE TABLE %1(num number)" ).arg(tableName))); | 
| 2076 |     else | 
| 2077 |         QVERIFY_SQL(q, exec(QString("CREATE TABLE %1(num numeric(10))" ).arg(tableName))); | 
| 2078 |     q.prepare(query: QString("INSERT INTO %1 VALUES(?)" ).arg(a: tableName)); | 
| 2079 |     q.addBindValue(val); | 
| 2080 |     QVERIFY_SQL(q, exec()); | 
| 2081 |  | 
| 2082 |     q.exec(query: QString("SELECT num FROM %1" ).arg(a: tableName)); | 
| 2083 |     if (q.next()) | 
| 2084 |         QCOMPARE(q.value(0).toUInt(), val); | 
| 2085 | } | 
| 2086 |  | 
| 2087 | void tst_QSqlDatabase::eventNotification() | 
| 2088 | { | 
| 2089 |     QFETCH(QString, dbName); | 
| 2090 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 2091 |     CHECK_DATABASE(db); | 
| 2092 |  | 
| 2093 |     QSqlDriver *driver = db.driver(); | 
| 2094 |     if (!driver->hasFeature(f: QSqlDriver::EventNotifications)) | 
| 2095 |         QSKIP("DBMS doesn't support event notifications" ); | 
| 2096 |  | 
| 2097 |     // Not subscribed to any events yet | 
| 2098 |     QCOMPARE(driver->subscribedToNotifications().size(), 0); | 
| 2099 |  | 
| 2100 |     // Subscribe to "event_foo" | 
| 2101 |     QVERIFY_SQL(*driver, subscribeToNotification(QLatin1String("event_foo" ))); | 
| 2102 |     QCOMPARE(driver->subscribedToNotifications().size(), 1); | 
| 2103 |     QVERIFY(driver->subscribedToNotifications().contains("event_foo" )); | 
| 2104 |  | 
| 2105 |     // Can't subscribe to the same event multiple times | 
| 2106 |     const QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db); | 
| 2107 |     if (dbType != QSqlDriver::PostgreSQL) { | 
| 2108 |         // We will resubscribe on PostgreSQL in case it is due to a disconnect, the call will | 
| 2109 |         // do nothing on the PostgreSQL side but it will indicate it succeeded anyway and there | 
| 2110 |         // will still only be one entry for it | 
| 2111 |         QVERIFY2(!driver->subscribeToNotification(QLatin1String("event_foo" )), | 
| 2112 |                  "Shouldn't be able to subscribe to event_foo twice" ); | 
| 2113 |     } | 
| 2114 |     QCOMPARE(driver->subscribedToNotifications().size(), 1); | 
| 2115 |  | 
| 2116 |     // Unsubscribe from "event_foo" | 
| 2117 |     QVERIFY_SQL(*driver, unsubscribeFromNotification(QLatin1String("event_foo" ))); | 
| 2118 |     QCOMPARE(driver->subscribedToNotifications().size(), 0); | 
| 2119 |  | 
| 2120 |     // Re-subscribing to "event_foo" now is allowed | 
| 2121 |     QVERIFY_SQL(*driver, subscribeToNotification(QLatin1String("event_foo" ))); | 
| 2122 |     QCOMPARE(driver->subscribedToNotifications().size(), 1); | 
| 2123 |  | 
| 2124 |     // closing the connection causes automatically unsubscription from all events | 
| 2125 |     db.close(); | 
| 2126 |     QCOMPARE(driver->subscribedToNotifications().size(), 0); | 
| 2127 |  | 
| 2128 |     // Can't subscribe to anything while database is closed | 
| 2129 |     QVERIFY2(!driver->subscribeToNotification(QLatin1String("event_foo" )), "Shouldn't be able to subscribe to event_foo" ); | 
| 2130 |     QCOMPARE(driver->subscribedToNotifications().size(), 0); | 
| 2131 |  | 
| 2132 |     db.open(); | 
| 2133 | } | 
| 2134 |  | 
| 2135 | void tst_QSqlDatabase::eventNotificationIBase() | 
| 2136 | { | 
| 2137 |     QFETCH(QString, dbName); | 
| 2138 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 2139 |     if (db.driverName().compare(other: QLatin1String("QIBASE" ), cs: Qt::CaseInsensitive)) | 
| 2140 |         QSKIP("QIBASE specific test" ); | 
| 2141 |     CHECK_DATABASE(db); | 
| 2142 |  | 
| 2143 |     const QString procedureName(qTableName(prefix: "posteventProc" , __FILE__, db)); | 
| 2144 |     QSqlDriver *driver=db.driver(); | 
| 2145 |     QVERIFY_SQL(*driver, subscribeToNotification(procedureName)); | 
| 2146 |     QTest::qWait(ms: 300);  // Interbase needs some time to call the driver callback. | 
| 2147 |  | 
| 2148 |     db.transaction();   // InterBase events are posted from within transactions. | 
| 2149 |     QSqlQuery q(db); | 
| 2150 |     q.exec(query: QString("DROP PROCEDURE %1" ).arg(a: procedureName)); | 
| 2151 |     q.exec(query: QString("CREATE PROCEDURE %1\nAS BEGIN\nPOST_EVENT '%1';\nEND;" ).arg(a: procedureName)); | 
| 2152 |     q.exec(query: QString("EXECUTE PROCEDURE %1" ).arg(a: procedureName)); | 
| 2153 |     QSignalSpy spy(driver, QOverload<const QString &, QSqlDriver::NotificationSource, const QVariant &>::of(ptr: &QSqlDriver::notification)); | 
| 2154 |     db.commit();        // No notifications are posted until the transaction is committed. | 
| 2155 |     // Interbase needs some time to post the notification and call the driver callback. | 
| 2156 |     // This happends from another thread, and we have to process events in order for the | 
| 2157 |     // event handler in the driver to be executed and emit the notification signal. | 
| 2158 |     QTRY_COMPARE(spy.count(), 1); | 
| 2159 |     QList<QVariant> arguments = spy.takeFirst(); | 
| 2160 |     QCOMPARE(arguments.at(0).toString(), procedureName); | 
| 2161 |     QVERIFY_SQL(*driver, unsubscribeFromNotification(procedureName)); | 
| 2162 |     q.exec(query: QString("DROP PROCEDURE %1" ).arg(a: procedureName)); | 
| 2163 | } | 
| 2164 |  | 
| 2165 | void tst_QSqlDatabase::eventNotificationPSQL() | 
| 2166 | { | 
| 2167 |     QFETCH(QString, dbName); | 
| 2168 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 2169 |     if (db.driverName().compare(other: QLatin1String("QPSQL" ), cs: Qt::CaseInsensitive)) | 
| 2170 |         QSKIP("QPSQL specific test" ); | 
| 2171 |     CHECK_DATABASE(db); | 
| 2172 |  | 
| 2173 |     QSqlQuery query(db); | 
| 2174 |     const auto procedureName = qTableName(prefix: "posteventProc" , __FILE__, db, escape: false); | 
| 2175 |     QString payload = "payload" ; | 
| 2176 |     QSqlDriver *driver = db.driver(); | 
| 2177 |     QVERIFY_SQL(*driver, subscribeToNotification(procedureName)); | 
| 2178 |     QSignalSpy spy(driver, QOverload<const QString &, QSqlDriver::NotificationSource, const QVariant &>::of(ptr: &QSqlDriver::notification)); | 
| 2179 |     query.exec(query: QString("NOTIFY \"%1\", '%2'" ).arg(a: procedureName).arg(a: payload)); | 
| 2180 |     QTRY_COMPARE(spy.count(), 1); | 
| 2181 |     QList<QVariant> arguments = spy.takeFirst(); | 
| 2182 |     QCOMPARE(arguments.at(0).toString(), procedureName); | 
| 2183 |     QCOMPARE(qvariant_cast<QSqlDriver::NotificationSource>(arguments.at(1)), QSqlDriver::SelfSource); | 
| 2184 |     QCOMPARE(qvariant_cast<QVariant>(arguments.at(2)).toString(), payload); | 
| 2185 |     QVERIFY_SQL(*driver, unsubscribeFromNotification(procedureName)); | 
| 2186 | } | 
| 2187 |  | 
| 2188 | void tst_QSqlDatabase::eventNotificationSQLite() | 
| 2189 | { | 
| 2190 |     QFETCH(QString, dbName); | 
| 2191 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 2192 |     if (db.driverName().compare(other: QLatin1String("QSQLITE" ), cs: Qt::CaseInsensitive)) | 
| 2193 |         QSKIP("QSQLITE specific test" ); | 
| 2194 |     CHECK_DATABASE(db); | 
| 2195 |  | 
| 2196 |     const QString tableName(qTableName(prefix: "sqlitnotifytest" , __FILE__, db)); | 
| 2197 |     const auto noEscapeTableName(qTableName(prefix: "sqlitnotifytest" , __FILE__, db, escape: false)); | 
| 2198 |     tst_Databases::safeDropTable(db, tableName); | 
| 2199 |  | 
| 2200 |     QSqlDriver *driver = db.driver(); | 
| 2201 |     QSignalSpy spy(driver, QOverload<const QString &, QSqlDriver::NotificationSource, const QVariant &>::of(ptr: &QSqlDriver::notification)); | 
| 2202 |     QSqlQuery q(db); | 
| 2203 |     QVERIFY_SQL(q, exec("CREATE TABLE "  + tableName + " (id INTEGER, realVal REAL)" )); | 
| 2204 |     driver->subscribeToNotification(name: noEscapeTableName); | 
| 2205 |     QVERIFY_SQL(q, exec("INSERT INTO "  + tableName + " (id, realVal) VALUES (1, 2.3)" )); | 
| 2206 |     QTRY_COMPARE(spy.count(), 1); | 
| 2207 |     QList<QVariant> arguments = spy.takeFirst(); | 
| 2208 |     QCOMPARE(arguments.at(0).toString(), noEscapeTableName); | 
| 2209 |     driver->unsubscribeFromNotification(name: noEscapeTableName); | 
| 2210 |     QVERIFY_SQL(q, exec("INSERT INTO "  + tableName + " (id, realVal) VALUES (1, 2.3)" )); | 
| 2211 |     QTRY_COMPARE(spy.count(), 0); | 
| 2212 | } | 
| 2213 |  | 
| 2214 | void tst_QSqlDatabase::sqlite_bindAndFetchUInt() | 
| 2215 | { | 
| 2216 |     QFETCH(QString, dbName); | 
| 2217 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 2218 |     CHECK_DATABASE(db); | 
| 2219 |     if (db.driverName().startsWith(s: "QSQLITE2" )) | 
| 2220 |         QSKIP("SQLite3 specific test" ); | 
| 2221 |  | 
| 2222 |     QSqlQuery q(db); | 
| 2223 |     const QString tableName(qTableName(prefix: "uint_test" , __FILE__, db)); | 
| 2224 |     QVERIFY_SQL(q, exec(QString("CREATE TABLE %1(uint_field UNSIGNED INTEGER)" ).arg(tableName))); | 
| 2225 |     QVERIFY_SQL(q, prepare(QString("INSERT INTO %1 VALUES(?)" ).arg(tableName))); | 
| 2226 |     q.addBindValue(val: 4000000000U); | 
| 2227 |     QVERIFY_SQL(q, exec()); | 
| 2228 |     QVERIFY_SQL(q, exec(QString("SELECT uint_field FROM %1" ).arg(tableName))); | 
| 2229 |     QVERIFY_SQL(q, next()); | 
| 2230 |  | 
| 2231 |     // All integers in SQLite are signed, so even though we bound the value | 
| 2232 |     // as an UInt it will come back as a LongLong | 
| 2233 |     QCOMPARE(q.value(0).type(), QVariant::LongLong); | 
| 2234 |     QCOMPARE(q.value(0).toUInt(), 4000000000U); | 
| 2235 | } | 
| 2236 |  | 
| 2237 | void tst_QSqlDatabase::db2_valueCacheUpdate() | 
| 2238 | { | 
| 2239 |     QFETCH(QString, dbName); | 
| 2240 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 2241 |     CHECK_DATABASE(db); | 
| 2242 |  | 
| 2243 |     const QString tableName(qTableName(prefix: "qtest" , __FILE__, db)); | 
| 2244 |     QSqlQuery q(db); | 
| 2245 |     q.exec(query: QString("SELECT id, t_varchar, t_char, t_numeric FROM %1" ).arg(a: tableName)); | 
| 2246 |     q.next(); | 
| 2247 |     QVariant c4 = q.value(i: 3); | 
| 2248 |     QVariant c3 = q.value(i: 2); | 
| 2249 |     QVariant c2 = q.value(i: 1); | 
| 2250 |     QVariant c1 = q.value(i: 0); | 
| 2251 |     QCOMPARE(c4.toString(), q.value(3).toString()); | 
| 2252 |     QCOMPARE(c3.toString(), q.value(2).toString()); | 
| 2253 |     QCOMPARE(c2.toString(), q.value(1).toString()); | 
| 2254 |     QCOMPARE(c1.toString(), q.value(0).toString()); | 
| 2255 | } | 
| 2256 |  | 
| 2257 | void tst_QSqlDatabase::sqlStatementUseIsNull_189093() | 
| 2258 | { | 
| 2259 |     // NULL = NULL is unknown, the sqlStatment must use IS NULL | 
| 2260 |     QFETCH(QString, dbName); | 
| 2261 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 2262 |     CHECK_DATABASE(db); | 
| 2263 |  | 
| 2264 |     // select a record with NULL value | 
| 2265 |     QSqlQuery q(QString(), db); | 
| 2266 |     QVERIFY_SQL(q, exec("select * from "  + qTableName("qtest" , __FILE__, db) + " where id = 4" )); | 
| 2267 |     QVERIFY_SQL(q, next()); | 
| 2268 |  | 
| 2269 |     QSqlDriver *driver = db.driver(); | 
| 2270 |     QVERIFY(driver); | 
| 2271 |  | 
| 2272 |     QString preparedStatment = driver->sqlStatement(type: QSqlDriver::WhereStatement, tableName: QString("qtest" ), rec: q.record(), preparedStatement: true); | 
| 2273 |     QCOMPARE(preparedStatment.count("IS NULL" , Qt::CaseInsensitive), 2); | 
| 2274 |  | 
| 2275 |     QString statment = driver->sqlStatement(type: QSqlDriver::WhereStatement, tableName: QString("qtest" ), rec: q.record(), preparedStatement: false); | 
| 2276 |     QCOMPARE(statment.count("IS NULL" , Qt::CaseInsensitive), 2); | 
| 2277 | } | 
| 2278 |  | 
| 2279 | void tst_QSqlDatabase::mysql_savepointtest() | 
| 2280 | { | 
| 2281 |     QFETCH(QString, dbName); | 
| 2282 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 2283 |     CHECK_DATABASE(db); | 
| 2284 |     QSqlQuery q(db); | 
| 2285 |     QVERIFY_SQL(q, exec("begin" )); | 
| 2286 |     QVERIFY_SQL(q, exec("insert into "  + qTableName("qtest" , __FILE__, db) + " VALUES (54, 'foo', 'foo', 54.54)" )); | 
| 2287 |     QVERIFY_SQL(q, exec("savepoint foo" )); | 
| 2288 | } | 
| 2289 |  | 
| 2290 | void tst_QSqlDatabase::mysql_connectWithInvalidAddress() | 
| 2291 | { | 
| 2292 |     // Ensure that giving invalid connection parameters fails correctly | 
| 2293 |     QSqlDatabase db = QSqlDatabase::addDatabase(type: "QMYSQL" ); | 
| 2294 |     db.setHostName("invalid.local" ); | 
| 2295 |     QCOMPARE(db.open(), false); | 
| 2296 | } | 
| 2297 |  | 
| 2298 | void tst_QSqlDatabase::oci_tables() | 
| 2299 | { | 
| 2300 |     QSKIP("Requires specific permissions to create a system table" ); | 
| 2301 |     QFETCH(QString, dbName); | 
| 2302 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 2303 |     CHECK_DATABASE(db); | 
| 2304 |     QSqlQuery q(db); | 
| 2305 |     const QString systemTableName("sys."  + qTableName(prefix: "mypassword" , __FILE__, db).toUpper()); | 
| 2306 |     QVERIFY_SQL(q, exec("CREATE TABLE " +systemTableName+"(name VARCHAR(20))" )); | 
| 2307 |     QVERIFY(!db.tables().contains(systemTableName.toUpper())); | 
| 2308 |     QVERIFY(db.tables(QSql::SystemTables).contains(systemTableName.toUpper())); | 
| 2309 | } | 
| 2310 |  | 
| 2311 | void tst_QSqlDatabase::sqlite_enable_cache_mode() | 
| 2312 | { | 
| 2313 |     QFETCH(QString, dbName); | 
| 2314 |     if(dbName.endsWith(s: ":memory:" )) | 
| 2315 |         QSKIP( "cache mode is meaningless for :memory: databases" ); | 
| 2316 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 2317 |     CHECK_DATABASE(db); | 
| 2318 |     db.close(); | 
| 2319 |     db.setConnectOptions("QSQLITE_ENABLE_SHARED_CACHE" ); | 
| 2320 |     QVERIFY_SQL(db, open()); | 
| 2321 |     QSqlDatabase db2 = QSqlDatabase::cloneDatabase(other: db, connectionName: dbName+":cachemodeconn2" ); | 
| 2322 |     db2.setConnectOptions("QSQLITE_ENABLE_SHARED_CACHE" ); | 
| 2323 |     QVERIFY_SQL(db2, open()); | 
| 2324 |     QSqlQuery q(db), q2(db2); | 
| 2325 |     QVERIFY_SQL(q, exec("select * from "  + qTableName("qtest" , __FILE__, db))); | 
| 2326 |     QVERIFY_SQL(q2, exec("select * from "  + qTableName("qtest" , __FILE__, db))); | 
| 2327 |     db2.close(); | 
| 2328 | } | 
| 2329 |  | 
| 2330 | void tst_QSqlDatabase::sqlite_enableRegexp() | 
| 2331 | { | 
| 2332 |     QFETCH(QString, dbName); | 
| 2333 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 2334 |     CHECK_DATABASE(db); | 
| 2335 |     if (db.driverName().startsWith(s: "QSQLITE2" )) | 
| 2336 |         QSKIP("SQLite3 specific test" ); | 
| 2337 |  | 
| 2338 |     db.close(); | 
| 2339 |     db.setConnectOptions("QSQLITE_ENABLE_REGEXP" ); | 
| 2340 |     QVERIFY_SQL(db, open()); | 
| 2341 |  | 
| 2342 |     QSqlQuery q(db); | 
| 2343 |     const QString tableName(qTableName(prefix: "regexp_test" , __FILE__, db)); | 
| 2344 |     QVERIFY_SQL(q, exec(QString("CREATE TABLE %1(text TEXT)" ).arg(tableName))); | 
| 2345 |     QVERIFY_SQL(q, prepare(QString("INSERT INTO %1 VALUES(?)" ).arg(tableName))); | 
| 2346 |     q.addBindValue(val: "a0" ); | 
| 2347 |     QVERIFY_SQL(q, exec()); | 
| 2348 |     q.addBindValue(val: "a1" ); | 
| 2349 |     QVERIFY_SQL(q, exec()); | 
| 2350 |  | 
| 2351 |     QVERIFY_SQL(q, exec(QString("SELECT text FROM %1 WHERE text REGEXP 'a[^0]' "  | 
| 2352 |                                 "ORDER BY text" ).arg(tableName))); | 
| 2353 |     QVERIFY_SQL(q, next()); | 
| 2354 |     QCOMPARE(q.value(0).toString(), QString("a1" )); | 
| 2355 |     QFAIL_SQL(q, next()); | 
| 2356 | } | 
| 2357 |  | 
| 2358 | void tst_QSqlDatabase::sqlite_openError() | 
| 2359 | { | 
| 2360 |     // see QTBUG-70506 | 
| 2361 |     if (!QSqlDatabase::drivers().contains(str: "QSQLITE" )) | 
| 2362 |         QSKIP("Database driver QSQLITE not available" ); | 
| 2363 |  | 
| 2364 |     QSqlDatabase db = QSqlDatabase::addDatabase(type: "QSQLITE" , connectionName: "sqlite_openError" ); | 
| 2365 |     db.setDatabaseName("/doesnotexist/foo.sqlite" ); | 
| 2366 |     QVERIFY(db.isValid()); | 
| 2367 |  | 
| 2368 |     QVERIFY(!db.open()); | 
| 2369 |     QSqlError error = db.lastError(); | 
| 2370 |     QCOMPARE(error.nativeErrorCode(), "14" );  // SQLITE_CANTOPEN | 
| 2371 |     QCOMPARE(error.databaseText(), "unable to open database file" ); | 
| 2372 | } | 
| 2373 |  | 
| 2374 | void tst_QSqlDatabase::sqlite_check_json1() | 
| 2375 | { | 
| 2376 |     QFETCH(QString, dbName); | 
| 2377 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 2378 |     CHECK_DATABASE(db); | 
| 2379 |     const QSqlDriver::DbmsType dbType = tst_Databases::getDatabaseType(db); | 
| 2380 |     if (dbType != QSqlDriver::SQLite) | 
| 2381 |         QSKIP("SQLite3 specific test" ); | 
| 2382 |  | 
| 2383 |     QSqlQuery q(db); | 
| 2384 |     const QString json1("{\"id\":1}" ); | 
| 2385 |     const QString tableName(qTableName(prefix: "sqlite_check_json1" , __FILE__, db)); | 
| 2386 |     tst_Databases::safeDropTable(db, tableName); | 
| 2387 |     QVERIFY_SQL(q, exec(QString("CREATE TABLE %1(text TEXT)" ).arg(tableName))); | 
| 2388 |     QVERIFY_SQL(q, exec(QString("INSERT INTO %1 VALUES(json('%2'))" ).arg(tableName, json1))); | 
| 2389 |     QVERIFY_SQL(q, prepare(QString("INSERT INTO %1 VALUES(?)" ).arg(tableName))); | 
| 2390 |     q.addBindValue(val: "json('{\"id\":2}')" ); | 
| 2391 |     QVERIFY_SQL(q, prepare(QString("SELECT * from %1 WHERE text = json('%2')" ).arg(tableName, json1))); | 
| 2392 |     QVERIFY_SQL(q, exec()); | 
| 2393 |     QVERIFY_SQL(q, next()); | 
| 2394 |     QCOMPARE(q.value(0).toString(), json1); | 
| 2395 |     QFAIL_SQL(q, next()); | 
| 2396 | } | 
| 2397 |  | 
| 2398 | void tst_QSqlDatabase::cloneDatabase() | 
| 2399 | { | 
| 2400 |     QFETCH(QString, dbName); | 
| 2401 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 2402 |     CHECK_DATABASE(db); | 
| 2403 |     { | 
| 2404 |         QSqlDatabase clonedDatabase = QSqlDatabase::cloneDatabase(other: db, connectionName: "clonedDatabase" ); | 
| 2405 |         QCOMPARE(clonedDatabase.databaseName(), db.databaseName()); | 
| 2406 |         QCOMPARE(clonedDatabase.userName(), db.userName()); | 
| 2407 |         QCOMPARE(clonedDatabase.password(), db.password()); | 
| 2408 |         QCOMPARE(clonedDatabase.hostName(), db.hostName()); | 
| 2409 |         QCOMPARE(clonedDatabase.driverName(), db.driverName()); | 
| 2410 |         QCOMPARE(clonedDatabase.port(), db.port()); | 
| 2411 |         QCOMPARE(clonedDatabase.connectOptions(), db.connectOptions()); | 
| 2412 |         QCOMPARE(clonedDatabase.numericalPrecisionPolicy(), db.numericalPrecisionPolicy()); | 
| 2413 |     } | 
| 2414 |     { | 
| 2415 |         // Now double check numericalPrecisionPolicy after changing it since it | 
| 2416 |         // is a special case, as changing it can set it on the driver as well as | 
| 2417 |         // the database object. When retrieving the numerical precision policy | 
| 2418 |         // it may just get it from the driver so we have to check that the | 
| 2419 |         // clone has also ensured the copied driver has the correct precision | 
| 2420 |         // policy too. | 
| 2421 |         db.setNumericalPrecisionPolicy(QSql::LowPrecisionDouble); | 
| 2422 |         QSqlDatabase clonedDatabase = QSqlDatabase::cloneDatabase(other: db, connectionName: "clonedDatabaseCopy" ); | 
| 2423 |         QCOMPARE(clonedDatabase.numericalPrecisionPolicy(), db.numericalPrecisionPolicy()); | 
| 2424 |     } | 
| 2425 | } | 
| 2426 |  | 
| 2427 | class DatabaseThreadObject : public QObject | 
| 2428 | { | 
| 2429 |     Q_OBJECT | 
| 2430 | public: | 
| 2431 |     DatabaseThreadObject(const QString &name, QObject *parent = nullptr) : QObject(parent), dbName(name) | 
| 2432 |     {} | 
| 2433 | public slots: | 
| 2434 |     void ready() | 
| 2435 |     { | 
| 2436 |         QTest::ignoreMessage(type: QtWarningMsg, | 
| 2437 |             message: "QSqlDatabasePrivate::database: requested database does not belong to the calling thread." ); | 
| 2438 |         QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 2439 |         QVERIFY(!db.isValid()); | 
| 2440 |  | 
| 2441 |         QSqlDatabase invalidDb = QSqlDatabase::database(connectionName: "invalid" ); | 
| 2442 |         QVERIFY(!invalidDb.isValid()); | 
| 2443 |  | 
| 2444 |         { | 
| 2445 |             QSqlDatabase clonedDatabase = QSqlDatabase::cloneDatabase(other: dbName, connectionName: "CloneDB" ); | 
| 2446 |             QVERIFY(!clonedDatabase.isOpen()); | 
| 2447 |             QVERIFY(clonedDatabase.isValid()); | 
| 2448 |             QVERIFY(clonedDatabase.open()); | 
| 2449 |             QVERIFY(clonedDatabase.isOpen()); | 
| 2450 |             clonedDatabase.close(); | 
| 2451 |         } | 
| 2452 |  | 
| 2453 |         QThread::currentThread()->exit(); | 
| 2454 |     } | 
| 2455 | private: | 
| 2456 |     QString dbName; | 
| 2457 | }; | 
| 2458 |  | 
| 2459 | void tst_QSqlDatabase::multipleThreads() | 
| 2460 | { | 
| 2461 |     QFETCH(QString, dbName); | 
| 2462 |     QSqlDatabase db = QSqlDatabase::database(connectionName: dbName); | 
| 2463 |     CHECK_DATABASE(db); | 
| 2464 |     DatabaseThreadObject dto(dbName); | 
| 2465 |     QThread t; | 
| 2466 |     dto.moveToThread(thread: &t); | 
| 2467 |     connect(sender: &t, signal: &QThread::started, receiver: &dto, slot: &DatabaseThreadObject::ready); | 
| 2468 |     t.start(); | 
| 2469 |     QTRY_VERIFY(t.isRunning()); | 
| 2470 |     QTRY_VERIFY(t.isFinished()); | 
| 2471 | } | 
| 2472 |  | 
| 2473 | QTEST_MAIN(tst_QSqlDatabase) | 
| 2474 | #include "tst_qsqldatabase.moc" | 
| 2475 |  |